3

Our Webpack bundle contains placeholders for the dynamic import of icons. An example dynamic import is as follows:

const { icon: iconName } = this.props;
const faIconName = `fa${iconName.replace(/./, c => c.toUpperCase())}`;

import(
  /* webpackInclude: /\.js$/ */
  `@fortawesome/pro-light-svg-icons/${faIconName}`
).then(faIcon => {
  if (this.mounted) {
    this.setState({ faIcon });
  }
});

We decided for this strategy in order to prevent Webpack from bundling up the whole collection of FontAwesome icons.

Most recently we've realised the need to have internal builds where the dynamic import does not occur and pay the price of the larger bundle. The following code has been placed in our icon code (alongside the dynamic import above):

const faIconName = `fa${iconName.replace(/./, c => c.toUpperCase())}`;
let faIcon;
try {
  faIcon = require(`@fortawesome/pro-light-svg-icons/${faIconName}.js`)[faIconName];
} catch (e) {}

Both loading strategies work fine when used one at a time. The issue comes when they coexist in the icon component.

I have verified that the import instruction leads Webpack to create in the bundle what to me seems a synthetic JS file generated with the command:

webpack:/// ./node_modules/@fortawesome/pro-light-svg-icons lazy ^\.\/.*$ include: \.js$ namespace object

When both import and require instructions are present in the Icon component, the synthetic file is different from when the sole import is encountered.

In detail, the object called map in the synthetic file contains values that are arrays with 3 elements in the import case and with 2 elements in the import+require case; the synthetic code tries to access the third element and everything crashes.

Can anyone comment on this issue?

Marco Faustinelli
  • 3,734
  • 5
  • 30
  • 49
  • Looks like over engineering, font-awesome 5 supports tree shaking out of the box, https://fontawesome.com/how-to-use/with-the-api/other/tree-shaking – felixmosh May 29 '19 at 15:20
  • Not at all. We are 100% happy with the dynamic bundle and we'd never want to specify in the imports exactly which icons we need. Your solution would impose to update somewhere the list of icons to import based on any new changes in the code. Moreover, since we request quite a lot of different icons, the initial bundle would be still too heavy for a fast load. Dynamic import is the way to go; too bad that it coexists poorly with static import. – Marco Faustinelli May 29 '19 at 15:30

1 Answers1

1

I found an answer, you may check my full answer here To make long story short i imported basing on the list and put all the imported components to Component's state. Afterwards i've created the React.createElememt's from the stored imported components and pulled all of them to Render

componentDidMount = () => {
//we get elements list from any source to redux-store
        this.props.getForms();
//access redux-store to the list
        const forms = this.props.configBody.sets;
//make deep object copy
        const updatedState = { ...this.state };
        updatedState.modules = [];
        if (forms) {
//here is the very dynamic import magic: we map the import list and prepare to store the imports in Component`s state
            const importPromises = forms.map(p =>
                import(`../TemplateOrders/Template${p.order}`)
                    .then(module => {
                        updatedState.modules.push(module.default)
                    })
                    .catch(errorHandler(p))
            )
//wait till all imports are getting resolved
            Promise.all(importPromises)
                .then(res =>
//then run setState
                    this.setState({ ...updatedState }, () => {
                        console.log(this.state);
                    }))
        }
    }
Alexey Nikonov
  • 4,958
  • 5
  • 39
  • 66