Webpack构建多页应用心得体会
Webpack构建的基于zepto的多页应用脚手架,本文聊聊本次项目中Webpack构建多页应用的一些心得体会。
1.前言
由于公司旧版的脚手架是基于Gulp构建的zepto多页应用(有兴趣可以看看web-mobile-cli),有着不少的痛点。例如:
这次升级有几个地方需要注意和改进:
Github仓库:
2.多页
Webpack的多页应用通过多入口entry和多实例html-webpack-plugin配合来构建,html-webpack-plugin的chunk属性传入对应entry的key就可以做到关联,例如:
module.exports = {entry: {pageOne: './src/pageOne/index.js',pageTwo: './src/pageTwo/index.js',pageThree: './src/pageThree/index.js'},plugins: [new HtmlWebpackPlugin({filename: `pageOne.html`,template: `./src/pageOne.html`,chunks: ['pageOne']}),new HtmlWebpackPlugin({filename: `pageTwo.html`,template: `./src/pageTwo.html`,chunks: ['pageTwo']}),new HtmlWebpackPlugin({filename: `pageTwo.html`,template: `./src/pageTwo.html`,chunks: ['pageTwo']})] } 复制代码那么问题来了,开发新的页面每次都得添加岂不是很麻烦。这里推荐神器glob根据正则规则匹配。
const glob = require('glob')module.exports = {entry: glob.sync('./src/js/*.js').reduce((pre, filepath) => {const tempList = filepath.split('src/')[1].split(/js\//)const filename = `${tempList[0]}${tempList[1].replace(/\.js/g, '')}`return Object.assign(pre, {[filename]: filepath})}, {}),plugins: [...glob.sync('./src/html/*.ejs').map((filepath, i) => {const tempList = filepath.split('src/')[1].split(/html\//)const fileName = tempList[1].split('.')[0].split(/[\/|\/\/|\\|\\\\]/g).pop()const fileChunk = `${tempList[0]}${fileName}`return new HtmlWebpackPlugin({filename: `${fileChunk}.html`,template: filepath,chunks: [fileChunk]})})] } 复制代码3.模板
项目没有直接使用html,而是使用了ejs作为模板,这里有至少两个好处:
<% include ./header.ejs %>就是引用了header.ejs文件,<%= title %>和<%= publicPath %>是我在配置文件定义的两个变量,publicPath是为了统一cdn缓存服务器的域名,非常有用。
4.垫片
项目中使用了zepto,所以需要垫片,所谓垫片就是shim 预置依赖,即全局依赖。
webpack compiler 能够识别遵循 ES2015 模块语法、CommonJS 或 AMD 规范编写的模块。然而,一些 third party(第三方库) 可能会引用一些全局依赖(例如 jQuery 中的 $)。因此这些 library 也可能会创建一些需要导出的全局变量。这些 "broken modules(不符合规范的模块)" 就是 shim(预置依赖) 发挥作用的地方。
垫片有两种方式:
最终我选择了Webpack配置shim预置依赖这种方式,因为:
5.拆分
一般来讲Webpack的配置entry中每个key就对应输出一个chunk,那么该项目中会提取这几类chunk:
这里注意的有两点:
6.缓存
缓存的目的是为了提高加载速度,Webpack在缓存方面已经是老生常谈的了,每个文件赋予唯一的hash值,只有更新过的文件,hash值才改变,以达到整体项目最少文件改动。
6.1 hash值
Webpack中有三种hash值:
6.2 module id
仅仅使用contexthash还不足够,每当import的资源文件顺序改变时,chunk依然会改变,目的没有达成。要解决这个问题首先要理解module和chunk分别是什么,简单理解:
因为Webpack内部维护了一个自增的id,依照顺序赋予给每个module,每当新增或者删减导致module的顺序改变时,受影响的chunk的hash值也会改变。解决办法就是使用唯一的hash值替代自增的id。
module.exports = {entry: {...},module: {...},plugins: [],optimization: {moduleIds: 'hashed'} } 复制代码7.优化
优化的目的是提高执行和打包的速度。
7.1 查找路径
告诉Webpack解析模块时应该搜索的目录,缩小编译范围,减少不必要的编译工作。
const {resolve} = require('path')module.exports = {entry: {...},module: {...},plugins: [],optimization: {...},resolve: {alias: {'@': resolve(__dirname, '../src'),},modules: [resolve('src'),resolve('node_modules'),]} } 复制代码7.2 指定目录
指定loader的include目录,作用是缩小编译范围。
const {resolve} = require('path')module.exports = {entry: {...},module: {rules: [{test: /\.css$/,include: [resolve("src"),],use: ['style-loader', 'css-loader']}]},plugins: [],optimization: {...},resolve: {...} } 复制代码7.3 babel缓存目录
babel-loader开始缓存目录cacheDirectory。
const {resolve} = require('path')module.exports = {entry: {...},module: {rules: [{test: /\.m?js$/,exclude: /(node_modules|bower_components)/,include: [resolve("src"),],use: {loader: 'babel-loader',options: {cacheDirectory: true,presets: ['@babel/preset-env'],plugins: ['@babel/plugin-transform-runtime']}}}]},plugins: [],optimization: {...},resolve: {...} } 复制代码7.4 插件TerserJSPlugin
TerserJSPlugin插件的作用是压缩JavaScript,优化的地方是开启缓存目录和开启多线程。
const {resolve} = require('path')module.exports = {entry: {...},module: {...},plugins: [],optimization: {minimizer: [new TerserJSPlugin({parallel: true,cache: true,})]},resolve: {...} } 复制代码8.总结
通过这次学习Webpack到升级脚手架,对前端工程化有了进一步的了解,也感受到了Webpack4带来的开箱即用,挺方便的。
参考文章:
Webpack官方文档
【实战】webpack4 + ejs + express 带你撸一个多页应用项目架构
基于 webpack 的持久化缓存方案
总结
以上是生活随笔为你收集整理的Webpack构建多页应用心得体会的全部内容,希望文章能够帮你解决所遇到的问题。
- 上一篇: 女模是什么
- 下一篇: flutter进行自动编译操作步骤