这个阶段实现将编写的业务组件通过配置webpack打包成html,css,js等最终产物文件,然后通过koa服务去加载它们,最后通过后端路由访问成功响应。
抖音“哲玄前端”《大前端全栈实践》
配置webapck主要分三大部分:解析编译、模块分包、压缩优化。先编写基础配置,然后再配置生产环境和开发环境。
解析编译
首先是入口entry,我们后面需要做多页面渲染,入口有约定好的路径。这样就可以用一个函数来读取文件,并动态的生成entryList。有了多入口,需要为它们提供不同的输出模版,这时需要使用HtmlWebpackPlugin,它可以把模版文件自动生成到打包产物中,自动引入打包后的css 、js等文件
// 动态构造 pageEntries 和 htmlWebpackPluginList
const pageEntries = {}
const htmlWebpackPluginList = []
// 获取 app/pages 目录下所有的 entry.xxx.js 文件
const entriyList = glob.sync(path.resolve(process.cwd(), './app/pages/**/entry.*.js'))
entriyList.forEach(file => {
const entryName = path.basename(file, '.js')
pageEntries[entryName] = file
htmlWebpackPluginList.push(new HtmlWebpackPlugin({
// 产物(最终模版)输出路径
filename: path.resolve(process.cwd(), './app/public/dist', `${entryName}.tpl`),
// 指定要使用的模版文件
template: path.resolve(process.cwd(), './app/view/entry.tpl'),
// 要注入的代码块
chunks: [entryName]
}))
})
然后是模块解析的配置,模块解析的作用是将我们书写的代码解析成浏览器可识别的内容。分别对vue、js、css、less、图片以及字体文件配置了loader解析。
模块分包
模块打包的主要思路是将第三方包和公共代码以及webpack的运行时分别打包。第三包通常不会变化,在多个文件都会使用,比如vue、lodash等。将它们单独分出来,可以充分利用浏览器的缓存,因为不会改动,文件指纹很稳定,浏览器不会重复加载它们。将公共代码抽取出来,它只用出现一次,不用多次出现在不同的文件中,可以减少打包体积同时浏览器不会重新加载它们。webapck的运行时代码和公共代码一样多次出现在不同的业务代码中,需要把它单独打包。
压缩优化
这一步需要考虑到不同环境的需求了,生产环境需要最终产物体积小和打包速度快,开发环境只需要落地模版文件,其他文件不需要生成,需要在代码变更时进行热更新.
生产环境:
- 使用了thread-loader开启多线程打包js、css,加快打包速度,注意: thread-loader不能MiniCssExtractPlugin.loader前,这样解析css会报错
- 使用MiniCssExtractPlugin插件提取公共的css, 有效利用缓存,CssMinimizerPlugin优化并压缩css资源
- 使用TerserPlugin利用多核cpu并发优势和缓存提升压缩阶段的性能
开发环境:
- 配置source-map呈现代码映射,便于代码调试
- 配置dev-server进行热更新,这里没有直接使用webpack的dev-server配置,这里自己实现了一个dev-server服务器。
devServer需要有监控本地文件变更和浏览器的模版文件进行双向通信的能力,其余文件存在内存中,所以在开发环境打包时配置了内存大小(--max_old_space_size=4096)。使用了devMiddleware监控文件改动,hotMiddleware往模版文件中注入代码使得devServer服务器可以和浏览器进行eventsource双向通信
其他配置
- 配置resolve,把代码中常用的文件后缀名加入到extensions中,配置路径别名。这样引入文件时可以不用写后缀名,书写路径时使用别名不用思考层级。
- webpack.ProvidePlugin把第三方库暴露到window context下,这样可以直接在业务代码中使用,无需显示导入
- DefinePlugin定去全局常量配置vue环境变量