webpack4

299 阅读4分钟

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 模块引入