Loader 深入:实战配置与优化
大家好,我是老李。今天咱们聊聊 Webpack 里几个最常用的 loader。说实话,刚接触这些 loader 时我也被各种配置搞晕过。后面踩了几个坑,才慢慢理清它们各自是干什么的。你想想看,一个项目里少说几十个文件,要是没几个好用的 loader,光靠 Webpack 自己可处理不了 JS、CSS、图片这些。
我就按自己的习惯,把常用 loader 分成几类:处理 JavaScript 的、处理 CSS 的、还有处理资源和普通文本的。每类我们挑一两个典型说透。
1. babel-loader:把现代 JS 变成兼容代码
babel-loader 可以说是前端构建里的「翻译官」。它把 ES6+ 语法转成浏览器能认的 ES5。我在一个老项目里遇到过,没配 babel-loader,结果用户用 IE11 打开页面直接白屏。那会儿真是头皮发麻。
配置上,我个人习惯这样写:
module.exports = {
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
cacheDirectory: true, // 缓存编译结果
presets: ['@babel/preset-env'],
plugins: ['@babel/plugin-transform-runtime']
}
}
}
]
}
};
cacheDirectory 后,第二次构建能快 50% 以上。另外记得 exclude: /node_modules/,不然每次编译都会去翻第三方库,那性能直接崩掉。
为什么还要加 @babel/plugin-transform-runtime?说白了,避免每个文件都重复注入辅助函数。我曾经在一个大项目里没配这个插件,打包体积直接多了 500KB,被组长点名批评。
2. css-loader + style-loader:让样式活起来
css-loader 解析 CSS 里的 @import 和 url(),style-loader 把 CSS 注入到 <style> 标签。两者是黄金搭档。不过,配置时有个坑——
我真的踩过的一个坑: 以前做多页应用,没配 modules,结果两个页面的类名冲突,样式互相覆盖。排查了一下午才发现是 css-loader 默认开启了全局模式。所以现在我建议,除非你很清楚不需要模块化,否则一定加上 modules: true。
{
test: /\.css$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
importLoaders: 1,
modules: {
localIdentName: '[name]__[local]___[hash:base64:5]'
}
}
},
'postcss-loader' // 比如加 autoprefixer
]
}
3. file-loader 与 url-loader:图片字体怎么处理
这两个 loader 处理文件(图片、字体等),但目标不同。file-loader 直接把文件拷贝到输出目录,返回 URL;url-loader 则是小文件转 base64 内联,大文件走 file-loader。
我喜欢这样区分使用场景:
| Loader | 适用场景 | 配置关键点 |
|---|---|---|
| file-loader | 大图片、字体文件(> 8KB) | 设置 outputPath、publicPath |
| url-loader | 小图标、小字体(< 8KB) | 设置 limit 阈值 |
| raw-loader | 文本文件(.txt, .md) | 直接返回字符串,适合模板注入 |
举个例子,用 url-loader 处理图片:
{
test: /\.(png|jpe?g|gif|svg)$/,
use: [
{
loader: 'url-loader',
options: {
limit: 8 * 1024, // 8KB 以下转 base64
name: 'images/[name].[hash:8].[ext]'
}
}
]
}
我这里有个经验: limit 别设太大。如果所有图片都转 base64,CSS 文件会膨胀几十倍,首屏加载反而变慢。我一般保持在 4~8KB,这是经过多次测试的平衡点。
4. raw-loader:一股清流,直接拿文本
raw-loader 很简单,它把文件内容当作字符串返回。比如你想把一段 Markdown 文件当作模板渲染,或者把 SVG 直接当字符串内联,这时候用它再合适不过。
{
test: /\.txt$/,
use: 'raw-loader'
}
然后你可以在 JS 里:
import readme from './README.txt';
console.log(readme); // 直接是文件内容的字符串
- babel-loader 要开缓存(cacheDirectory),排除 node_modules
- css-loader 配置 modules 防止类名冲突,生产环境用 MiniCssExtractPlugin 代替 style-loader
- url-loader 设合理的 limit(4-8KB),小图内联,大图走 file-loader
- raw-loader 处理纯文本,在模板引擎、国际化资源场景里很好用
好了,loader 这块我先讲这么多。每个 loader 都有自己的脾气,配置对了能省不少时间。下次有空咱们再聊聊 Plugin,那又是另一番天地了。