Administrar la dependencia del complemento jQuery en el paquete web

480

Estoy usando Webpack en mi aplicación, en la que creo dos puntos de entrada: bundle.js para todos mis archivos / códigos JavaScript y vendors.js para todas las bibliotecas como jQuery y React. ¿Qué hago para usar complementos que tienen jQuery como sus dependencias y quiero tenerlos también en vendors.js? ¿Qué pasa si esos complementos tienen múltiples dependencias?

Actualmente estoy tratando de usar este complemento de jQuery aquí: https://github.com/mbklein/jquery-elastic . La documentación de Webpack menciona providePlugin e import-loader. Usé providePlugin, pero aún así el objeto jQuery no está disponible. Así es como se ve mi webpack.config.js-

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;

Pero a pesar de esto, todavía arroja un error en la consola del navegador:

Uncaught ReferenceError: jQuery is not defined

Del mismo modo, cuando uso el cargador de importaciones, arroja un error,

require is not defined'

en esta línea:

var jQuery = require("jquery")

Sin embargo, podría usar el mismo complemento cuando no lo agrego a mi archivo vendors.js y, en su lugar, lo requiero de la forma normal de AMD, ya que incluyo mis otros archivos de código JavaScript, como-

define(
[
    'jquery',
    'react',
    '../../common-functions',
    '../../libs/jquery.elastic.source'
],function($,React,commonFunctions){
    $("#myInput").elastic() //It works

});

Pero esto no es lo que quiero hacer, ya que esto significaría que jquery.elastic.source.js está incluido junto con mi código JavaScript en bundle.js, y quiero que todos mis complementos de jQuery estén en el paquete vendors.js. Entonces, ¿cómo hago para lograr esto?

2
  • 3
    No estoy seguro si este es su problema, pero definitivamente necesita cambiar windows.jQuery a "window.jQuery": "jquery". Hay un error tipográfico en el sitio web de webpack de donde supongo que obtuviste ese código. Alex Hawkins 28/03/15 a las 0:46
  • @AlexHawkins Oh, sí, lo noté y lo arreglé. ¡Gracias por mencionarlo! booleanhunter 26 de mayo de 2015 a las 7:32
806

Ha mezclado diferentes enfoques sobre cómo incluir módulos de proveedores heredados. Así es como lo abordaría:

1. Prefiere CommonJS / AMD no minificado sobre dist

La mayoría de los módulos vinculan la distversión en el maincampo de su package.json. Si bien esto es útil para la mayoría de los desarrolladores, para el paquete web es mejor asignar un alias a la srcversión porque de esta manera el paquete web puede optimizar mejor las dependencias (por ejemplo, cuando se usa DedupePlugin).

// webpack.config.js

module.exports = {
    ...
    resolve: {
        alias: {
            jquery: "jquery/src/jquery"
        }
    }
};

Sin embargo, en la mayoría de los casos, la distversión también funciona bien.


2. Utilice ProvidePluginpara inyectar globales implícitas

La mayoría de los módulos heredados se basan en la presencia de globales específicos, como lo hacen los complementos de jQuery en $o jQuery. En este escenario, puede configurar el paquete web, para anteponer var $ = require("jquery")cada vez que encuentre el $identificador global .

var webpack = require("webpack");

    ...

    plugins: [
        new webpack.ProvidePlugin({
            $: "jquery",
            jQuery: "jquery"
        })
    ]

3. Utilice el cargador de importaciones para configurarthis

Algunos módulos heredados se basan en thisser el windowobjeto. Esto se convierte en un problema cuando el módulo se ejecuta en un contexto CommonJS donde thises igual module.exports. En este caso, puede anular thiscon el cargador de importaciones .

Corre npm i imports-loader --save-devy luego

module: {
    loaders: [
        {
            test: /[\/\\]node_modules[\/\\]some-module[\/\\]index\.js$/,
            loader: "imports-loader?this=>window"
        }
    ]
}

El cargador de importaciones también se puede utilizar para inyectar manualmente variables de todo tipo. Pero la mayoría de las veces ProvidePlugines más útil cuando se trata de globales implícitas.


4. Utilice el cargador de importaciones para deshabilitar AMD

Hay módulos que admiten diferentes estilos de módulos, como AMD, CommonJS y legacy. Sin embargo, la mayoría de las veces primero verifican definey luego usan algún código peculiar para exportar propiedades. En estos casos, podría ayudar forzar la ruta CommonJS estableciendo define = false.

module: {
    loaders: [
        {
            test: /[\/\\]node_modules[\/\\]some-module[\/\\]index\.js$/,
            loader: "imports-loader?define=>false"
        }
    ]
}

5. Utilice el cargador de scripts para importar scripts de forma global.

Si no le importan las variables globales y solo desea que funcionen los scripts heredados, también puede usar el cargador de scripts. Ejecuta el módulo en un contexto global, como si los hubiera incluido a través de la <script>etiqueta.


6. Úselo noParsepara incluir discos grandes

Cuando no hay una versión AMD / CommonJS del módulo y desea incluirlo dist, puede marcar este módulo como noParse. Luego, el paquete web solo incluirá el módulo sin analizarlo, lo que puede usarse para mejorar el tiempo de compilación. Esto significa que cualquier función que requiera el AST , como el ProvidePlugin, no funcionará.

module: {
    noParse: [
        /[\/\\]node_modules[\/\\]angular[\/\\]angular\.js$/
    ]
}
24
  • 3
    Se ProvidePluginaplica a todas las apariciones de los identificadores dados en todos los archivos. Se imports-loaderpuede aplicar solo en archivos específicos, pero no debe usar ambos para las mismas variables / dependencias. Johannes Ewald 13/03/15 a las 16:32
  • 6
    Estoy confundido por esto. ¿De dónde proviene realmente jquery? ¿Localmente o una CDN? Todo lo que sigue a 3. no está claro si es necesario. ¿Cuáles son los pasos reales para integrar jquery en su proyecto usando webpack. ¿Omite la versión que está disponible a través de CDN? HelpMeStackOverflowMyOnlyHope 7 de mayo de 2015 a las 0:17
  • 3
    Todo lo de un CDN está fuera del alcance del paquete web, por lo que se refiere a una instalación de jquery local. Jquery solo puede ser requerido, no hay pasos especiales necesarios para integrarlo. Esta pregunta trata sobre cómo integrar los complementos de jquery que dependen de la $variable global . Johannes Ewald 8 de mayo de 2015 a las 9:39
  • 8
    Hice todo esto, todavía no funciona; Luego agregó: "module": { "loaders": [ { test: require.resolve("jquery"), loader: "expose?$!expose?jQuery" },y funcionó bien. musicformellons 23 de mayo de 2016 a las 13:49
  • 7
    ¿Hacer todo esto, para solo incluir un paquete de jquery ?, que molestia. Voy a volver a mi compilación gulpRahul Gupta 4 de septiembre de 2017 a las 5:08
94

Para el acceso global a jquery, existen varias opciones. En mi proyecto de paquete web más reciente, quería acceso global a jquery, así que agregué lo siguiente a mis declaraciones de complementos:

 plugins: [
    new webpack.ProvidePlugin({
      $: "jquery",
      jQuery: "jquery"
    })
  ]

Esto significa que se puede acceder a jquery desde el código fuente de JavaScript a través de referencias globales $ y jQuery.

Por supuesto, también debe haber instalado jquery a través de npm:

$ npm i jquery --save

Para obtener un ejemplo práctico de este enfoque, siéntase libre de bifurcar mi aplicación en github

8
  • 2
    Por favor, ¿puede dejar un comentario si rebaja un voto explicando el motivo? La información anterior es precisa. Consulte mi aplicación de trabajo en: github.com/arcseldon/react-babel-webpack-starter-app utilizando el enfoque anterior. arcseldon 28/12/15 a las 16:49
  • No soy el votante negativo, pero tal vez esto se deba a que la ProvidePluginsolución que sugieres ya se propuso. Léo Lam 31/12/15 a las 12:24
  • @ LéoLam - gracias por tu comentario. Aprecio su punto: había deducido la respuesta a través de consultas separadas y solo compartí el fragmento aquí que pensé que probablemente era más relevante para otros que deseen emular lo que había hecho. Sin embargo, tiene razón, la respuesta oficial cubre esta opción. arcseldon 31/12/15 a las 16:39
  • 1
    Está funcionando pero recibo 2 advertencias: ./~/jQuery/dist/jquery.js There is another module with an equal name when case is ignored.y la misma con./~/jquery/dist/jquery.jspistou 25 de enero de 2016 a las 10:27
  • 8
    Necesitaba agregar 'window.jQuery': 'jquery'a esa lista para hacer que se cargara el paquete npm ms-signalr-client. También puse en 'window.$': 'jquery'buena medida :)Sammi 27/04/2016 a las 12:48
60

No sé si entiendo muy bien lo que está tratando de hacer, pero tuve que usar los complementos de jQuery que requerían que jQuery estuviera en el contexto global (ventana) y puse lo siguiente en mi entry.js:

var $ = require('jquery');
window.jQuery = $;
window.$ = $;

Solo tengo que requerir donde quiera jqueryplugin.min.jsy window.$se extiende con el complemento como se esperaba.

2
  • 2
    Básicamente, estaba cometiendo el error de usar ProvidePlugin junto con la condición noParse. Los complementos como ProvidePlugin no funcionan si hacemos NoParse, como se indica en el punto número 6 de la respuesta. Puedes ver ese error en el códigobooleanhunter 26 de mayo de 2015 a las 7:27
  • sí, descubrí que funciona de manera más consistente en todos los complementos que los complementos proporcionados, etc., especialmente si está incorporando angular 1.x a través del cargador de scripts. Tracker1 22 de febrero de 2017 a las 1:35
31

Hice que las cosas funcionaran bien al exponer $y jQuerycomo variables globales con Webpack 3.8.1 y lo siguiente.

Instale jQuery como una dependencia del proyecto. Puede omitir @3.2.1instalar la última versión o especificar otra versión.

npm install --save [email protected]

Instalar expose-loadercomo una dependencia de desarrollo si aún no está instalado.

npm install expose-loader --save-dev

Configure Webpack para cargar y exponer jQuery para nosotros.

// webpack.config.js
const webpack = require('webpack')

module.exports = {
  entry: [
    // entry bits
  ],
  output: {
    // output bits
  },
  module: {
    rules: [
      // any other rules
      {
        // Exposes jQuery for use outside Webpack build
        test: require.resolve('jquery'),
        use: [{
          loader: 'expose-loader',
          options: 'jQuery'
        },{
          loader: 'expose-loader',
          options: '$'
        }]
      }
    ]
  },
  plugins: [
    // Provides jQuery for other JS bundled with Webpack
    new webpack.ProvidePlugin({
      $: 'jquery',
      jQuery: 'jquery'
    })
  ]
}
5
  • 7
    Olvidó mencionar que necesita instalar expose-loaderpara que funcione correctamente npm install expose-loader --save-devPaulo Griiettner 15/11/2017 a las 20:13
  • 4
    Esto funcionó para mí 👍. jquery: 3.3.1, expose-loader: 0.7.5, paquete web: 4.20.2AKT 28/09/18 a las 6:01
  • Lo expose-loadedhicieron por mí. No recibí un error en el momento de la compilación, sino en las herramientas de desarrollo de Chrome. Eso está resuelto ahora. Johan Vergeer 7/12/19 a las 20:46
  • 1
    ¡Gracias! Esto funcionó con "jquery": "^ 3.4.1" y "webpack": "^ 4.41.5". ¿Soy solo yo o hacer que jQuery funcione con Webpack no debería ser tan ridículo? Carles Alcolea 5 feb.20 a las 10:17
  • 1
    Para mí funcionó usando una sintaxis ligeramente diferente: `test: require.resolve (" jquery "), loader:" expose-loader ", options: {exposes: [" $ "," jQuery "],},},`iBobb 8 dic.20 a las 13:46
20

En su archivo webpack.config.js agregue a continuación:

 var webpack = require("webpack");
 plugins: [
    new webpack.ProvidePlugin({
        $: "jquery",
        jQuery: "jquery"
    })
 ],

Instale jQuery usando npm:

$ npm i jquery --save

En el archivo app.js, agregue las siguientes líneas:

import $ from 'jquery';
window.jQuery = $;
window.$ = $;

Esto funcionó para mí. :)

2
  • 1
    ¿Cómo actuará esto si tienes por ex. app.js y jquery-module.js, que ambos requieren jquery ?, para mí obtengo jquery13981378127 y jquery12389723198 como instancias en la ventana? Martea 10 de diciembre de 2019 a las 8:44
  • 1
    Ocúpate de la distinción entre mayúsculas y minúsculas en "jquery". En mis externos webpack.config, tenía "jquery: 'jQuery'". Tenía "importar $ de 'jQuery'" en mi script. Cambiar a "importar $ de 'jquery'" resolvió mi problema :)Jono 7 de agosto de 2020 a las 5:36
18

Agregue esto a su matriz de complementos en webpack.config.js

new webpack.ProvidePlugin({
    'window.jQuery': 'jquery',
    'window.$': 'jquery',
})

luego requiere jquery normalmente

require('jquery');

Si el dolor persiste al hacer que otros scripts lo vean, intente colocarlo explícitamente en el contexto global a través de (en la entrada js)

window.$ = jQuery;
10

Probé algunas de las respuestas proporcionadas, pero ninguna pareció funcionar. Entonces probé esto:

new webpack.ProvidePlugin({
    'window.jQuery'    : 'jquery',
    'window.$'         : 'jquery',
    'jQuery'           : 'jquery',
    '$'                : 'jquery'
});

Parece funcionar sin importar la versión que esté usando

2
  • +1 parece ser un malentendido de que los globales agregados aquí se establecerán automáticamente en la ventana, no parece funcionar así, debe ser explícito. James 14 de septiembre de 2017 a las 21:26
  • Correcto, esto no lo agrega al objeto de ventana. Crea un alias de ventana dentro del paquete web. Entonces, si intenta usar $fuera de un archivo requerido de paquete web, no estará definido. Cam Tullos 18 de septiembre de 2017 a las 17:23
7

Esto funciona en el paquete web 3:

en el archivo webpack.config.babel.js:

resolve: {
    alias: {
         jquery: "jquery/src/jquery"
    },
 ....
}

Y usa ProvidePlugin

new webpack.ProvidePlugin({
        '$': 'jquery',
        'jQuery': 'jquery',
    })
2
  • 2
    (! Como yo) para otros que son super nuevo en webpack "resolver" va en sus webpack.config.js bajo module.exports = {} como entrada, salida, plugins, módulos, etc ..DavGarcia 19 de marzo de 2018 a las 16:38
  • 2
    Y el nuevo webpack.ProvidePlugin va dentro de la matriz de complementos. DavGarcia 19 de marzo de 2018 a las 16:38
3

Editar: A veces, desea usar el paquete web simplemente como un paquete de módulos para un proyecto web simple, para mantener su propio código organizado. La siguiente solución es para aquellos que solo quieren que una biblioteca externa funcione como se espera dentro de sus módulos, sin gastar mucho tiempo sumergiéndose en configuraciones de paquetes web. (Editado después de -1)

Solución rápida y simple (es6) si todavía tiene problemas o desea evitar la configuración externa / configuración adicional del complemento de paquete web:

<script src="cdn/jquery.js"></script>
<script src="cdn/underscore.js"></script>
<script src="etc.js"></script>
<script src="bundle.js"></script>

dentro de un módulo:

const { jQuery: $, Underscore: _, etc } = window;
2

La mejor solución que encontré fue:

https://github.com/angular/angular-cli/issues/5139#issuecomment-283634059

Básicamente, debe incluir una variable ficticia en typings.d.ts, eliminar cualquier "importación * como $ de 'jquery" de su código, y luego agregar manualmente una etiqueta al script jQuery a su html SPA. De esta manera, el paquete web no se interpondrá en su camino y debería poder acceder a la misma variable global de jQuery en todos sus scripts.

2

Esto me funciona en el webpack.config.js

    new webpack.ProvidePlugin({
        $: 'jquery',
        jQuery: 'jquery',
        'window.jQuery': 'jquery'
    }),

en otro javascript o en HTML agregue:

global.jQuery = require('jquery');