如何使用Webpack / SplitChunks插件按目录动态拆分?

时间:2019-01-21 13:20:39

标签: reactjs webpack-4 webpack-splitchunks splitchunksplugin

我正尝试通过以下方式使用splitChunks插件拆分我的React代码(使用create-react-app创建):

我具有以下组件(JSX)结构:

  • 服务
    • serviceA
      • ComponentA1
      • ComponentA2
      • 子文件夹
        • ComponentA3
      • ...
    • serviceB
      • ComponentB1
      • ComponentB2
      • ...
    • serviceC
      • ComponentB1
      • ComponentB2
      • ...
    • ...

并且我想要以下输出(构建):

  • static / js
    • serviceA
      • serviceA.bundle.chunkhash.js
    • serviceB
      • serviceB.bundle.chunkhash.js
    • serviceC
      • serviceC.bundle.chunkhash.js

(其他运行时/主电源位于/ static / js的根目录)

另一个限制是组件使用动态加载

const Component = lazy(() => import(componentPath));
...
<Suspense fallback={..}>Component</suspense>

“ componentPath”是即时确定的(用户单击图标然后打开给定的服务)。

这样做的原因是,我想将每个捆绑包包含在运行后端的单独的Docker映像中。然后,借助应用程序路由,每个Docker映像都可以访问:

static/js/serviceA/  ==> js served by Docker container running service A
static/js/serviceB/  ==> js served by Docker container running service B
static/js/serviceC/  ==> js served by Docker container running service C

到目前为止,我试图:

  • 将output.chunkFilename设置为[name] / [name]。[chunkhash] .js
  • 将webpackChunkName与[name]和[request]一起使用:

    • [name]似乎不起作用(只是将“ [name]”作为目录名的一部分而已)。

    • [请求]展平目录名称:

      serviceA-ComponentA1 serviceA-ComponentA2 serviceA-subFolder-ComponentA3 serviceB-componentB1 serviceB-componentB2 ...

然后我尝试通过以下方式使用splitChunks插件:

  splitChunks: {
    chunks: 'all',
    name: function(module) {
      let serviceName = module.rawRequest ? module.rawRequest : 'default';
      serviceName = serviceName.replace('../', '').replace('./', '');
      serviceName = serviceName.split('/')[0];
      return serviceName;
    },
    cacheGroups: {
      vendors: {
        test: /[\\/]node_modules[\\/]/,
        priority: -10
      },
      default: {
        minChunks: 2,
        priority: -20,
        reuseExistingChunk: true
      },
      serviceA: {
        test: /[\\/]serviceA[\\/]/,
        priority: -10
      },
      serviceB: {
        test: /[\\/]serviceB[\\/]/,
        priority: -10
      },
      serviceC: {
        test: /[\\/]serviceC[\\/]/,
        priority: -10
      },              
    }
  },

由于我的所有服务都在各自的目录中,因此这种方法看起来像在工作。但是我还有一些其他目录,例如数字(可能是捆绑ID),我希望它们会包含在默认目录中。

所以问题是:我的方法正确吗?

1 个答案:

答案 0 :(得分:0)

我不确定以下选项是否适合您。我遇到了类似的问题,我需要在不同的分发包中输出不同的文件夹。

就我而言,我从建议here开始使用全局解决方案。 然后,知道需要为每个所需的输出使用输入数组,就想到了:

const path = require('path');
const glob = require('glob');

const plugins = [...];

module.exports = {
    entry: glob.sync('./src/**/*.js').reduce((acc, item) => {
        const path = item.split('/');
        path.pop();
        const rootFolder = path[2] ? `${path[0]}/${path[2]}` : path[0];
        if (acc[rootFolder]) {
            acc[rootFolder].push(item);
        } else {
            acc[rootFolder] = [item];
        }
        return acc;
    }, {}),
    output: {
        filename: '[name]/main.js',
        path: path.resolve(__dirname, 'dist'),
    },
  module: { ... },
    plugins,
};

这是我的 config 的简化版本,可能会得到改进,但可以满足我的需求。 :)

有关glob库的更多信息:https://github.com/isaacs/node-glob