16

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

这不是由于编译时间(我知道 watchify),而是希望将我所有的供应商特定库提取到其中vendor.js以保持我的app.js文件大小并且不会因大量源映射而使浏览器崩溃。另外,如果需要查看已编译的 js,我发现它会更干净。所以:

// vendor.js

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

从 NPM 加载代码而不是从 Bower 加载代码非常重要,或者保存到某个“供应商”目录中,以便通过相对路径导入并通过 shim 识别。我想保留通过 NPM 提取的所有库引用,除了我的实际应用程序源。

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

// app.js 

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

var Component = React.createClass()

// ...

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

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

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

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

谢谢!

4

3 回答 3

26

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

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

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

现在假设您既想要又想要 fastclickmprogress您的供应商块中,您可能会尝试这个:

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

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

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

它变老了,即使有一些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;
      }
    )
  ]
};

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

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

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

希望有帮助。

于 2015-03-16T22:11:02.633 回答
11

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

取自webpack 文档


要将您的应用程序拆分为 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"
    )
  ]
};

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

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

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

于 2014-10-29T10:53:03.893 回答
0
// vendor anything coming from node_modules
minChunks: module => /node_modules/.test(module.resource)

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

于 2016-06-15T05:36:53.393 回答