webpack一个打包工具,前端半自动化开发工具。它是基于nodejs运行的,它的功能有:压缩代码,压缩图片,解析es6,解析sass语法,代码热更新等
入口,出口,插件,装载机loader,本地服务devServer
脚手架使用webpack来执行配置文件,默认是webpack.config.js或者vue.config.js。然后执行入口文件的js,进行解析处理。
build:则生成物理文件存在磁盘上;
server:则将编译的结果存入内存条中。
自下而上,从右向左
raw-loader
:加载文件原始内容(utf-8)
file-loader
:把文件输出到一个文件夹中,在代码中通过相对 URL 去引用输出的文件 (处理图片和字体)
url-loader
:与 file-loader 类似,区别是用户可以设置一个阈值,大于阈值会交给 file-loader 处理,小于阈值时返回文件 base64 形式编码 (处理图片和字体)
source-map-loader
:加载额外的 Source Map 文件,以方便断点调试
svg-inline-loader
:将压缩后的 SVG 内容注入代码中
image-loader
:加载并且压缩图片文件
json-loader
加载 JSON 文件(默认包含)
handlebars-loader
: 将 Handlebars 模版编译成函数并返回
babel-loader
:把 ES6 转换成 ES5
ts-loader
: 将 TypeScript 转换成 JavaScript
awesome-typescript-loader
:将 TypeScript 转换成 JavaScript,性能优于 ts-loader
sass-loader
:将SCSS/SASS代码转换成CSS
css-loader
:加载 CSS,支持模块化、压缩、文件导入等特性
style-loader
:把 CSS 代码注入到 JavaScript 中,通过 DOM 操作去加载 CSS
postcss-loader
:扩展 CSS 语法,使用下一代 CSS,可以配合 autoprefixer 插件自动补齐 CSS3 前缀
eslint-loader
:通过 ESLint 检查 JavaScript 代码
tslint-loader
:通过 TSLint检查 TypeScript 代码
mocha-loader
:加载 Mocha 测试用例的代码
coverjs-loader
:计算测试的覆盖率
vue-loader
:加载 Vue.js 单文件组件
i18n-loader
: 国际化
cache-loader
: 可以在一些性能开销较大的 Loader 之前添加,目的是将结果缓存到磁盘里
define-plugin
:定义环境变量 (Webpack4 之后指定 mode 会自动配置)
ignore-plugin
:忽略部分文件
html-webpack-plugin
:简化 HTML 文件创建 (依赖于 html-loader)
web-webpack-plugin
:可方便地为单页应用输出 HTML,比 html-webpack-plugin 好用
uglifyjs-webpack-plugin
:不支持 ES6 压缩 (Webpack4 以前)
terser-webpack-plugin
: 支持压缩 ES6 (Webpack4)
webpack-parallel-uglify-plugin
: 多进程执行代码压缩,提升构建速度
mini-css-extract-plugin
: 分离样式文件,CSS 提取为独立文件,支持按需加载 (替代extract-text-webpack-plugin)
serviceworker-webpack-plugin
:为网页应用增加离线缓存功能
clean-webpack-plugin
: 目录清理
ModuleConcatenationPlugin
: 开启 Scope Hoisting
speed-measure-webpack-plugin
: 可以看到每个 Loader 和 Plugin 执行耗时 (整个打包耗时、每个 Plugin 和 Loader 耗时)
webpack-bundle-analyzer
: 可视化 Webpack 输出文件的体积 (业务组件、依赖第三方模块)
webpack-dashboard
:可以更友好的展示相关打包信息。
webpack-merge
:提取公共配置,减少重复配置代码
speed-measure-webpack-plugin
:简称 SMP,分析出 Webpack 打包过程中 Loader 和 Plugin 的耗时,有助于找到构建过程中的性能瓶颈。
size-plugin
:监控资源体积变化,尽早发现问题
HotModuleReplacementPlugin
:模块热替换
loader
本质就是一个函数,在该函数中对接收到的内容进行转换,返回转换后的结果。 因为 Webpack 只认识 JavaScript,所以 Loader 就成了翻译官,对其他类型的资源进行转译的预处理工作;
Plugin
就是插件,基于事件流框架 Tapable
,插件可以扩展 Webpack 的功能,在 Webpack 运行的生命周期中会广播出许多事件,Plugin 可以监听这些事件,在合适的时机通过 Webpack 提供的 API 改变输出结果。
Loader
在 module.rules 中配置,作为模块的解析规则,类型为数组。每一项都是一个 Object,内部包含了 test(类型文件)、loader、options (参数)等属性;
Plugin
在 plugins 中单独配置,类型为数组,每一项是一个 Plugin 的实例,参数都通过构造函数传入。
loader
是专门用于处理各种资源的,编译过程;
plugins
是对webpack没有的功能的补充。
正常情况下,先用loader把资源处理完之后再执行插件。
source map
是将编译、打包、压缩后的代码映射回源代码的过程。打包压缩后的代码不具备良好的可读性,想要调试源码就需要 soucre map。
map文件只要不打开开发者工具,浏览器是不会加载的。
线上环境一般有三种处理方案:
hidden-source-map
:借助第三方错误监控平台 Sentry 使用nosources-source-map
:只会显示具体行数以及查看源代码的错误栈。安全性比 sourcemap 高sourcemap
:通过 nginx 设置将 .map 文件只对白名单开放(公司内网)注意:避免在生产中使用
inline-
和eval-
,因为它们会增加 bundle 体积大小,并降低整体性能。
Webpack 实际上为每个模块创造了一个可以导出和导入的环境,本质上并没有修改 代码的执行逻辑,代码执行顺序与模块加载顺序也完全一致。
在发现源码发生变化时,自动重新构建出新的输出文件。
Webpack开启监听模式,有两种方式:
缺点:每次需要手动刷新浏览器
原理:轮询判断文件的最后编辑时间是否变化,如果某个文件发生了变化,并不会立刻告诉监听者,而是先缓存起来,等 aggregateTimeout
后再执行。
module.export = {
// 默认false,也就是不开启
watch: true,
// 只有开启监听模式时,watchOptions才有意义
watchOptions: {
// 默认为空,不监听的文件或者文件夹,支持正则匹配
ignored: /node_modules/,
// 监听到变化发生后会等300ms再去执行,默认300ms
aggregateTimeout:300,
// 判断文件是否发生变化是通过不停询问系统指定文件有没有变化实现的,默认每秒问1000次
poll:1000
}
}
Webpack
的热更新又称热替换(Hot Module Replacement
),缩写为 HMR
。 这个机制可以做到不用刷新浏览器而将新变更的模块替换掉旧的模块。
HMR的核心就是客户端从服务端拉去更新后的文件,准确的说是 chunk diff (chunk 需要更新的部分),实际上 WDS(webpack dev server) 与浏览器之间维护了一个 Websocket
,当本地资源发生变化时,WDS 会向浏览器推送更新,并带上构建时的 hash,让客户端与上一次资源进行对比。客户端对比出差异后会向 WDS 发起 Ajax
请求来获取更改内容(文件列表、hash),这样客户端就可以再借助这些信息继续向 WDS 发起 jsonp
请求获取该chunk的增量更新。
后续的部分(拿到增量更新之后如何处理?哪些状态该保留?哪些又需要更新?)由 HotModulePlugin
来完成,提供了相关 API 以供开发者针对自身场景进行处理,像react-hot-loader
和 vue-loader
都是借助这些 API 实现 HMR。
原理解析
VSCode
中有一个插件 Import Cost
可以帮助我们对引入模块的大小进行实时监测,还可以使用 webpack-bundle-analyzer
生成 bundle
的模块组成图,显示所占体积。
bundlesize
工具包可以进行自动化资源体积监控。
打包后输出的文件名的后缀
Hash
:和整个项目的构建相关,只要项目文件有修改,整个项目构建的 hash 值就会更改
Chunkhash
:和 Webpack 打包的 chunk 有关,不同的 entry 会生出不同的 chunkhash
Contenthash
:根据文件内容来定义 hash,文件内容不变,则 contenthash 不变
JS的文件指纹
设置 output 的 filename,用 chunkhash
module.exports = {
entry: {
app: './scr/app.js',
search: './src/search.js'
},
output: {
filename: '[name][chunkhash:8].js',
path:__dirname + '/dist'
}
}
CSS的文件指纹
设置 MiniCssExtractPlugin 的 filename,使用 contenthash。
module.exports = {
entry: {
app: './scr/app.js',
search: './src/search.js'
},
output: {
filename: '[name][chunkhash:8].js',
path:__dirname + '/dist'
},
plugins:[
new MiniCssExtractPlugin({
filename: `[name][contenthash:8].css`
})
]
}
图片的文件指纹
设置file-loader的name,使用hash。
占位符名称及含义
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename:'bundle.js',
path:path.resolve(__dirname, 'dist')
},
module:{
rules:[{
test:/\.(png|svg|jpg|gif)$/,
use:[{
loader:'file-loader',
options:{
name:'img/[name][hash:8].[ext]'
}
}]
}]
}
}
可以使用 enforce
强制执行 loader
的作用顺序,pre
代表在所有正常 loader 之前执行,post
是所有 loader 之后执行。(inline 官方不推荐使用)
使用`高版本`的 Webpack 和 Node.js
多进程/多实例构建:HappyPack(不维护了)、thread-loader
压缩代码
图片压缩
缩小打包作用域
提取页面公共资源
DLL
充分利用缓存提升二次构建速度
Tree shaking
Scope hoisting
动态Polyfill
官方-构建性能
Babel 最初基于 acorn
项目(轻量级现代 JavaScript 解析器) Babel大概分为三大部分:
npm i webpack webpack-cli
webpack-dev-server
创建一个webpack.config.js文件进行配置
只能打包js文件,打包后的文件一定叫main.js
成 AST
npm i webpack webpack-cli
webpack-dev-server
创建一个webpack.config.js文件进行配置
只能打包js文件,打包后的文件一定叫main.js