【问题标题】:Make webpack resolve context dependencies of the follow kind: require(someVariable)让 webpack 解析以下类型的上下文依赖:require(someVariable)
【发布时间】:2021-12-30 16:26:01
【问题描述】:

我试图捆绑 nestjs 应用程序以在 lambda 中运行它。但放弃了。过了一会儿,我尝试对连接到mysqlfreshly created nestjs application 做同样的事情。 problemsequelize 需要 mysql2 this way

require(moduleName);

嗯,它需要我要求它需要的方言,但在本例中是mysql2。显然webpack 不能靠自己做太多的事情并退出。我解决了它as they suggested。但后来我想,“我想知道webpack 是否可以替换特定文件中的特定行?”或者更确切地说,假装它不同。假设它不是require(moduleName),而是require('mysql2')

有一个similar question,但我专门针对nodejs。而且我担心在webpack-speak 中可能会调用context dependency。请求是表达式而不是字符串的依赖项。

ContextReplacementPlugin 不能在此处应用,因为对于单个标识符,请求始终为 .(此类请求无法区分)。 NormalReplacementPlugin 不适用,因为这是上下文依赖。而DefinePlugin 似乎不能胜任这项任务,因为它不允许你替换任何你喜欢的东西,尤其是局部变量和函数参数。

如果您有兴趣捆绑nodejs 应用程序,您可能需要查看this question。这里我关心webpack 和上下文依赖关系。

附:虽然我找到了一个不需要解决上下文依赖关系的解决方案,但我可能会在路上遇到它。或者其他人。

UPD 这是一个无法解决的案例,例如 nestjs + sequelize + mysql2sequelize-typescript 在运行时加载模型:

https://github.com/RobinBuschmann/sequelize-typescript/blob/v2.1.1/src/sequelize/sequelize/sequelize-service.ts#L51

【问题讨论】:

  • 是的,有。 webpacks 文档涵盖了如何做到这一点,所以你应该可以查一下。请参阅How can I replace files at compile time using webpack? 上的插件相关答案
  • @Mike'Pomax'Kamermans 替换 require('some string')require(someVar) 是有区别的。标题可能会有所改进。
  • 您能否更具体一些,例如您如何决定要导入什么以及是在编译时还是运行时?此外,如果您真的使用 require 而不是 es6 导入,以及为什么。
  • @Dominic 我想用require('mysql2') 替换node_modules/sequelize/lib/dialects/abstract/connection-manager.js 中的require(moduleName)(因为我使用的是单个mysql 数据库)。或者更确切地说让webpack 认为该行是require('mysql2'),而不是require(packageName)
  • 问题:捆绑包是为客户准备的。为什么您的客户端代码需要直接与您的数据库通信?

标签: node.js webpack


【解决方案1】:

免责声明。提供的实现可能不适合您。您可能需要修改它以使用您的webpack 版本。另外,我的目标是nodejs(不是浏览器),因此我忽略了源映射。

假设你有src/index.js:

const mysql2 = require('whatever');

以及以下软件包:

{
  "dependencies": {
    "mysql2": "2.3.3",
    "webpack": "5.64.2",
    "webpack-cli": "4.9.1"
  }
}

webpack.config.js:

const path = require('path');
const RewriteRequirePlugin = require('./rewrite-require-plugin');
module.exports = {
    mode: 'development',
    target: 'node',
    module: {
        rules: [
            // {test: path.resolve('src/index.js'),
            // use: [
            //     {loader: path.resolve('rewrite-require-loader.js'),
            //     options: {
            //         search: "'whatever'",
            //         replace: JSON.stringify('mysql2'),
            //     }},
            // ]}
        ],
    },
    plugins: [
        // new RewriteRequirePlugin([
        //     [path.resolve('src/index.js'),
        //         "'whatever'",
        //         JSON.stringify('mysql2')],
        // ])
    ],
    stats: {
        modulesSpace: Infinity,
        groupModulesByPath: false,
    }
};

它不会构建。但如果你取消注释插件或加载器,它会。

rewrite-require-loader.js:

// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#escaping
function escapeRegExp(string) {
  return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string
}

function processFile(source, search, replace) {
    const re = `require\\(${escapeRegExp(search)}\\)`;
    return source.replace(
        new RegExp(re, 'g'),
        `require(${replace})`);
}

module.exports = function(source) {
    const options = this.getOptions();
    return processFile(source, options.search, options.replace);
};

rewrite-require-plugin.js:

const path = require('path');
const NormalModule = require('webpack/lib/NormalModule');

// https://github.com/webpack/loader-runner/blob/v4.2.0/lib/LoaderRunner.js#L9-L16
function utf8BufferToString(buf) {
    var str = buf.toString("utf-8");
    if(str.charCodeAt(0) === 0xFEFF) {
        return str.substr(1);
    } else {
        return str;
    }
}

// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#escaping
function escapeRegExp(string) {
  return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string
}

function processFile(source, search, replace) {
    source = Buffer.isBuffer(source) ? utf8BufferToString(source) : source;
    const re = `require\\(${escapeRegExp(search)}\\)`;
    return source.replace(
        new RegExp(re, 'g'),
        `require(${replace})`);
}

class RewriteRequirePlugin {
    constructor(rewrites) {
        this.rewrites = rewrites.map(r => [path.resolve(r[0]), r[1], r[2]]);
    }

    apply(compiler) {
        compiler.hooks.compilation.tap('RewriteRequirePlugin', compilation => {
            // https://github.com/webpack/webpack/blob/v5.64.2/lib/schemes/FileUriPlugin.js#L36-L43
            const hooks = NormalModule.getCompilationHooks(compilation);
            hooks.readResource
                .for(undefined)
                .tapAsync("FileUriPlugin", (loaderContext, callback) => {
                    const { resourcePath } = loaderContext;
                    loaderContext.addDependency(resourcePath);
                    loaderContext.fs.readFile(resourcePath, (err, data) => {
                        if (err) return callback(err, data);
                        callback(
                            err,
                            this.rewrites.reduce(
                                (prev, cur) =>
                                    resourcePath == cur[0]
                                        ? processFile(data, cur[1], cur[2])
                                        : data,
                                data));
                    });
                });
        });
    }
};

module.exports = RewriteRequirePlugin;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-06-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-10
    • 2018-05-20
    • 1970-01-01
    相关资源
    最近更新 更多