J'utilise Webpack pour construire un projet Angular 1.4. Le projet utilise plusieurs plugins jQuery, qui sont enveloppés dans des directives angular. Ces directives utilisent en interne angular.element
, Impliquant probablement que angular.element est le vrai jQuery, pas jqLite.
Je veux angular pour détecter automatiquement jQuery et l'utiliser à la place de jqLite. J'ai essayé d'exiger jquery localement dans mon module de point d'entrée app.js
: require('jquery')
et pour exposer jQuery globalement avec require(expose?$!expose?jQuery!jquery)
.
Quoi que je fasse, angular.element
Fait référence à jqLite.
Ma recherche a abouti à plusieurs constats:
window.angular
, Donc je n'ai pas besoin de expose
avec Webpack: - Angular s'assigne-t-il à `window.angular` globalement, lorsqu'il est chargé en tant que module CommonJS? .require('jquery')
. Je ne suis pas sûr à 100%, mais il semble que Angular n'accède pas directement à jQuery
à partir de l'espace de noms global, mais essaie d'accéder à window.jQuery
Dans bindJQuery
, donc cette approche n'aide pas: Exposez jQuery à un objet Window réel avec Webpack .imports-loader
Semble impropre: Angular veut window.jQuery
, Pas seulement jQuery
.expose-loader
, Jquery arrive à l'objet window. Mon problème était que Babel hisse toutes ses importations en haut du module dans le code résultant. Par conséquent, bien que require(expose?jquery!jquery)
était avant import angular from "angular"
Dans les fichiers source, dans le bundle require("angular")
est en haut du fichier, avant jquery, donc au moment Angular est importé, jquery n'est pas encore disponible. Je me demande comment utiliser les chargeurs Webpack avec la syntaxe d'importation ECMA6.import
au lieu de la syntaxe require
avec jquery: import "jquery"
Ou import $ from "jquery"
, Pas require(jquery)
: (Petr Averyanov: Comment utiliser la syntaxe des chargeurs Webpack (importations/exportations/exposition) avec les importations ECMAScript 6? ). le code source de jquery est enveloppé avec un wrapper spécial , qui identifie la façon dont jquery est requis (avec AMD/require, CommonJS ou globalement avec l'instruction <script>
). Sur cette base, il définit un argument spécial noGlobal
pour le tissu jquery et crée window.jQuery
Ou non, en fonction de la valeur de noGlobal
. Depuis jquery 2.2.4, sur import "jquery"
noGlobal === true
Et window.jQuery
N'est pas créé. IIRC, certaines anciennes versions de jquery ne reconnaissaient pas import
comme import CommonJS et ajoutaient import
ed jquery à l'espace de noms global, ce qui permettait à angular de l'utiliser).Détails: voici mon app.js
:
'use strict';
require("expose?$!expose?jQuery!jquery");
require("metisMenu/dist/metisMenu");
require("expose?_!lodash");
require("expose?angular!angular");
import angular from "angular";
import "angular-animate";
import "angular-messages";
import "angular-resource";
import "angular-sanitize";
import "angular-ui-router";
import "bootstrap/dist/css/bootstrap.css";
import "font-awesome/css/font-awesome.css";
import "angular-bootstrap";
require("../assets/styles/style.scss");
require("../assets/fonts/pe-icon-7-stroke/css/pe-icon-7-stroke.css");
// Import all html files to put them in $templateCache
// If you need to use lazy loading, you will probably need
// to remove these two lines and explicitly require htmls
const templates = require.context(__dirname, true, /\.html$/);
templates.keys().forEach(templates);
import HomeModule from "home/home.module";
import UniverseDirectives from "../components/directives";
angular.module("Universe", [
"ngAnimate",
"ngMessages",
"ngResource",
"ngSanitize",
"ui.router",
"ui.bootstrap",
HomeModule.name,
UniverseDirectives.name,
])
.config(function($urlRouterProvider, $locationProvider, $stateProvider){
// $urlRouterProvider.otherwise('/');
// $locationProvider.html5Mode(true);
$stateProvider
.state('test', {
url: "/test",
template: "This is a test"
});
});
J'ai obtenu cette réponse de john-reilly :
Le cas mystérieux du webpack angular et jquery
bob-sponge la réponse n'est pas tout à fait juste - le plugin Provider fait en fait un remplacement de texte sur les modules qu'il traite, nous devons donc fournir window.jQuery
(qui est ce que angular recherche) et pas seulement jQuery
.
Dans votre
webpack.config.js
vous devez ajouter l'entrée suivante à vos plugins:
new webpack.ProvidePlugin({
"window.jQuery": "jquery"
}),
Cela utilise le webpack ProviderPlugin et, au point de webpackification (© 2016 John Reilly) toutes les références dans le code à window.jQuery sera remplacé par une référence au module webpack qui contient jQuery. Ainsi, lorsque vous regardez le fichier fourni, vous verrez que le code qui vérifie l'objet
window
pourjQuery
est devenu ceci:
jQuery = isUndefined(jqName) ?
__webpack_provided_window_dot_jQuery : // use jQuery (if present)
!jqName ? undefined : // use jqLite
window[jqName]; // use jQuery specified by `ngJq`
C'est vrai; webpack fournit Angular avec jQuery tout en pas en plaçant une variable
jQuery
sur lawindow
. Neat hein?
Apparemment, vous devez toujours utiliser les commonJs requis pour angular dans l'exemple ES6.
import $ from "jquery"
window.$ = $;
window.jQuery = $;
var angular = require("angular");
ci-dessous est la réponse originale
Je veux proposer une solution plus simple. Faites simplement de jQuery une fenêtre globale pour que angular puisse le reconnaître:
var $ = require("jquery")
window.$ = $;
window.jQuery = $;
var angular = require("angular");
ou dans votre cas (HORS DATE):
import $ from "jquery"
window.$ = $;
window.jQuery = $;
import angular from "angular";
J'espère que ça aide :)
Dans votre cas, il vaut mieux utiliser ProviderPlugin . Ajoutez simplement ces lignes à votre configuration de webpack dans la section plugins et jquery sera disponible dans votre application:
new webpack.ProvidePlugin({
"$": "jquery",
"jQuery": "jquery"
})
Donc, je donne ma solution, qui est en fait un mashup de la réponse @BobSponge et des astuces/commentaires de @ Bob. Donc, rien d'original, juste montrer ce qui fonctionne pour moi (dans un projet n'utilisant pas Babel/ES6, BTW) et essayer d'expliquer pourquoi cela fonctionne ...
L'astuce (finale) est en effet d'utiliser le exposer le chargeur .
Comme expliqué dans leur page, nous devons mettre module.loaders
:
{ test: require.resolve("jquery"), loader: "expose?$!expose?jQuery" },
De plus, dans la liste plugins
, j'ai:
new webpack.ProvidePlugin(
{
$: 'jquery',
jQuery: 'jquery',
_: 'lodash',
// [...] some other libraries that put themselves in the global scope.
//angular: 'angular', // No, I prefer to require it everywhere explicitly.
}),
qui trouve réellement les occurrences globales de ces variables dans le code, et les requiert en variables locales à chaque module. Cela facilite la migration d'un projet existant (de RequireJS vers Webpack) comme je le fais ... Je pense que nous pouvons nous passer de ce plugin si vous préférez être explicite dans vos importations.
Et, surtout (je pense), au point d'entrée de la demande, je les demande dans l'ordre que je veux. Dans mon cas, j'ai créé un bundle fournisseur, c'est donc l'ordre dans ce bundle.
require('jquery');
require('lodash');
// [...]
var angular = require('angular');
// Use the angular variable to declare the app module, etc.
Webpack ajoutera les bibliothèques au bundle correspondant dans l'ordre où il voit les require
s (sauf si vous utilisez un plugin/chargeur qui les réorganise). Mais les importations sont isolées (pas de fuite globale), donc Angular n'a pas pu voir la bibliothèque jQuery. D'où la nécessité de expose
. (J'ai essayé window.jQuery = require('jquery');
à la place, mais cela n'a pas fonctionné, il est peut-être trop tard.)
Il y a cet article japonais je veux utiliser le jQuery pas jQLite dans webpack + AngularJS qui semble parler du même problème (je ne connais pas encore le japonais btw). J'ai utilisé google pour traduire en anglais, les crédits vont à cither pour cette belle réponse.
Il propose quatre façons de résoudre ce problème:
Attribuer directement à la fenêtre (pas vraiment cool)
window.jQuery = require('jquery');
var angular = require('angular');
console.log(angular.element('body'));
//[body, prevObject: jQuery.fn.init[1], context: document, selector: "body"]
Utilisez le expose-loader (ok, mais pas trop cool)
npm install --saveDev expose-loader
webpack.config.js
module.exports = {
entry: "./index",
output: {
path: __dirname,
filename: "bundle.js"
},
module: {
loaders: [{
test: /\/jquery.js$/,
loader: "expose?jQuery"
}]
}
};
usage:
require('jquery');
var angular = require('angular');
console.log(angular.element('body'));
//[body, prevObject: jQuery.fn.init[1], context: document, selector: "body"]
Utilisez exposer-chargeur (mieux)
npm install --saveDev expose-loader
webpack.config.js
module.exports = {
entry: "./index",
output: {
path: __dirname,
filename: "bundle.js"
},
module: {
loaders: [{
test: /\/angular\.js$/,
loader: "imports?jQuery=jquery"
}, {
test: /\/jquery.js$/,
loader: "expose?jQuery"
}]
}
};
usage:
var angular = require('angular');
console.log(angular.element('body'));
//[body, prevObject: jQuery.fn.init[1], context: document, selector: "body"]
Utilisez ProviderPlugin (Meilleure solution)
C'est en fait la même chose que réponse acceptée de studds ici
module.exports = {
entry: "./index",
output: {
path: __dirname,
filename: "bundle.js"
},
plugins: [
new webpack.ProvidePlugin({
"window.jQuery": "jquery"
})
],
};
usage:
var angular = require('angular');
console.log(angular.element('body'));
//[body, prevObject: jQuery.fn.init[1], context: document, selector: "body"]
Je pensais partager cela ici car nous avions exactement le même problème. Nous avons utilisé le expose-loader
solution dans notre projet avec succès. Je suppose que le ProvidePlugin
qui injecte directement jquery dans window
est aussi une bonne idée.