Ik'gebruik Webpack in mijn applicatie, waarin ik twee ingangspunten maak - bundle.js voor al mijn JavaScript-bestanden/codes, en vendors.js voor alle bibliotheken zoals jQuery en React. Wat moet ik doen om plugins te gebruiken die jQuery als hun afhankelijkheden hebben en die ik ook in vendors.js wil hebben? Wat als die plugins meerdere afhankelijkheden hebben?
Op dit moment probeer ik deze jQuery plugin hier te gebruiken - https://github.com/mbklein/jquery-elastic. De Webpack documentatie vermeldt providePlugin en imports-loader. Ik heb providePlugin gebruikt, maar nog steeds is het jQuery object niet beschikbaar. Hier is hoe mijn webpack.config.js eruit ziet-
var webpack = require('webpack');
var bower_dir = __dirname + '/bower_components';
var node_dir = __dirname + '/node_modules';
var lib_dir = __dirname + '/public/js/libs';
var config = {
addVendor: function (name, path) {
this.resolve.alias[name] = path;
this.module.noParse.push(new RegExp(path));
},
plugins: [
new webpack.ProvidePlugin({
$: "jquery",
jquery: "jQuery",
"window.jQuery": "jquery"
}),
new webpack.optimize.CommonsChunkPlugin('vendors', 'vendors.js', Infinity)
],
entry: {
app: ['./public/js/main.js'],
vendors: ['react','jquery']
},
resolve: {
alias: {
'jquery': node_dir + '/jquery/dist/jquery.js',
'jquery.elastic': lib_dir + '/jquery.elastic.source.js'
}
},
output: {
path: './public/js',
filename: 'bundle.js'
},
module: {
loaders: [
{ test: /\.js$/, loader: 'jsx-loader' },
{ test: /\.jquery.elastic.js$/, loader: 'imports-loader' }
]
}
};
config.addVendor('react', bower_dir + '/react/react.min.js');
config.addVendor('jquery', node_dir + '/jquery/dist/jquery.js');
config.addVendor('jquery.elastic', lib_dir +'/jquery.elastic.source.js');
module.exports = config;
Maar ondanks dit, geeft het nog steeds een foutmelding in de browser console:
Uncaught ReferenceError: jQuery is niet gedefinieerd
Evenzo, wanneer ik de imports-loader gebruik, geeft hij een foutmelding,
require is niet gedefinieerd'
in deze regel:
var jQuery = require("jquery")
Ik zou echter dezelfde plugin kunnen gebruiken als ik het niet toevoeg aan mijn vendors.js bestand en het in plaats daarvan nodig heb op de normale AMD manier als hoe ik mijn andere JavaScript code bestanden toevoeg, zoals-
define(
[
'jquery',
'react',
'../../common-functions',
'../../libs/jquery.elastic.source'
],function($,React,commonFunctions){
$("#myInput").elastic() //It works
});
Maar dit is niet wat ik wil doen, want dit zou betekenen dat jquery.elastic.source.js wordt gebundeld samen met mijn JavaScript-code in bundle.js, en ik wil al mijn jQuery plugins te zijn in de vendors.js bundel. Dus hoe kan ik dit bereiken?
U'heeft verschillende benaderingen gemengd hoe legacy vendor modules op te nemen. Dit is hoe ik het zou aanpakken:
dist
De meeste modules linken de dist
versie in het main
veld van hun package.json
. Hoewel dit handig is voor de meeste ontwikkelaars, is het voor webpack beter om de src
versie te aliasen, omdat webpack op deze manier de afhankelijkheden beter kan optimaliseren (bijv. bij gebruik van de DedupePlugin
).
// webpack.config.js
module.exports = {
...
resolve: {
alias: {
jquery: "jquery/src/jquery"
}
}
};
Echter, in de meeste gevallen werkt de dist
versie ook prima.
ProvidePlugin
om impliciete globals te injecterenDe meeste legacy modules vertrouwen op de aanwezigheid van specifieke globals, zoals jQuery plugins doen op $
of jQuery
. In dit scenario kunt u webpack configureren, om var $ = require("jquery")
te preppen telkens als het de globale $
identifier tegenkomt.
var webpack = require("webpack");
...
plugins: [
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery"
})
]
dit
te configurerenSommige legacy modules vertrouwen erop dat this
het window
object is. Dit wordt een probleem als de module wordt uitgevoerd in een CommonJS context waar this
gelijk is aan module.exports
. In dit geval kun je this
overriden met de imports-loader.
Voer npm i imports-loader --save-dev
uit en dan
module: {
loaders: [
{
test: /[\/\\]node_modules[\/\\]some-module[\/\\]index\.js$/,
loader: "imports-loader?this=>window"
}
]
}
De imports-loader kan ook gebruikt worden om handmatig allerlei variabelen te injecteren. Maar meestal is de ProvidePlugin
nuttiger als het gaat om impliciete globals.
Er zijn modules die verschillende module stijlen ondersteunen, zoals AMD, CommonJS en legacy. Echter, meestal controleren ze eerst op define
en gebruiken dan wat eigenzinnige code om eigenschappen te exporteren. In deze gevallen kan het helpen om het CommonJS pad te forceren door define = false
in te stellen.
module: {
loaders: [
{
test: /[\/\\]node_modules[\/\\]some-module[\/\\]index\.js$/,
loader: "imports-loader?define=>false"
}
]
}
Als je niet om globale variabelen geeft en alleen je oude scripts wilt laten werken, kun je ook de script-loader gebruiken. Het voert de module uit in een globale context, net alsof je ze had opgenomen via de <script>
tag.
noParse
om grote dists op te nemenWanneer er geen AMD/CommonJS versie van de module is en je wilt de dist
includen, dan kun je deze module markeren als noParse
. Dan zal webpack gewoon de module includen zonder deze te parsen, wat gebruikt kan worden om de bouwtijd te verbeteren. Dit betekent dat elke functie die de AST vereist, zoals de ProvidePlugin
, niet zal werken.
module: {
noParse: [
/[\/\\]node_modules[\/\\]angular[\/\\]angular\.js$/
]
}
Voor globale toegang tot jquery zijn er verschillende opties. In mijn meest recente webpack project, wilde ik globale toegang tot jquery dus voegde ik het volgende toe aan mijn plugins declaraties:
plugins: [
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery"
})
]
Dit betekent dan dat jquery toegankelijk is vanuit de JavaScript broncode via globale referenties $ en jQuery.
Natuurlijk moet je jquery ook geïnstalleerd hebben via npm:
$ npm i jquery --save
Voor een werkend voorbeeld van deze aanpak, voel je vrij om mijn app te forken op github
Ik weet niet of ik goed begrijp wat je probeert te doen, maar ik moest jQuery plugins gebruiken die vereisten dat jQuery zich in de globale context (venster) bevond en ik zette het volgende in mijn entry.js
:
var $ = require('jquery');
window.jQuery = $;
window.$ = $;
Ik hoef alleen maar de jqueryplugin.min.js
te vereisen waar ik maar wil en window.$
wordt uitgebreid met de plugin zoals verwacht.