loader简介
在webpack中loader 用于对模块的源代码进行转换。常见的loader有css-loader、babel-loader、vue-loader等。
一个简单的loader
loader本身只是一个导出为函数的js的模块。
moudule.exports = function (source) {
return source.replace('代码', '新代码')
}
这段代码是最简单的文案替换的loader。书写完loader,我们需要在项目中配置该loader。
项目如何使用
项目中单个laoder的配置:
const webpack = {
module: {
rules: [{
test: /main\.js/,
use: [{
loader: path.resolve(__dirname, 'loaders/my-loader.js')
}]
}]
}
}
项目中多个loader的配置:
const webpack = {
module: {
rules: [{
test: /main\.js/,
use: [{
loader: path.resolve(__dirname, 'loaders/my-loader.js')
}, {
loader: 'other-loader.js',
options: {
...options
}
}]
}]
}
}
多个loader为串行执行。即一个loader执行完后,另一个loader才开始处理上一个loader输出的文件内容。多个loader的执行顺序为从右往左。即从后往前。
loader的几种使用方式
loader的执行类型可以通过在进行loader时的enforce来决定。loader 的类型有以下三种:
-
pre loader (前置)
-
post loader (后置)
-
normal loader 正常执行
-
inline loader 行内loader
module: {
rules: [{
test: /\.js$/,
use: 'loader1',
enforce: 'pre'
}, {
test: /\.js$/,
use: 'loader2'
}, {
test: /\.js$/,
use: 'loader3',
enforce: 'post'
}]
}
加上了enforce会改变原有自下而上的执行顺序,更改为pre、normal、post的执行顺序。
除上面配置中这三种loader,还有一种为行内loader,一般行内loader的执行顺序在后置loader之前normal loader 之后。
inline loader的引用为:
const a = require('loader!./b')
inline loader的特殊符号的含义为:
-!:不会让文件再去通过pre + normal loader处理
!:不会让文件再去通过normal loader处理
!!:只让inline-loader来处理
loader-runner
-
webpack依赖loader-runner去执行loader
-
loader-runner 可帮助我们来快速开发loader
import { runLoaders } from "loader-runner";
runLoaders({
resource: "/abs/path/to/file.txt?query",
// String: Absolute path to the resource (optionally including query string)
loaders: ["/abs/path/to/loader.js?query"],
// String[]: Absolute paths to the loaders (optionally including query string)
// {loader, options}[]: Absolute paths to the loaders with options object
context: { minimize: true },
// Additional loader context which is used as base context
processResource: (loaderContext, resourcePath, callback) => { ... },
// Optional: A function to process the resource
// Must have signature function(context, path, function(err, buffer))
// By default readResource is used and the resource is added a fileDependency
readResource: fs.readFile.bind(fs)
// Optional: A function to read the resource
// Only used when 'processResource' is not provided
// Must have signature function(path, function(err, buffer))
// By default fs.readFile is used
}, function(err, result) {
// err: Error?
// result.result: Buffer | String
// The result
// only available when no error occured
// result.resourceBuffer: Buffer
// The raw resource as Buffer (useful for SourceMaps)
// only available when no error occured
// result.cacheable: Bool
// Is the result cacheable or do it require reexecution?
// result.fileDependencies: String[]
// An array of paths (existing files) on which the result depends on
// result.missingDependencies: String[]
// An array of paths (not existing files) on which the result depends on
// result.contextDependencies: String[]
// An array of paths (directories) on which the result depends on
})
编写一个复杂的loader
// loader-utils@2.xx
const { getOptions } = require("loader-utils")
// 同步loader
moudule.exports = function (source) {
const options = getOptions(this)
/**
对代码的处理方式
*/
someOperation()
// 可以使用这种返回方式
// return newSource or
this.callback(null, newSource)
return;
}
// 异步loader
module.exports = function (content) {
var callback = this.async();
someAsyncOperation(content, function (err, result) {
if (err) return callback(err);
callback(null, result);
});
};