使用require进行的webpack动态模块加载

24

好的,我已经反复搜索过了,但是无法可靠地确定是否可以使用webpack实现这一点。

https://github.com/webpack/webpack/tree/master/examples/require.context似乎表明可以将字符串传递给函数并加载一个模块...

但是我的尝试就是不起作用:

webpack.config.js

'use strict';
let webpack     = require('webpack'),
    jsonLoader  = require("json-loader"),
    path        = require("path"),
    fs          = require('fs'),
    nodeModules = {};

fs.readdirSync('node_modules')
    .filter(function(x) {
        return ['.bin'].indexOf(x) === -1;
    })
    .forEach(function(mod) {
        nodeModules[mod] = 'commonjs ' + mod;
    });


let PATHS = {
    app: __dirname + '/src'
};

module.exports = {
    context: PATHS.app,
    entry: {
        app: PATHS.app+'/server.js'
    },
    target: 'node',
    output: {
        path: PATHS.app,
        filename: '../build/server.js'
    },
    externals: nodeModules,
    performance: {
        hints: "warning"
    },
    plugins: [
        jsonLoader
    ],
    resolve: {
        modules: [
            './node_modules',
            path.resolve(__dirname),
            path.resolve(__dirname + "/src"),
            path.resolve('./config')
        ]
    },
    node: {
        fs: "empty"
    }
};

服务器.js

let _ = require('lodash');
let modules = [ "modules/test" ];

require( 'modules/test' )();

_.map( modules, function( module ){
    require( module );
});

位于modules/目录下名为test.js的模块

module.exports = () => {
    console.log('hello world');
};

但结果总是相同的... pm2日志仅显示静态require的“hello world”... 但对于相同模块的动态加载

错误:找不到模块“。”

我想做的就是循环遍历模块路径数组并加载它们...

3个回答

71

您不能将变量用作require的参数。Webpack在编译时需要知道要捆绑哪些文件。它不进行程序流分析,因此无法知道您传递给函数的内容。在某些情况下可能很明显,但这可能会延伸到使用用户输入来决定要求哪个模块,而webpack无论如何都无法知道要在编译时包含哪些模块,因此webpack不允许这样做。

您贴出的示例略有不同。您可以使用连接字符串与require一起使用。例如:

require(`./src/${moduleName}/test`);

webpack需要包括哪些模块到捆绑包中?变量moduleName可以是任何内容,因此在编译时不知道确切的模块。相反,它包括所有可能与上述表达式匹配的模块。假设以下目录结构:

src
├─ one
│   └─ test.js
├─ two
│   ├─ subdir
│   │   └─ test.js
│   └─ test.js
└─ three
    └─ test.js

所有这些test.js文件都将被包含在捆绑包中,因为moduleName可以是one或类似于two/subdir的嵌套形式。

有关详细信息,请参见官方文档中的使用表达式进行 require

您不能循环遍历一个数组并导入每个模块,但可以通过连接字符串的方式实现上述例外情况,但这会导致包括所有可能的模块,并且通常应该避免使用该方法。


20
如果Webpack文档能像这样清晰明了就好了。 - Stephan-v
2
非常感谢,我很感激您澄清了这一点,特别是对根本原因进行了详细的描述。您有什么建议,关于如何加载我的文件以便在显示方面符合一般惯例吗?我对React编程和任何严肃的编程都非常陌生,所以大致了解哪种设计模式适合会很好,这样我就可以进一步研究它们。谢谢。 - MoSheikh
1
有没有一种方法可以让Webpack打包package.json中的每个模块?(当然,除非需要其中一个模块,否则不会全部加载到客户端浏览器上) - user5182794
附加文档 https://webpack.js.org/api/module-methods/#dynamic-expressions-in-import - xlm
基本上,起始路径不能是动态的!例如,这仍然有效:require('./src/' + moduleName );。请阅读附加的带表达式的require文档。 - niranjan_harpale

23

我在electron环境中遇到了这个问题。我的使用情况是能够在类似IDE的应用程序中动态创建文件并进行“require”。我想使用electron的require,它基本上是一个NodeJS通用模块加载器。经过一番探索,我得出了一个解决方案,该方案使用webpack的noParse模块配置。

首先创建一个被webpack解析器忽略的模块:

// file: native-require.js
// webpack replaces calls to `require()` from within a bundle. This module
// is not parsed by webpack and exports the real `require`
// NOTE: since the module is unparsed, do not use es6 exports
module.exports = require

在我的webpack配置文件中,在module下,指示打包程序不解析此模块:

{
  module: {
    noParse: /\/native-require.js$/,
  }
}

最后,在任何想要访问原始 require 的捆绑包中:

import nativeRequire from './native-require'
const someModule = nativeRequire('/some/module.js') // dynamic imports

1
这个解决方案在我这里运行良好,但需要做一些调整:
  1. 访问时,我必须使用:import nativeRequire = require('./native-require')。因为该模块没有默认导出而且报错了。
  2. 为了导出全局的 require,在 native-require.js 中,我必须使用:module.exports = require。因为对于我来说(Node 10.13,webpack 4.29),global.require 是未定义的。
- Andrew Aarestad
你可以直接使用__non_webpack_require__吗? - Alexey Romanov

10
有点晚了……但是……因为你正在捆绑到 target: 'node',所以有一个解决动态需要模块和绕过“包含所有可能模块的影响”的解决方法。
该解决方案来自于: 在没有解析或捆绑目标模块时,在节点目标上使用动态需要 · 问题#4175 · webpack/webpack 引用自那个评论:
const requireFunc = typeof __webpack_require__ === "function" ? __non_webpack_require__ : require;
const foo = requireFunc(moduleName);

打包成:
const requireFunc = true ? require : require;
const foo = requireFunc(moduleName);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接