基于
webpack3
一、webpack简介
1.1 版本更迭

大版本变化

1.2 功能进化
Webpack V1
- 编译、打包
HMR(模块热更新)- 代码分割
- 文件处理
Webpack V2
Tree ShakingES module- 动态
Import - 新的文档
Webpack V3
Scope Hoisting(作用域提升)Magic Comments(配合动态import使用)
版本迁移
V1 -> V2
迁移指南 https://doc.webpack-china.org/guides/migrating/
V2 -> V3
更新升级即可
二、webpack核心概念
2.1 Entry
- 代码的入口
- 打包的入口
- 单个或多个
写法建议使用键值对写法
module.exports = { |
module.exports = { |
module.exports = { |
module.exports = { |
2.2 Output
- 打包成的文件(
bundle) - 一个或多个
- 自定义规则
- 配合
CDN
module.exports = { |
module.exports = { |
2.3 Loaders
- 处理文件
- 转化为模块
module.exports = { |
2.3.1 常用Loader
编译相关
babel-loaderts-loader
样式相关
style-loadercss-loaderless-loaderpostcss-loader
文件相关
file-loaderurl-loader
2.4 Plugins
- 参与打包整个过程
- 打包优化和压缩
- 配置编译时的变量
- 极其灵活
module.exports = { |
2.4.1 常用plugins
优化相关
CommonsChunkPluginUglifyJsWebpackPlugin
功能相关
ExtractTextWebpackPlugin提取cssHtmlWebpackPlugin生成HTML模板HotModuleReplacementPlugin热模块替换CopyWebpackPlugin拷贝文件
2.5 名词
Chunk打包过程分割的代码块Bundle打包后的文件Module
三、初探 webpack
3.1 使用babel打包es6
3.1.1 编译 ES 6/7
Babel
npm install babel-loader@8.0.0-beta.0 @babel/core |
Babel Presets
主要有几种类型选择
es2015es2016es2017envbabel-preset-reactbabel-preset-stage 0 - 3
npm install @babel/preset-env –save-dev |
Babel Polyfill
针对一些不能处理的函数方法(
Generator、Set、Map、Array.from...)需要用到babel-Polyfill处理
- 全局垫片
- 为应用准备
npm install babel-polyfill –save |
import “babel-polyfill” |
Babel Runtime Transform
- 局部垫片
- 为开发框架准备
npm install babel-plugin-transform-runtime –save-dev |
例子
module.exports = { |
对于
webpack中babel的配置可以单独提取处理.babelrc统一管理
{ |
3.2 打包 Typescript
npm i typescipt ts-loader --save-dev |
配置
tsconfig.jsonwebpack.config.js
tsconfig
- 配置选项:官网
/docs/handbook/compiler-options.html - 常用选项
compilerOptionsincludeexclude
声明文件
用于编译时检查错误
以loadsh为例,需要安装@types/lodash带有声明文件的,而不是安装lodash
npm install @types/lodash |
Typings
也可以这样安装带有
type的包
npm install typings |
例子
module.exports = { |
在项目根目录创建
tsconfig.json
{ |
3.3 提取 js 的公用代码
- 减少代码冗余
- 提高加载速度
主要使用内置插件实现
webpack.optimize.CommonsChunkPlugin
{ |
例子
module.exports = { |

3.4 代码分割和懒加载
第一种方式:通过wepack内置方法
require.ensure动态加载一个模块,接收四个参数
[]:dependencies初次并不会执行callback的时候才会执行errorCallback可省略chunkName
第二种方式:通过ES2015 Loader Spec
System.import()后面演变为import()来动态加载模块
import()方式返回一个promise在import中传入需要依赖的明,动态加载模块,就可以像使用Promise一样使用import().then()
代码分割场景
- 分离业务代码 和 第三方依赖
- 分离业务代码 和 业务公共代码 和 第三方依赖
- 分离首次加载 和 访问后加载的代码
例子
module.exports = { |
目标是提取
pageA、pageB中公共的模块moduleA
//src/pageA.js |
运行打包这时loadash提取到vendor中

这时候还不是我们想要的
//src/pageA.js |

这时候这有
pageA中才有moduleA

新建一个html验证是否动态加载
<html> |

import()动态加载的写法
//src/pageA.js |
如果
/** webpackChunkName: 'subPageA' **/相同,则会合并处理
合并了subPageA和subPageB

来看看打包后的文件,既有A、B

在webpack代码分割中使用async异步加载
module.exports = { |
//src/subPageA.js |
//src/subPageB.js |
//src/subPageB.js |
//src/pageA.js |
//src/pageB.js |


这样就把
subpageA和subPageB共同依赖的moduleA异步提取出来
3.5 处理 CSS 和 CSS 模块化
引入css
需要两个
loader,style-loader(创建标签到文档流中)、css-loader(可以import一个样式文件,使得在js中可以使用)
Style-Loader
style-loader除了本身,还有这几个loader
style-loader/url可以注入link标签到页面style-loader/useable控制样式是否插入到页面中
Style-Loader的options
insertAt(插入位置)insertInto(插入到dom)singleton(是否只使用一个style标签)transform(转化,浏览器环境下,插入页面前)
例子
module.exports = { |
CSS-Loader
options
alias(解析的别名)importLoader(@import)Minimize(是否压缩)modules(启用css-modules)
CSS-Modules
localIdentName: '[path][name]__[local]--[hash:base64:5]' |
例子
module.exports = { |
配置Less / Sass
npm install less-loader less --save-dev |
例子
module.exports = { |
提取 CSS
extract-loaderExtractTextWebpackPlugin
例子
module.exports = { |

3.6 PostCSS in Webpack
安装
postcsspostcss-loaderAutoprefixercssnanopostcss-cssnext
例子
module.exports = { |
3.7 Tree shaking
3.7.1 JS Tree shaking
使用场景
- 常规优化
- 引入第三方库的某一个功能
例子
module.exports = { |
有些库不是es模块写的,并不能
tree shaking。需要借助其他工具
npm i babel-loader babel-core babel-preset-env babel-plugin-lodash --save |
lodash Tree不生效
lodash-es–> nobabel-lugin-lodash—>working
查看模块是否Tree Shaking方式:去第三方库index.js中看模块书写方式是否是es
3.7.2 CSS Tree shaking
主要使用
purifycss-webpack
例子
const glob = require('glob-all') |
四、由浅入深Webpack
4.1 文件处理
4.1.1 图片处理
css中引入图片- 自动合成雪碧图
- 压缩图片
Base64编码
处理需要用到的
loader
file-loadercss中引入图片url-loaderbase64编码img-loader压缩图片postcss-sprites合成雪碧图
4.1.2 处理雪碧图、base64、压缩图片
module.exports = { |
4.1.2 处理字体文件
file-loaderurl-loader
module.exports = { |
4.1.3 处理第三方 JS 库
处理第三方库 用到
providePlugin、imports-loader
1.providePlugin
以引入jQuery为例
npm i jquery |
module.exports = { |
引入本地libs中的jQuery
module.exports = { |
2.imports-loader
module.exports = { |
4.2 HTML in webpack(自动生成HTML)
自动生成
HTML,把这个页面需要的js、css插入到页面中
4.2.1 生成 HTML
htmlWebpackPlugin
options
templatefilenameminify是否压缩chunksinject是否让css、js通过标签形式插入到页面中
module.exports = { |
4.2.2 HTML 中引入图片
需要用到
html-loader
html-loader
options
attrs: [img:src]
module.exports = { |
require在HTML中引入图片
<img src="${require('./public/imgs/xx.png)}" /> |
4.2.3 配合优化
提前载入webpack加载代码
inline-manifest-webpack-pluginhtml-webpack-inline-chunk-plugin
建议使用 html-webpack-inline-chunk-plugin
npm i html-webpack-inline-chunk-plugin |
var HTMLInlieChunk = require('html-webpack-inline-chunk-plugin') |
五、Webpack 环境配置
5.1 Webpack Watch Mode
webpack --watch |
//webpack.config.js |
5.2 Webpack Dev Server
5.2.1 Dev Server
不能用来直接打包文件,
Dev Server搭建本地开发,文件存在内存中
特性
live reloading- 路径重定向
- 支持
HTTPS - 浏览器中显示编译错误
- 接口代理
- 模块热更新
dev server
inlinecontentBaseporthistApiFllbackhttpsproxyhotopenpagelazyoverlay开启错误遮罩
使用
"script"{ |
module.exports = { |
5.2.2 proxy代理远程接口
- 代理远程接口请求
http-proxy-middlewaredevServer.proxy
module.exports = { |
5.2.3 模块热更新
保持应用的数据状态
节省调试时间
不需要刷新
devServer.hotwebpack.HotModleReplacementPluginwebpack.NamedModulesPlugin看到模块更新的路径
Module Hot Reloading
module.hotmodule.hot.accept
module.exports = { |
模块热更新配置
需要通过module.hot
f (module.hot) { |
5.2.4 开启调试SourceMap
Source Map调试
把生成以后代码和之前的做一个映射
开启Source Map方式
JS Source Map设置
develpoment
evaleval-source-mapcheap-eval-source-mapcheap-module-eval-source-map
推荐使用
cheap-module-source-map
production
source-maphidden-source-mapnosource-source-map
推荐使用
source-map
CSS Source Map设置
改变
loader的options选项
css-loader.options.soucemapless-loader.options.soucemapsass-loader.options.soucemap
module.exports = { |
5.2.5 设置 ESLint 检查代码格式
eslinteslint-loaderesling-plugin-htmleslint-frindly-formatter友好提示错误
配置eslint
wepback config新增loader.eslintrc或者在package.json的eslintConfig中写
配置eslint的规范,推荐使用JavaScript standard style(https://standardjs.com)
需要安装以下插件
eslint-config-standardeslint-plugin-promiseeslint-plugin-standardeslint-plugin-importeslint-plugin-node
eslint-loader
options.failOnWarning出现警告options.failOnErroroptions.formatteroptions.outputReport
设置
devServer.overlay在浏览器中看提示的错误
// .eslintrc |
module.exports = { |
5.2.6 区分开发环境 和 生产环境
开发环境
- 模块热更新
sourceMap- 接口代理
- 代码规范检查
生产环境
- 提取公共代码
- 压缩
- 文件压缩或
base64编码 - 去除无用的代码
共同点
- 入口一致
- loader处理
- 解析配置一致
使用
webpack-merge合并公共配置
webpack.dev.conf.jswepback.prod.conf.jswebpack.common.conf.js
"scripts":{ |
公共配置
build/webpack.common.conf.js
const merge = require('webpack-merge') |
开发环境配置
build/webpack.dev.conf.js
const webpack = require('webpack') |
生产环境配置
build/webpack.prod.conf.js
const webpack = require('webpack') |
5.3 使用 middleware 来搭建开发环境
可以更灵活配置,需要以下插件搭建
Express or koawebpack-dev-middlewarewebpack-hot-middleware热更新http-proxy-middleware代理connect-history-api-fallback地址rewriteopn命令工具打开浏览器页面
// build/server.js |
六、webpack实战场景
6.1 分析打包结果
6.2 优化打包速度
6.2.1 方法一:分开vendor和app
分开第三方代码和业务代码,借助
DllPlugin和DllReferencePlugin
之前的打包时间
现在我们来优化这个时间

第一步:新建webpack.dll.conf.js
// build/webpack.dll.conf.js |
第二步:加一个命令
// package.json |
执行
npm run dll

第三步: 在plugins中增加配置
// build/webpack.prod.conf.js |
再次执行
npm run build

编译时间大大减少了
6.2.2 方法二:UglifyJsPlugin并行处理
UglifyJsPlugin
parallelcache
// build/webpack.prod.conf.js |
6.2.3 方法三:happyPack
happyPack把所有串行的东西并行处理,使得loader并行处理,较少文件处理时间
https://www.npmjs.com/package/happypack
// build/webpack.prod.conf.js |
这时的编译时间也减小了一些

6.2.4 方法四:较少babel-loader编译时间
babel-loader
开启缓存,指定编译范围
options.cacheincludeexclude
6.2.5 其他
- 减少
resolve Devtool去除sourcemapcache-loader- 升级
node - 升级
webpack
6.3 长缓存优化
场景
改变
app代码,vendor变化
解决
- 提取
vendor hash–>chunkhash(把hash变为代码块的hash,而不是文件的hash)- 提取
webpack runtime
output: { |

每次打包
vendor都不会变化,这样就达到了缓存的目的(服务端开启cache-ctrol)
场景:引入新模块,模块顺序变化,vendor hash变化
解决:
NamedChunksPluginNamedModulesPlugin
对于动态模块引入需要给名称
6.4 多页面应用
6.4.1 多页面特点
- 多入口
- 多页面
HTML - 每个页面不同的
chunk - 每个页面不同的参数
6.4.2 多页面多配置
wepback从3.1.0开始支持
优点:
- 可以使用
parallel-webpack(并行处理多份配置)提高打包速度 - 配置更独立、灵活
缺点
- 不能多页面之间共享代码
//package.json |
/** |
6.4.3 多页面单配置
多个页面共享一个配置
- 优点:可以共享各个
entry之间公用代码 - 缺点:打包速度比较慢,输出的内容比较复杂
/** |