Webpack多入口打包如何将双版本React应用产物输出到独立目录
问题描述
你开发了一款包含两个发布版本的React应用:
- standalone(独立版):包含完整功能
- embedded(嵌入版):移除了部分非必要组件,通过大量懒加载实现大幅体积缩减,构建时会生成较多懒加载JS分片
期望的构建效果为每次执行构建命令时,自动生成两个完全独立的产物目录,两个版本的资源互不干扰可独立部署:
build/standalone:存放独立版应用运行所需的全部JS及静态资源,可直接在任意HTML项目中引入使用build/embedded:存放嵌入版应用运行所需的全部JS及静态资源,可直接在任意HTML项目中引入使用
当前使用的webpack配置存在产物混杂问题:构建后两个入口的主bundle、懒加载分片、抽离的公共包全部堆在build根目录,无法区分不同版本需要引入的对应文件,无法满足独立部署要求。
实现方案
核心需要调整webpack的输出规则、分包策略、html生成逻辑三个部分,修正后的配置如下:
const path = require('path'); const HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = { entry: { standalone: path.resolve(__dirname, '../src/index.standalone.tsx'), embedded: path.resolve(__dirname, '../src/index.embedded.tsx') }, resolve: { extensions: ['.tsx', '.ts', '.js'] }, output: { path: path.resolve(__dirname, '..', './build'), // 主入口bundle输出到对应版本的子目录 filename: '[name]/[name].[contenthash].bundle.js', // 懒加载分片、抽离的公共包输出到对应版本的chunks子目录 chunkFilename: '[name]/chunks/[id].[contenthash].js', // 静态资源输出到对应版本的assets子目录(如果使用asset module处理静态资源) assetModuleFilename: '[name]/assets/[hash][ext][query]', publicPath: './', clean: true // 每次构建前清空旧的build目录 }, optimization: { // 废弃原来的single模式,按入口生成独立runtime文件,避免跨版本共享 runtimeChunk: { name: (entrypoint) => `${entrypoint.name}/runtime` }, splitChunks: { chunks: 'all', // 关闭默认的跨入口公共包抽离规则 cacheGroups: { default: false, defaultVendors: false, // 独立版第三方依赖抽离规则 standaloneVendors: { name: 'standalone/vendors', test: /[\\/]node_modules[\\/]/, chunks: (chunk) => chunk.name === 'standalone', priority: 10 }, // 嵌入版第三方依赖抽离规则 embeddedVendors: { name: 'embedded/vendors', test: /[\\/]node_modules[\\/]/, chunks: (chunk) => chunk.name === 'embedded', priority: 10 }, // 独立版内部公共代码抽离规则 standaloneCommon: { name: 'standalone/common', minChunks: 2, chunks: (chunk) => chunk.name === 'standalone', priority: 5, reuseExistingChunk: true }, // 嵌入版内部公共代码抽离规则 embeddedCommon: { name: 'embedded/common', minChunks: 2, chunks: (chunk) => chunk.name === 'embedded', priority: 5, reuseExistingChunk: true } } } }, plugins: [ // 为独立版生成专属入口html new HtmlWebpackPlugin({ template: path.resolve(__dirname, '..', './public/index.html'), filename: 'standalone/index.html', chunks: ['standalone/runtime', 'standalone/vendors', 'standalone/common', 'standalone'], inject: true }), // 为嵌入版生成专属入口html new HtmlWebpackPlugin({ template: path.resolve(__dirname, '..', './public/index.html'), filename: 'embedded/index.html', chunks: ['embedded/runtime', 'embedded/vendors', 'embedded/common', 'embedded'], inject: true }) ] };
配置说明
- 输出规则调整:给主bundle、懒加载分片、静态资源全部加上入口名
[name]作为路径前缀,所有资源会自动归属到对应版本的子目录下,不会散落在build根目录。 - runtime配置调整:原来的
runtimeChunk: 'single'会生成两个版本共用的runtime文件,导致跨版本依赖,改成按入口生成独立runtime后,每个版本的运行时代码完全独立。 - 分包策略调整:默认的splitChunks规则会跨入口抽离公共依赖,生成不属于任何版本目录的共享文件。关闭默认缓存组后,为两个版本分别配置独立的第三方依赖、公共代码抽离规则,两个版本的分包完全独立,没有共享文件。
- HtmlWebpackPlugin调整:废弃原来的单实例配置,为每个版本单独生成html文件,通过
chunks字段指定每个html只引入对应版本的JS资源,不会出现混引的问题。
构建完成后,build/standalone和build/embedded就是两个完全独立的发布目录,部署时直接取用对应目录的全部资源即可,不需要额外做文件筛选。
内容的提问来源于stack exchange,提问作者Martijn Ebbens
相关产品推荐
相关产品推荐

