【问题标题】:How to bundle isomorphic commonJS code with webpack如何将同构的 commonJS 代码与 webpack 捆绑在一起
【发布时间】:2016-02-02 17:58:29
【问题描述】:

我有一个使用 nodeJS 模块格式 (commonJS) 的项目,也应该(部分)在浏览器中运行。

我确实有非同构的代码路径,我有条件地包含模块:

var impl;
try {
    // in node, use node-impl
   impl = require('../node-impl');
} catch (err) {
    // running in browser, use browser-impl
    impl = require('../browser-impl');
}

现在,我想使用webpack 创建一个在浏览器中运行的包。因此,我需要在webpack.config.js 中将外部(特定于nodeJS)模块定义为external,这样它们就不会被包含在包中:

external: {
    '../node-impl': true
}

我验证了 '../node-impl' 代码实际上并未包含在 bundle 中,但发出的代码如下所示:

/***/ },
/* 33 */
/***/ function(module, exports) {

    module.exports = ../node-impl;

/***/ },

这是语法错误的JS,浏览器会在那里抛出语法错误。

如何使用 webpack.js 正确处理这种情况?请注意,我不希望使用 webpack 来运行 nodeJS,只有浏览器包应该使用 webpack 创建。

【问题讨论】:

    标签: javascript webpack commonjs isomorphic-javascript


    【解决方案1】:

    // Your actual situation: var impl; try { impl = require('../node-impl'); } catch(e) { impl = require('../browser-impl'); }

    您需要将此 sn-p 重构为:

    var impl = require('../node-impl');

    这次返工后,您的代码只能在 node js 环境中工作,这很好,因为我们将在为浏览器捆绑时模拟这个请求。 .. // webpack.browser.config.js module.exports = { resolve: { alias: { '../node-impl': '../browser-impl' } } };

    Webpack - Resolve.Alias 或使用package.json#browser,或https://webpack.github.io/docs/configuration.html#resolve-packagealias

    【讨论】:

    • 但这涉及在我的 nodeJS 代码上调用 webpack - 我不喜欢那样。代码按原样运行,节点上没有任何 webpack,我宁愿不介绍 webpack 特定代码
    • 虽然这适用于浏览器中可用的那些 deps,但 nodeJS impl 仍然会抛出语法异常,因为在我原来的问题中发出的代码仍然存在
    • 我再举一个例子
    • 问题不在于浏览器包没有找到某些模块。问题是 webpack 将 externals 部分中列出的模块如下所示:module.exports = ../node-impl - 这是无效的 JS 代码,在执行任何代码之前将立即失败。
    • 我不明白你的意思,对不起...externals: {"../node-impl": "window.something"} 必须工作。
    【解决方案2】:

    我不认为这是外部配置的预期目的。根据文档,

    指定不应该由 webpack 解析的依赖项,但应该成为结果包的依赖项。依赖的种类取决于 output.libraryTarget。

    所以你告诉 webpack 你的构建需要那个模块,但不要把它捆绑进去。它把它排除在外,而是试图要求它。

    可能有几种方法可以做你想做的事。值得一提的是,您可以轻松地让 webpack 从单个配置文件生成多个构建,具有不同/共享的配置,这开辟了很多可能性。但我建议的方法是使用DefinePlugin 定义一个表示执行上下文的布尔“常量”(例如IN_BROWSER = true)。在require() 周围的条件中检查该常量。 Webpack 的解析器不是那么聪明,但它可以评估布尔变量,因此它会正确解析条件并且只需要适当的模块。 (使用非布尔值,如 CONTEXT = 'browser' 对 webpack 来说太混乱了,它会解析每个 require 语句。)然后你可以使用 Uglify 插件删除条件中的“死代码”,这样它就不会膨胀你的生产构建。

    【讨论】:

      【解决方案3】:

      在@Hitmands 的帮助下,我可以想出一个仍然不完美但符合我需求的解决方案。我介绍了一个虚构的nonexistingmodule 并将其声明为外部;然后,我将 node-impl 特定模块声明为 nonexistingmodule

      externals: {
          'nonexistingmodule': true,
          '../node-impl': 'nonexistingmodule'
      }
      

      这样我可以保留try/catch 模式来加载特定的实现,它仍然会在节点上运行。在浏览器中,nonexistingmodule 的加载失败,browser-impl 模块被加载——正如我所想的那样。

      我是“不要重构代码以匹配工具”的忠实拥护者,因此我将采用此解决方案。

      【讨论】:

        猜你喜欢
        • 2017-11-05
        • 2017-05-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多