webpack多文件入口配置
问题
公司项目是基于vue的中后台管理类型的系统,同时在系统中还有一个H5页面用于在移动端查看信息。
所以项目中需要混杂pc端和移动端代码,考虑到pc端依赖很多,为防止移动端的包也包含这些移动端依赖,故选择了分成两个项目开发。
在项目即将完成时,开发任务不是很多,苦于两个项目切换着开发确实很难受,于是萌生了将两个项目合并为一个项目的想法。
目标
但是合并时,我们需要考虑几个问题:
-
一次启动,h5和pc端都可以正常访问开发
-
移动端包体积不能受到pc端包依赖影响
-
一次打包可打出移动端和pc端两个包
基于以上几个问题,我想到了webpack的多入口打包特性,于是经过大概一天的探索,最终完美将两端代码合并在一个项目中。
实践
公司的项目是基于vue-cli创建的webpack3的模板开发的,webpack配置文件如下,想必大家都已经非常清楚了。
配置多文件入口的第一步是修改webpack的entry
字段,在webpack.base.conf.js
文件中:
module.exports = {
context: path.resolve(__dirname, '../'),
// 这里就是webpack的入口文件
entry: {
app: './src/main.js',
},
output: {
path: config.build.assetsRoot,
filename: '[name].js',
publicPath: process.env.NODE_ENV === 'production'
? config.build.assetsPublicPath
: config.dev.assetsPublicPath
},
module: {},
plugins: [],
devServer:{}
}
首先在项目根目录下创建src-h5
,与src
目录齐平,其中放入移动端代码(其实就是另一个src),附图如下:
之后将移动端的入口文件加入到webpack的入口文件配置处,如下所示:
module.exports = {
// 这里就是webpack的入口文件
entry: {
app: './src/main.js',
h5: './src-h5/main.js'
},
output: {},
module: {},
plugins: [],
devServer:{}
}
入口文件配置好了,那如何打包出不同的html页面呢,这里就需要HtmlWebpackPlugin
这个插件的帮助了,HtmlWebpackPlugin
这个插件,new
一个,就打包一个 HTML 页面,所以我们在 plugins
配置里 new
两个,就能打包出两个页面来。
有了以上的知识,我们打开webpack.dev.conf.js
文件,在其中找到plugins
选项,如下所示:
modules.exports = {
plugins:[
...
new HtmlWebpackPlugin({
filename: 'index.html',
template: 'index.html',
// 是否将生成的静态资源插入模板中
inject: true
}),
...
]
}
其上代码只会生成一个index.html
文件,依照前面说的我们来修改下这个配置,生成一个index-h5.html
文件,如下修改:
modules.exports = {
plugins:[
...
new HtmlWebpackPlugin({
filename: 'index.html',
template: 'index.html',
// 是否将生成的静态资源插入模板中
inject: true,
// 输出的html文件引入的入口chunk
chunks: ['manifest', 'vendor', 'app']
}),
new HtmlWebpackPlugin({
filename: 'index-h5.html',
template: 'index-h5.html',
// 是否将生成的静态资源插入模板中
inject: true,
// 输出的html文件引入的入口chunk
chunks: ['manifest', 'vendor', 'h5']
}),
...
]
}
如上配置,配置中需要注意的配置项是chunks
,此配置项表示的是生成的html文件需要引入的chunk
名称,如果不配置该字段的话,那么在生成的两个html文件中会把所有的chunk都引入,导致路由错乱问题。
大家可以看到除了我们打包生成的 chunk
文件 app.js
和 h5.js
之外,还有 manifest
和 vendor
这两个,这里稍微解释一下这两个 chunk
:
1.vendor
是指提取涉及 node_modules
中的公共模块;
2.manifest
是对 vendor
模块做的缓存;
需要注意一点,在module的rules字段解析js文件的配置中加入resolve('src-h5')
代码,转换其中的es6代码。
module: {
rules: [
{
test: /\.js$/,
loader: 'babel-loader',
include: [resolve('src'), resolve('src-h5'),resolve('test'), resolve('node_modules/webpack-dev-server/client')]
}
]
}
配置完成后,运行npm run dev
启动代码,浏览器输入http://localhost:8080/
可以正常访问pc端项目,输入http://localhost:8080/index-h5.html/
可以访问移动端项目。
ok!大功告成。
打包试试~~
打包一看,大跌眼镜。
打包出来的移动端包将pc端的依赖文件都打包进来了,这使得原本功能很少的移动端,现在变得异常臃肿,而且加载缓慢,这并不是我们想要的,那如何解决呢?
当然是让移动端的包只包含移动端的依赖。
想要分包,就得依赖webpack的CommonsChunkPlugin
插件,该插件就是用来提取项目的公共依赖的,也是生成vendor
和manifest
文件的家伙。
所以,我们来到webpack.prod.conf.js
文件,其中配置如下:
module.exports = {
plugins:[
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
minChunks (module) {
// any required modules inside node_modules are extracted to vendor
return (
module.resource &&
/\.js$/.test(module.resource) &&
module.resource.indexOf(
path.join(__dirname, '../node_modules')
) === 0
)
}
}),
]
}
CommonsChunkPlugin可配置的属性如下:
-
name
:可以是已经存在的chunk(一般指入口文件)对应的name,那么就会把公共模块代码合并到这个chunk上;否则,会创建名字为name的commons chunk进行合并 -
filename
:指定commons chunk的文件名 -
chunks
:指定source chunk,即指定从哪些chunk当中去找公共模块,省略该选项的时候,默认就是entry chunks -
minChunks
:既可以是数字,也可以是函数,还可以是Infinity,具体用法和区别下面会说
注意加粗的配置项chunks
,他表示当前抽离的公共配置是从哪个入口去找的,现在我们的项目是多入口,我们只需要告诉webpack哪些依赖需要从PC端入口去查找,那些依赖需要从移动端入口去查找,并生成对应的vendor文件,这样就能将移动端和pc端依赖分开,按需引入。修改配置如下:
modules.exports = {
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
minChunks (module) {
return (
module.resource &&
/\.js$/.test(module.resource) &&
module.resource.indexOf(
path.join(__dirname, '../node_modules')
) === 0
)
},
// 设置公共包入口来源为app
chunks:['app']
}),
new webpack.optimize.CommonsChunkPlugin({
name: 'h5-vendor',
minChunks (module) {
return (
module.resource &&
/\.js$/.test(module.resource) &&
module.resource.indexOf(
path.join(__dirname, '../node_modules')
) === 0
)
},
// 设置公共包入口来源为h5
chunks:['h5']
}),
]
}
注意这里我们配置了一个vendor.js和h5-vendor.js文件,chunks分别配置为app和h5,依照上面的介绍,这里的vendor.js文件中提取的公共模块是app入口的公共依赖,而h5-vendor.js文件中提取的公共模块是h5入口的公共依赖,这样我们就将移动端和pc端的依赖分开了。
提取出了各自的公共模块,我们也需要在html中引入,配置HtmlWebpackPlugin
插件如下:
modules.exports = {
plugins: [
new HtmlWebpackPlugin({
filename: process.env.NODE_ENV === 'testing'
? 'index.html'
: config.build.index,
template: 'index.html',
inject: true,
minify: {
removeComments: true,
collapseWhitespace: true,
removeAttributeQuotes: true
},
chunksSortMode: 'dependency',
chunks: ['manifest', 'vendor', 'app'] // 注意引入vendor
}),
new HtmlWebpackPlugin({
filename: 'index-h5.html',
template: 'index-h5.html',
inject: true,
minify: {
removeComments: true,
collapseWhitespace: true,
removeAttributeQuotes: true
},
chunksSortMode: 'dependency',
chunks: ['manifest', 'h5-vendor', 'h5'] // 引入移动端依赖vendor
}),
]
}
再次尝试打包,这次真的是大功告成了,pc端和移动端的依赖各自打包到各自的vendor文件中,移动端首屏加载页快了,又可以愉快的摸鱼了~~~~
转载自:https://juejin.cn/post/6968722488666619935