01-基础篇-认识webpack
为什么需要构建工具?
转换es6语法,转换jsx,css前缀补全/预处理器、压缩混淆、图片压缩等
为什么选择webpack?
社区活跃度高,配置灵活、插件化扩展,官方更新迭代速度快,官方提供的loader和plugin非常丰富,也可以自定义去满足个性化需要
webpack配置文件
默认配置文件:webpack.config.js 可以通过webpack --config XXX 指定配置文件
通过npm script运行webpack
就是在package.json文件里的script里添加配置命令
原理:项目里安装的依赖模块,安装的时候会在node_modules/.bin 里创建相应软连接,这样的话npm就可以通过软连接寻找到文件
02-基础篇-webpack基础概念
entry
entry是用来指定打包入口,根据入口文件找到不同模块和文件的依赖关系, 遍历完之后形成一个依赖树,才能生成最终打包之后的资源
单入口:entry的值是个字符串路径,多入口:entry的值是key-value对象
output
output是用来指定打包后输出文件的文件名和文件路径
loaders
webpack默认只支持js和json文件类型,通过loaders转换可以使webpack支持其他文件类型
loader本身是一个函数,接受源文件作为参数,返回转换的结果
module:{rules: [ {test: /\.txt$/, use: 'raw-loader'}]}test 指定匹配规则, use 指定使用的loader的名称,loader是从右到左链式调用
style-loader:将样式通过<style>标签插入到 head 中
css-loader: 用于加载.css文件,并且转换成 commonjs 对象
less-loader:用于将less转换成css
url-loader: 也可以处理图片和字体,可以设置较小资源自动转换为 base64,直接内联在代码里
plugins
plugin是用来增强webpack的功能,通常用于打包文件的优化,资源管理和环境变量注入
比如:构建之前要删除上一次构建的文件,就可以用plugin来完成
mode
用来指定当前的构架环境:production(默认)、development 还是 none
设置mode就会自动使用webpack内置的函数,配置默认的一些参数和功能
webpack文件监听及原理
文件监听是在源代码发生变化时,自动重新构建出新的输出文件,但是每次还需要手动刷新浏览器
两种开启方式:
1.启动 webpack 命令时,带上 --watch 参数
2. 在配置 webapck.config.js 中设置 watch: true
webpack中的热更新及原理分析
一种方式:
WDS:webpack-dev-server 结合使用 HotModuleReplacementPlugin 插件可以开启热更新功能
WDS 输出的文件是放在内存中,而不是像--watch那样输出在磁盘中(存在I/O操作),所以说WDS 的构建速度更快
另一种方式:
使用 webpack-dev-middleware
WDM:将 webpack 输出的文件传输给服务器 适用于灵活的定制场景
文件指纹策略:chunkhash、contenthash和hash
通常用来做版本管理,替换hash变化的文件,没有修改的文件其实不用替换,还可以继续用浏览器缓存
常见的文件指纹有以下三种:
Hash:和整个项目的构建相关,只要项目文件修改,整个项目构建的 hash 值就会更改
Chunkhash:和 webpack 打包的 chunk 有关,不同的 entry 会生成不同的 chunkhash 值
Contenthash:根据文件内容来定义 hash,文件内容不变,则 contenthash 不变
1.在 webpack 配置里对于 js 文件我们通常使用 chunkhash
output: { filename: '[name][chunkhash:8].js', path: __dirname + '/dist'}
2.对于css文件我们通常使用 contenthash
设置 MiniCssExtractPlugin 的 filename,使用 contenthash
用 MiniCssExtractPlugin 把 css 提取出来,提取成独立的文件
plugins:[new MiniCssExtractPlugin({filename:`[name][contenthash:8].css`})]
3.对于图片/字体类的文件我们通常使用 hash
代码压缩
html、js、css 代码压缩: 占用空间小、访问速度快
1.js文件的压缩
webpack 内置了 uglifyjs-webpack-plugin
2.css文件的压缩
使用 optimize-css-assets-webpack-plugin 同时使用 cssnano 预处理器
3.html文件的压缩
html-webpack-plugin 可以设置打包完的哪些chunk自动注入到该html页面,每个页面对应一个 html-webpack-plugin 配置
03-基础篇-webpack高阶设置
自动清理构建目录产物
避免构建前每次都需要手动删除 dist
1. package.json文件的 scripts 打包命令里添加 rm -rf ./dist
2. 使用 clean-webpack-plugin 默认会删除 output 指定的输出目录
PostCSS插件autoprefixer自动补齐CSS3前缀
不同浏览器内核的 css 需要添加不同的前缀
使用 postcss-loader 的 autoprefixer 插件可以对 css 代码进行后置处理,添加前缀
移动端CSS px自动转换成rem
css 媒体查询实现响应式布局 @media screen and
css3 提出 rem: font-size of the root element
.rem是相对单位 .px是绝对单位
使用 px2rem-loader px自动转换成rem
安装并引入 lib-flexible 页面渲染时会根据当前屏幕分辨率计算根元素的 font-size 值
静态资源内联
HTML 和 JS 内联: raw-loader@0.5.1
<script>${require('raw-loader!babel-loader! 文件路径/文件名.html或文件路径/文件名.js ')}</script>
CSS 内联: html-inline-css-webpack-plugin
通过这个插件将打包好的css文件自动插入到 html 文件
多页面应用(MPA)打包通用方案
多页面应用:每一次页面跳转,服务器都会返回一个新的 html 文档,对 SEO 更加友好
使用sourcemap
通过 sourcemap 定位代码错误,开发环境开启,生产环境关闭
sourcemap 关键字:
eval:使用 eval 包裹模块代码,嵌入在相对应的js打包文件里,不产生单独的 .map 文件
source map:产生 map 文件
cheap:不包含列信息
inline:将 .map 作为 DataURI 嵌入相对应的js打包文件里,不单独生成 .map 文件
module:包含 loader 的 sourcemap
提取公共资源
1. 基础库分离
使用 html-webpack-externals-plugin 插件将 react、react-dom 等基础包通过 cdn 引入,不打入 bundle 中
2. 公共脚本分离
利用 SplitChunksPlugin(webpack4内置的) 进行公共脚本分离(打包生成common文件),也可以分离基础库(单独打包生成vendors文件),参数很多,功能很强大, 替代 CommonsChunkPlugin(webpack3内置的)
chunks 参数说明:
- async:异步引入的库进行分离(默认)
- initial: 同步引入的库进行分离
- all: 所有引入的库进行分离(推荐)
treeshaking(摇树优化)的使用和原理分析
概念: 1个模块可能有多个方法,只要其中的某个方法使用到了,则整个文件都会被打到 bundle 里面去, tree shaking 就是只把用到的方法打入 bundle,没用到的方法会在 uglify 阶段被擦除掉
使用: webpack 默认支持,在 .babelrc 里设置 modules:false 即可, 生产环境默认开启
要求:模块的引入必须是 ES6 的语法才支持 treeshaking,CJS 的方式不支持
原理:
先了解一下 DCE(Dead-Code-Elimination):把不会执行到的代码、执行的结果不会被用到的代码消除掉
利用了 ES6 模块的特点:
- 只能作为模块的顶层的语句出现
- import 的模块名只能是字符串常量
- import binding 是 immutable 的
ScopeHoisting特性的使用和原理分析
模块打包后函数代码是用闭包包裹着的,这样就会导致一些问题:
- 如果大量函数闭包包裹代码,导致体积增大(模块越多越明显)
- 运行代码时创建的函数作用域变多,内存开销变大
使用:webpack4 生产环境默认开启,必须是 ES6 语法,CJS 不支持, webpack 3要手动添加 new webpack.optimize.ModuleConcatenationPlugin()
原理: 将所有模块的代码按照引用顺序放在一个函数作用域里,然后适当的重命名一些变量以防止变量名冲突,通过 scope hoisting 可以减少函数声明代码和内存开销
代码分割和动态import
意义:将所有的代码都放在一个文件中显然是不够有效的,特别是当你的某些代码块是在某些特殊的时候才会被使用到的。webpack 可以将代码库分割成 chunks(语块),当代码运行到需要他们的时候再进行加载
使用场景:
- 抽离相同代码到一个共享块
- 脚本懒加载,使得初始下载的代码更小
动态 import 可以让 js 脚本实现懒加载,在代码调用的时候再加载该 js脚本 ,通过动态创建jsonp 的形式引入到页面,懒加载的 js 脚本会单独打包
webpack和ESlint的结合
webpack 打包组件和基础库
实现一个大整数加法库的打包,要求如下:
- 需要打包压缩版和非压缩版本
- 支持 AMD/CJS/ESM 模块引入