Loader 是 Webpack 生态中最核心的概念之一,理解 Loader 的原理和使用,是掌握前端工程化的关键一步。
目录
- 1. Loader 是什么
- 2. Loader 的核心原理
- 3. Loader 的基础用法
- 4. 常用 Loader 详解
- 5. 自定义 Loader
- 6. Loader 链式调用
- 7. 常见使用场景
- 8. 最佳实践
- 9. 常见问题
1. Loader 是什么
1.1 定义
Loader 是文件转换器,它的作用是将非 JavaScript 文件转换成 Webpack 能够理解和处理的模块。
1.2 为什么需要 Loader
Webpack 本身只认识 JavaScript 文件。但在前端开发中,我们需要处理各种类型的文件:
| 文件类型 | 需要 Loader 转换 |
|---|---|
.vue |
vue-loader |
.scss/.sass |
sass-loader |
.ts |
ts-loader |
.png/.jpg |
file-loader / url-loader |
.svg |
svg-loader |
.md |
markdown-loader |
1.3 Loader 的作用
┌─────────────────────────────────────────────────────┐
│ 源文件 │
│ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ │
│ │.vue │ │ .scss │ │ .ts │ │ .png │ │
│ └────────┘ └────────┘ └────────┘ └────────┘ │
└─────────────────────────────────────────────────────┘
↓ Loader 转换
┌─────────────────────────────────────────────────────┐
│ Webpack 可处理的模块 │
│ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ │
│ │ JS │ │ CSS │ │ JS │ │ JS │ │
│ └────────┘ └────────┘ └────────┘ └────────┘ │
└─────────────────────────────────────────────────────┘
2. Loader 的核心原理
2.1 执行顺序
Loader 的执行顺序是从右到左,从下到上。
{ test: /\.scss$/, use: [ 'style-loader', // 3. 最后执行 'css-loader', // 2. 中间执行 'sass-loader' // 1. 最先执行 ] }
执行流程:
main.scss
↓
sass-loader (SCSS → CSS)
↓
main.css
↓
css-loader (处理 @import、url())
↓
处理后的 CSS
↓
style-loader (插入到 style 标签)
↓
注入到页面
2.2 Loader 函数签名
每个 Loader 本质上是一个函数:
/** * @param {string|Buffer} source - 文件内容 * @returns {string|Buffer} - 转换后的内容 */ module.exports = function(source) { // 转换逻辑 return transformedSource }
2.3 更完整的 Loader 结构
module.exports = function(source, sourceMap, meta) { // source: 文件内容 // sourceMap: 源映射 // meta: 元数据// 可以使用 this 访问上下文
const callback = this.async()
const options = this.getOptions()// 异步处理
someAsyncProcess(source, options, (error, result) => {
callback(error, result, sourceMap, meta)
})
}
3. Loader 的基础用法
3.1 基本配置
module.exports = { module: { rules: [ { test: /\.js$/, // 匹配文件 use: 'babel-loader' // 使用的 Loader(字符串形式) } ] } }
3.2 数组形式(链式调用)
{ test: /\.scss$/, use: [ 'style-loader', 'css-loader', 'sass-loader' ] }
3.3 对象形式(传递选项)
{ test: /\.js$/, use: { loader: 'babel-loader', options: { presets: ['@babel/preset-env'], cacheDirectory: true } } }
3.4 混合形式
{ test: /\.scss$/, use: [ // 字符串简写 'style-loader', // 对象带选项 { loader: 'css-loader', options: { modules: true, importLoaders: 1 } }, // 字符串简写 'sass-loader' ] }
3.5 条件匹配
{ test: /\.js$/, include: path.resolve(__dirname, 'src'), // 只处理 src 目录 exclude: /node_modules/ // 排除 node_modules use: 'babel-loader' }
4. 常用 Loader 详解
4.1 babel-loader - ES6+ 转换
作用: 将 ES6+ 代码转换成 ES5,兼容旧浏览器。
安装:
npm install -D babel-loader @babel/core @babel/preset-env
配置:
{ test: /\.js$/, exclude: /node_modules/, use: { loader: 'babel-loader', options: { presets: [ ['@babel/preset-env', { targets: { browsers: ['> 1%', 'last 2 versions'] } }] ], cacheDirectory: true // 开启缓存 } } }
效果:
// 源代码 const greeting = () => 'Hello'// 转换后
var greeting = function greeting() {
return ‘Hello’;
}
4.2 sass-loader - SCSS 编译
作用: 将 SCSS/Sass 文件编译成 CSS。
安装:
npm install -D sass-loader sass
配置:
{ test: /\.(scss|sass)$/, use: [ 'style-loader', 'css-loader', 'sass-loader' ] }
效果:
// 源代码 $primary: #42b983;.button {
background: $primary;
}// 编译后
.button {
background: #42b983;
}
4.3 css-loader - CSS 处理
作用: 处理 CSS 中的 @import 和 url(),将其转换成 require 或 import。
安装:
npm install -D css-loader
配置:
{ loader: 'css-loader', options: { modules: true, // 启用 CSS Modules importLoaders: 1 // 在 @import 之前应用几个 loader } }
效果:
/* 源代码 */ @import 'variables.scss';/* 转换后 */
require(‘variables.scss’);
4.4 style-loader - CSS 注入
作用: 将 CSS 注入到 DOM 的 <style> 标签中。
安装:
npm install -D style-loader
配置:
{ loader: 'style-loader', options: { injectType: 'styleTag', // 注入方式 attributes: { id: 'app-styles' // 添加自定义属性 } } }
4.5 file-loader - 文件处理
作用: 将文件输出到输出目录,返回文件 URL。
安装:
npm install -D file-loader
配置:
{ test: /\.(png|jpg|gif|svg)$/, use: { loader: 'file-loader', options: { name: '[name].[hash].[ext]', // 文件名 outputPath: 'images/' // 输出目录 publicPath: '/images/' // 公共路径 } } }
效果:
// 源代码 import logo from './logo.png'// 转换后
import logo from ‘/images/logo.abc123.png’
4.6 url-loader - Base64 处理
作用: 小文件转成 Base64,减少 HTTP 请求。
安装:
npm install -D url-loader
配置:
{ test: /\.(png|jpg|gif)$/, use: { loader: 'url-loader', options: { limit: 8192, // 小于 8KB 转 Base64 fallback: 'file-loader' // 大于限制使用 file-loader } } }
效果:
// 小于 8KB import logo from './small.png' // 转换成 import logo from 'data:image/png;base64,iVBORw0KG...'// 大于 8KB
import logo from ‘./large.png’
// 保持原样,输出到文件
4.7 vue-loader - Vue 单文件组件
作用: 解析 .vue 单文件组件。
安装:
npm install -D vue-loader vue-template-compiler
配置:
{ test: /\.vue$/, use: 'vue-loader' }
效果:
<!-- 源代码 -->
<template>
<div>{{ message }}</div>
</template>
<script>
export default {
data() {
return { message: ‘Hello’ }
}
}
</script>
<style scoped>
div { color: red; }
</style>
<!-- 转换成可执行的 JS 模块 -->
5. 自定义 Loader
5.1 同步 Loader
场景: 给所有 JS 文件添加版权注释。
// copyright-loader.js module.exports = function(source) { const copyright = `/** * Copyright © 2025 My Company */\n` return copyright + source }
使用:
{ test: /\.js$/, use: './copyright-loader' }
5.2 异步 Loader
场景: 调用异步 API 处理文件。
// translate-loader.js module.exports = function(source) { const callback = this.async()// 模拟异步操作
setTimeout(() => {
const translated = source.replace(/Hello/g, ‘你好’)
callback(null, translated)
}, 1000)
}
5.3 带选项的 Loader
场景: 根据 options 决定行为。
// banner-loader.js module.exports = function(source) { const options = this.getOptions() || {} const banner = options.prefix || '// Custom Banner\n' return banner + source }
使用:
{ loader: './banner-loader', options: { prefix: '// My Project\n' } }
5.4 获取文件信息
// info-loader.js module.exports = function(source) { const filepath = this.resourcePath // 文件完整路径 const query = this.resourceQuery // 查询参数 const context = this.context // 上下文目录console.log(‘处理文件:’, filepath)
console.log(‘上下文:’, context)return source
}
6. Loader 链式调用
6.1 基本链式
{ test: /\.scss$/, use: [ 'style-loader', // 输出:注入到 style 'css-loader', // 输入:CSS 'sass-loader' // 输出:CSS ] }
6.2 多次使用同一 Loader
{ test: /\.css$/, use: [ 'style-loader', { loader: 'css-loader', options: { import: false } }, { loader: 'postcss-loader', options: { plugins: [...] } } ] }
6.3 内联 Loader(不推荐)
// 在 import 语句中直接指定 import styles from 'style-loader!css-loader!sass-loader!./main.scss'
7. 常见使用场景
场景一:Vue + TypeScript + SCSS
module.exports = { module: { rules: [ // Vue 单文件组件 { test: /\.vue$/, use: 'vue-loader' }, // TypeScript { test: /\.ts$/, exclude: /node_modules/, use: 'ts-loader' }, // SCSS { test: /\.scss$/, use: [ 'style-loader', 'css-loader', 'sass-loader' ] } ] } }
场景二:图片优化
{ test: /\.(png|jpg|gif)$/, use: [ { loader: 'image-webpack-loader', options: { mozjpeg: { progressive: true }, gifsicle: { interlaced: false } } }, 'url-loader' ] }
场景三:处理字体文件
{ test: /\.(woff|woff2|eot|ttf)$/, use: { loader: 'file-loader', options: { name: '[name].[hash].[ext]', outputPath: 'fonts/' } } }
场景四:CSS Modules
{ test: /\.module\.css$/, use: [ 'style-loader', { loader: 'css-loader', options: { modules: { localIdentName: '[name]__[local]--[hash:base64:5]' } } } ] }
场景五:处理 Markdown
{ test: /\.md$/, use: [ 'html-loader', { loader: 'markdown-loader', options: { gfm: true, tables: true } } ] }
8. 最佳实践
8.1 使用缓存
{ loader: 'babel-loader', options: { cacheDirectory: true, // 开启缓存 cacheCompression: false } }
8.2 排除不必要的文件
{ test: /\.js$/, exclude: [ /node_modules/, // 排除第三方库 /vendor/, // 排除供应商文件 /\.test\.js$/ // 排除测试文件 ], use: 'babel-loader' }
8.3 合理配置 include
{ test: /\.js$/, include: path.resolve(__dirname, 'src'), // 只处理 src 目录 use: 'babel-loader' }
8.4 使用 oneOf 优化
{ test: /\.js$/, oneOf: [ // 特殊文件特殊处理 { test: /\.worker\.js$/, use: 'worker-loader' }, // 普通文件 { use: 'babel-loader' } ] }
9. 常见问题
Q1: Loader 执行顺序搞反了?
A: Loader 是从右到左、从下到上执行的。
// 假设 use 是数组 use: [ 'style-loader', // 3. 最后 'css-loader', // 2. 中间 'sass-loader' // 1. 最先 ]
Q2: Loader 找不到?
A: 确保已安装:
npm install -D css-loader
Q3: 如何调试 Loader?
A:
// my-loader.js module.exports = function(source) { console.log('处理文件:', this.resourcePath) console.log('内容:', source) return source }
Q4: Loader 性能慢?
A:
- 开启缓存
- 减少不必要的 Loader
- 使用
include/exclude缩小范围 - 使用
thread-loader多线程处理
Q5: 如何获取 Loader 版本?
A:
npm view css-loader version
总结
| 概念 | 说明 |
|---|---|
| Loader | 文件转换器,将非 JS 文件转换成 Webpack 可处理的模块 |
| 执行顺序 | 从右到左,从下到上 |
| 同步/异步 | 都支持,用 this.async() 处理异步 |
| 链式调用 | 多个 Loader 组合,输出作为下一个输入 |
| 最佳实践 | 缓存、合理 exclude/include、性能优化 |
Loader 是 Webpack 生态的核心,掌握 Loader 的原理和使用,能够让你更灵活地处理各种前端资源,提升开发效率。
希望这篇文章对你有帮助!有任何问题欢迎交流。