构建工具篇
webpack是事实上的前端打包标准,使用较广泛,相比其他打包工具webpack更是面试中的热点

用的webpack3还是版本4,知道有哪些改进嘛

webpack4是18年8月25号发布的,相比webpack3主要以下大改动:
    node环境升级,不再支持node4.0及之前版本,最低node版本6.11.5
    配置增加了mode:production/development/none,必须指定其中一个,在不同的mode下开启了一些默认的优化手段;
    不再需要某些plugin,改为在对应生产或者开发模式下默认打开
详细改进:webpack Release v4.0.0

loader和plugin的不同

    loader能让webpack处理不同的文件,然后对文件进行一些处理,编译,压缩等,最终一起打包到指定文件中(比如loader可以将sass,less文件写法转换成css,而不需要在使用其他转换工具),loader本身是一个函数,接收源文件作为参数,返回转换的结果
1
// build/webpack.base.conf.js
2
module: {
3
rules: [
4
{
5
test: /\.vue$/,
6
loader: 'vue-loader',
7
options: vueLoaderConfig
8
},
9
]
10
},
Copied!
    plugins则用于执行广泛的任务,从打包,优化,压缩,一直到重新定义环境中的变量,接口很强大,主要用来扩展webpack的功能,可以实现loader不能实现的更复杂的功能
1
// build/webpack.prod.conf.js
2
plugins: [
3
new webpack.DefinePlugin({
4
'process.env': env
5
}),
6
new UglifyJsPlugin({
7
uglifyOptions: {
8
compress: {
9
warnings: false
10
}
11
},
12
sourceMap: config.build.productionSourceMap,
13
parallel: true
14
}),
15
]
Copied!

有手动编写过loader和plugin,说一下思路

loader能把源文件经过转化后输出新的结果,一个loader遵循单一职责原则,只完成一种转换,然后链式的顺序去依次经过多个loader转换,直到得到最终结果并返回,所以在写loader时要保持其职责的单一性,同时webpack还提供了一些API供loader调用
1
// 一个简单的loader例子
2
function replace(source) {
3
// 使用正则把 @require '../style/index.css' 转换成 require('../style/index.css');
4
return source.replace(/(\/\/ *@require) +(('|").+('|")).*/, 'require($2);');
5
}
6
module.exports = function (content) {
7
return replace(content);
8
};
Copied!
开发plugin中最常用的两个对象是Compiler和Compilation,他们是plugin和webpack之间的桥梁
    Compiler对象包含了webpack环境的所有配置信息,包含options,loaders,plugins这些信息,这个对象在Webpack启动时候被实例化,它是全局唯一的
    Compilation对象包含了当前的模块资源,编译生成资源,变换的文件等。当webpack以开发模式运行时,每当检测到一个文件变化,一个新的Compilation将会被创建
1
// 最基础的plugin代码
2
class BasicPlugin{
3
// 在构造函数中获取用户给该插件传入的配置
4
constructor(options){ }
5
// Webpack会调用BasicPlugin实例的apply方法给插件实例传入compiler对象
6
apply(compiler){
7
conpiler.plugin('compilation',function(compilation){ })
8
}
9
}
10
module.exports = BasicPlugin;
Copied!

webpack如何配置单页和多页应用

单页应用即为webpack的标准模式,直接在entry中指定单页面应用的入口即可:
1
module.exports = {
2
entry: {
3
app: './src/main.js'
4
},
5
}
Copied!
多页面应用可以考虑使用webpack的AutoWebPlugin来完成简单的自动化构建,前提是项目目录结构要符合预先设定的规范
1
├── pages
2
│ ├── index
3
│ │ ├── index.css // 该页面单独需要的 CSS 样式
4
│ │ └── index.js // 该页面的入口文件
5
│ └── login
6
│ ├── index.css
7
│ └── index.js
8
├── common.css // 所有页面都需要的公共 CSS 样式
9
├── google_analytics.js
10
├── template.html
11
└── webpack.config.js
Copied!

webpack如何做到热更新

webpack热更新(Hot Module Replacement),缩写为HMR,实现了不用刷新浏览器而将新变更的模块替换掉旧的模块,原理如下:
图片来自Webpack HMR 原理解析
server端和client端都做了处理:
    webpack监听到文件变化,重新编译打包,webpack-dev-server和webpack之间接口交互(主要是webpack-dev-middleware调用webpack暴露的API对代码进行监控,并告诉webpack将打包后代码保存到内存中)
    通过sockjs(webpack-dev-server的依赖)在浏览器和服务器之间建立 一个websocket长连接,将webpack编译打包各阶段的信息告知浏览器端
    webpack根据 webpack-dev-server/client 传给它的信息以及 dev-server的配置决定是刷新浏览器还是进⾏模块热更新,如果是模块热更新继续执行,否者刷新浏览器
    HotModuleReplacement.runtime 是客户端 HMR 的中枢,它接收到上⼀步传递给他的新模块的 hash 值,它通过JsonpMainTemplate.runtime 向 server 端发送 Ajax 请求,服务端返回⼀个 json,该 json 包含了所有要更新的模块的 hash 值,获取到更新列表后,该模块再次通过 jsonp 请求,获取到最新的模块代码
    HotModulePlugin 将会对新旧模块进⾏对⽐,决定是否更新模块
    当 HMR 失败后,回退到 live reload 操作,也就是进⾏浏览器刷新来获取最新打包代码

webpack的构建流程(原理)是怎样的

webpack的构建流程是一个串行的过程,从启动到结束依次执行如下:
    ① 初始化参数:从配置文件和shell语句中读取与合并参数,得出最终的参数
    ② 开始编译:用上一步得到的参数初始化 Compiler对象,加载所有配置的插件,通过执行对象的run方法开始执行编译
    ③ 确定入口:根据配置中的entry找出所有的入口文件
    ④ 编译模块:从入口文件出发,调用所有配置的loader对模块进行"加载",再找出该模块依赖的模块,递归此步骤知道所有入口依赖的文件都经过处理结束
    ⑤ 完成编译模块:处理结束,得到了每个模块被"加载"之后的最终内容以及他们之间的依赖关系
    ⑥ 输出资源:根据入口和模块之间的依赖关系,组装成一个个包含多个模块的chunk,再将每个chunk转换成一个单独的文件加入输出列表中
    ⑦ 输出完成:确定输出内容之后,根据配置确定输出的路径和⽂件名,写⼊到⽂件系统

如何用webpack优化前端性能

    压缩代码:比如利用UglifyJsPlugin来对js文件压缩
    CDN加速:将引用的静态资源修改为CDN上的路径。比如可以抽离出静态js,在index利用CDN引入;利⽤webpack对于 output 参数和各loader的publicPath参数来修改资源路径
    删除Tree Shaking:将代码中永远不会走到的片段删除。可以通过在启动webpack时追加参数 --optimize-minimize 来实现
    按照路由拆分代码,实现按需加载,提取公共代码
    优化图片,对于小图可以使用 base64 的方式写入文件中
Last modified 1yr ago