Javascript 如何单独捆绑供应商脚本并根据需要使用 Webpack?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/30329337/
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
How to bundle vendor scripts separately and require them as needed with Webpack?
提问by bensampaio
I'm trying to do something that I believe should be possible, but I really can't understand how to do it just from the webpack documentation.
我正在尝试做一些我认为应该可行的事情,但我真的无法仅从 webpack 文档中了解如何做到这一点。
I am writing a JavaScript library with several modules that may or not depend on each other. On top of that, jQuery is used by all modules and some of them may need jQuery plugins. This library will then be used on several different websites which may require some or all modules.
我正在编写一个 JavaScript 库,其中包含多个可能相互依赖或不相互依赖的模块。最重要的是,所有模块都使用 jQuery,其中一些模块可能需要 jQuery 插件。然后,该库将用于可能需要部分或全部模块的多个不同网站。
Defining the dependencies between my modules was very easy, but defining their third-party dependencies seems to be harder then I expected.
定义我的模块之间的依赖关系非常容易,但定义它们的第三方依赖关系似乎比我预期的要困难。
What I would like to achieve: for each app I want to have two bundle files one with the necessary third-party dependencies and other with the necessary modules from my library.
我想要实现的目标:对于每个应用程序,我希望有两个捆绑文件,一个具有必要的第三方依赖项,另一个具有我的库中的必要模块。
Example: Let's imagine that my library has the following modules:
示例:假设我的库具有以下模块:
- a (requires: jquery, jquery.plugin1)
- b (requires: jquery, a)
- c (requires: jquery, jquery.ui, a, b)
- d (requires: jquery, jquery.plugin2, a)
- a(需要:jquery、jquery.plugin1)
- b (需要: jquery, a)
- c (需要: jquery, jquery.ui, a, b)
- d(需要:jquery、jquery.plugin2、a)
And I have an app (see it as a unique entry file) that requires modules a, b and c. Webpack for this case should generate the following files:
我有一个需要模块 a、b 和 c 的应用程序(将其视为唯一的入口文件)。这种情况下的 Webpack 应该生成以下文件:
- vendor bundle: with jquery, jquery.plugin1 and jquery.ui;
- website bundle: with modules a, b and c;
- 供应商包:使用 jquery、jquery.plugin1 和 jquery.ui;
- 网站包:包含模块 a、b 和 c;
In the end, I would prefer to have jQuery as a global so I don't need to require it on every single file (I could require it only on the main file, for example). And jQuery plugins would just extend the $ global in case they are required (it is not a problem if they are available to other modules that don't need them).
最后,我更喜欢将 jQuery 作为全局变量,因此我不需要在每个文件上都需要它(例如,我可以只在主文件上需要它)。并且 jQuery 插件只会在需要时扩展 $ global(如果它们可用于不需要它们的其他模块,这不是问题)。
Assuming this is possible, what would be an example of a webpack configuration file for this case? I tried several combinations of loaders, externals, and plugins on my configuration file, but I don't really get what they are doing and which ones should I use. Thank you!
假设这是可能的,对于这种情况,webpack 配置文件的示例是什么?我在我的配置文件中尝试了几种加载器、外部和插件的组合,但我真的不明白它们在做什么以及我应该使用哪些。谢谢!
采纳答案by Rafael De Leon
in my webpack.config.js (Version 1,2,3) file, I have
在我的 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;
}
in my plugins array
在我的插件数组中
plugins: [
new CommonsChunkPlugin({
name: 'vendors',
minChunks: function(module) {
return isExternal(module);
}
}),
// Other plugins
]
Now I have a file that only adds 3rd party libs to one file as required.
现在我有一个文件,它只根据需要将 3rd 方库添加到一个文件中。
If you want get more granular where you separate your vendors and entry point files:
如果您想更详细地分离供应商和入口点文件:
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);
}
})
]
Note that the order of the plugins matters a lot.
请注意,插件的顺序很重要。
Also, this is going to change in version 4. When that's official, I update this answer.
此外,这将在第 4 版中更改。当正式发布时,我会更新此答案。
Update:indexOf search change for windows users
更新:windows 用户的 indexOf 搜索更改
回答by Micha? Margiel
I am not sure if I fully understand your problem but since I had similar issue recently I will try to help you out.
我不确定我是否完全理解您的问题,但由于我最近遇到了类似的问题,我会尽力帮助您。
Vendor bundle.
供应商捆绑。
You should use CommonsChunkPluginfor that. in the configuration you specify the name of the chunk (e.g. vendor), and file name that will be generated (vendor.js).
您应该为此使用CommonsChunkPlugin。在配置中,您指定块的名称(例如vendor)和将生成的文件名(vendor.js)。
new webpack.optimize.CommonsChunkPlugin("vendor", "vendor.js", Infinity),
Now important part, you have to now specify what does it mean vendorlibrary and you do that in an entry section. One one more item to entry list with the same name as the name of the newly declared chunk (i.e. 'vendor' in this case). The value of that entry should be the list of all the modules that you want to move to vendorbundle.
in your case it should look something like:
现在是重要的部分,您现在必须指定vendor库的含义,并在条目部分执行此操作。一个与新声明的块名称相同的条目列表中的一项(即在这种情况下为“供应商”)。该条目的值应该是您要移动到vendor捆绑包的所有模块的列表。在您的情况下,它应该类似于:
entry: {
app: 'entry.js',
vendor: ['jquery', 'jquery.plugin1']
}
JQuery as global
JQuery 作为全局
Had the same problem and solved it with ProvidePlugin. here you are not defining global object but kind of shurtcuts to modules. i.e. you can configure it like that:
遇到了同样的问题并使用ProvidePlugin解决了它。在这里,您不是在定义全局对象,而是在定义模块的快捷方式。即你可以这样配置它:
new webpack.ProvidePlugin({
$: "jquery"
})
And now you can just use $anywhere in your code - webpack will automatically convert that to
现在你可以$在代码中的任何地方使用- webpack 会自动将其转换为
require('jquery')
I hope it helped. you can also look at my webpack configuration file that is here
我希望它有所帮助。您还可以看看我的WebPack配置文件,它是在这里
I love webpack, but I agree that the documentation is not the nicest one in the world... but hey.. people were saying same thing about Angular documentation in the begining :)
我喜欢 webpack,但我同意该文档不是世界上最好的文档......但是嘿......人们一开始对 Angular 文档也说同样的话:)
Edit:
编辑:
To have entrypoint-specific vendor chunks just use CommonsChunkPlugins multiple times:
要拥有特定于入口点的供应商块,只需多次使用 CommonsChunkPlugins :
new webpack.optimize.CommonsChunkPlugin("vendor-page1", "vendor-page1.js", Infinity),
new webpack.optimize.CommonsChunkPlugin("vendor-page2", "vendor-page2.js", Infinity),
and then declare different extenral libraries for different files:
然后为不同的文件声明不同的外部库:
entry: {
page1: ['entry.js'],
page2: ['entry2.js'],
"vendor-page1": [
'lodash'
],
"vendor-page2": [
'jquery'
]
},
If some libraries are overlapping (and for most of them) between entry points then you can extract them to common file using same plugin just with different configuration. See thisexample.
如果某些库在入口点之间重叠(对于大多数库),那么您可以使用相同的插件将它们提取到公共文件中,只是配置不同。请参阅此示例。
回答by Freezystem
In case you're interested in bundling automatically your scripts separately from vendors ones:
如果您有兴趣将您的脚本与供应商的脚本分开自动捆绑:
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'})
]
};
You can read more about this feature in official documentation.
您可以在官方文档中阅读有关此功能的更多信息。
回答by Alex Fedoseev
Also not sure if I fully understand your case, but here is config snippet to create separate vendor chunks for each of your bundles:
也不确定我是否完全理解你的情况,但这里是配置片段,为你的每个包创建单独的供应商块:
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
}),
]
And link to CommonsChunkPlugindocs: http://webpack.github.io/docs/list-of-plugins.html#commonschunkplugin
并链接到CommonsChunkPlugin文档:http: //webpack.github.io/docs/list-of-plugins.html#commonschunkplugin

