tag - Webpack: cómo hacer angular la autodetección jQuery y usarla como angular.element en lugar de jqLite?
document queryselector angular element (5)
!!Actualizar
Aparentemente, todavía necesita usar los valores comunes de commonJs necesarios para angular en el ejemplo de ES6.
import $ from "jquery"
window.$ = $;
window.jQuery = $;
var angular = require("angular");
a continuación está la respuesta original
Quiero proponer una solución más fácil. Simplemente haga que jQuery sea una ventana global para que angular pueda reconocerlo:
var $ = require("jquery")
window.$ = $;
window.jQuery = $;
var angular = require("angular");
o en su caso ( FUERA DE FECHA ):
import $ from "jquery"
window.$ = $;
window.jQuery = $;
import angular from "angular";
Espero que esto ayude :)
Estoy usando Webpack para construir un proyecto Angular 1.4. El proyecto hace uso de varios plugins jQuery, que están envueltos en directivas angulares. Esas directivas usan internamente el elemento angular.element
, lo que probablemente implica que angular.element es el jQuery real, no jqLite.
Quiero angular para detectar automáticamente jQuery y usarlo en lugar de jqLite. Intenté solicitar jquery localmente en mi módulo de punto de entrada app.js
: require(''jquery'')
y exponer jQuery globalmente con require(expose?$!expose?jQuery!jquery)
.
Aún así, haga lo que haga, angular.element
refiere a jqLite.
Mi investigación dio como resultado varios hallazgos:
- Incluso cuando se importa como un módulo CommonJS, Angular se asigna a una variable global
window.angular
, por lo que no necesitoexpose
con Webpack: ¿Angular se asigna a `window.angular` globalmente, cuando se carga como módulo CommonJS? . - ProviderPlugin no parece hacer el truco: no expone jQuery al espacio de nombres global; en cambio, para cada módulo que depende del nombre global jQuery, inserta
require(''jquery'')
en él. No estoy 100% seguro, pero parece que Angular no accede directamente ajQuery
desde el espacio de nombres global, sino que trata de acceder awindow.jQuery
en la funciónbindJQuery
, por lo que este enfoque no ayuda: exponer jQuery a un objeto de ventana real con Webpack . - Por la misma razón que ProviderPlugin,
imports-loader
parece inadecuado: Angular quierewindow.jQuery
, no solojQuery
. - Con
expose-loader
, jquery lo hace al objeto ventana. Mi problema fue que Babel eleva todas sus importaciones a la parte superior del módulo en el código resultante. Por lo tanto, aunquerequire(expose?jquery!jquery)
antes de laimport angular from "angular"
en los archivos de origen, en bundlerequire("angular")
está en la parte superior del archivo, antes de jquery, por lo que cuando se importa Angular, jquery aún no está disponible. Me pregunto cómo usar los cargadores Webpack con la sintaxis de importación ECMA6. - Hubo una sugerencia para usar la sintaxis de
import
lugar derequire
sintaxis con jquery:import "jquery"
oimport $ from "jquery"
, norequire(jquery)
: (Petr Averyanov: Cómo usar la sintaxis de los cargadores Webpack (imports / exports / expone) con ECMAScript 6 importaciones? ). El código fuente de jquery está envuelto con un contenedor especial , que identifica cómo se requiere jquery (con AMD / require, CommonJS o globalmente con la instrucción<script>
). Basado en eso, establece un argumento especialnoGlobal
para jquery fabric y creawindow.jQuery
o no, basado en el valor denoGlobal
. A partir de jquery 2.2.4, alimport "jquery"
noGlobal === true
ywindow.jQuery
no se crea. IIRC, algunas versiones anteriores de jquery no reconocían laimport
comoimport
CommonJS y agregaban laimport
archivos jquery al espacio de nombres global, lo que permitía que angular lo usara.
Detalles: aquí está mi 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"
});
});
En su caso, es mejor usar ProvidePlugin . Simplemente agregue estas líneas a la configuración de su paquete web en la sección de complementos y jquery estará disponible en su aplicación:
new webpack.ProvidePlugin({
"$": "jquery",
"jQuery": "jquery"
})
Hay este artículo japonés . Quiero utilizar jQuery not jQLite en webpack + AngularJS que parece hablar sobre el mismo problema (aún no sé japonés). Utilicé Google para traducir al inglés, los créditos van a cither para esta buena respuesta.
Él proporciona cuatro formas de resolver esto:
Asignar directamente a la ventana (no muy bueno)
window.jQuery = require(''jquery''); var angular = require(''angular''); console.log(angular.element(''body'')); //[body, prevObject: jQuery.fn.init[1], context: document, selector: "body"]
Usa el expose-loader (vale, pero no tan genial)
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" }] } };
uso:
require(''jquery''); var angular = require(''angular''); console.log(angular.element(''body'')); //[body, prevObject: jQuery.fn.init[1], context: document, selector: "body"]
Use expose-loader (mejor)
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" }] } };
uso:
var angular = require(''angular''); console.log(angular.element(''body'')); //[body, prevObject: jQuery.fn.init[1], context: document, selector: "body"]
Use ProvidePlugin (Mejor solución)
Esto es en realidad lo mismo que la respuesta aceptada por los studds aquí
module.exports = { entry: "./index", output: { path: __dirname, filename: "bundle.js" }, plugins: [ new webpack.ProvidePlugin({ "window.jQuery": "jquery" }) ], };
uso:
var angular = require(''angular''); console.log(angular.element(''body'')); //[body, prevObject: jQuery.fn.init[1], context: document, selector: "body"]
Pensé en compartir esto aquí ya que teníamos exactamente el mismo problema. Usamos la solución expose-loader
en nuestro proyecto con éxito. Supongo que el ProvidePlugin
que inyecta jquery directamente en la window
también es una buena idea.
Obtuve esta respuesta de john-reilly :
El misterioso caso de webpack angular y jquery
La respuesta de bob-sponge no es del todo correcta: el plugin Provide está haciendo un reemplazo de texto en los módulos que procesa, por lo que debemos proporcionar window.jQuery
(que es lo que angular busca) y no solo jQuery
.
En su
webpack.config.js
necesita agregar la siguiente entrada a sus complementos:
new webpack.ProvidePlugin({
"window.jQuery": "jquery"
}),
Esto utiliza el paquete web ProvidePlugin y, en el punto de webpackification (© 2016 John Reilly), todas las referencias en el código de window.jQuery serán reemplazadas por una referencia al módulo de paquete web que contiene jQuery. Así que cuando mires el archivo incluido verás que el código que verifica el objeto de la
window
parajQuery
ha convertido en esto:
jQuery = isUndefined(jqName) ?
__webpack_provided_window_dot_jQuery : // use jQuery (if present)
!jqName ? undefined : // use jqLite
window[jqName]; // use jQuery specified by `ngJq`
Está bien; webpack le proporciona a Angular jQuery sin dejar una variable
jQuery
en lawindow
. Neat ¿eh?
Por lo tanto, doy mi solución, que en realidad es una combinación de la respuesta de @BobSponge y los consejos / comentarios de @Bob. Así que nada original, simplemente mostrando lo que funciona para mí (en un proyecto que no usa Babel / ES6, BTW) y tratando de explicar por qué funciona ...
El truco (final) es utilizar el cargador de exposición .
Como se explica en su página, tenemos que poner module.loaders
. module.loaders
:
{ test: require.resolve("jquery"), loader: "expose?$!expose?jQuery" },
Además, en la lista de plugins
, tengo:
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.
}),
que realmente encuentra las ocurrencias globales de estas variables en el código, y las requiere en variables locales para cada módulo. Facilita la migración de un proyecto existente (de RequireJS a Webpack) como lo hago ... Creo que podemos prescindir de este complemento si prefiere ser explícito en sus importaciones.
Y, lo que es más importante (creo), en el punto de entrada de la aplicación, los requiero en el orden en que los quiero. En mi caso, hice un paquete de proveedores, así que ese es el orden en este paquete.
require(''jquery'');
require(''lodash'');
// [...]
var angular = require(''angular'');
// Use the angular variable to declare the app module, etc.
Webpack agregará las bibliotecas al paquete relevante en el orden en que ve las necesidades (a menos que use un complemento / cargador que las reordene). Pero las importaciones están aisladas (sin pérdida global), por lo que Angular no pudo ver la biblioteca jQuery. De ahí la necesidad de expose
. (Intenté window.jQuery = require(''jquery'');
lugar, pero no funcionó, tal vez es demasiado tarde.)