Loader
Loader 是一个打包方案,本身是一个函数,接受源文件作为参数,返回转换的结果。
loaders 需要安装:npm install [loader名称] -D
。
Loader 的使用方式
-
配置方式(Configuration)
Loader 是有执行顺序的,从下到上,从右到左 ,因为 Webpack 使用的是 compose 函数式编程方式,这种表达式的执行是从右到左。jsmodule.exports = { module: { rules: [ { test: /\.css$/, use: ["style-loader", "css-loader", "postcss-loader"], }, ] } }
-
内联方式(Inline)
可以在import
语句或任何与import
方法同等的引用方式中指定 loader。
使用!
将资源中的 loader 分开。jsimport Styles from 'style-loader!css-loader?modules!./styles.css';
常用的 Loader
babel-loader
转换 ES6+ 新语法为 ES5。
js
module.exports = {
module: {
rules: [
{
test: /\.js$/,
use: ['babel-loader'],
include: srcPath,
exclude: /node_modules/
}
]
}
}
style-loader
把 CSS 插入到 DOM 中。
推荐将 style-loader
与 css-loader
一起使用。
css-loader
对 @import
和 url()
进行处理,分析 CSS 模块之间的关系,并合并成一个 CSS。
js
module.exports = {
module: {
rules: [
{
test: /.css$/i,
use: ['style-loader', 'css-loader'],
},
],
},
};
postcss-loader
- CSS 预处理器 :可以使用像 Sass、Less 或 Stylus 这样的预处理器编写 CSS 代码,然后通过
postcss-loader
将其转换为标准的 CSS。 - 自动添加前缀 :通过 Autoprefixer 等插件,
postcss-loader
可以自动为 CSS 属性添加浏览器前缀,以确保在不同浏览器中具有一致的表现。
js
module.exports = {
module: {
rules: [
{
test: /.css$/i,
use: ['style-loader', 'css-loader', 'postcss-loader'],
},
],
},
};
手写一个 loader
- loader 是一个函数,不能使用箭头函数,因为要用到上下文中的 this
- 接收一个源文件参数
- 返回处理后的文件结果
js
// customLoader.js
// 转化文件大小写
module.exports = function (source) {
const transform = source.replace(/[A-Z]/g, function (match) {
return match.toLowerCase();
});
return transform;
};
使用:
js
module.exports = {
// ...
module: {
rules: [
{
test: /\.js$/, // 匹配需要使用 loader 的文件
use: path.resolve(__dirname, "./customBabel.js"),
},
],
},
};
测试文件:
js
// index.js
const a = "A";
const B = "B";
console.log("a", a);
console.log("B", B);
打包后结果:
js
// dist/bundle.js
console.log("a","a"),console.log("b","b");
Plugin
插件的目的是为了解决 Loader 无法实现的其他事。
Webpack 插件是一个具有 apply
方法的 js 对象。
用法: new xxxPlugin(参数)
常用的 plugin
CommonsChunkPlugin
提取 chunk 之间的公共模块用来共享,是一个 Webpack 的内置插件,不需要安装。
js
new webpack.optimize.CommonsChunkPlugin({
name: 'commons',
filename: 'commons.js',
});
CleanWebpackPlugin
删除/清理构建目录。
shell
$ yarn add clean-webpack-plugin -D
js
const CleanWebpackPlugin = require('clean-webpack-plugin');
module.exports = {
plugins: [
// 打包之前清除 dist 文件
new CleanWebpackPlugin(['dist'], { root: process.cwd(), verbose: true })
]
}
HtmlWebpackPlugin
在打包结束后,自动生成一个 html 文件,并把打包生成的 js 模块引入到该 html 中。
shell
$ npm install --save-dev html-webpack-plugin
js
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
plugins: [
new HtmlWebpackPlugin({
template: path.join(__dirname, "../../src/template.html.ejs"),
filename: "index.html",
chunks: ["vendor", "runtime"],
inject: "body",
}),
]
};
html
<!-- src/template.html.ejs -->
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>
<%= htmlWebpackPlugin.options.title || '标题' %>
</title>
</head>
<body></body>
</html>
EJS 是一套简单的模版语法,帮你利用普通的 JavaScript 代码生成 HTML 文件。
MiniCssExtractPlugin
提取 CSS 到一个单独的文件中。
shell
$ npm install --save-dev mini-css-extract-plugin
js
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
...,
module: {
rules: [
{
test: /\.s[ac]ss$/,
use: [
{
loader: MiniCssExtractPlugin.loader
},
'css-loader',
'sass-loader'
]
}
]
},
plugins: [
...,
new MiniCssExtractPlugin({
filename: '[name].css'
}),
...
]
}
DefinePlugin
允许在编译时创建配置的全局对象,是一个 webpack 内置的插件,不需要安装。
js
module.exports = {
plugins: [
new webpack.DefinePlugin({
'process.env.NODE_ENV': '"production"',
PRODUCTION: true
})
]
}
CopyWebpackPlugin
复制文件或目录到执行区域。
shell
$ yarn add copy-webpack-plugin -D
js
const pathUtil = require('path');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const appRoot = pathUtil.join(__dirname, '../..');
module.exports = {
plugins: [
new CopyWebpackPlugin([
{
from: './static', // 设置从哪一个源开始复制
to: pathUtil.join(appRoot, 'priv/static'), // 复制到的位置,可以省略,默认复制到打包的目录中
globOptions: {} // 设置一些额外的选项,其中可以编写需要忽略的文件
}
])
]
}
__dirname :返回当前模块文件解析后,所在的文件夹(目录)的绝对路径。
__filename:返回当前模块文件被解析后的绝对路径。
手写一个 Plugin
- plugin 是一个构造函数,能够通过
new
来实例化对象; - PluginName 可以写成普通函数,
apply
方法必须挂载到原型对象(PluginName.prototype
)上; - 有一个
apply
方法,作为插件的入口点,Webpack 会调用此方法并传入compiler
对象参数。
js
// customPlugin.js
// 该定义插件会在打包完成后会输出每个模块的打包时间
class CustomPlugin {
// 构造函数接收一个 options 参数,用来配置插件的行为
constructor(options) {}
// apply 方法是插件的入口点,webpack 会调用此方法并传入 compiler 对象
apply(compiler) {
// 注册一个钩子函数,监听 webpack 打包完成的事件
compiler.hooks.compilation.tap("CustomPlugin", (compilation) => {
compilation.hooks.buildModule.tap("CustomPlugin", (module) => {
module.startTime = Date.now();
});
});
compiler.hooks.thisCompilation.tap("CustomPlugin", (compilation) => {
compilation.hooks.finishModules.tap("CustomPlugin", (modules) => {
modules.forEach((module) => {
if (module.resource) {
const buildTime = module.startTime ? Date.now() - module.startTime : "N/A";
console.log(`${module.resource} - Build Time: ${buildTime}ms`);
}
});
});
});
}
}
module.exports = CustomPlugin;
执行结果:
loader 🆚 plugin
功能不同
- Loader:加载器,Webpack 将一切文件视为模块,但 Webpack 原生只能解析 JS 文件,所以 Loader 的作用是让 Webpack 拥有了加载和解析非 JS 文件的能力。
- Plugin:插件,Plugin 是用于拓展 Webpack 的功能,在 Webpack 构建过程中执行一些额外的任务,如优化资源、打包输出结果、注入环境变量等。
用法不同
- Loader :在
module.rules
中配置,类型是数组,每一项都是 Object,里面描述了对于什么类型的文件(test),使用什么加载(use),使用的参数(options)等。 - Plugin :在
plugins
中单独配置,类型是数组,每一项为一个 pluin 的实例,参数通过构造函数传入。
运行时机不同
- Loader:打包之前。
- Plugin:整个构建过程都起作用。
参考:官方文档 Loaders
参考:官方文档 Plugins
欢迎纠错~