前言
我们接着上一篇文章react+webpack4.x搭建前端项目之配置抽取和区分环境来进行多页面打包的配置
这里小编推荐一个福利,更多精彩内容请点击链接,点击这里
首先修改src下的代码,项目的结构目录
源码见修改src下代码,添加测试a,b??橥暾?.0.2
开发环境多页面的配置
新建build/module-entry.js
,获取额外打包的??槊腿肟趀ntry配置
const glob = require("glob")
// 获取各个??槊?function getModuleList(){
const moduleList = glob.sync("././src/modules/*");
for(let index = 0 ; index < moduleList.length ; index++){
const item = moduleList[index];
const tmpList = item.split("/");
moduleList[index] = tmpList[tmpList.length-1];
}
return moduleList;
}
// 获取webpack entry
function getBuildEntry(){
const moduleList = getModuleList();
let entry = {};
for(let index in moduleList){
const moduleName = moduleList[index]
entry[moduleName] = "./src/modules/" + moduleName + "/index.js"
}
// 额外添加./src/index的配置(把这个也当做一个页面)
entry["app"] = "./src/index.js"
return entry
}
module.exports = {
getModuleList,
getBuildEntry,
};
然后我们修改webpack.dev.config.js
组装htmlwebpackplugin
多页面模板和输出模板
const { getModuleList , getBuildEntry} = require("./module-entry")
// 获取各个???const moduleList = getModuleList();
const HtmlWebpackPluginList = [];
for(let index in moduleList){
const moduleName = moduleList[index]
HtmlWebpackPluginList.push(new HtmlWebpackPlugin({
filename: utils.resolve('./../dist/'+ moduleName+ '/index.html'), // html模板的生成路径
template: utils.resolve("./../src/modules/" + moduleName + "/index.html"),//html模板
inject: true, // true:默认值,script标签位于html文件的 body 底部
chunks: [moduleName], // 注入哪个名称bundel
}))
}
最后把HtmlWebpackPluginList
放入plugins
属性下,在plugins
数组最后加如下代码
.concat(HtmlWebpackPluginList)
修改entry
属性
entry: getBuildEntry(),
执行npm run dev
浏览器打开http://localhost:8081
,结果如下图
发现怎么是b
页面的内容?
那么是为什么呢?经过排查,打开控制台选择elements
看到如下图
index.html
注入了所有bundle
。a
,b
模块(页面)的bundle
也注入到html
页面中,b
模块的bundle
在最后边,把前边的覆盖了。这就是问题的根源。
这时候我们需要修改webapck.dev.config.js
默认HtmlWebpackPlugin
的实例的参数,新增chunks: ['app']
new HtmlWebpackPlugin({
filename: utils.resolve('./../dist/index.html'), // html模板的生成路径
template: 'index.html',//html模板
chunks: ['app'], // 至注入app和app相关的bundle
inject: true, // true:默认值,script标签位于html文件的 body 底部
}),
这时候重新运行成功解决!
然后我们打开http://localhost:8081/a
,http://localhost:8081/b
页面正常显示。
但是存在一个问题!点击二级路由的时候也可以正常显示,但是我们直接打开或者刷新二级路由的时候(http://localhost:8081/a/test
)时候发现页面显示成http://localhost:8081
这个页面了
因为这里我们设置的webpack-dev-server
的historyApiFallback
是true,那么它就把所有的地址全部重定向到根目录的index.html,也就会重定向到http://localhost:8081
打开的页面了,然后在这下边寻找路由进行匹配
怎么解决呢?
historyApiFallback
提供的有一个rewrites
属性,可以使用如rewrites选项进一步控制此行为
详细使用请看官方文档
我们这里需要构建rewrites
内容
// 需要在开发环境重写的规则数组
const rewrites = []; // webpack-dev-server的historyApiFallback中使用
for(let index in moduleList){
const moduleName = moduleList[index]
// 以模块名开头的路径,重定向到 改??橄碌膇ndex.html模板文件 比如路径一以/a开头,会重定向到a??橄碌膇ndex.html
rewrites.push({
from:new RegExp('^\/' + moduleName),
to:utils.resolve('/' + moduleName +'/index.html')
})
}
最后修改historyApiFallback
historyApiFallback: {
rewrites: rewrites
},
重新运行npm run dev
,再次刷新http://localhost:8081/a/test
,页面显示正常。那么开发环境的多页面配置已经完成喽
打包环境多页面的配置
和上边的配置差不多,修改webapck.prod.config.js
,只是对于打包环境添加了压缩代码的配置项
const { getModuleList , getBuildEntry} = require("./module-entry")
// 获取各个???const moduleList = getModuleList();
const HtmlWebpackPluginList = [];
for(let index in moduleList){
const moduleName = moduleList[index]
HtmlWebpackPluginList.push(new HtmlWebpackPlugin({
filename: utils.resolve('./../dist/'+ moduleName+ '/index.html'), // html模板的生成路径
template: utils.resolve("./../src/modules/" + moduleName + "/index.html"),//html模板
inject: true, // true:默认值,script标签位于html文件的 body 底部
// html 文件进行压缩
chunks: [moduleName,'vendors'], // 必须指定,不然会把多有打包的东西插入html模板当中
minify: {
removeComments: true, //去注释
collapseWhitespace: true, //压缩空格
removeAttributeQuotes: true //去除属性引用
},
}))
}
最后把HtmlWebpackPluginList
放入plugins
属性下,在plugins
属相后加如下代码
.concat(HtmlWebpackPluginList)
我们还需要修改webapck.prod.config.js
默认HtmlWebpackPlugin
的实例的参数,新增chunks: ['app']
new HtmlWebpackPlugin({
filename: utils.resolve('./../dist/index.html'), // html模板的生成路径
template: 'index.html',//html模板
inject: true, // true:默认值,script标签位于html文件的 body 底部
chunks: ['app'], // 注入app名称bundel
minify: {
removeComments: true, //去注释
collapseWhitespace: true, //压缩空格
removeAttributeQuotes: true //去除属性引用
}
}),
执行npm run build
测试打包结果,dist目录如下:
通过webpack-bundle-analyzer
分析webpack的拆包和bundle包之间的依赖关系
得出结论:
这种多页面打包方式,在整个项目的基础上打包,webpack会对这些页面的引用的第三方模块进行拆包,导致不同的页面存在相同的bundle包,也就是不同页面存在共用的bundle包。这样的好处是可以减小打包的总体积
抽取HtmlWebpackPluginList
在module-entry.js
添加工具方法如下
const HtmlWebpackPlugin = require("html-webpack-plugin")
const utils = require("./utils")
// 获取htmlwebpackplugin列表
function getHtmlWebpackPluginList(options={}){
const moduleList = getModuleList();
const HtmlWebpackPluginList = [];
for(let index in moduleList){
const moduleName = moduleList[index];
const HtmlWebpackPluginOptions = {
filename: utils.resolve('./../dist/'+ moduleName+ '/index.html'), // html模板的生成路径
template: utils.resolve("./../src/modules/" + moduleName + "/index.html"),//html模板
inject: true, // true:默认值,script标签位于html文件的 body 底部
chunks: [moduleName], // 注入哪个名称bundel
};
if(options.extract){
HtmlWebpackPluginOptions = Object.assign(HtmlWebpackPluginOptions,{
minify: {
removeComments: true, //去注释
collapseWhitespace: true, //压缩空格
removeAttributeQuotes: true //去除属性引用
},
})
}
HtmlWebpackPluginList.push(new HtmlWebpackPlugin(HtmlWebpackPluginOptions))
}
return HtmlWebpackPluginList;
}
导出该方法。然后在webpack.dev.config.js
以及webpack.prod.config.js
中导入getHtmlWebpackPluginList
方法,
const { getModuleList , getBuildEntry,getHtmlWebpackPluginList } = require("./module-entry")
最后.concat(HtmlWebpackPluginList)
替换成.concat(getHtmlWebpackPluginList())
然后在把rewrites
数组提取,在module-entry.js
添加工具方法如下:
// 获取开发环境重定向的规则,只在开发环境中使用
function getRewritesList(){
// 获取各个??? const moduleList = getModuleList();
// 需要在开发环境重写的规则数组
const rewrites = []; // webpack-dev-server的historyApiFallback中使用
for(let index in moduleList){
const moduleName = moduleList[index]
// 以模块名开头的路径,重定向到 改??橄碌膇ndex.html模板文件 比如路径一以/a开头,会重定向到a??橄碌膇ndex.html
rewrites.push({
from:new RegExp('^\/' + moduleName),
to:utils.resolve('/' + moduleName +'/index.html')
})
}
return rewrites;
}
导出该方法,然后为webpack.dev.config.js
文件导入getRewritesList
方法
···
const { getModuleList , getBuildEntry,getHtmlWebpackPluginList, getRewritesList} = require("./module-entry")
···
把historyApiFallback: {rewrites: rewrites}
修改成 historyApiFallback: {rewrites: getRewritesList()}
执行npm run build
测试打包结果,一切正常!