如何单独捆绑供应商脚本并根据需要使用Webpack?

Ana*_*kin 165 javascript external-dependencies webpack

我正在尝试做一些我认为应该可行的事情,但我真的无法理解如何从webpack文档中做到这一点.

我正在编写一个包含多个模块的JavaScript库,这些模块可能相互依赖或不相互依赖.最重要的是,jQuery被所有模块使用,其中一些可能需要jQuery插件.然后,该库将用于几个可能需要部分或全部模块的不同网站.

定义我的模块之间的依赖关系非常简单,但定义他们的第三方依赖关系似乎比我预期的更难.

我想要实现的目标:对于每个应用程序,我希望有两个捆绑文件,一个包含必要的第三方依赖项,另一个包含我库中的必要模块.

示例:假设我的库具有以下模块:

  • a(需要:jquery,jquery.plugin1)
  • b(要求:jquery,a)
  • c(要求:jquery,jquery.ui,a,b)
  • d(需要:jquery,jquery.plugin2,a)

我有一个应用程序(将其视为唯一的条目文件),需要模块a,b和c.此案例的Webpack应生成以下文件:

  • 供应商包:使用jquery,jquery.plugin1和jquery.ui;
  • 网站包:模块a,b和c;

最后,我更喜欢将jQuery作为全局文件,因此我不需要在每个文件上都需要它(例如,我只需要在主文件上使用它).并且jQuery插件只是在需要时扩展$ global(如果它们可用于不需要它们的其他模块则不是问题).

假设这是可能的,那么这个案例的webpack配置文件的例子是什么?我在我的配置文件上尝试了几种加载器,外部和插件的组合,但我并没有真正了解他们正在做什么以及我应该使用哪些.谢谢!

Raf*_*eon 136

在我的webpack.config.js(版本1,2,3)文件中,我有

function isExternal(module) {
  var context = module.context;

  if (typeof context !== 'string') {
    return false;
  }

  return context.indexOf('node_modules') !== -1;
}
Run Code Online (Sandbox Code Playgroud)

在我的插件数组中

plugins: [
  new CommonsChunkPlugin({
    name: 'vendors',
    minChunks: function(module) {
      return isExternal(module);
    }
  }),
  // Other plugins
]
Run Code Online (Sandbox Code Playgroud)

现在我有一个文件,只根据需要将第三方库添加到一个文件中.

如果您希望在分离供应商和入口点文件时更精细:

plugins: [
  new CommonsChunkPlugin({
    name: 'common',
    minChunks: function(module, count) {
      return !isExternal(module) && count >= 2; // adjustable
    }
  }),
  new CommonsChunkPlugin({
    name: 'vendors',
    chunks: ['common'],
    // or if you have an key value object for your entries
    // chunks: Object.keys(entry).concat('common')
    minChunks: function(module) {
      return isExternal(module);
    }
  })
]
Run Code Online (Sandbox Code Playgroud)

请注意,插件的顺序很重要.

此外,这将在版本4中发生变化.当这是官方的时候,我更新了这个答案.

更新: indexOf为Windows用户搜索更改

  • 这在使用加载器时不起作用,因为加载器的路径也将在`module.userRequest`中(并且加载器可能在`node_modules`中).我的代码是`isExternal()`:`return typeof module.userRequest ==='string'&& !! module.userRequest.split('!').pop().match(/(node_modules | bower_components | libraries)/ );` (2认同)

Mic*_*iel 52

我不确定我是否完全理解你的问题,但由于我最近有类似的问题,我会尽力帮助你.

供应商捆绑.

你应该使用CommonsChunkPlugin.在配置中,您可以指定块的名称(例如vendor),以及将生成的文件名(vendor.js).

new webpack.optimize.CommonsChunkPlugin("vendor", "vendor.js", Infinity),
Run Code Online (Sandbox Code Playgroud)

现在重要的是,您必须现在指定vendor库的含义,并在入口部分执行此操作.还有一个项目到条目列表,其名称与新声明的块名称相同(在本例中为"供应商").该条目的值应该是您要移动到vendorbundle 的所有模块的列表.在你的情况下,它应该看起来像:

entry: {
    app: 'entry.js',
    vendor: ['jquery', 'jquery.plugin1']
}
Run Code Online (Sandbox Code Playgroud)

JQuery作为全球性的

遇到了同样的问题并用ProvidePlugin解决了它.在这里,您不是要定义全局对象,而是模块化的类型.即你可以这样配置:

new webpack.ProvidePlugin({
    $: "jquery"
})
Run Code Online (Sandbox Code Playgroud)

现在你可以$在代码中的任何地方使用- webpack会自动将其转换为

require('jquery')
Run Code Online (Sandbox Code Playgroud)

我希望它有所帮助.你也可以看看我在这里的 webpack配置文件

我喜欢webpack,但我同意这个文档并不是世界上最好的文档...但是嘿..人们在开始时对Angular文档说了同样的话:)


编辑:

要使入口点特定的供应商块多次使用CommonsChunkPlugins:

new webpack.optimize.CommonsChunkPlugin("vendor-page1", "vendor-page1.js", Infinity),
new webpack.optimize.CommonsChunkPlugin("vendor-page2", "vendor-page2.js", Infinity),
Run Code Online (Sandbox Code Playgroud)

然后为不同的文件声明不同的extenral库:

entry: {
    page1: ['entry.js'],
    page2: ['entry2.js'],
    "vendor-page1": [
        'lodash'
    ],
    "vendor-page2": [
        'jquery'
    ]
},
Run Code Online (Sandbox Code Playgroud)

如果某些库在入口点之间重叠(对于大多数库),那么您可以使用相同的插件将它们提取到公共文件,只是使用不同的配置.看这个例子.

  • 此解决方案的问题在于它假设我知道每个页面的依赖项.但是我无法预测......如果页面中使用的某个模块需要jQuery,它应该只包含在供应商包中.通过在配置文件中指定它,即使页面中使用的任何模块都不需要,它也将始终位于供应商包中,对吧?基本上,我无法预测供应商捆绑的内容,否则我将有一个地狱的工作,因为我没有只有2页我有数百...你有问题吗?有任何想法吗?:) (4认同)

Fre*_*tem 41

如果您有兴趣将自己的脚本与供应商分开自动捆绑:

var webpack = require('webpack'),
    pkg     = require('./package.json'),  //loads npm config file
    html    = require('html-webpack-plugin');

module.exports = {
  context : __dirname + '/app',
  entry   : {
    app     : __dirname + '/app/index.js',
    vendor  : Object.keys(pkg.dependencies) //get npm vendors deps from config
  },
  output  : {
    path      : __dirname + '/dist',
    filename  : 'app.min-[hash:6].js'
  },
  plugins: [
    //Finally add this line to bundle the vendor code separately
    new webpack.optimize.CommonsChunkPlugin('vendor', 'vendor.min-[hash:6].js'),
    new html({template : __dirname + '/app/index.html'})
  ]
};
Run Code Online (Sandbox Code Playgroud)

您可以在官方文档中阅读有关此功能的更多信息.

  • 我喜欢这个.它让我小便一点. (16认同)
  • 请注意,`vendor:Object.keys(pkg.dependencies)`并不总是有效,并且取决于包的构建方式. (4认同)
  • 请注意,它甚至会包含您甚至可能在代码中根本不使用的软件包......由于`Object.keys(pkg.dependencies)`将捆绑所有内容!让我说你在那里列出了一堆装载机......是的,将包括在内!!! 所以要小心......分开什么是devDependency,什么是依赖 (3认同)
  • 你总是取决于你的 `package.json` 是如何设置的。此解决方法在大多数情况下都有效,但也有例外,您必须采取不同的路径。发布您自己的问题答案以帮助社区可能会很有趣。 (2认同)

Ale*_*eev 12

还不确定我是否完全理解您的情况,但这里是配置片段为每个捆绑包创建单独的供应商块:

entry: {
  bundle1: './build/bundles/bundle1.js',
  bundle2: './build/bundles/bundle2.js',
  'vendor-bundle1': [
    'react',
    'react-router'
  ],
  'vendor-bundle2': [
    'react',
    'react-router',
    'flummox',
    'immutable'
  ]
},

plugins: [
  new webpack.optimize.CommonsChunkPlugin({
    name: 'vendor-bundle1',
    chunks: ['bundle1'],
    filename: 'vendor-bundle1.js',
    minChunks: Infinity
  }),
  new webpack.optimize.CommonsChunkPlugin({
    name: 'vendor-bundle2',
    chunks: ['bundle2'],
    filename: 'vendor-bundle2-whatever.js',
    minChunks: Infinity
  }),
]
Run Code Online (Sandbox Code Playgroud)

并链接到CommonsChunkPlugindocs:http://webpack.github.io/docs/list-of-plugins.html#commonschunkplugin