【webpack】自定义loader

相关文章

自定义loader


一、什么是自定义Loader

自定义Loader是Webpack的一个重要特性,它允许你对各种类型的资源文件进行处理,比如将Sass文件转换为CSS、将ES6代码转换为ES5等。下面是自定义Loader的基本步骤:

二、如何自定义Loader

1、创建一个Node.js模块

首先,你需要创建一个Node.js模块来定义你的Loader。这个模块需要导出一个函数,这个函数就是你的Loader的实际处理逻辑。

1
2
3
4
5
6
// my-custom-loader.js
module.exports = function(source) {
// source 是传入的资源文件的内容
// 在这里编写你的处理逻辑
return modifiedSource; // 返回处理后的内容
};

2、处理资源文件

在导出的函数中,你可以通过source参数获取到传入的资源文件的内容,然后进行你想要的处理。处理完成后,将处理后的内容返回即可。

3、注册Loader

在Webpack配置文件中,通过module.rules配置项来注册你的Loader。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// webpack.config.js
module.exports = {
// 其他配置...
module: {
rules: [
{
test: /\.custom$/, // 匹配需要使用该Loader的文件
use: [
// 指定使用的Loader,可以是一个字符串或一个数组
// 如果是数组,则按顺序依次应用多个Loader
'my-custom-loader'
]
}
]
}
};

4、使用Loader

在你的项目中,通过import或require等方式引入需要使用该Loader的文件。当Webpack构建过程中遇到匹配该Loader的文件时,就会自动调用你定义的Loader来处理。

三、用法准则

编写 loader 时应该遵循以下准则。它们按重要程度排序。

  • 保持 简单 。

    loaders 应该只做单一任务。这不仅使每个 loader 易维护,也可以在更多场景链式调用。

  • 使用 链式 传递。

    利用 loader 可以链式调用的优势。写五个简单的 loader 实现五项任务,而不是一个 loader 实现五项任务。功能隔离不仅使 loader 更简单,可能还可以将它们用于你原先没有想到的功能。

  • 模块化 的输出。

    保证输出模块化。loader 生成的模块与普通模块遵循相同的设计原则。

  • 确保 无状态 。

    确保 loader 在不同模块转换之间不保存状态。每次运行都应该独立于其他编译模块以及相同模块之前的编译结果。

  • 使用 loader utilities 。

    充分利用 loader-utils 包。它提供了许多有用的工具,但最常用的一种工具是获取传递给 loader 的选项。schema-utils 包配合 loader-utils,用于保证 loader 选项,进行与 JSON Schema 结构一致的校验。

  • 记录 loader 的依赖 。

    如果一个 loader 使用外部资源(例如,从文件系统读取),必须声明它。

  • 解析 模块依赖关系 。

    根据模块类型,可能会有不同的模式指定依赖关系。例如在 CSS 中,使用 @import 和 url(…) 语句来声明依赖。这些依赖关系应该由模块系统解析。

  • 提取 通用代码 。

    避免在 loader 处理的每个模块中生成通用代码。相反,你应该在 loader 中创建一个运行时文件,并生成 require 语句以引用该共享模块:

  • 避免 绝对路径 。

    不要在模块代码中插入绝对路径,因为当项目根路径变化时,文件绝对路径也会变化。loader-utils 中的 stringifyRequest 方法,可以将绝对路径转化为相对路径。

  • 使用 peer dependencies。

    如果你的 loader 简单包裹另外一个包,你应该把这个包作为一个 peerDependency 引入。这种方式允许应用程序开发者在必要情况下,在 package.json 中指定所需的确定版本。

四、常用Loader

babel-loader

用于将ES6+的JavaScript代码转换为ES5,以便让现代JavaScript代码在老版本浏览器中运行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
const path = require('path');

module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [
{
test: /\.js$/, // 匹配以.js结尾的文件
exclude: /node_modules/, // 排除node_modules目录
use: {
loader: 'babel-loader' // 使用babel-loader处理匹配到的文件
}
}
]
}
};

style-loader 和 css-loader

用于处理CSS文件,可以解析CSS文件并将其注入到HTML页面中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
const path = require('path');

module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [
{
test: /\.css$/, // 匹配以.css结尾的文件
use: [
'style-loader', // 将样式通过<style>标签插入到HTML中
'css-loader' // 解析CSS文件
]
}
]
}
};

sass-loader 和 less-loader

用于处理Sass和Less等预处理器的文件,将其编译为普通的CSS文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
const path = require('path');

module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [
{
test: /\.scss$/, // 匹配以.scss结尾的文件
use: [
'style-loader', // 将样式通过<style>标签插入到HTML中
'css-loader', // 解析CSS文件
'sass-loader' // 将Sass代码编译为CSS代码
]
},
{
test: /\.less$/, // 匹配以.less结尾的文件
use: [
'style-loader', // 将样式通过<style>标签插入到HTML中
'css-loader', // 解析CSS文件
'less-loader' // 将Less代码编译为CSS代码
]
}
]
}
};

file-loader 和 url-loader

用于处理图片、字体等文件,可以将这些文件复制到输出目录并返回文件路径。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
const path = require('path');

module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [
{
test: /\.(png|jpg|gif)$/i, // 匹配以.png、.jpg或.gif结尾的文件
use: [
{
loader: 'url-loader', // 使用url-loader处理图片文件
options: {
limit: 8192, // 小于8KB的图片文件会被转换为base64编码
name: '[name].[ext]', // 输出文件名为原始文件名
outputPath: 'images/' // 输出到指定目录下
}
}
]
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/i, // 匹配以.woff、.woff2、.eot、.ttf或.otf结尾的文件
use: [
{
loader: 'file-loader', // 使用file-loader处理字体文件
options: {
name: '[name].[ext]', // 输出文件名为原始文件名
outputPath: 'fonts/' // 输出到指定目录下
}
}
]
}
]
}
};

eslint-loader

用于集成ESLint,可以在构建过程中检查JavaScript代码是否符合规范。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const path = require('path');

module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [
{
test: /\.js$/, // 匹配以.js结尾的文件
exclude: /node_modules/, // 排除node_modules目录
use: ['eslint-loader'] // 使用eslint-loader处理匹配到的文件
}
]
}
};

ts-loader

用于处理TypeScript文件,可以将TypeScript代码转换为JavaScript代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
const path = require('path');

module.exports = {
entry: './src/index.ts', // TypeScript入口文件
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
},
resolve: {
extensions: ['.ts', '.js'] // 解析文件时自动补全.ts和.js后缀
},
module: {
rules: [
{
test: /\.ts$/, // 匹配以.ts结尾的文件
exclude: /node_modules/, // 排除node_modules目录
use: ['ts-loader'] // 使用ts-loader处理匹配到的文件
}
]
}
};

vue-loader

用于处理Vue单文件组件,可以将.vue文件中的模板、脚本和样式等内容分离开来并进行相应处理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
const path = require('path');
const VueLoaderPlugin = require('vue-loader/lib/plugin');

module.exports = {
entry: './src/main.js', // Vue入口文件
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
},
resolve: {
extensions: ['.vue', '.js'] // 解析文件时自动补全.vue和.js后缀
},
module: {
rules: [
{
test: /\.vue$/, // 匹配以.vue结尾的文件
loader: 'vue-loader' // 使用vue-loader处理匹配到的文件
},
{
test: /\.js$/, // 匹配以.js结尾的文件
exclude: /node_modules/, // 排除node_modules目录
loader: 'babel-loader' // 使用babel-loader处理匹配到的文件
}
]
},
plugins: [
new VueLoaderPlugin() // VueLoaderPlugin用于解析.vue文件中的模板和样式
]
};

postcss-loader

用于处理CSS文件,可以使用PostCSS插件来处理CSS代码,比如自动添加浏览器前缀等。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
const path = require('path');

module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [
{
test: /\.css$/, // 匹配以.css结尾的文件
use: [
'style-loader', // 将样式通过<style>标签插入到HTML中
'css-loader', // 解析CSS文件
'postcss-loader' // 使用postcss-loader处理CSS文件
]
}
]
}
};

image-webpack-loader

用于处理图片文件,可以压缩图片文件以减小文件大小。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
const path = require('path');

module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [
{
test: /\.(png|jpe?g|gif|svg)$/i, // 匹配图片文件
use: [
{
loader: 'url-loader', // 使用url-loader处理图片文件
options: {
limit: 8192, // 小于8KB的图片文件会被转换为base64编码
name: '[name].[hash:8].[ext]', // 输出文件名格式
outputPath: 'images/' // 输出到指定目录下
}
},
{
loader: 'image-webpack-loader', // 使用image-webpack-loader处理图片文件
options: {
mozjpeg: {
progressive: true,
quality: 65
},
// optipng.enabled: false will disable optipng
optipng: {
enabled: false,
},
pngquant: {
quality: [0.65, 0.90],
speed: 4
},
gifsicle: {
interlaced: false,
},
// the webp option will enable WEBP
webp: {
quality: 75
}
}
}
]
}
]
}
};

json-loader

用于导入 JSON 文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const path = require('path');

module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [
{
test: /\.json$/, // 匹配以.json结尾的文件
loader: 'json-loader' // 使用json-loader处理匹配到的文件
}
]
}
};

喜欢这篇文章?打赏一下支持一下作者吧!
【webpack】自定义loader
https://www.cccccl.com/20221103/webpack/自定义loader/
作者
Jeffrey
发布于
2022年11月3日
许可协议