# webpack配置工程师之路
什么是webpack?
我的理解是:最早期的前端开发,什么工具都没有,如果B.html用到了A.html的一部分代码,需要从A.html复制几百行粘贴到B.html,非常恶心。
当前端开发越来越规范以后,模块化开发也成为了主流,A.html里面的那几百行就可以提取为模块供其他地方使用。
以vue.js开发举例,你写的vue文件需要解析成浏览器可以直接运行的js、css代码,这个解析的工具就可以是webpack。
webpack配置相当繁杂,所以有网友开玩笑自称是webpack配置工程师。
本笔记来自玩转Webpack专栏,这里是相关PDF (opens new window) ,国内请访问码云仓库 (opens new window)
安装webpack:
npm i webpack webpack-cli -D
webpack Github主页 (opens new window)
# 初识webpack:
配置文件
webpack 默认配置: webpack.config.js 可以通过webpack -- config指定配置文件
配置组成:
//webpack.config.js
module.exports = {
// 1 打包的入口文件
entry: "./src/index.js",
// 2 打包的输出
output: "./dist/main.js",
/* 打包的输出也可以这样,需要 const path = require("path");
output: {
path: path.join(__dirname, "dist"),
filename: "bundle.js",
},
*/
// 3 环境
mode: "production",
module: {
rules: [
// 4 Loader 配置
{ test: /\.txt$/, use: "raw-loader" },
],
},
plugins: [
// 5 插件配置
new HtmlwebpackPlugin({
template: "./src/index.html",
}),
],
};
通过npm run build运行:
{
"name": "hello-world",
"version": "1.0.0",
"description": "Hello world",
"main": "index.js",
"scripts": {
"build": "webpack"
},
"keywords": [],
"author": "",
"license": "ISC"
}
# 多入口配置
module.exports = {
// 多入口配置
entry: {
app: "./src/app.js",
search: "./src/search.js",
},
output: {
filename: "[name].js",
path: _dirname + "/dist",
},
};
# Loaders
webpack默认只支持JS和JSON两种文件类型,通过Loaders去支持其它文件类型并且把它们转化成有效的模块,并且可以添加到依赖图中。
本身是一个函数,接受源文件作为参数,返回转换的结果。
常见的Loaders及作用:
名称 | 作用 |
---|---|
babel-loader | 转换ES6、ES7等JS新特性语法 |
css-loader | 支持.css文件的加载和解析 |
less-loader | 将less文件转换成css |
ts-loader | 将TS转换成JS |
file-loader | 进行图片、字体等的打包 |
raw-loader | 将文件以字符串的形式导入 |
thread-loader | 多进程打包JS和CSS |
Loaders的用法
const path = require("path");
module.exports = {
output: {
filename: "bundle.js",
},
module: {
rules: [
{
//test指定匹配规则
test: /.txt$/,
//use指定使用的loader名称
use: "raw-loader",
},
],
},
};
# Plugin
常见的Plugins及功能:
名称 | 描述 |
---|---|
CommonsChunkPlugin | 将chunks相同的模块代码提取成公共js |
CleanWebpackPlugin | 清理构建目录 |
ExtractTextWebpackPlugin | 将CSS从bunlde文件里提取成一个独立的CSS文件 |
CopyWebpackPlugin | 将文件或者文件夹拷贝到构建的输出目录 |
HtmlWebpackPlugin | 创建html文件去承载输出的bundle |
UglifyjsWebpackPlugin | 压缩JS |
ZipWebpackPlugin | 将打包出的资源生成一个zip包 |
# Mode的内置函数功能
Mode的内置函数功能
选项 | 描述 |
---|---|
deve lopment | 设置process.env.NODE_ENV 的值为development。 开启NamedChunksPlugin F NamedModulesPlugin |
production | 设置 process.env.NODE_ENV 的值为production。 开启FlagDependencyUsagePlugin , FlagIncludedChunksPlugin,ModuleConcatenationPlugin,NoEmitOnErrorsPlugin,Occurrence0rderPlugin , SideEffectsFlagPlugin和TerserPlugin |
none | 不开启任何优化选项 |
# 解析ES6
使用babel-loader
babel的配置文件是: .babelrc
需要安装的依赖是:
npm i @babel/core @babel/preset-env babel-loader -D
示例:
const path = require("path");
module.exports = {
entry: "./src/index.js",
output: {
path: path.join(__dirname, "dist"),
filename: "bundle.js",
},
module: {
rules: [
{
//使用babel-loader解析ES语法的JS
test: /.js$/,
use: "babel-loader",
},
],
},
};
资源解析:增加ES6的babel preset配置
{
presets: ["@babel/preset-env"],
plugins: ["@babel/proposal-class-properties"],
};
# 解析CSS
css- -loader用于加载.css 文件,并且转换成commonjs对象
style- loader将样式通过<style>
标签插入到head中
const path = require("path");
module.exports = {
entry: "./src/index.js",
output: {
filename: "bundle.js",
path: path.resolve(__dirname, "dist"),
},
module: {
rules: [
{
test: /\.css$/,
use: ["style-loader", "css-loader"],
},
],
},
};
webpack中的文件监听
文件监听是在发现源码发生变化时,自动重新构建出新的输出文件。
webpack开启监听模式,有两种方式:
启动webpack命令时,带上--watch参数
在配置webpack.config.js中设置watch:true
文件监听的原理分析 轮询判断文件的最后编辑时间是否变化 某个文件发生了变化,并不会立刻告诉监听者,而是先缓存起来,等 aggregate Timeout
module.export = {
//默认false,也就是不开启
watch: true,
//只有开启监听模式时,watchOptions才有意义
wathcOptions: {
//默认为空,不监听的文件或者文件夹,支持正则匹配
ignored: /node_ modules/,
//监听到变化发生后会等300ms再去执行,默认300ms
aggregateTimeout: 300,
//判断文件是否发生变化是通过不停询问系统指定文件有没有变化实现的,默认每秒问1000次
poll: 1000,
},
};
# 热更新的原理分析
Webpack Compile:将JS编译成Bundle
HMR Server:将热更新的文件输出给HMR Rumtime
Bundle server:提供文件在浏览器的访问
HMR Rumtime:会被注入到浏览器,更新文件的变化
bundle.js:构建输出的文件
图:
# CSS的文件指纹设置
设置 MiniCssExtractPlugin 的 filename, 使用 [contenthash]
module.exports = {
entry: {
app: "./src/app.js",
search: "./src/search.js",
},
output: {
filename: "[name]_[chunkhash:8].js",
path: _dirname + "/dist",
},
plugins: [
// 保证输出的CSS唯一性
new MiniCssExtractPlugin({
filename: "[name]_[chunkhash:8].css",
}),
],
};
# JS文件的压缩
内置了 uglifyjs-webpack-plugin
# CSS 文件的压缩
使用 optimize-css-assets-webpack-plugin 同时使用 cssnano
module.exports = {
entry: {
app: "./src/app.js",
search: "./src/search.js",
},
output: {
filename: "[name][chunkhash:8].js",
path: dirname + "/dist",
},
plugins: [
new OptimizeCSSAssetsPlugin({
assetNameRegExp: /\.css$/g,
cssProcessor: require("cssnano"),
}),
],
};
# html 文件的压缩
修改html-webpack-plugin,设置压缩参数
module.exports = {
entry: {
app: "./src/app.js",
search: "./src/search.is",
},
output: {
filename: "name]chunkhash:8].js",
path: __dirname + "/dist",
},
plugins: [
new HtmlWebpackPlugin({
template: path.join(__dirname, "src/search.html"),
filename: "search.html",
chunks: ["search"],
inject: true,
minify: {
html5: true,
collapseWhitespace: true,
preserveLineBreaks: false,
minifyCSS: true,
minifyJS: true,
removeComments: false,
},
}),
],
};
# PostCss 插件 autoprefixer 自动补齐 CSS3 前缀
使用 autoprefixer 插件 根据 Can I Use 规则( https://caniuse.com/)
module.exports = {
module: {
rules: [
{
// 使用 autoprefixer 插件
test: /\.less$/,
use: [
"style-loader",
"css-loader",
"less-loader",
{
loader: "postcss-loader",
options: {
plugins: () => [
require("autoprefixer")({
browsers: ["last 2 version", "> 1%", "iOS 7"],
}),
],
},
},
],
},
],
},
};
# CSS 媒体查询实现响应式布局
缺陷:需要写多套适配样式代码
@media screen and (max-width: 980px) {
header {
width: 900px;
}
}
@media screen and (max-width: 480px) {
header {
width: 400px;
}
}
@media screen and (max-width: 350px) {
header {
width: 300px;
}
}
# 参考链接
https://github.com/cpselvis/geektime-webpack-course
# 3到4迁移指南:
inline和hot的区别 (opens new window)
// 1. 不会刷新浏览器
$ webpack-dev-server
//2. 刷新浏览器
$ webpack-dev-server --inline
//3. 重新加载改变的部分,不会刷新页面
$ webpack-dev-server --hot
//4. 重新加载改变的部分,HRM失败则刷新页面
$ webpack-dev-server --inline --hot
https://webpack.js.org/migrate/4/
https://v4.webpack.js.org/loaders/
https://github.com/webpack/webpack-dev-server/blob/master/migration-v4.md
Sass-loader和less-loader首次支持webpack5的版本: https://stackoverflow.com/a/66111894/4493393
style-loader v3 also dropped support for Webpack 4.
npm install vue-loader@14.2.2
"less": "^4.1.2", 不行
Cannot find module 'webpack/bin/config-yargs'
For webpack-cli 3.x
:
"scripts": { "start:dev": "webpack-dev-server" }
For webpack-cli 4.x
:
"scripts": { "start:dev": "webpack serve" }
[webpack-cli] Error: Unknown option '--inline'
工程目录/node_modules/html-webpack-plugin/lib/compiler.js:81 var outputName = compilation.mainTemplate.applyPluginsWaterfall('asset-path', outputOptions.filename, {
TypeError: compilation.mainTemplate.applyPluginsWaterfall is not a function
npm i html-webpack-plugin@3
https://stackoverflow.com/a/52020551/4493393
← Vue