问题
I'm working in a Rails app, migrating from Sprockets to Webpack. Our current JavaScript relies on libraries globally assigned to window
. In order to migrate over, I'd like to maintain global assignment until we address it at a later date. I'd like to swap from Sprockets to Webpack without any JavaScript changes.
We have several JavaScript bundles, which have been manually split up for performance:
core.js
, which contains jQuery and a couple other files. It's a blocking bundle.vendor.js
, which contains all other libraries and jQuery plugins. It's a deferred bundle.application.js
, which contains our custom application code. Also a deferred bundle.
All the bundles rely on jQuery, and application.js
relies on vendor.js
. That's fine for Sprockets, but is an issue with Webpack.
How can I keep jQuery in core.js
, but exclude it from vendor.js
and application.js
in Webpack? or another way to ask this is How do I share the same instance of jQuery across multiple webpack bundles? I need to use the same instance because application.js
relies on jQuery plugins defined in vendor.js
My config file includes both expose-loader
and ProvidePlugin
, but these include jQuery in the bundle itself, which is not the same instance. In other words, I'm getting jQuery bundled multiple times (which is fixed with splitChunks()
), but I can't guarantee which instance I'm using, therefore can't guarantee the plugin is available.
// Webpacker environment.js config
const { environment } = require('@rails/webpacker');
const path = require('path');
const webpack = require('webpack');
environment.loaders.append('expose', {
test: require.resolve('jquery'),
use: [
{
loader: 'expose-loader',
options: 'jQuery'
},
{
loader: 'expose-loader',
options: '$'
}
]
});
environment.plugins.append(
'Provide',
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery'
})
);
module.exports = environment;
回答1:
I have had success with splitChunks
forcing a single instance for jquery combined with the exports-loader config like you have described.
Here's the key part of the Webpack config I'm using:
environment.splitChunks((config) => {
return Object.assign({}, config, {
optimization: {
splitChunks: {
chunks: 'all',
name: true,
cacheGroups: {
vendors: {
test: /[\\/]node_modules[\\/]/,
priority: -10,
},
default: {
minChunks: 2,
priority: -20,
reuseExistingChunk: true,
},
},
},
},
})
})
The key here is to understand that Webpack splitChunks replaces the need for manual code splitting. In other words, let go of the need to explicitly create core.js
and vendor.js
packs; consolidate all your imports as part of the application.js
dependency tree. Let Webpack do the code-splitting for you.
Another caveat to mention is that Webpacker's implementation of splitChunks
means placing a single javascript_packs_with_chunks_tag
in the view so that the shared "runtime" chunk will ensure that modules, like jQuery, aren't duplicated.
I used to split my bundles manually like you in my previous projects with Sprockets. When I had to do my own migration to Webpack, it took awhile for this new approach to sink in. I gave a talk about it which will shed some more light on my answer here: https://youtu.be/fKOq5_2qj54?t=185
回答2:
Not really sure if this is will work, but maybe you could try:
# vendor.js
import JQuery from 'jquery'
window.$ = window.JQuery = JQuery
// rest of vendor.js code
#application.js
import './vendor.js'
//rest of application.js code
回答3:
While I don't have a solution yet, I've found setting jQuery
as an external library seems to force a single global instance.
// Webpacker environment.js config
const { environment } = require('@rails/webpacker');
const path = require('path');
const webpack = require('webpack');
environment.config.set('externals', {
$: 'jquery',
jquery: 'jQuery'
});
module.exports = environment;
I've been able to test this by using my Sprockets core.js
bundle and Webpack for the everything else. It all works as expected.
I've posted a follow-up question to try to conditionally set externals and use Webpack for everything: Conditionally set externals for a specific Webpack bundle
来源:https://stackoverflow.com/questions/58881948/how-to-share-the-same-instance-of-jquery-across-multiple-webpack-packs