基本篇
对webpack的看法
webpack是一个模块打包工具。可以用webpack管理我们的模块依赖,并编绎输出模块们所需的静态文件。它能够很好地管理、打包Web开发中所用到的HTML、Javascript、CSS以及各种静态文件(图片、字体等),让开发过程更加高效。对于不同类型的资源,webpack有对应的模块加载器。webpack模块打包器会分析模块间的依赖关系,最后 生成了优化且合并后的静态资源
entry && output
loader
loader其实就是一个打包的方案,它知道对于某些特定的文件,webpack应该如何去打包。写在配置文件的 module 项中定义rules。
常用的loader
- 打包图片:file-loader,url-loader(会把图片打包成base64字符串直接放在打包好的js文件中。这样能使得html打开时候少点http请求,但是只适合于图片不要太大的情况,否则js文件太大也不好。所以可以加limit配置项)
- 打包样式文件:style-loader(把打包好的css挂载在html的
<head>
),css-loader(分析各css文件的关系,合并成一个css文件)。如果是sass或stylus文件,还需要借助sass-loader,node-sass和stylus-loader。自动添加产商前缀(提高css兼容性)的postcss-loader
PS:use中的loader的执行顺序的是从下到上,从右到左,所以顺序不能弄错
plugins
plugin可以在webpack运行到某个时刻的时候,帮我们做一些事情(有点像生命周期函数)。写在配置文件的 plugins 项中
常用的plugins
- html-webpack-plugin。会在打包结束后,自动生成一个html文件,并把打包生成的js自动引入到这个html文件中
- clean-webpack-plugin。不是官网写的插件。会在打包开始前,把原来的打包目录删除
SourceMap
当 webpack 打包源代码时,可能会很难追踪到错误和警告在源代码中的原始位置(只是显示在打包后的文件中的错误的位置),用SouceMap即可通过映射关系能知道该错误在源代码中的位置
使用方法
在development模式下默认SourceMap已经被配置进去了,若想关闭可用 devtool: none
devtool配置项的几种写法
- cheap:使打包性能提升,sourcemap提示错误只提示到行不提示列
- inline:把映射关系文件放在打包好的js文件中而不是生成一个单独的文件
- module:使得cheap-sourcemap不仅管打包好的文件和源js的关系,还会管loader、第三方模块等的关系
- eval:是最快的,会以eval的方式检查
devtool最配置
在development下,用 cheap-module-eval-source-map
在production下,用 cheap-module-source-map
webpack-dev-server
为我们提供了一个简单的 web 服务器,并且能够实时重新加载;不会生成打包好的目录,是把打包好的文件存在内存中,提高效率
使用方法:安装,添加命令,写 devServer 项
proxy转发
proxy配置项,其实用 Vue-cli 和 create-react-app 构建的项目的proxy功能本质就是这个配置项
模块热替换
Hot Module Replacement,HMR。
功能
当源文件的发生改变的时候,理论上webpack-dev-server会帮我们打包更新,但是这个过程会刷新页面,使得页面上已有的样式/数据被刷新了。用HMR能实现在运行时更新各种模块,而无需进行完全刷新
原理
使用
- 更新 webpack-dev-server 的配置:devSever配置项中写 hot: true
- 在plugins中实例化HMR插件
对js文件的HMR功能需要手动多写一段代码
1 | if (module.hot) { // 注意 |
css-loader 中内置了if(module.hot)...
这样的代码,所以我们手写
Babel
安装 babel-loader(其实只是打通webpack和babel的一个通道),@babel/core,@babel/preset-env(这个才是翻译器)@babel/polyfill(添加ES6中的新函数新变量,eg. Promise和Map)
具体配置方法见Babel官方文档
@babel/polyfill
- 默认情况下polyfill会把所有新变量和函数都添加进打包好的文件,文件会变得较大,可写 useBuiltIns实现按需添加;可写target设定在目标浏览器,会自己判断是否添加这些新变量。(当options太长的时候可以直接把该对象放在根目录下的.babelrc )
1
2
3
4
5
6
7
8
9
10options: {
presets: [["@babel/preset-env", {
targets: {
edge: "17",
firefox: "60",
chrome: "67",
safari: "11.1",
},
useBuiltIns: 'usage' }]]
} - 此外,polyfill添加新变量是以全局变量的形式,会污染全局环境,当我们在打包UI组件库/类库的时候,就不能用这种配置方式。应安装@babel/plugin-transform-runtime,@babel/runtime 。配置方法见文档
高级概念
Tree Shaking
Code Splitting
CSS文件的代码分割
- 一般情况下,css会被打包在js文件中,如果想把css文件单独打包,需要用 MiniCssExtractPlugin (该插件不支持HMR,一般只在生产环境下使用,详细用法见笔记)
- css 压缩用 optimize-css-assets-webpack-plugin
Chunks:打包生成的每个文件都是一个chunk,打包生成很多个js文件,就有很多个chunk
output的chunkFilename配置项:如果一个打包后的文件会直接被html引用,那就是走filename,否则就是chunkFilename
Lazy loading
Shimming
应用场景:由于webpack具有模块化开发的理念,所以当index.js中有引入jQuery,而有个模块用了$变量却没import jQuery的时候,打包的时候这个模块的$还是会翻译不出,手动往每个用了$的模块去import却很麻烦。故可用shimming。
解决方法:
在common中require(‘webpack’),然后在plugin中写入new webpack.ProvidePlugin({ $: ‘jquery’ })
当发现模块中有 $ 时,就会自动给这个模块引入jQuery
打包分析
当我们用webpack打包之后,可以用打包分析的工具进行分析,看打包是否合理。看代码分割是否合理
使用
按文档提示加命令,会在打包过程中生成json文件描述打包过程,把这个文件传到网站即可;也可以用官方文档建议的方法
preloading & prefetching
怎么看页面的代码使用率? 用coverage
webpack希望我们多写异步加载的代码(多用懒加载),能提高页面的代码使用率,eg,把具体代码写在一个js文件中,然后在index.js中写。(所以代码分割默认是async)
1 | document.addEventListener('click', () => { |
但是等到用户点击的时候再加载代码,加载时间可能也比较长,这时就可用preloading、prefetching:实现在页面加加载完之后,在接下来的空闲时间偷偷地把异步操作的代码下载好,这样真正用的时候只需要加载缓存即可(这个其实是prefetching;preloading是会和主代码一起加载)。
使用方法是在import语句中写入魔法注释即可 /* webpackPrefetch: true */
提升webpack打包速度的方法
原理篇
如何编写一个plugin
如何编写一个loader
Bundler源码编写
Vue Cli3
如果想改Vue项目中webpack配置,是直接建立vue.config.js然后按文档简单粗暴地去配置就可以了,对新手十分友好,vue-cli会在底层自己转变成webpack配置并实施
参考资料
慕课网-从基础到实战 手把手带你掌握新版Webpack4.0
webpack官方文档