如何单独捆绑供应商脚本并根据需要使用 Webpack 要求它们?
How to bundle vendor scripts separately and require them as needed with 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 配置文件的示例是什么?我在我的配置文件中尝试了加载程序、外部程序和插件的几种组合,但我并不真正了解它们在做什么以及我应该使用哪些。谢谢!
我不确定我是否完全理解你的问题,但由于我最近遇到了类似的问题,我会尽力帮助你。
供应商包。
您应该为此使用 CommonsChunkPlugin。在配置中指定块的名称(例如 vendor
)和将生成的文件名(vendor.js
)。
new webpack.optimize.CommonsChunkPlugin("vendor", "vendor.js", Infinity),
现在是重要的部分,您现在必须指定 vendor
库的含义,并且您在条目部分中执行此操作。条目列表中的一项与新声明的块的名称相同(即在本例中为 'vendor')。该条目的值应该是您要移动到 vendor
捆绑包的所有模块的列表。
在您的情况下,它应该类似于:
entry: {
app: 'entry.js',
vendor: ['jquery', 'jquery.plugin1']
}
JQuery 作为全局
遇到了同样的问题,用ProvidePlugin解决了。在这里你没有定义全局对象,而是一种模块的快捷方式。也就是说,您可以这样配置它:
new webpack.ProvidePlugin({
$: "jquery"
})
现在您可以在代码中的任何地方使用 $
- webpack 会自动将其转换为
require('jquery')
希望对您有所帮助。您还可以查看我的 webpack 配置文件 here
我喜欢 webpack,但我同意文档不是世界上最好的文档......但是嘿......人们在开始时对 Angular 文档说了同样的话 :)
编辑:
要获得特定于入口点的供应商块,只需多次使用 CommonsChunkPlugins:
new webpack.optimize.CommonsChunkPlugin("vendor-page1", "vendor-page1.js", Infinity),
new webpack.optimize.CommonsChunkPlugin("vendor-page2", "vendor-page2.js", Infinity),
然后为不同的文件声明不同的扩展库:
entry: {
page1: ['entry.js'],
page2: ['entry2.js'],
"vendor-page1": [
'lodash'
],
"vendor-page2": [
'jquery'
]
},
如果某些库在入口点之间重叠(并且对于其中的大多数),那么您可以使用具有不同配置的相同插件将它们提取到公共文件中。请参阅 this 示例。
也不确定我是否完全理解你的情况,但这里是配置片段,用于为你的每个包创建单独的供应商块:
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
}),
]
和 link 到 CommonsChunkPlugin
文档:http://webpack.github.io/docs/list-of-plugins.html#commonschunkplugin
如果您有兴趣将您的脚本与供应商的脚本分开自动捆绑:
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'})
]
};
您可以在 official documentation 中阅读有关此功能的更多信息。
在我的 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;
}
在我的插件数组中
plugins: [
new CommonsChunkPlugin({
name: 'vendors',
minChunks: function(module) {
return isExternal(module);
}
}),
// Other plugins
]
现在我有一个文件,它只根据需要将第 3 方库添加到一个文件中。
如果您想更详细地分离供应商和入口点文件:
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);
}
})
]
请注意,插件的顺序很重要。
此外,这将在版本 4 中发生变化。当它正式发布时,我会更新此答案。
更新: windows 用户的搜索索引更改
我正在尝试做一些我认为应该可行的事情,但我真的无法仅从 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 配置文件的示例是什么?我在我的配置文件中尝试了加载程序、外部程序和插件的几种组合,但我并不真正了解它们在做什么以及我应该使用哪些。谢谢!
我不确定我是否完全理解你的问题,但由于我最近遇到了类似的问题,我会尽力帮助你。
供应商包。
您应该为此使用 CommonsChunkPlugin。在配置中指定块的名称(例如 vendor
)和将生成的文件名(vendor.js
)。
new webpack.optimize.CommonsChunkPlugin("vendor", "vendor.js", Infinity),
现在是重要的部分,您现在必须指定 vendor
库的含义,并且您在条目部分中执行此操作。条目列表中的一项与新声明的块的名称相同(即在本例中为 'vendor')。该条目的值应该是您要移动到 vendor
捆绑包的所有模块的列表。
在您的情况下,它应该类似于:
entry: {
app: 'entry.js',
vendor: ['jquery', 'jquery.plugin1']
}
JQuery 作为全局
遇到了同样的问题,用ProvidePlugin解决了。在这里你没有定义全局对象,而是一种模块的快捷方式。也就是说,您可以这样配置它:
new webpack.ProvidePlugin({
$: "jquery"
})
现在您可以在代码中的任何地方使用 $
- webpack 会自动将其转换为
require('jquery')
希望对您有所帮助。您还可以查看我的 webpack 配置文件 here
我喜欢 webpack,但我同意文档不是世界上最好的文档......但是嘿......人们在开始时对 Angular 文档说了同样的话 :)
编辑:
要获得特定于入口点的供应商块,只需多次使用 CommonsChunkPlugins:
new webpack.optimize.CommonsChunkPlugin("vendor-page1", "vendor-page1.js", Infinity),
new webpack.optimize.CommonsChunkPlugin("vendor-page2", "vendor-page2.js", Infinity),
然后为不同的文件声明不同的扩展库:
entry: {
page1: ['entry.js'],
page2: ['entry2.js'],
"vendor-page1": [
'lodash'
],
"vendor-page2": [
'jquery'
]
},
如果某些库在入口点之间重叠(并且对于其中的大多数),那么您可以使用具有不同配置的相同插件将它们提取到公共文件中。请参阅 this 示例。
也不确定我是否完全理解你的情况,但这里是配置片段,用于为你的每个包创建单独的供应商块:
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
}),
]
和 link 到 CommonsChunkPlugin
文档:http://webpack.github.io/docs/list-of-plugins.html#commonschunkplugin
如果您有兴趣将您的脚本与供应商的脚本分开自动捆绑:
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'})
]
};
您可以在 official documentation 中阅读有关此功能的更多信息。
在我的 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;
}
在我的插件数组中
plugins: [
new CommonsChunkPlugin({
name: 'vendors',
minChunks: function(module) {
return isExternal(module);
}
}),
// Other plugins
]
现在我有一个文件,它只根据需要将第 3 方库添加到一个文件中。
如果您想更详细地分离供应商和入口点文件:
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);
}
})
]
请注意,插件的顺序很重要。
此外,这将在版本 4 中发生变化。当它正式发布时,我会更新此答案。
更新: windows 用户的搜索索引更改