使用自定义webpack加载程序将额外字段附加到默认导出

问题描述 投票:1回答:1

我正在尝试编写一个自定义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似乎没有办法做到这一点。

javascript webpack webpack-loader
1个回答
0
投票

想出了如何使用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()呼叫解决后面的魔力,但它的效果很好!我打算本周晚些时候发布一个模块(带有一些其他功能)。

© www.soinside.com 2019 - 2024. All rights reserved.