一个 webpack loader,在构建时执行给定模块,并在模块在 bundle 中被需要时返回执行结果。通过这种方式,该 loader 将模块从代码转换为结果。
另一种看待 val-loader
的方式是,它允许用户实现自定义 loader 逻辑,而无需编写完整的自定义 loader。
目标模块会以两个参数调用:(options, loaderContext)
options
: loader 选项(例如在 webpack 配置中提供。请参阅下面的示例)。loaderContext
: loader 上下文。首先,你需要安装 val-loader
npm install val-loader --save-dev
yarn add -D val-loader
pnpm add -D val-loader
然后,将加载器添加到你的 webpack
配置中。例如:
target-file.js
module.exports = (options, loaderContext) => {
return { code: "module.exports = 42;" };
};
webpack.config.js
module.exports = {
module: {
rules: [
{
test: /target-file.js$/,
use: [
{
loader: `val-loader`,
},
],
},
],
},
};
src/entry.js
const answer = require("target-file");
最后,使用你通常使用的方法运行 webpack
(例如,通过 CLI 或 npm 脚本)。
executableFile
类型
type executableFile = string;
默认值:undefined
允许指定可执行文件的路径。
data.json
{
"years": "10"
}
executable-file.js
module.exports = function yearsInMs(options, loaderContext, content) {
const { years } = JSON.parse(content);
const value = years * 365 * 24 * 60 * 60 * 1000;
return {
cacheable: true,
code: "module.exports = " + value,
};
};
webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.(json)$/i,
rules: [
{
loader: "val-loader",
options: {
executableFile: path.resolve(
__dirname,
"fixtures",
"executableFile.js",
),
},
},
],
},
{
test: /\.json$/i,
type: "asset/resource",
},
],
},
};
此 loader 的目标模块必须导出一个返回对象的函数
,或解析为对象的 Promise
(例如 async function),其中至少包含一个 code
属性,但也可以包含其他属性。
code
类型
type code = string | Buffer;
默认值:undefined
必填
传递给 webpack 或下一个 loader 的代码,它将替换原始模块。
sourceMap
类型
type sourceMap = object;
默认值:undefined
传递给 webpack 或下一个 loader 的 Source Map。
ast
类型
type ast = Array<object>;
默认值:undefined
一个将传递给下一个 loader 的抽象语法树 (AST)。如果下一个 loader 使用相同的 AST,则有助于加快构建时间。
dependencies
类型
type dependencies = Array<string>;
默认值:[]
一个包含文件依赖项的绝对原生路径数组,webpack 应该监视这些路径以检测更改。
依赖项也可以使用 loaderContext.addDependency(file: string)
添加。
contextDependencies
类型
type contextDependencies = Array<string>;
默认值:[]
一个包含目录依赖项的绝对原生路径数组,webpack 应该监视这些路径以检测更改。
上下文依赖项也可以使用 loaderContext.addContextDependency(directory: string)
添加。
buildDependencies
类型
type buildDependencies = Array<string>;
默认值:[]
一个包含目录依赖项的绝对原生路径数组,webpack 应该监视这些路径以检测更改。
构建依赖项也可以使用 loaderContext.addBuildDependency(file: string)
添加。
cacheable
类型
type cacheable = boolean;
默认值:false
如果为 true
,则指定如果 dependencies
都没有改变,则代码可以在监听模式下重复使用。
在此示例中,loader 被配置为处理名为 years-in-ms.js
的文件,执行代码,并将执行结果存储在 bundle 中。此示例将 years
作为 option
传递,这对应于目标模块导出函数中的 years
参数。
years-in-ms.js
module.exports = function yearsInMs({ years }) {
const value = years * 365 * 24 * 60 * 60 * 1000;
// NOTE: this return value will replace the module in the bundle
return {
cacheable: true,
code: "module.exports = " + value,
};
};
webpack.config.js
module.exports = {
module: {
rules: [
{
test: require.resolve("src/years-in-ms.js"),
use: [
{
loader: "val-loader",
options: {
years: 10,
},
},
],
},
],
},
};
在 bundle 中,require 该模块将返回
import tenYearsMs from "years-in-ms";
console.log(tenYearsMs); // 315360000000
示例展示了如何构建 modernizr
。
entry.js
import modenizr from "./modernizr.js";
modernizr.js
const modernizr = require("modernizr");
module.exports = function (options) {
return new Promise(function (resolve) {
// It is impossible to throw an error because modernizr causes the process.exit(1)
modernizr.build(options, function (output) {
resolve({
cacheable: true,
code: `var modernizr; var hadGlobal = 'Modernizr' in window; var oldGlobal = window.Modernizr; ${output} modernizr = window.Modernizr; if (hadGlobal) { window.Modernizr = oldGlobal; } else { delete window.Modernizr; } export default modernizr;`,
});
});
});
};
webpack.config.js
const path = require("path");
module.exports = {
module: {
rules: [
{
test: path.resolve(__dirname, "src", "modernizr.js"),
use: [
{
loader: "val-loader",
options: {
minify: false,
options: ["setClasses"],
"feature-detects": [
"test/css/flexbox",
"test/es6/promises",
"test/serviceworker",
],
},
},
],
},
],
},
};
示例展示了如何构建 figlet
。
entry.js
import { default as figlet } from "./figlet.js";
console.log(figlet);
figlet.js
const figlet = require("figlet");
function wrapOutput(output, config) {
let figletOutput = "";
if (config.textBefore) {
figletOutput += encodeURI(`${config.textBefore}\n`);
}
output.split("\n").forEach((line) => {
figletOutput += encodeURI(`${line}\n`);
});
if (config.textAfter) {
figletOutput += encodeURI(`${config.textAfter}\n`);
}
return `module.exports = decodeURI("${figletOutput}");`;
}
module.exports = function (options) {
const defaultConfig = {
fontOptions: {
font: "ANSI Shadow",
horizontalLayout: "default",
kerning: "default",
verticalLayout: "default",
},
text: "FIGLET-LOADER",
textAfter: null,
textBefore: null,
};
const config = Object.assign({}, defaultConfig, options);
return new Promise(function (resolve, reject) {
figlet.text(config.text, config.fontOptions, (error, output) => {
if (error) {
return reject(error);
}
resolve({
cacheable: true,
code: "module.exports = " + wrapOutput(output, config),
});
});
});
};
webpack.config.js
const path = require("path");
module.exports = {
module: {
rules: [
{
test: path.resolve(__dirname, "src", "figlet.js"),
use: [
{
loader: "val-loader",
options: {
text: "FIGLET",
},
},
],
},
],
},
};
我们欢迎所有贡献!如果您是新用户,请在提交问题或拉取请求之前花一些时间阅读我们的贡献指南。