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

Posted

技术标签:

【中文标题】在 Webpack 4 中,我们可以使用 import() 令牌动态生成页面块,以便我们可以将 react 组件转换为 react-loadable 吗?【英文标题】:In Webpack 4, can we dynamically generate page chunk with import() token so we can turn a react component into a react-loadable one? 【发布时间】:2019-07-18 17:28:45 【问题描述】:

我们使用 react 和 react-loadable。

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

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

我们使用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 */
);
    我们的&lt;Route /&gt;node_modules 中声明,并且来自不同的包。 可以使用&lt;Resource /&gt;(来自react-admin)而不是&lt;Route /&gt;来声明 它们不以 ESM 格式分发,而仅以 CJS (CommonJS) 格式分发。

【问题讨论】:

你可以编写自己的 webpack 加载器。我不知道有任何现有的可以帮助解决这个问题。 webpack.js.org/contribute/writing-a-loader 【参考方案1】:

我不确定这是不是正确的方法,但也许你可以编写某种 webpack 加载器来预处理你的文件,在你的文件中找到 &lt;Route /&gt; 模式,识别它们渲染的组件的路径并使用该信息将它们转换为可加载的组件。

这有点老套,但它应该可以工作(仅适用于导入,但您可以根据需要对其进行调整):

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 的路径应该是绝对的,它只在页面组件被导入时有效,可加载组件不在单独的文件中,这可能导致重复,...)但是你得到想法

【讨论】:

非常感谢您的回答,我可以看到全局,处理起来有点复杂。像这样解决时我可以更复杂,因为:(1)我们的&lt;Route /&gt;node_modules 中声明,并且来自不同的包。 (2)它使用&lt;Resource /&gt;(来自react-admin),(3)它不是以ESM格式分发的,而是CJS。 (4) 我们希望仅在它不是可加载组件时 这样做。一个优点是我们的MyLoadable 已经在它自己的包中了。

以上是关于在 Webpack 4 中,我们可以使用 import() 令牌动态生成页面块,以便我们可以将 react 组件转换为 react-loadable 吗?的主要内容,如果未能解决你的问题,请参考以下文章

Webpack 4 学习11(用clean-webpack-plugin来清除文件)

webpack教程

webpack 使用教程--实时刷新测试

webpack结合koa实现自动刷新

webpack 4 简单介绍

Webpack 4 学习02(使用配置文件进行打包)