在 Webpack 4 中,我们可以使用 import() 令牌动态生成页面块,以便我们可以将反应组件转换为可反应加载的组件吗?

In Webpack 4, can we dynamically generate page chunk with import() token so we can turn a react component into a react-loadable one?

我们使用react和react-loadable

在我们的应用程序初始化期间,我们正在验证 component.preload 方法对于我们定义的每个 <Route /> 是否存在。

如果该方法丢失,我们会显示一条警告,表明该组件应该是可加载的。

我们使用webpack 4,有没有办法自动包装组件,这样我们就不用手动了?

这是组件的样子:

/** MyComponent.js: page component */
export default () => <div>Hello world</div>;

这是包装在 react-loadable 组件中的同一个组件:

/**
 * preconfigured react-loadable 
 * See https://github.com/jamiebuilds/react-loadable#how-do-i-avoid-repetition)
 */
import MyLoadable from '@scopped/react-loadable';

/** loadable component */
export default MyLoadable({
  loader: () => import('./MyComponent'), /** import page component */
});
  1. 我们的 <Route />node_modules 中声明并且来自不同的包。
  2. 可以使用 <Resource /> (from react-admin) 而不是 <Route />
  3. 来声明
  4. 它们不是以 ESM 格式分发的,而是 CJS (CommonJS)。

我不确定这是正确的方法,但也许你可以编写某种 webpack 加载器来预处理你的文件,在你的文件中找到 <Route /> 模式,确定文件的路径他们呈现的组件并将它们转换为具有该信息的可加载组件。

这有点 hacky,但它应该可以工作(仅适用于导入,但您可以根据需要调整它以满足您的要求):

Webpack 配置:

{
  test: /\.js$/,
  exclude: /node_modules/,
  use: {
    loader: [
      "babel-loader", // Rest of your loaders
      path.resolve(__dirname, 'path/to/your/loader.js')
    ]
  }
}

loader.js:

module.exports = function (source) {
  const routeRegex = new RegExp(/<Route.*component={(.*)}.*\/>/g);
  let matches;
  let components = [];

  while (matches = routeRegex.exec(source)) {
    components.push(matches[1]); // Get all the component import names
  }

  // Replace all import lines by a MyLoadable lines
  components.forEach((component) => {
    const importRegex = new RegExp(`import ${component} from '(.*)'`);
    const path = importRegex.exec(source)[1];

    source = source.replace(importRegex, `
      const ${component} = MyLoadable({
        loader: () => import('${path}')
      });
    `);
  });

  source = `
    import MyLoadable from './MyLoadable';
    ${source}
  `;

  return source;
};

这绝对是 hacky,但如果您坚持惯例,这可能会奏效。它转换这种文件:

import Page1 from './Page1';
import Page2 from './Page2';

export default () => (
  <Switch>
    <Route path='/page1' component={Page1} />
    <Route path='/page2' component={Page2} />
  </Switch>
);

进入此文件:

import MyLoadable from './MyLoadable;

const Page1 = MyLoadable({
  loader: () => import('./Page1')
});

const Page2 = MyLoadable({
  loader: () => import('./Page2')
});

export default () => (
  <Switch>
    <Route path='/page1' component={Page1} />
    <Route path='/page2' component={Page2} />
  </Switch>
);

这个例子有一些问题(到MyLoadable的路径应该是绝对路径,它只在导入页面组件时有效,可加载组件不在单独的文件中,这可能导致重复,... ) 但你明白了