webpack 基础知识
entry 入口
entry 作为项目的入口,如果只有一个入口,entry 的值就可以直接是一个访问路径的字符串,多个入口则需要是一个对象,对象的 key 就是入口的名称,value 就是入口的访问路径。
output 出口
output 作为项目的打包出口,有两个属性,一个是 path,一个是 filename。
- filename 是一个文件名,如果有多个入口,需要打包出多个文件的话,可以直接使用占位符[name],其中 name 就是入口的名称。
- path 就是要输出的打包后的文件路径
loaders
webpack 原生是只支持 js 和 json 文件的,loader 的作用就是将 webpack 识别不了的文件转换成 webpack 可以识别的文件,比如 less, sass, vue, jsx, ts, json 等等
常用的 loader
- css-loader
- style-loader
- file-loader
- babel-loader
- ts-loader
- thread-loader
- raw-loader
用法
放在 webpack.config.js 文件中,module.rules 对象数组中添加需要的 loader,每一个项有两个属性,test 和 use,test 用来匹配需要处理的文件,use 用来指定使用哪个 loader
const path = require("path");
module.exports = {
output: { filename: "bundle.js" },
module: { rules: [{ test: /^.txt$/, use: "raw-loader" }] },
};plugins
所有 loader 不能做的事情都可以做。
- 文件优化主要对一些打包体积的优化,做一些文件内容的处理,类如压缩,移动,增删等。作用域整个构建的过程中。
- 环境变量注入
- 资源管理
常见的插件:
- html-webpack-plugin
- clean-webpack-plugin
- mini-css-extract-plugin
- uglifyjs-webpack-plugin
- bundle-analyzer
- CommonsChunkPlugin 将 chunks 相同的模块代码提取成公共 js
- CopyWebpackPlugin 将文件或者文件夹拷贝到构建的输出目录
- ZipWebpackPlugin 将打包出的资源生成一个 zip 包
解析 ES6 模块 和 react/vue 的 语法
- babel-core
- babel-loader
- babel-preset-env
- babel-preset-react
- babel-preset-vue
解析 css,less,scss
- style-loader 将样式通过使用 style 标签插入到 head 中,这个插入过程是使用 js 来进行操作的,样式可以是被提取出来的 css,也可以是在 js 中的,主要在于是否将 css 提取出来
- css-loader 将 css 转换成 commonjs 模块
- less-loader 将 less 转换成 css
- sass-loader 将 sass 转换成 css
解析图片,字体等文件
file-loader 一般的文件都可以使用 file-loader 来解析
url-loader 可以将图片转换成 base64,设置 limit 属性,如果图片大小小于这个值,就会将图片转换成 base64,否则就会使用 file-loader 来解析。url-loader 里面封装了 file-loader
pdf-loader 让 pdf 文件可以正常显示
文件监听
文件监听是指:当文件发生改变的时候,会自动重新编译打包输出编译后的结果,但是不会自动刷新页面。需要手动刷新页面。
webpack 开启监听模式,有两种方式:
- 启动 webpack 命令时,带上--watch 参数
- 在配置 webpack.config.js 中设置 watch:true
"script": "webpack --watch"//更细致的配置
module.export = {
//默认false,也就是不开启
watch: true,
//只有开启监听模式时,watchOptions才有意义
watchOptions: {
//默认为空,不监听的文件或者文件夹,支持正则匹配
ignored: /node_modules/,
//监听到变化发生后会等300ms再去执行,默认300ms
aggregateTimeout: 300,
//判断文件是否发生变化是通过不停询问系统指定文件有没有变化实现的,默认每秒问1000次
poll: 1000,
},
};热更新
热更新是指:当文件发生改变的时候,会自动重新编译打包输出编译后的结果,并且会自动刷新页面。
需要使用:
- webpack-dev-server
- 内置插件 hot-module-replacement-plugin
module.exports = {
// ...省略其他配置
mode: "development",
plugins: [
new webpack.HotModuleReplacementPlugin()
]
devServer: {
// 告诉服务器从哪里提供热更新内容
contentBase: path.join(__dirname, "dist"),
hot: true,
}
}其他方式:
- webpack-dev-middleware 配合 express/koa 等自己写服务更加灵活
热更新原理
一般通知浏览器更新是 websocket 
- 开发服务启动打包阶段:1-->2,A-->B
- 文件修改:3-->4
文件指纹
- hash 是整个项目的 hash
- chunkhash 和打包的 chunk 有关,不同的 entry 会生成不同的 hash。一般 js 使用
- contenthash 文件内容 hash,一般 css, 图片使用
占位符分类:
- [name] 占位符,文件名
- [hash] 占位符,hash 值
- [ext] 占位符,文件后缀
- [contenthash] 占位符,文件内容 hash
- [chunkhash] 占位符,chunk 的 hash 值
- [folder] 占位符,文件所在目录
- [path] 占位符,文件路径
注意提取 css 的时候,如果使用 mini-css-extract-plugin,那么 style-loader 就不能使用,可以替换成 mini-css-extract-plugin.loader。
html、css、js 压缩
- html-webpack-plugin 插件可以帮助提取 html,一些配置项可以帮助压缩 html,比如去除 html 中的空格,去除 html 中的注释等。多个入口就需要多个 html-webpack-plugin
- mini-css-extract-plugin 都可以压缩 css
- uglify-js-webpack-plugin 压缩 js
自动添加 css 样式前缀
为什么要添加前缀呢?浏览器会根据不同的版本,对 css 样式进行不同的处理,比如 css3 的 transform 属性,在 IE 浏览器下,需要添加前缀,才能正常显示。
需要的 npm 包有 autoprefixer 和 postcss-loader
使用:
module.exports = {
module: {
rules:[
{
test:/\.less$/,
use:[
'style-loader',
'css-loader',
'less-loader',
+ {
+ loader:'postcss-loader',
+ options:{
+ plugins:() => [
+ require('autoprefixer')({
+ browsers:["last 2 version",">1%", "ios 7"]
+ })
+ ]
+ }
+ }
]
}
]
}
}优化
实际使用可以简化
在项目根目录创建 postcss.config.js 文件,这样不需要在 Webpack 中重复配置 plugins
// postcss.config.js
module.exports = {
plugins: {
autoprefixer: {},
},
};最后 rules 里面加上 postcss-loader 即可
px 转 rem
- 使用 postcss-pxtorem
- 使用 px2rem-loader
静态资源内联
内联意义
- 页面初始化脚本
- 上报打点脚本
- css 内联避免页面闪烁,CLS 性能
- 减少请求数,减少带宽消耗,使用 url-loader
配置步骤
依赖的包有
- html-webpack-plugin 支持在 html 中写 ejs 语法
- raw-loader
- babel-loader 如果需要降级安装这个模块
<!DOCTYPE html>
<html lang="en">
<head>
<!-- 引入meta.html的全部内容 -->
${ require('raw-loader!./meta.html')}
<title>Document</title>
<!-- 引入path.js 并使用babel降级 -->
<script>
${ require('raw-loader!babel-loader!../path.js')}
</script>
</head>
<body>
<div id="root"></div>
</body>
</html>动态多页面打包
使用的包:
- glob 匹配文件
- html-webpack-plugin 生成 html 文件
创建函数来生成 entry 和 htmlWebpackPlugin 配置
source-map 使用
开发环境使用 cheap-module-eval-source-map 比较快 生产环境一般不开启 source-map,如果需要定位问题,可以上传 source-map
提取公共资源
- 代码分割 splitChunks
- 公共模块提取 commonChunks
- 排除不需要的第三方模块,使用 cdn 引入,exclude
tree-shaking
静态分析,只针对 ES6 模块,commonjs 不支持.
因为 require 是动态的导入的使用的时候才会去加载模块,而 import 是静态的,在打包的时候就会去分析模块的引用关系,然后进行打包
代码分割和动态 import 加载
动态加载就是使用的时候再去加载文件,webpack 对需要动态加载的文件单独分割成一个文件。
加载的原理就是通过 jsonp 的方式,通过 script 标签引入文件。
webpack 和 ESLint 的配合
- 编辑器添加 ESLint 插件
- 安装 ESLint 相关的包和规则包
- 配置 ESLint 的配置文件
- eslint-loader 来对 js,ts 等文件进行 eslint 检查,不通过的代码会直接报错
webpack 打包库并发布到 npm 上
要求:
实现一个大整数加法库的打包:
- 打包压缩版和非压缩版,未压缩版命名为:large-number.min.js,压缩版命名为:large-number.js
- 支持 AMD/CJS/ESM 模块引入
- 支持 script 标签引入
实现:
- library:指定打包后的库的全局变量名
- libraryTarget:指定打包后的库的模块类型,一般是 umd
- mode 设置为 none,不然会默认打包成生产环境,使用 TerserPlugin 单独对 min.js 进行压缩
设置入口文件: package.json 的 main 字段为 index.js,包的根目录创建 index.js,内容如下:
if (process.env.NODE_ENV === "production") {
module.exports = require("./dist/large-number.min.js");
} else {
module.exports = require("./dist/large-number.js");
}package.json 添加 prepublish 的 Script 字段:
"scripts": {
"build": "webpack --config webpack.config.js",
"prepublish": "npm run build"
}命令行显示输出
控制日志显示的内容,配置字段为 stats,一般是开发环境在 decServer 中,生产环境写在根配置中,error-only
通常使用 friendly-errors-webpack-plugin 插件
构建异常和中断处理
检测构建异常,webpack 有构建钩子可以检测,done 的状态。
中断处理,一般就是终端的时候如果有异常的话,有错误号码,可以进行错误上报。