react+webpack4.x搭建前端项目(五)多页面配置

前言 我们接着上一篇文章react+webpack4.x搭建前端项目之配置抽取和区分环境来进行多页面打包的配置 首先修改src下的代码,项目的结构目录 QQ截图20191213143525.png 源码见修改src下代码,添加测试a,b模块完整代码0.0.2 开发环境多页面的配置 新建build/module-entry.js,获取额外打包的模块名,和入口entry配置 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,结果如下图 QQ截图20191213161552.png 发现怎么是b页面的内容? 那么是为什么呢?经过排查,打开控制台选择elements看到如下图 QQ截图20191213161753.png 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 底部 }), 这时候重新运行成功解决! QQ截图20191213162054.png 然后我们打开http://localhost:8081/a,http://localhost:8081/b页面正常显示。 QQ截图20191213162633.png QQ截图20191213162649.png 但是存在一个问题!点击二级路由的时候也可以正常显示,但是我们直接打开或者刷新二级路由的时候(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] // 以模块名开头的路径,重定向到 改模块下的index.html模板文件 比如路径一以/a开头,会重定向到a模块下的index.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目录如下: QQ截图20191213171322.png 通过webpack-bundle-analyzer分析webpack的拆包和bundle包之间的依赖关系 QQ截图20191213171520.png 得出结论: 这种多页面打包方式,在整个项目的基础上打包,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] // 以模块名开头的路径,重定向到 改模块下的index.html模板文件 比如路径一以/a开头,会重定向到a模块下的index.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测试打包结果,一切正常! 源码:react+webpack4.x多页面 release-tag-0.0.3 下一篇:react+webpack4.x多模块打包配置

本文章由javascript技术分享原创和收集

发表评论 (审核通过后显示评论):