Loader 详解
Loader 是 Webpack 的核心功能之一,用于转换非 JavaScript 文件。本章详细介绍 Loader 的工作原理、常用 Loader 的使用方法,以及如何自定义 Loader。
📋 学习目标
- ✅ 理解 Loader 的工作原理
- ✅ 掌握常用 Loader 的配置
- ✅ 理解 Loader 的执行顺序
- ✅ 学会自定义 Loader
- ✅ 掌握 Loader 的最佳实践
Loader 工作原理
什么是 Loader
Loader 是一个函数,接收源文件内容,返回转换后的内容。
源文件 → Loader1 → Loader2 → Loader3 → 最终结果
Loader 的基本结构
module.exports = function(source) {
// source 是源文件的内容(字符串)
// 进行转换处理
const result = transform(source)
// 返回转换后的内容
return result
}Loader 的执行流程
- Webpack 识别需要处理的文件(通过
test匹配) - 按顺序执行 Loader(从右到左)
- 每个 Loader 接收上一个 Loader 的输出
- 最后一个 Loader 返回 JavaScript 代码
常用 Loader
1. Babel Loader(转译 JavaScript)
安装:
npm install --save-dev babel-loader @babel/core @babel/preset-env配置:
module.exports = {
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'],
plugins: []
}
}
}
]
}
}高级配置:
module.exports = {
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
cacheDirectory: true, // 启用缓存
presets: [
['@babel/preset-env', {
useBuiltIns: 'usage',
corejs: 3
}],
'@babel/preset-react'
],
plugins: [
'@babel/plugin-proposal-class-properties'
]
}
}
}
]
}
}2. CSS Loader
安装:
npm install --save-dev style-loader css-loader基础配置:
module.exports = {
module: {
rules: [
{
test: /\.css$/,
use: [
'style-loader', // 将 CSS 注入到 DOM
'css-loader' // 解析 CSS 文件
]
}
]
}
}CSS Modules 配置:
module.exports = {
module: {
rules: [
{
test: /\.css$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
modules: {
localIdentName: '[name]__[local]__[hash:base64:5]'
},
importLoaders: 1
}
}
]
}
]
}
}3. Sass/Less Loader
安装:
npm install --save-dev sass-loader sass
# 或
npm install --save-dev less-loader lessSass 配置:
module.exports = {
module: {
rules: [
{
test: /\.scss$/,
use: [
'style-loader',
'css-loader',
'sass-loader'
]
}
]
}
}Less 配置:
module.exports = {
module: {
rules: [
{
test: /\.less$/,
use: [
'style-loader',
'css-loader',
'less-loader'
]
}
]
}
}4. PostCSS Loader
安装:
npm install --save-dev postcss postcss-loader autoprefixer配置:
module.exports = {
module: {
rules: [
{
test: /\.css$/,
use: [
'style-loader',
'css-loader',
{
loader: 'postcss-loader',
options: {
postcssOptions: {
plugins: [
require('autoprefixer')
]
}
}
}
]
}
]
}
}postcss.config.js:
module.exports = {
plugins: [
require('autoprefixer')
]
}5. 文件资源 Loader(Webpack 5)
Webpack 5 使用 Asset Modules:
module.exports = {
module: {
rules: [
{
test: /\.(png|jpg|jpeg|gif|svg)$/,
type: 'asset/resource',
generator: {
filename: 'images/[hash][ext]'
}
}
]
}
}小文件转 base64:
module.exports = {
module: {
rules: [
{
test: /\.(png|jpg|jpeg|gif)$/,
type: 'asset',
parser: {
dataUrlCondition: {
maxSize: 8 * 1024 // 8KB 以下转 base64
}
}
}
]
}
}6. TypeScript Loader
安装:
npm install --save-dev ts-loader typescript
# 或使用 babel-loader
npm install --save-dev @babel/preset-typescriptts-loader 配置:
module.exports = {
module: {
rules: [
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/
}
]
}
}Babel 配置:
module.exports = {
module: {
rules: [
{
test: /\.tsx?$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-typescript']
}
}
}
]
}
}7. 字体文件 Loader
module.exports = {
module: {
rules: [
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
type: 'asset/resource',
generator: {
filename: 'fonts/[hash][ext]'
}
}
]
}
}8. 数据文件 Loader
JSON:
// Webpack 5 内置支持,无需配置
import data from './data.json'CSV/TSV:
npm install --save-dev csv-loadermodule.exports = {
module: {
rules: [
{
test: /\.(csv|tsv)$/,
use: 'csv-loader'
}
]
}
}Loader 执行顺序
执行顺序规则
Loader 从右到左(或从下到上)执行:
module.exports = {
module: {
rules: [
{
test: /\.scss$/,
use: [
'style-loader', // 3. 最后执行
'css-loader', // 2. 然后执行
'sass-loader' // 1. 最先执行
]
}
]
}
}执行流程:
sass-loader将 SCSS 转换为 CSScss-loader解析 CSS 中的@import和url()style-loader将 CSS 注入到 DOM
使用对象配置 Loader
module.exports = {
module: {
rules: [
{
test: /\.scss$/,
use: [
{
loader: 'style-loader',
options: {
injectType: 'singletonStyleTag'
}
},
{
loader: 'css-loader',
options: {
modules: true
}
},
'sass-loader'
]
}
]
}
}自定义 Loader
基础 Loader
loaders/my-loader.js:
module.exports = function(source) {
// source 是源文件内容
const result = source.replace(/console\.log\(/g, '// console.log(')
return result
}使用自定义 Loader:
const path = require('path')
module.exports = {
module: {
rules: [
{
test: /\.js$/,
use: [
path.resolve(__dirname, 'loaders/my-loader.js')
]
}
]
}
}带选项的 Loader
loaders/replace-loader.js:
module.exports = function(source) {
const options = this.getOptions() || {}
const { search, replace } = options
if (search && replace) {
return source.replace(new RegExp(search, 'g'), replace)
}
return source
}使用:
module.exports = {
module: {
rules: [
{
test: /\.js$/,
use: [
{
loader: path.resolve(__dirname, 'loaders/replace-loader.js'),
options: {
search: 'OLD_TEXT',
replace: 'NEW_TEXT'
}
}
]
}
]
}
}异步 Loader
module.exports = function(source) {
const callback = this.async()
// 异步操作
setTimeout(() => {
const result = source.toUpperCase()
callback(null, result)
}, 1000)
}返回多个结果
module.exports = function(source) {
// 返回多个结果
this.emitFile('extra-file.js', 'extra content')
return source
}Loader 最佳实践
1. 使用 include/exclude
module.exports = {
module: {
rules: [
{
test: /\.js$/,
include: path.resolve(__dirname, 'src'),
exclude: /node_modules/,
use: 'babel-loader'
}
]
}
}2. 使用 oneOf(只匹配一个规则)
module.exports = {
module: {
rules: [
{
oneOf: [
{
test: /\.tsx?$/,
use: 'ts-loader'
},
{
test: /\.js$/,
use: 'babel-loader'
}
]
}
]
}
}3. 启用缓存
module.exports = {
module: {
rules: [
{
test: /\.js$/,
use: {
loader: 'babel-loader',
options: {
cacheDirectory: true
}
}
}
]
}
}4. 使用 enforce 控制执行顺序
module.exports = {
module: {
rules: [
{
test: /\.js$/,
enforce: 'pre', // 在其他 Loader 之前执行
use: 'eslint-loader'
},
{
test: /\.js$/,
enforce: 'post', // 在其他 Loader 之后执行
use: 'some-loader'
}
]
}
}完整配置示例
const path = require('path')
module.exports = {
module: {
rules: [
{
test: /\.(ts|tsx)$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
cacheDirectory: true,
presets: [
'@babel/preset-env',
'@babel/preset-react',
'@babel/preset-typescript'
]
}
}
},
{
test: /\.(css|scss)$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
modules: {
localIdentName: '[name]__[local]__[hash:base64:5]'
},
importLoaders: 2
}
},
'postcss-loader',
'sass-loader'
]
},
{
test: /\.(png|jpg|jpeg|gif|svg)$/,
type: 'asset',
parser: {
dataUrlCondition: {
maxSize: 8 * 1024
}
},
generator: {
filename: 'images/[hash][ext]'
}
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
type: 'asset/resource',
generator: {
filename: 'fonts/[hash][ext]'
}
}
]
}
}总结
- Loader 作用:转换非 JavaScript 文件
- 执行顺序:从右到左(或从下到上)
- 常用 Loader:Babel、CSS、Sass、文件资源等
- 自定义 Loader:可以创建自己的 Loader 处理特殊需求
- 最佳实践:使用 include/exclude、启用缓存、控制执行顺序
下一步
- Plugin 详解 - 学习插件的使用
- 开发环境配置 - 配置开发环境
- 实战项目:从零搭建 React 项目 - 实践 Loader 配置