webpack 的核心功能是分析出各种模块的依赖关系,然后形成资源列表,最终打包生成到指定的文件中。更多复杂的功能需要借助 webpack loaders 和 plugins 来完成。
1. 什么是 Loader
Loader 本质上是一个函数,它的作用是将某个源码字符串转换成另一个源码字符串返回。Loader 在模块解析的过程中被调用,以得到最终的源码。
2. Loader 的工作流程
全流程
- 初始化:webpack 读取配置文件,解析入口模块。
- 编译:
- 创建 chunk:根据入口模块创建 chunk。
- 解析模块:解析每个模块的依赖关系。
- 应用 loader:根据配置的 loader 对模块进行转换。
- 输出:将编译后的资源输出到指定的文件中。
Chunk 中解析模块的流程
- 读取模块内容:读取模块的源代码。
- 解析依赖:解析模块中的依赖关系。
- 生成 AST:生成抽象语法树(AST)。
- 生成模块代码:根据 AST 生成最终的模块代码。
更详细的流程
- 读取模块内容:读取模块的源代码。
- 解析依赖:解析模块中的依赖关系。
- 应用 loader:
- 从右到左:多个 loader 会从右到左依次执行。
- 链式调用:每个 loader 的输出作为下一个 loader 的输入。
- 生成 AST:生成抽象语法树(AST)。
- 生成模块代码:根据 AST 生成最终的模块代码。
处理 loaders 的流程
-
当前模块是否满足某个规则?
- 如果当前模块满足某个规则,则继续下一步。
- 如果不满足,则跳过所有 loader,直接进入下一个模块。
-
读取规则中对应的 loaders
- 根据当前模块所满足的规则,找到相应的 loader 列表。
-
加载 loaders 数组
- 将找到的所有 loader 放入一个数组中。
-
处理 loader 流程
- 从右到左依次执行每个 loader。
- 第一个 loader 接收原始代码作为输入。
- 每个 loader 执行完后,将其结果作为下一个 loader 的输入。
- 最终的结果就是经过所有 loader 处理后的源码。
总的来说,当一个模块满足特定规则时,webpack 会按照配置好的顺序,从右到左依次应用每个 loader,直到获得最终的源码。如果模块不满足任何规则,则不会应用任何 loader。这种机制允许开发者灵活地定义不同类型的文件应该如何被处理。
- 从右到左依次执行每个 loader。
3. Loader 配置
完整配置
module.exports = {module: { // 针对模块的配置,目前版本只有两个配置,rules、noParserules: [ // 模块匹配规则,可以存在多个规则{ // 每个规则是一个对象test: /\.js$/, // 匹配的模块正则use: [ // 匹配到后应用的规则模块{ // 其中一个规则loader: "模块路径", // loader 模块的路径,该字符串会被放置到 require 中options: { // 向对应 loader 传递的额外参数// 配置选项}}]}]}
};
简化配置
module.exports = {module: { // 针对模块的配置,目前版本只有两个配置,rules、noParserules: [ // 模块匹配规则,可以存在多个规则{ // 每个规则是一个对象test: /\.js$/, // 匹配的模块正则use: ["模块路径1", "模块路径2"] // loader 模块的路径,该字符串会被放置到 require 中}]}
};
4. 常见的 Loader
babel-loader
:将 ES6+ 代码转换为 ES5 代码。css-loader
:解析 CSS 文件中的@import
和url()
语句。style-loader
:将 CSS 插入到 DOM 中。file-loader
:将文件输出到指定目录,并返回文件的 URL。url-loader
:类似于file-loader
,但可以将小文件转为 Data URL。less-loader
:将 Less 文件编译为 CSS。sass-loader
:将 Sass/SCSS 文件编译为 CSS。ts-loader
:将 TypeScript 文件编译为 JavaScript。
5. 示例
假设我们有一个项目,需要使用 babel-loader
来转换 ES6 代码,使用 css-loader
和 style-loader
来处理 CSS 文件。
项目结构
my-project/
├── src/
│ ├── index.js
│ ├── styles.css
├── dist/
├── package.json
└── webpack.config.js
webpack.config.js
const path = require('path');module.exports = {mode: 'development', // 或 'production'entry: './src/index.js',output: {filename: 'bundle.js',path: path.resolve(__dirname, 'dist')},module: {rules: [{test: /\.js$/,exclude: /node_modules/,use: {loader: 'babel-loader',options: {presets: ['@babel/preset-env']}}},{test: /\.css$/,use: ['style-loader', 'css-loader']}]}
};
安装依赖
npm install --save-dev webpack webpack-cli babel-loader @babel/core @babel/preset-env css-loader style-loader
运行构建
在 package.json
中添加一个 build
脚本:
{"scripts": {"build": "webpack"}
}
然后运行:
npm run build
构建完成后,dist
目录下会生成 bundle.js
文件,你可以在 HTML 文件中引入这个文件:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>My Webpack Project</title>
</head>
<body><script src="dist/bundle.js"></script>
</body>
</html>
总结
通过本课程,你已经了解了 webpack 中 loader 的概念、工作流程以及如何配置 loader。合理使用 loader 可以帮助你处理各种类型的文件,提高项目的可维护性和灵活性。