构建工具
Webpack
Webpack 特性要点
本质上,webpack 是一个现代 JavaScript 应用程序的_静态模块打包器(module bundler)。当 webpack 处理应用程序时,它会递归地构建一个_依赖关系图(dependency graph),其中包含应用程序需要的每个模块,然后将所有这些模块打包成一个或多个 bundle
webpack 用于编译 JavaScript 模块;一旦完成安装,就可以通过 webpack 的 CLI 或 API 与其配合交互
Webpack是一个打包模块化javascript的工具,在Webpack里一切文件皆模块,因为 webpack 只识别 js和json 文件,所以需要通过 loader 转换文件,通过 plugin 注入钩子,最后输出由多个模块组合成的文件,Webpack 专注构建模块化项目,Webpack 可以看做是模块打包机;它做的事情是,分析项目结构,找到JavaScript模块以及其它的一些浏览器不能直接运行的拓展语言(Scss, TypeScript等),并将其打包为合适的格式以供浏览器使用
Webpack 优点
- 专注于处理模块化的项目,能做到开箱即用,一步到位
- 通过 plugin 扩展,完整好用又不失灵活
- 使用场景不局限于 web 开发
- 社区庞大活跃,经常引入紧跟时代发展的新特性,能为大多数场景找到已有的开源扩展
- 提供了更好的开发体验
Webpack 执行机制
Webpack 的运行流程是一个串行的过程,从启动到结束会依次执行以下流程
- 初始化参数:从配置文件和Shel1语句中读取与合并参数,得出最终的参数
- 开始编译:用上一步得到的参数初始化Compiler对象,加载所有配置的插件,执行对象的run方法开始执行编译
- 确定入口:根据配置中的entry找出所有的入口文件
- 编译模块:从入口文件出发,调用所有配置的Loader对模块进行翻译,再找出该模块依赖的模块,再递归本步骤直到所有入口依赖的文件都经过了本步骤的处理
- 完成模块编译:在经过第4步使用Loader翻译完所有模块后,得到了每个模块被翻译后的最终内容以及它们之间的依赖关系
- 输出资源:根据入口和模块之间的依赖关系,组装成一个个包含多个模块的Chunk,再把每个Chunk转换成一个单独的文件加入到输出列表,这步是可以修改输出内容的最后机会
- 输出完成:在确定好输出内容后,根据配置确定输出的路径和文件名,把文件内容写入到文件系统,在以上过程中, Webpack会在特定的时间点广播出特定的事件,插件在监听到感兴趣的事件后会执行特定的逻辑,并且插件可以调用Webpack提供的API改变Webpack的运行结果
Webpack 热更新原理
1. 基本定义
Webpack的热更新又称热替换(Hot Module Replacement),缩写为HMR。这个机制可以做到不用刷新浏览器而将新变更的模块替换掉旧的模块。
2. 核心定义
- HMR 的核心就是客户端从服务端拉去更新后的文件,准确的说是 chunk diff(chunk需要更新的部分),实际上WDS与浏览器之间维护了一个websocket,当本地资源发生变化时,WDS会向浏览器推送更新,并带上构建时的hash,让客户端与上一次资源进行对比
- 客户端对比出差异后会向WDS发起Ajax请求来获取更改内容(文件列表、hash),这样客户端就可以再借助这些信息继续向WDS发起jsonp请求获取该chunk的增量更新
- 后续的部分(拿到增量更新之后如何处理?哪些状态该保留?哪些又需要更新?)由HotModulePlugin来完成,提供了相关API以供开发者针对自身场景进行处理,像react-hot-loader和vue-loader都是借助这些API实现HMR
Loader 和 Plugin 的不同
1. 不同的作用
- Loader 直译为"加载器"。Webpack将一切文件视为模块,但是Webpack原生是只能解析js文件,如果想将其他文件也打包的话,就会用到loader。所以Loader的作用是让Webpack拥有了加载和解析非JavaScript文件的能力。
- Plugin 直译为"插件", Plugin 可以扩展Webpack的功能,让Webpack具有更多的灵活性。在Webpack运行的生命周期中会广播出许多事件, Plugin可以监听这些事件,在合适的时机通过Webpack提供的API改变输出结果
2. 不同的用法
- Loader 在module.rules中配置,也就是说他作为模块的解析规则而存在。类型为数组,每一项都是一个Object,里面描述了对于什么类型的文件(test),使用什么加载(1oader)和使用的参数(options)
- Plugin 在plugins中单独配置。类型为数组,每一项是一个plugin的实例,参数都通过构造函数传入
webpack 核心概念
entry (入口)
**入口起点(entry point)_指示 webpack 应该使用哪个模块,来作为构建其内部_依赖图的开始。进入入口起点后,webpack 会找出有哪些模块和库是入口起点(直接和间接)依赖的
output (输出)
output 属性告诉 webpack 在哪里输出它所创建的 bundles,以及如何命名这些文件,默认值为
./dist。基本上,整个应用程序结构,都会被编译到你指定的输出路径的文件夹中。你可以通过在配置中指定一个output字段,来配置这些处理过程
loader (加载器)
loader 让 webpack 能够去处理那些非 JavaScript 文件(webpack 自身只理解 JavaScript)。loader 可以将所有类型的文件转换为 webpack 能够处理的有效模块,然后你就可以利用 webpack 的打包能力,对它们进行处理
本质上,webpack loader 将所有类型的文件,转换为应用程序的依赖图(和最终的 bundle)可以直接引用的模块
plugins (插件)
loader 被用于转换某些类型的模块,而插件则可以用于执行范围更广的任务。插件的范围包括,从打包优化和压缩,一直到重新定义环境中的变量。插件接口功能极其强大,可以用来处理各种各样的任务
mode (构建模式)
通过选择
development或production之中的一个,来设置mode参数,启用相应模式下的 webpack 内置的优化
- development (开发环境)
开发模式顾名思义就是我们开发代码时使用的模式。这个模式下我们主要做两件事:
编译代码,使浏览器能识别运行
- 开发时我们有样式资源、字体图标、图片资源、html 资源等,webpack 默认都不能处理这些资源,所以我们要加载配置来编译这些资源
代码质量检查,树立代码规范
- 提前检查代码的一些隐患,让代码运行时能更加健壮。
- 提前检查代码规范和格式,统一团队编码风格,让代码更优雅美观。
不会对打包生成的文件进行代码压缩和性能优化,打包速度快,适合在开发阶段使用
会将 process.env.NODE_ENV 的值设为 development。启用 NameChunksPlugin 和 NameModulesPlugin。特点是能让代码本地调试运行的环境
- production (生产环境)
生产模式是开发完成代码后,我们需要得到代码将来部署上线。这个模式下我们主要对代码进行优化,让其运行性能更好。优化主要从两个角度出发:
提升开发体验提升打包构建速度优化代码体积优化代码运行性能
会将 process.env.NODE_ENV 的值设为 production。启用 FlagDependencyUsagePlugin, FlagIncludedChunksPlugin, ModuleConcatenationPlugin, NoEmitOnErrorsPlugin, OccurrenceOrderPlugin, SideEffectsFlagPlugin 和 UglifyJsPlugin。特点是能让代码优化上线运行的环境
webpack 基本配置
webpack 生态安装
npm install webpack webpack-cli -D
webpack 操作
npx webpack ./src/main.js --mode=development // 开发模式打包
npx webpack ./src/main.js --mode=production // 生产模式打包
npx webpack // 如有配置文件,按配置文件进行打包操作
// 后续在 package.json script 节点中配置命令可简化命令操作
webpack 配置文件
// Node.js的核心模块,专门用来处理文件路径
const path = require("path");
module.exports = {
// 入口
// 相对路径和绝对路径都行
entry: "./src/main.js",
// 输出
output: {
// path: 文件输出目录,必须是绝对路径
// path.resolve()方法返回一个绝对路径
// __dirname 当前文件的文件夹绝对路径
path: path.resolve(__dirname, "dist"),
filename: "static/js/main.js", // 将 js 文件输出到 static/js 目录中
clean: true, // 自动将上次打包目录资源清空(开发服务器下没有输出文件,生成环境则不需要)
},
// 加载器
module: {
rules: [],
},
// 插件
plugins: [],
// 模式
mode: "development", // 开发模式
};
webpack 开发环境配置
处理样式文件
下载包
npm i css-loader style-loader less-loader less sass-loader sass stylus-loader -D
- 功能介绍
css-loader:负责将 Css 文件编译成 Webpack 能识别的模块style-loader:会动态创建一个 Style 标签,里面放置 Webpack 中 Css 模块内容less-loader:负责将 Less 文件编译成 Css 文件sass-loader:负责将 Sass 文件编译成 css 文件sass:sass-loader依赖sass进行编译stylus-loader:负责将 Styl 文件编译成 Css 文件
- 配置
module: {
rules: [
{
// 用来匹配 .css 结尾的文件
test: /\.css$/,
// use 数组里面 Loader 执行顺序是从右到左
use: ["style-loader", "css-loader"],
},
{
test: /\.less$/,
use: ["style-loader", "css-loader", "less-loader"],
},
{
test: /\.s[ac]ss$/,
use: ["style-loader", "css-loader", "sass-loader"],
},
{
test: /\.styl$/,
use: ["style-loader", "css-loader", "stylus-loader"],
},
],
}
处理图片文件
过去在 Webpack4 时,我们处理图片资源通过
file-loader和url-loader进行处理
现在 Webpack5 已经将两个 Loader 功能内置到 Webpack 里了,我们只需要简单配置即可处理图片资源
配置
module: {
rules: [
{
test: /\.(png|jpe?g|gif|webp)$/,
type: "asset",
parser: {
dataUrlCondition: {
maxSize: 10 * 1024 // 小于10kb的图片会被base64处理
// 优点:减少请求数量
// 缺点:体积变得更大
}
},
generator: {
// 将图片文件输出到 static/imgs 目录中
// 将图片文件命名 [hash:8][ext][query]
// [hash:8]: hash值取8位
// [ext]: 使用之前的文件扩展名
// [query]: 添加之前的query参数
filename: "static/imgs/[hash:8][ext][query]",
},
},
],
}
处理jS文件
Webpack 对 js 处理是有限的,只能编译 js 中 ES 模块化语法,不能编译其他语法,导致 js 不能在 IE 等浏览器运行,所以我们希望做一些兼容性处理。
其次开发中,团队对代码格式是有严格要求的,我们不能由肉眼去检测代码格式,需要使用专业的工具来检测。
- 针对 js 兼容性处理,我们使用
Babel来完成- 针对代码格式,我们使用
Eslint来完成
我们先完成 Eslint,检测代码格式无误后,在由 Babel 做代码兼容性处理
ESlint
配置文件
配置文件由很多种写法:
.eslintrc.*:新建文件,位于项目根目录.eslintrc
.eslintrc.js.eslintrc.json
- 区别在于配置格式不一样
package.json中eslintConfig:不需要创建文件,在原有文件基础上写
ESLint 会查找和自动读取它们,所以以上配置文件只需要存在一个即可
下载包
npm i eslint-webpack-plugin eslint -D
功能介绍eslint-webpack-plugin :eslint 插件,主要用于使用 eslint 进行语法检查eslint :eslint-webpack-plugin依赖eslint进行编译
具体配置
// .eslintrc.js || .eslintignore :eslint 忽略文件
module.exports = {
// 解析选项
parserOptions: {
ecmaVersion: 6, // ES 语法版本
sourceType: "module", // ES 模块化
ecmaFeatures: {
// ES 其他特性
jsx: true // 如果是 React 项目,就需要开启 jsx 语法
}
},
// 具体检查规则
// "off" 或 0 - 关闭规则
// "warn" 或 1 - 开启规则,使用警告级别的错误:warn (不会导致程序退出)
// "error" 或 2 - 开启规则,使用错误级别的错误:error (当被触发的时候,程序会退出)
rules: {
},
// 继承其他规则(vue官方,eslint官方)
extends: ['plugin:vue/recommended', 'eslint:recommended'],
// 启用环境配置
"env": {
"browser": true, // 浏览器环境中的全局变量
"node": true, // Node.js 全局变量和 Node.js 作用域
"es6": true // 启用除了 modules 以外的所有 ECMAScript 6 特性(该选项会自动设置 ecmaVersion 解析器选项为 6)。
},
// 使用插件
"plugins": ["example"],
// 其他规则详见:https://eslint.bootcss.com/docs/user-guide/configuring
};
在 webpack 中使用
const ESLintWebpackPlugin = require("eslint-webpack-plugin");
plugins: [
new ESLintWebpackPlugin({
// 指定检查文件的根目录
context: path.resolve(__dirname, "src"),
}),
],
ESLint 注释规则
// eslint-disable-next-line
此行无规则
此处无规则 // eslint-disable-line
/* eslint-disable */
此块都无规则
/* eslint-enable */
Babel
配置文件
配置文件由很多种写法:
babel.config.*:新建文件,位于项目根目录
babel.config.jsbabel.config.json.babelrc.*:新建文件,位于项目根目录
.babelrc.babelrc.js.babelrc.jsonpackage.json中babel:不需要创建文件,在原有文件基础上写
Babel 会查找和自动读取它们,所以以上配置文件只需要存在一个即可
下载包
npm i babel-loader @babel/core @babel/preset-env -D
功能介绍babel-loader :负责将 js 文件交给 babel 进行处理@babel/core :如果某些代码需要调用 Babel 的 API 进行转码,就要使用@babel/core模块@babel/preset-env :babel官方预设
具体配置
// babel.config.js
module.exports = {
// 预设
presets: [],
// 插件
plugins: []
};
在 webpack 中使用
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/, // 排除node_modules代码不编译
loader: "babel-loader",
}
],
}
预设参数设置
# .browserslistrc || package.json
# .browserslistrc 配置
> 1% # 市场份额大于 1% 的浏览器
last 2 versions # 适配最新的两个版本
not dead # 确保浏览器未被遗弃
# package.json 添加节点
"browserslist": [
"> 1%",
"last 2 ve rsions"
],
处理HTML文件
下载包
npm i html-webpack-plugin -D
功能介绍html-webpack-plugin:html 插件,主要用于对html文件的处理
在 webpack 中使用
const HtmlWebpackPlugin = require("html-webpack-plugin");
plugins: [
new HtmlWebpackPlugin({
// 以 public/index.html 为模板创建文件
// 新的html文件有两个特点:1. 内容和源文件一致 2. 自动引入打包生成的js等资源
template: path.resolve(__dirname, "public/index.html"),
}),
],
其他资源
type: "asset/resource"和type: "asset"的区别:
type: "asset/resource"相当于file-loader, 将文件转化成 Webpack 能识别的资源,其他不做处理type: "asset"相当于url-loader, 将文件转化成 Webpack 能识别的资源,同时小于某个大小的资源会处理成 data URI 形式
配置
module: {
rules: [
{
test: /\.(ttf|woff2?|map4|map3|avi)$/,
type: "asset/resource", //
generator: {
filename: "static/media/[hash:8][ext][query]",
},
},
],
}
开发服务器配置
下载包
npm i webpack-dev-server -D
功能介绍webpack-dev-server:开发服务器,能够让所有代码都会在内存中编译打包
在 webpack 中使用
module.exports = {
// 开发服务器
devServer: {
host: "localhost", // 启动服务器域名
port: "3000", // 启动服务器端口号
open: true, // 是否自动打开浏览器
}
}
使用命令
npx webpack serve
webpack 生产环境配置
考虑生产环境打包就需要对原有配置文件进行重新梳理,划分两个文件进行管理
文件目录
├─webpack-test (项目根目录)
├── node_modules (下载包存放目录)
├── src (项目源码目录,除了html其他都在src里面)
│ └── 略
├── public (项目html文件)
│ └── index.html
├── .browserslistrc(babel预设配置文件)
├── .eslintrc.js(Eslint配置文件)
├── babel.config.js(Babel配置文件)
├── webpack.dev.js(开发模式配置文件)
├── webpack.prod.js(生产模式配置文件)
└── package.json (包的依赖管理配置文件)
设置 webpack.dev.js
const path = require("path");
const ESLintWebpackPlugin = require("eslint-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
entry: "./src/main.js",
output: {
path: undefined, // 开发模式没有输出,不需要指定输出目录
filename: "static/js/main.js", // 将 js 文件输出到 static/js 目录中
// clean: true, // 开发模式没有输出,不需要清空输出结果
},
module: {
rules: [
{
// 用来匹配 .css 结尾的文件
test: /\.css$/,
// use 数组里面 Loader 执行顺序是从右到左
use: ["style-loader", "css-loader"],
},
{
test: /\.less$/,
use: ["style-loader", "css-loader", "less-loader"],
},

最低0.47元/天 解锁文章
294





