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

时间:2014-10-28 08:10:26

标签: javascript node.js npm browserify webpack

将我的头发拉出来寻找一个简单解决方案,通过NPM,跨多个Browserify或Webpack捆绑包共享代码。思考,是否存在文件" bridge"?

这样的事情

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

// vendor.js

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

非常重要的是,代码可以从NPM加载而不是Bower,或保存到某些供应商的代码中。目录,以便通过相对路径导入并通过垫片识别。除了我的实际应用程序源之外,我想通过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能够&#34;看到&#34;进入那些通过npm加载的模块?我知道创建一个包含外部的包,然后通过别名引用直接文件(例如,node_modules),但我希望找到一个更自动且更少的解决方案&#34; Require.js&#34;喜欢。

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

谢谢!

3 个答案:

答案 0 :(得分: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;

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

希望有所帮助。

答案 1 :(得分:11)

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

取自webpack docs


要将您的应用分成两个文件,例如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"
    )
  ]
};

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

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

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

答案 2 :(得分:0)

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

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