javascript 跨多个 Browserify 或 Webpack 包共享通过 NPM 加载的模块的简单解决方案

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/26603499/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-28 06:11:56  来源:igfitidea点击:

Simple solution to share modules loaded via NPM across multiple Browserify or Webpack bundles

javascriptnode.jsnpmbrowserifywebpack

提问by cnp

Pulling my hair out here looking for a simplesolution to share code, required via NPM, across multiple Browserify or Webpack bundles. Thinking, is there such a thing as a file "bridge"?

在这里拉我的头发,寻找一个简单的解决方案来共享代码,需要通过 NPM,跨多个 Browserify 或 Webpack 包。想一想,有没有文件“桥”这样的东西?

This isn't due to compile time (I'm aware of watchify) but rather the desire to extract out all of my vendor specific libs into vendor.jsso to keep my app.jsfilesize down and to not crash the browser with massive sourcemaps. Plus, I find it way cleaner should the need to view the compiled js arise. And so:

这不是因为编译时间(我知道 watchify),而是希望将我所有供应商特定的库提取出来,vendor.js以便app.js减小我的文件大小,并且不会因大量源映射而导致浏览器崩溃。另外,如果需要查看已编译的 js,我发现它会更清晰。所以:

// vendor.js

require('react');
require('lodash');
require('other-npm-module');
require('another-npm-module');

Its very important that the code be loaded from NPM as opposed to Bower, or saved into some 'vendor' directory in order to be imported via a relative path and identified via a shim. I'd like to keep every library reference pulled via NPM except for my actual application source.

代码从 NPM 加载而不是 Bower,或者保存到某个“供应商”目录中以便通过相对路径导入并通过垫片识别,这一点非常重要。除了我的实际应用程序源之外,我希望通过 NPM 保留每个库引用。

In app.jsI keep all of my sourcecode, and via the externalsarray, exclude vendor libraries listed above from compilation:

app.js我保留所有源代码中,并通过externals数组,从编译中排除上面列出的供应商库:

// app.js 

var React = require('react');
var _     = require('lodash');

var Component = React.createClass()

// ...

And then in index.html, I require both files

然后在index.html,我需要两个文件

// index.html
<script src='vendor.js'></script>
<script src='app.js'></script>

Using Browserify or Webpack, how can I make it so that app.jscan "see" into those module loaded via npm? I'm aware of creating a bundle with externals and then referencing the direct file (in, say, node_modules) via an alias, but I'm hoping to find a solution that is more automatic and less "Require.js" like.

使用 Browserify 或 Webpack,我该如何制作app.js才能“看到”通过 npm 加载的那些模块?我知道创建一个带有外部的包,然后node_modules通过别名引用直接文件(例如,),但我希望找到一个更自动化且更少“Require.js”的解决方案。

Basically, I'm wondering if it is possible to bridge the two so that app.jscan look inside vendor.jsin order to resolve dependencies. This seems like a simple, straightforward operation but I can't seem to find an answer anywhere on this wide, wide web.

基本上,我想知道是否有可能将两者连接起来,以便app.js可以查看内部vendor.js以解决依赖关系。这似乎是一个简单、直接的操作,但我似乎无法在这个宽阔的网络上的任何地方找到答案。

Thanks!

谢谢!

采纳答案by Johannes Ewald

With webpack you'd use multiple entry points and the CommonChunkPlugin.

使用 webpack,您将使用多个入口点和CommonChunkPlugin

Taken from the webpack docs:

取自webpack 文档



To split your app into 2 files, say app.jsand vendor.js, you can require the vendor files in vendor.js. Then pass this name to the CommonChunkPlugin as shown below.

要将您的应用程序拆分为 2 个文件,例如app.jsvendor.js,您可以在vendor.js. 然后将此名称传递给 CommonChunkPlugin,如下所示。

module.exports = {
  entry: {
    app: "./app.js",
    vendor: ["jquery", "underscore", ...],
  },
  output: {
    filename: "bundle.js"
  },
  plugins: [
    new webpack.optimize.CommonsChunkPlugin(
        /* chunkName= */"vendor",
        /* filename= */"vendor.bundle.js"
    )
  ]
};

This will remove all modules in the vendor chunk from the app chunk. The bundle.jswill now contain just your app code, without any of it's dependencies. These are in vendor.bundle.js.

这将从应用程序块中删除供应商块中的所有模块。现在bundle.js将只包含您的应用程序代码,没有任何依赖项。这些在vendor.bundle.js.

In your HTML page load vendor.bundle.jsbefore bundle.js.

在您的 HTML 页面加载vendor.bundle.js之前bundle.js

<script src="vendor.bundle.js"></script>
<script src="bundle.js"></script>


回答by sebastien.b

Listing all the vendor files/modules and using CommonChunkPluginis indeed the recommended way. This gets pretty tedious though, and error prone.

列出所有供应商文件/模块并使用CommonChunkPlugin确实是推荐的方法。不过,这变得非常乏味,而且容易出错。

Consider these NPM modules: fastclickand mprogress. Since they have not adopted the CommonJSmodule format, you need to give webpack a hand, like this:

考虑这些 NPM 模块:fastclickmprogress. 由于他们没有采用CommonJS模块格式,你需要帮助 webpack,像这样:

require('imports?define=>false!fastclick')(document.body);
require('mprogress/mprogress.min.css');
var Mprogress = require('mprogress/mprogress.min.js'),

Now assuming you would want both fastclickand mprogressin your vendor chunk, you would probably try this:

现在假设您同时需要 fastclickmprogress在您的供应商块中,您可能会尝试以下操作:

module.exports = {
  entry: {
    app: "./app.js",
    vendor: ["fastclick", "mprogress", ...]

Alas, it doesn't work. You need to match the calls to require():

唉,它不起作用。您需要将调用匹配到require()

module.exports = {
  entry: {
    app: "./app.js",
    vendor: [
      "imports?define=>false!fastclick", 
      "mprogress/mprogress.min.css", 
      "mprogress/mprogress.min.js", 
      ...]

It gets old, even with some resolve.aliastrickery. Here is my workaround. CommonChunkPlugin lets you specify a callback that will return whether or not you want a module to be included in the vendor chunk. If your own source code is in a specific srcdirectory, and the rest is in the node_modulesdirectory, just reject the modules based on their path:

它会变老,即使有一些resolve.alias技巧。这是我的解决方法。CommonChunkPlugin 允许您指定一个回调,该回调将返回您是否希望将模块包含在供应商块中。如果您自己的源代码在特定src目录中,而其余部分在该node_modules目录中,则只需根据其路径拒绝模块:

var node_modules_dir = path.join(__dirname, 'node_modules'),
    app_dir          = path.join(__dirname, 'src');

module.exports = {
  entry: {
    app: "./app.js",
  },
  output: {
    filename: "bundle.js"
  },
  plugins: [
    new webpack.optimize.CommonsChunkPlugin(
      /* chunkName= */"vendor",
      /* filename= */"vendor.bundle.js"
      function (module, count) {
       return module.resource && module.resource.indexOf(app_dir) === -1;
      }
    )
  ]
};

Where module.resourceis the path to the module being considered. You could also do the opposite, and include only the module if it is inside node_modules_dir, i.e.:

module.resource正在考虑的模块的路径在哪里。你也可以做相反的事情,如果它在里面node_modules_dir,只包含模块,即:

       return module.resource && module.resource.indexOf(node_modules_dir) === 0;

but in my situation, I'd rather say: "put everything that is not in my source source tree in a vendor chunk".

但在我的情况下,我宁愿说:“将不在我的源代码树中的所有内容都放在供应商块中”。

Hope that helps.

希望有帮助。

回答by Alex

// vendor anything coming from node_modules
minChunks: module => /node_modules/.test(module.resource)

Source: https://github.com/webpack/webpack/issues/2372#issuecomment-213149173

来源:https: //github.com/webpack/webpack/issues/2372#issuecomment-213149173