使用自定义 webpack 加载器将额外字段附加到默认导出
Using a custom webpack loader to attach extra fields onto default export
我正在尝试编写一个自定义的 webpack 加载器,用于加载演示 javascript 文件及其源代码以供文档使用。应该
- 加载指示的 javascript 文件(例如
Simple.demo.js
)
- 将文件的原始来源作为新字段附加到默认导出
完成后,我应该可以在我的 webpack 配置中配置加载程序:
{
test: /\.demo.js$/,
exclude: /node_modules/,
use: [{
loader: "babel-loader",
}, {
loader: resolve("./demo-loader.js"),
}]
}
...然后在导入后访问我的演示的源代码:
import SimpleDemo from 'demo-loader!./Simple.demo.js';
console.log(SimpleDemo.__source__);
SimpleDemo(); //run the demo code
尝试 1
我已经使用以下加载程序成功加载了原始源代码并完成了命名导出:
const { readFile } = require("fs");
const escapeSource = require("js-string-escape");
module.exports = function withSourceLoader(content, map, meta) {
const onComplete = this.async();
const fileName = this.resource;
readFile(fileName, (error, fileContents) => {
if ( error ) {
return onComplete(error);
}
const exportSource = `export const rawSource = "${ escapeSource(fileContents)}";`;
const newContent = `${ content }\n\n${ exportSource }`;
onComplete(null, newContent, map, meta);
});
};
这让我做
import SimpleDemo, { rawSource } from 'demo-loader!./Simple.demo.js`;
console.log(rawSource);
SimpleDemo(); //run the demo code
...但我想将整个 SimpleDemo
作为对象传递给另一个函数,所以我想将它们作为一个块导入(会有很多演示)。
尝试 2
因为我不知道演示文件中用于默认导出的内部变量名称(没有进行完整的 AST 解析),我不能只在文件中附加一行来修改它。相反,我尝试编写一个包装文件来导入和重新导出默认值,如下所示:
const { readFile } = require("fs");
const { basename } = require("path");
const escapeSource = require("js-string-escape");
module.exports = function withSourceLoader(content, map, meta) {
const onComplete = this.async();
const fileName = this.resource;
readFile(fileName, (error, fileContents) => {
if ( error ) {
return onComplete(error);
}
const newContent = `
const rawSource = "${ escapeSource(fileContents) }";
import DemoDefault from './${ basename(fileName) }';
DemoDefault.__source__ = rawSource;
export default DemoDefault;
`;
onComplete(null, newContent, map, meta);
});
};
我希望这个新的 import
指令能够被 webpack 解析(我知道这可能会导致无限回归,因为它应该只是根据文件名再次触发相同的加载器)。这似乎并没有发生,但是 - 我只是得到
TypeError: _Simple_demo_js__WEBPACK_IMPORTED_MODULE_0__.default is undefined
这似乎是因为 webpack 已经构建了它的依赖树并且不想向它添加任何其他东西。我也尝试过使用 require()
而不是 import
,这并没有改善问题。
我是不是走错了路?我想通过组合其他加载器的输出来使用一些简单的链接,但是 API 似乎没有办法做到这一点。
想出如何使用 webpack "pitching" loader:
const { readFile } = require("fs");
const escapeSource = require("js-string-escape");
const { stringifyRequest } = require("loader-utils");
module.exports = function empty() { /* do nothing */ };
module.exports.pitch = function withSourceLoader(remainingRequest) {
const onComplete = this.async();
const filename = this.resource;
readFile(filename, (error, fileContents) => {
if ( error ) {
return onComplete(error);
}
const newContent = `
module.exports = require(${stringifyRequest(this, "!!" + remainingRequest)});
const rawSource = "${ escapeSource(fileContents) }";
module.exports.default.__source__ = rawSource;
`;
onComplete(null, newContent);
});
};
仍然不是 100% 清楚我的 require()
呼叫如何解决背后的魔法,但效果很好!我计划在本周晚些时候作为模块发布(具有其他一些功能)。
我正在尝试编写一个自定义的 webpack 加载器,用于加载演示 javascript 文件及其源代码以供文档使用。应该
- 加载指示的 javascript 文件(例如
Simple.demo.js
) - 将文件的原始来源作为新字段附加到默认导出
完成后,我应该可以在我的 webpack 配置中配置加载程序:
{
test: /\.demo.js$/,
exclude: /node_modules/,
use: [{
loader: "babel-loader",
}, {
loader: resolve("./demo-loader.js"),
}]
}
...然后在导入后访问我的演示的源代码:
import SimpleDemo from 'demo-loader!./Simple.demo.js';
console.log(SimpleDemo.__source__);
SimpleDemo(); //run the demo code
尝试 1
我已经使用以下加载程序成功加载了原始源代码并完成了命名导出:
const { readFile } = require("fs");
const escapeSource = require("js-string-escape");
module.exports = function withSourceLoader(content, map, meta) {
const onComplete = this.async();
const fileName = this.resource;
readFile(fileName, (error, fileContents) => {
if ( error ) {
return onComplete(error);
}
const exportSource = `export const rawSource = "${ escapeSource(fileContents)}";`;
const newContent = `${ content }\n\n${ exportSource }`;
onComplete(null, newContent, map, meta);
});
};
这让我做
import SimpleDemo, { rawSource } from 'demo-loader!./Simple.demo.js`;
console.log(rawSource);
SimpleDemo(); //run the demo code
...但我想将整个 SimpleDemo
作为对象传递给另一个函数,所以我想将它们作为一个块导入(会有很多演示)。
尝试 2
因为我不知道演示文件中用于默认导出的内部变量名称(没有进行完整的 AST 解析),我不能只在文件中附加一行来修改它。相反,我尝试编写一个包装文件来导入和重新导出默认值,如下所示:
const { readFile } = require("fs");
const { basename } = require("path");
const escapeSource = require("js-string-escape");
module.exports = function withSourceLoader(content, map, meta) {
const onComplete = this.async();
const fileName = this.resource;
readFile(fileName, (error, fileContents) => {
if ( error ) {
return onComplete(error);
}
const newContent = `
const rawSource = "${ escapeSource(fileContents) }";
import DemoDefault from './${ basename(fileName) }';
DemoDefault.__source__ = rawSource;
export default DemoDefault;
`;
onComplete(null, newContent, map, meta);
});
};
我希望这个新的 import
指令能够被 webpack 解析(我知道这可能会导致无限回归,因为它应该只是根据文件名再次触发相同的加载器)。这似乎并没有发生,但是 - 我只是得到
TypeError: _Simple_demo_js__WEBPACK_IMPORTED_MODULE_0__.default is undefined
这似乎是因为 webpack 已经构建了它的依赖树并且不想向它添加任何其他东西。我也尝试过使用 require()
而不是 import
,这并没有改善问题。
我是不是走错了路?我想通过组合其他加载器的输出来使用一些简单的链接,但是 API 似乎没有办法做到这一点。
想出如何使用 webpack "pitching" loader:
const { readFile } = require("fs");
const escapeSource = require("js-string-escape");
const { stringifyRequest } = require("loader-utils");
module.exports = function empty() { /* do nothing */ };
module.exports.pitch = function withSourceLoader(remainingRequest) {
const onComplete = this.async();
const filename = this.resource;
readFile(filename, (error, fileContents) => {
if ( error ) {
return onComplete(error);
}
const newContent = `
module.exports = require(${stringifyRequest(this, "!!" + remainingRequest)});
const rawSource = "${ escapeSource(fileContents) }";
module.exports.default.__source__ = rawSource;
`;
onComplete(null, newContent);
});
};
仍然不是 100% 清楚我的 require()
呼叫如何解决背后的魔法,但效果很好!我计划在本周晚些时候作为模块发布(具有其他一些功能)。