loader 概念
官网对 loader
的解释是这样的:
webpack 只能理解 JavaScript 和 JSON 文件,这是 webpack 开箱可用的自带能力。loader 让 webpack 能够去处理其他类型的文件,并将它们转换为有效 模块,以供应用程序使用,以及被添加到依赖图中。
我对 loader
的理解:就是将不同类型的文件转换为 webpack
可以识别的模块。有点像中间件的感觉,如果自己写过loader 的话,应该就知道loader 就是一个个的函数
- 接收文件内容
content
- 在
loader
函数中对内容进行处理(比如将style.less
转换成style.css
) - 返回文件内容
content
和 plugin
的区别:
plugin 是监听打包整个过程中的某些结点(比如打包之后的合并压缩等等),
loader
能做的事情有时候plugin
也可以做,有些plugin
能做的事情loader
也可以做,plugin
的生命周期更长一些,会覆盖到loader
的生命周期
loader 分类和执行顺序
-
分类
pre
: 前置loader
normal
:普通loader
(默认值)inline
:内联loader
post
:后置loader
-
执行顺序
pre
>normal
>inline
>post
- 相同优先级的loader执行顺序为:从右到左,从下到上
// 执行顺序就是:loader3 -> loader2 -> loader1 module: { rules: [ {test: /.js$/, loader: "loader1"}, {test: /.js$/, loader: "loader2"}, {test: /.js$/, loader: "loader3"}, ] }
因为
loader
的执行顺序,如果想要改变 loader 的执行顺序,除了移动我们的代码,还可以通过 设置他们的分类 来达到改变执行顺序的目的module: { rules: [ {enforce: "pre", test: /.js$/, loader: "loader1"}, {test: /.js$/, loader: "loader2"}, {enforce: "post", test: /.js$/, loader: "loader3"}, ] }
-
使用方式
- 配置方式:在webpack.config.js中指定loader(只能指定pre,normal,post)
- 内联方式:在每一个 import 语句中显示指定 loader (这种方式就是
inline-loader
,用的比较少)// 使用 css-loader 和 style-loader 处理 styles.css文件 // 通过 !将资源中的 loader 分开 import styles from 'style-loader!css-loader?modules!./styles.css'
!
: 跳过normal loader
-!
: 跳过 pre 和 normal loader
!!
: 跳过 pre、normal和post loader
loader 的属性
- 同步 loader
function someSyncOperation(content) { // 进行一些同步操作,如清楚console.log return content.repace(/console\.log\(\.*\)/g, '') } module.exports = function(content, map, meta) { this.callback(null, someSyncOperation(content), map, meta); return; // 当调用 callback() 时总是返回 undefined };
- 异步 loader
const options = {} function someAsyncOperation(content, cb) { // 进行一些异步操作, 比如:babel 将 es6 代码转成 es5 就是异步的,就可以这样操作 babel.transform(content, options, function(error, result) { if (error) { cb(error) } else { cb(null, result.code) } }) } module.exports = function(content, map, meta) { var callback = this.async(); someAsyncOperation(content, function(err, result) { if (err) return callback(err); callback(null, result, map, meta); }); };
- Raw loader
默认情况下,资源文件会被转化为 UTF-8 字符串,然后传给 loader。通过设置 raw,loader 可以接收原始的 Buffer。每一个 loader 都可以用 String 或者 Buffer 的形式传递它的处理结果。Complier 将会把它们在 loader 之间相互转换。
// 比如:进行文件处理的时候,给文件名加个 hash 串 const loaderUtils = require('loader-utils') module.exports = function(content) { const interpolatedName = loaderUtils.interopolateName(this, "[hash].[ext][query]", {content}) this.emitFile(interpolatedName, content); return `module.exports = "${interpolatedName}"` }; module.exports.raw = true
- Pitching loader
loader 总是从右到左地被调用。有些情况下,loader 只关心 request 后面的元数据(metadata),并且忽略前一个 loader 的结果。在实际(从右到左)执行 loader 之前,会先从左到右调用 loader 上的 pitch 方法。对于以下 use 配置:
module.exports = { ... rules: [ { ... use: [ 'loader1', 'loader2', 'loader3' ] } ] ... }
loader1 pitch
>loader2 pitch
>loader3 pitch
loader3
正常执行 ->loader2
正常执行 ->loader1
正常执行
有点类似 “洋葱模型”,进去了之后再出来