基础概念
Webpack 是什么?
Webpack 是一种前端资源构建工具,一个 静态模块打包器 (module bundler)
在 Webpack 看来,前端的所有资源文件 ( js / json / css / img / sass / ... ) 都会 作为模块处理 。它将根据模块的依赖关系进行静态分析,打包生成对应的 静态资源 (bundle)
我们所写的代码最终都会被打包为静态资源:js / css / jpg / png 文件
webpack 支持各种模块化开发,通过 ES Module、CommonJS、AMD 方式导入的模块都会被 webpack 打包为浏览器可以识别的代码
场景:
- 在原生不使用任何框架的情况下,直接在 .html 文件中通过 link 引入 sass 样式文件时,浏览器并不能解析
- 在 .js 文件中使用 ES6 的 import 语法等高级语法,浏览器也可能不会识别
important
在上述场景下,我们需要一种工具来将这些浏览器不能识别的东西来编译为浏览器可识别的。如果我们又使用了其他浏览器不能直接编译的技术,则又需要其他的工具来进行编译。以前在没有 webpack 的时候,我们来一个个的维护这些工具是十分麻烦的,所以引入了构建工具的概念,作用是通过构建工具将这些不同技术都预处理工具全都包含进来,方便维护。
Webpack 依赖图
- Webpack 在打包项目时,它会根据命令或者配置文件找到入口文件
- 从入口开始,会生成一个 依赖关系图 ,其中每一个结点就相当于一个 文件模块,比如 .js、.css、图片、字体等文件
- 最后遍历这个 依赖关系图,根据文件的不同使用不同的 loader 来解析,进行打包
important
- 如果某个模块,没有在 依赖关系图 中,那么最终它也不会被打包
- 比如,我们安装了 axios 模块,但是它并没有被使用到项目中,那么它也不会被打包
Webpack 的工作流程
- 入口文件:接收引入资源的文件就是入口文件
- 在入口文件中引入资源:比如
import "xxx.scss"
、import App from "./App"
- 此时会以入口文件为根结点形成依赖关系图,依次引入资源,形成 chunk (代码块)
- 对资源进行打包:通过 webpack 对不同的资源进行不同的处理
- 输出 (bundle) :将打包好的资源输出
Webpack 五个核心概念
- Entry:入口指的是 webpack 以哪个文件为入口起点开始打包,分析构建内部依赖图
- Loader:让 webpack 能够去处理那些非 JavaScript 文件 (webpack 自身只能理解 JavaScript),可以将 css、img ... 等文件转换为 webpack 可以识别的内容
- Plugins:插件可以用于执行范围更广的任务。比如打包优化和压缩, 定义环境变量等
- Output:输出表示 webpack 打包后的资源 bundles 输出到哪里去,以及如何命名。
- Mode:模式表示 webpack 使用相应模式的配置
选项 | 描述 | 特点 |
---|---|---|
development | 会将 DefinePlugin 中 process.env.NODE_ENV 的值设置为 development。启用 NamedChunksPlugin 和 NamedModulesPlugin | 能让代码本地调试 运行的环境 |
production | 会将 DefinePlugin 中 process.env.NODE_ENV 的值设置为 production。启用 FlagDependencyUsagePlugin, FlagIncludedChunksPlugin, ModuleConcatenationPlugin, NoEmitOnErrorsPlugin, OccurrenceOrderPlugin, SideEffectsFlagPlugin 和 TerserPlugin | 能让代码优化上线 运行的环境 |
important
在 React 项目中,项目根目录中的 index.js 就是入口文件,其引入了 App.jsx,然后 App.jsx 中又引入了其他的组件,这样就形成了一个依赖关系图,从根结点开始打包,打包过程中遇到了 .scss / img ... 资源则会通过 Loader 进行翻译为 webpack 可以处理的资源,在这过程中还可以通过 Plugins 来打包优化、压缩资源等功能更加强大的事情,最后形成 代码块 (bundle) ,然后通过 Output 指定这些资源输出到哪。
使用命令行参数配置 Webpack
全局安装
$ npm i -g webpack webpack-cli
创建项目
首先我们创建一个如下结构的项目。
webpack-demo
├── src
│ ├── sayHello.js
│ └── sayHi.js
└── index.js
export default function sayHello() {
console.log("hello");
}
export default function sayHi() {
console.log("hi");
}
import sayHi from "./src/sayHi.js";
import sayHello from "./src/sayHello.js";
sayHi();
sayHello();
进行打包
当我们在项目的根目录下运行如下命令。
$ webpack --entry=./index.js --output-path=./build --mode=production
表示 ./index.js
为打包入口,打包后的输出内容存放在 ./build
目录下, 并且以 production
模式打包。
打包成功后,就会在项目根目录生成一个 build/main.js
文件。
(() => {
"use strict";
console.log("hi"), console.log("hello");
})();
important
--entry
参数的默认值为项目根目录下的 ./src/index.js
,--output-path
的默认值为 ./dist
,并且打包时最好把 --mode
参数带上,如果不带则默认为 production
,但是会提出警告。
使用配置文件配置 Webpack
在实际开发中,使用 webpack 进行打包时,对其进行配置时,可以在项目的根目录下创建 webpack.config.js
文件来对 webpack 打包进行配置,为命令行添加参数这种方式来配置 webpack 的打包方式并不常用。
还是使用上面的那个项目例子,不过我们在里面新增一个 webpack.config.js
文件。
webpack-demo
├── src
│ ├── sayHello.js
│ └── sayHi.js
├── index.js
└── webpack.config.js
然后在该文件内添加下面的配置内容。
const path = require("path");
module.exports = {
entry: "./src/main.js", // 配置打包入口文件
output: {
// 配置打包出口文件
filename: "bundle.js", // 文件名
path: path.resolve(__dirname, "./build"), // 文件夹路径
},
mode: "development", // 打包模式
};
这里简单提一下,关于 output.path
字段,它表示打包后内容输出的目标文件夹路径,这里必须是一个绝对路径,因此使用了 path.resolve
。
接下来在项目的根目录下直接运行 webpack
命令,webpack 就会自动读取根目录下 webpack.config.js
中的配置,然后对项目进行打包。
打包后的内容根之前的一样。
(() => {
"use strict";
console.log("hi"), console.log("hello");
})();
当然,我们也可以指定 webpack 在打包过程中使用哪个配置文件,只需在命令后加上 --config
参数。
# 让 webpack 加载 ./config/webpack.prod.config.js 配置文件进行打包
$ webpack --config ./config/webpack.prod.config.js
方便起见,实际上我们可以把这个命令封装到 npm script
中,当我们运行 npm run build
那么就会执行这行命令了。