排除使用库组件/片段时的Webpack外部依赖

8

Webpack在编写同构JavaScript和在打包时替换npm包为浏览器全局变量方面对我们非常有帮助。

因此,如果我想在Node.js上使用node-fetch npm包但在打包时排除它并仅使用本地浏览器fetch全局变量,我只需要在我的webpack.config.js中提及它:

{
  externals: {
    'node-fetch': 'fetch',
    'urlutils': 'URL',
    'webcrypto': 'crypto', // etc
  }
}

然后我的CommonJS需要 const fetch = require('node-fetch') 将被转译为 const fetch = window.fetch(或者是其他的内容)。
到此为止一切都很好。这里有一个问题:当我需要引用一个导出模块的子模块/单个属性时该怎么办?
例如,假设我想以同构方式使用WhatWG URL标准。我可以使用urlutils npm 模块,它module.exports整个URL类,因此我的引用看起来像:
const URL = require('urlutils')

然后我可以在我的externals部分列出urlutils,没有问题。但是当我想使用一个更近期(并且更受支持的)npm包,比如whatwg-url时,我不知道如何Webpack它,因为我的requires看起来像:

const { URL } = require('whatwg-url')
// or, if you don't like destructuring assignment
const URL = require('whatwg-url').URL

我该如何告诉Webpack将require('whatwg-url').URL替换为浏览器全局对象URL


重构不是一个选项吗? - Mardoxx
但是重构后应该变成什么样子呢? - Dmitri Zagidulin
我认为您可能在要求一件几乎不可能的事情。假设URL是一个函数,它存在于一个庞大的文件中,Webpack将不得不去查找那个文件并跟踪所有所需的URL函数相关的代码。Webpack是一个文件打包器,无法根据请求的属性拆分和合并依赖项。 - Oskar
嗯,我想我没有清楚地解释问题,抱歉。我的意思不是只希望Webpack仅仅打包URL函数。它可以轻松地将整个npm包装入其中,没有问题。我需要的是require()在Node和浏览器之间透明地工作。 - Dmitri Zagidulin
@DmitriZagidulin 好的,但您明白它会打包Web的两个模块,我不确定您是否想要这样做,因为在Web上您想要节省每KB。如果您不关心大小,我认为我有一个想法可以帮助您实现您想要的。 - Oskar
关于这两个模块,不,我只是举了“urlutils”作为一个例子(展示webpack如何将require操作直接映射到全局)。我只想使用“whatwg-url”,最好不要重新导出。 - Dmitri Zagidulin
1个回答

1

首先,我想强调一下我不是一个webpack专家。我认为在构建期间有更好的打包方式。无论如何,这是我的想法:

webpack.config.js

  module.exports = {
    target: "web",
    entry: "./entry.js",
    output: {
      path: __dirname,
      filename: "bundle.js"
    }
  };

entry.js

  var URL = require("./content.js");
  document.write('Check console');
  console.log('URL function from content.js', URL);

content.js

  let config = require('./webpack.config.js');
  let urlutils = require('urlutils');
  let whatwgUrl = require('whatwg-url');

  console.log('urlutils:', urlutils);
  console.log('whatwgUrl', whatwgUrl);

  module.exports = {
    URL: undefined
  };

  if (config.target === 'web') {
    module.exports.URL = urlutils;
  } else {
    module.exports.URL = whatwgUrl.URL;
  }

index.html

  <html>
    <head>
      <meta charset="utf-8">
    </head>
    <body>
      <script type="text/javascript" src="bundle.js" charset="utf-8"></script>
    </body>
  </html>

正如我在评论中所说,这将为Web包捆绑两个库——浪费空间。

现在,对于NodeJS,您需要将targetweb更改为node,然后它应该使用另一个库。https://webpack.github.io/docs/configuration.html#target

我找到了一个适用于“同构”应用程序的模块:https://github.com/halt-hammerzeit/universal-webpack

我认为您可以尝试使用两个单独的中间content.js文件作为模块的参数。一个包含urlutils,第二个是whatwg-url。然后它会动态识别编译文件的用途并使用适当的模块。

希望能有所帮助。


1
这还不太对,因为我正在寻找一种将 require('whatwg-url').URL 映射到浏览器全局变量的方法,而不需要通过 content.js 进行重新导出。不过,我很感激您所付出的努力,因此我将选择这个答案来获得奖励。 - Dmitri Zagidulin
@DmitriZagidulin,你是在寻找一种自动导出和映射这些包的方法吗?我可以想象如果你有很多这样的依赖关系,你将不得不自己制定一个自动化解决方案。请查看universal-webpack的链接,我相信可以在构建过程中使用此模块创建这样的映射,而无需将webpack配置暴露给网络。感谢您的慷慨奖励。 - Oskar

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