loader 简写

306 阅读2分钟

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

loader-runner文档


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);

});

};