Gérer la dépendance du plugin jQuery dans le webpack

451

J'utilise Webpack dans mon application, dans laquelle je crée deux points d'entrée - bundle.js pour tous mes fichiers / codes JavaScript et vendors.js pour toutes les bibliothèques comme jQuery et React. Que dois-je faire pour utiliser des plugins qui ont jQuery comme dépendances et je veux les avoir aussi dans vendors.js? Et si ces plugins ont plusieurs dépendances?

Actuellement, j'essaie d'utiliser ce plugin jQuery ici - https://github.com/mbklein/jquery-elastic . La documentation Webpack mentionne providePlugin et imports-loader. J'ai utilisé providePlugin, mais toujours l'objet jQuery n'est pas disponible. Voici à quoi ressemble mon 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;

Mais malgré cela, il lance toujours une erreur dans la console du navigateur:

UnCaught ReferenceError: jQuery n'est pas défini

De même, lorsque j'utilise le chargeur d'importations, il génère une erreur,

exiger n'est pas défini »

dans cette ligne:

var jQuery = require("jquery")

Cependant, je pouvais utiliser le même plugin lorsque je ne l'ajoutais pas à mon fichier vendors.js et le demandais à la place de la manière AMD normale comme j'inclus mes autres fichiers de code JavaScript, comme-

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

});

Mais ce n'est pas ce que je veux faire, car cela signifierait que jquery.elastic.source.js est fourni avec mon code JavaScript dans bundle.js, et je veux que tous mes plugins jQuery soient dans le bundle vendors.js. Alors, comment dois-je procéder pour y parvenir?

booleanhunter
la source
3
Je ne sais pas si c'est votre problème mais vous devez absolument changer windows.jQuery en "window.jQuery": "jquery". Il y a une faute de frappe sur le site Web de webpack où je suppose que vous avez obtenu ce code.
Alex Hawkins
@AlexHawkins Oh oui, j'ai remarqué cela et l'ai corrigé. Merci de l'avoir signalé!
booleanhunter

Réponses:

771

Vous avez mélangé différentes approches pour inclure des modules de fournisseur hérités. Voici comment je m'y attaquerais:

1. Préférez CommonJS / AMD non réduit à dist

La plupart des modules lient la distversion dans le maindomaine de leur package.json. Bien que cela soit utile pour la plupart des développeurs, pour webpack, il est préférable d'alias la srcversion car de cette façon, webpack est en mesure d'optimiser les dépendances mieux (par exemple lors de l'utilisation de DedupePlugin).

// webpack.config.js

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

Cependant, dans la plupart des cas, la distversion fonctionne également très bien.


2. Utilisez le ProvidePluginpour injecter des globaux implicites

La plupart des modules hérités reposent sur la présence de globaux spécifiques, comme le font les plugins jQuery sur $ou jQuery. Dans ce scénario, vous pouvez configurer le webpack pour l'ajouter à var $ = require("jquery")chaque fois qu'il rencontre l' $identifiant global .

var webpack = require("webpack");

    ...

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

3. Utilisez le imports-loader pour configurerthis

Certains modules hérités reposent sur thisl' windowobjet. Cela devient un problème lorsque le module est exécuté dans un contexte CommonJS où thisest égal à module.exports. Dans ce cas, vous pouvez remplacer thisle chargeur d'importations .

Courez npm i imports-loader --save-devpuis

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

L'import-loader peut également être utilisé pour injecter manuellement des variables de toutes sortes. Mais la plupart du temps l' ProvidePluginest plus utile en matière de GLOBALS implicites.


4. Utilisez le chargeur d' importations pour désactiver AMD

Il existe des modules qui prennent en charge différents styles de module, comme AMD, CommonJS et hérité. Cependant, la plupart du temps, ils vérifient d'abord definepuis utilisent du code original pour exporter des propriétés. Dans ces cas, il peut être utile de forcer le chemin CommonJS en définissant define = false.

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

5. Utilisez le chargeur de scripts pour importer globalement des scripts

Si vous ne vous souciez pas des variables globales et souhaitez simplement que les scripts hérités fonctionnent, vous pouvez également utiliser le chargeur de scripts. Il exécute le module dans un contexte global, comme si vous les aviez inclus via la <script>balise.


6. Utilisez noParsepour inclure de grandes dists

Lorsqu'il n'y a pas de version AMD / CommonJS du module et que vous souhaitez inclure le dist, vous pouvez marquer ce module comme noParse. Ensuite, webpack inclura simplement le module sans l'analyser, ce qui peut être utilisé pour améliorer le temps de construction. Cela signifie que toute fonctionnalité nécessitant l' AST , comme le ProvidePlugin, ne fonctionnera pas.

module: {
    noParse: [
        /[\/\\]node_modules[\/\\]angular[\/\\]angular\.js$/
    ]
}
Johannes Ewald
la source
3
Le ProvidePluginest appliqué à toutes les occurrences des identifiants donnés dans tous les fichiers. Le imports-loaderpeut être appliqué uniquement à des fichiers spécifiques, mais vous ne devez pas utiliser les deux pour les mêmes variables / dépendances.
Johannes Ewald
5
Je suis confus par cela. D'où vient jquery? Localement ou un CDN? Tout après 3. il n'est pas clair si cela est nécessaire. Quelles sont les étapes réelles pour intégrer jquery dans votre projet à l'aide de webpack. Contourne-t-il la version disponible via CDN?
HelpMeStackOverflowMyOnlyHope
2
Tout à partir d'un CDN est hors de portée pour webpack, donc cela fait référence à une installation jquery locale. Jquery peut juste être requis, aucune étape spéciale n'est nécessaire pour l'intégrer. Cette question concerne la façon d'intégrer des plugins jquery qui dépendent de la $variable globale .
Johannes Ewald
8
A fait tout cela, ne fonctionnait toujours pas; Puis ajouté: "module": { "loaders": [ { test: require.resolve("jquery"), loader: "expose?$!expose?jQuery" },et cela a bien fonctionné.
musicformellons
5
Faites tout cela, pour simplement inclure un package jquery?, Quelle douleur. Je reviens à ma version de Gulp
Rahul Gupta
89

Pour un accès global à jquery, plusieurs options existent. Dans mon dernier projet webpack, je voulais un accès global à jquery, j'ai donc ajouté ce qui suit à mes déclarations de plugins:

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

Cela signifie alors que jquery est accessible à partir du code source JavaScript via les références globales $ et jQuery.

Bien sûr, vous devez également avoir installé jquery via npm:

$ npm i jquery --save

Pour un exemple de travail de cette approche, n'hésitez pas à fourcher mon application sur github

arcseldon
la source
2
Veuillez laisser un commentaire si vous rétrogradez un vote expliquant la raison. Les informations ci-dessus sont exactes. Veuillez consulter mon application de travail sur: github.com/arcseldon/react-babel-webpack-starter-app en utilisant l'approche ci-dessus.
arcseldon
Je ne suis pas le downvoter, mais c'est peut-être parce que la ProvidePluginsolution que vous proposez a déjà été proposée?
Léo Lam
@ LéoLam - merci pour votre commentaire. appréciez votre point - j'avais déduit la réponse via des enquêtes séparées, et juste partagé l'extrait ici, je pensais que c'était probablement le plus pertinent pour d'autres souhaitant imiter ce que j'avais fait. Vous avez raison cependant, la réponse officielle couvre cette option.
arcseldon
1
Cela fonctionne, mais je reçois 2 avertissements: ./~/jQuery/dist/jquery.js There is another module with an equal name when case is ignored.et le même avec./~/jquery/dist/jquery.js
pistou
7
J'avais besoin d'ajouter 'window.jQuery': 'jquery'à cette liste pour charger le paquet ms-signalr-client npm. J'ai aussi mis 'window.$': 'jquery'pour faire bonne mesure :)
Sammi
57

Je ne sais pas si je comprends très bien ce que vous essayez de faire, mais j'ai dû utiliser des plugins jQuery qui nécessitaient que jQuery soit dans le contexte global (fenêtre) et j'ai mis ce qui suit dans mon entry.js:

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

Le je dois juste exiger où je veux jqueryplugin.min.jset window.$est étendu avec le plugin comme prévu.

sanfilippopablo
la source
2
Fondamentalement, je faisais l'erreur d'utiliser le plugin Provider avec la condition noParse. Les plugins comme GivePlugin ne fonctionnent pas si nous faisons NoParse, comme indiqué au point 6 de la réponse. Vous pouvez voir cette erreur dans le code
booleanhunter
ouais, j'ai trouvé que cela fonctionne de manière plus cohérente sur tous les plugins que les plugins fournis etc ... surtout si vous introduisez angulaire 1.x via le chargeur de script.
Tracker1
27

J'ai bien fonctionné tout en exposant $et en jQuerytant que variables globales avec Webpack 3.8.1 et les suivants.

Installez jQuery en tant que dépendance de projet. Vous pouvez omettre @3.2.1d'installer la dernière version ou spécifier une autre version.

npm install --save jquery@3.2.1

Installer en expose-loadertant que dépendance de développement s'il n'est pas déjà installé.

npm install expose-loader --save-dev

Configurez Webpack pour charger et exposer jQuery pour nous.

// 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'
    })
  ]
}
HarlemSquirrel
la source
5
Vous avez oublié de mentionner que vous devez installer expose-loaderpour que cela fonctionne correctement npm install expose-loader --save-dev
Paulo Griiettner
4
Cela a fonctionné pour moi 👍. jquery: 3.3.1, exposer-chargeur: 0.7.5, webpack: 4.20.2
AKT
Ils l' expose-loadedont fait pour moi. Je n'ai pas eu d'erreur au moment de la compilation, mais dans les outils de développement Chrome. C'est résolu maintenant.
Johan Vergeer
Je vous remercie! Cela a fonctionné avec "jquery": "^ 3.4.1" et "webpack": "^ 4.41.5". Est-ce juste moi ou faire fonctionner jQuery avec Webpack ne devrait pas être aussi ridicule?
Carles Alcolea
18

Ajoutez ceci à votre tableau de plugins dans webpack.config.js

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

nécessite alors jquery normalement

require('jquery');

Si la douleur persiste à obtenir d'autres scripts pour le voir, essayez de le placer explicitement dans le contexte global via (dans l'entrée js)

window.$ = jQuery;
KhaledMohamedP
la source
18

Dans votre fichier webpack.config.js, ajoutez ci-dessous:

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

Installez jQuery en utilisant npm:

$ npm i jquery --save

Dans le fichier app.js, ajoutez les lignes ci-dessous:

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

Cela a fonctionné pour moi. :)

ashwini
la source
Comment cela agira-t-il si vous avez par exemple. app.js et jquery-module.js, qui nécessitent tous les deux jquery ?, pour moi j'obtiens jquery13981378127 et jquery12389723198 comme instances sur la fenêtre?
Martea
8

J'ai essayé certaines des réponses fournies, mais aucune ne semblait fonctionner. Ensuite, j'ai essayé ceci:

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

Semble fonctionner quelle que soit la version que j'utilise

Cam Tullos
la source
+1 semble être un malentendu que les globaux ajoutés ici seront automatiquement définis par rapport à la fenêtre, ne semble pas fonctionner comme ça, vous devez être explicite.
James
Correct, cela ne l'ajoute pas à l'objet fenêtre. Il crée un alias de fenêtre à l'intérieur du webpack. Donc, si vous essayez d'utiliser en $dehors d'un fichier Webpack requis, il ne sera pas défini.
Cam Tullos
7

Cela fonctionne dans le webpack 3:

dans le fichier webpack.config.babel.js:

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

Et utilisez ProviderPlugin

new webpack.ProvidePlugin({
        '$': 'jquery',
        'jQuery': 'jquery',
    })
SharpCoder
la source
1
Pour les autres qui sont super nouveaux chez webpack (comme moi!) "Résoudre" va dans votre webpack.config.js sous module.exports = {} tout comme l'entrée, la sortie, les plugins, le module, etc.
DavGarcia
1
Et le nouveau webpack.ProvidePlugin va à l'intérieur du tableau des plugins.
DavGarcia
2

La meilleure solution que j'ai trouvée était:

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

Fondamentalement, vous devez inclure une variable fictive sur typings.d.ts, supprimer tout "import * as $ from 'jquery" de votre code, puis ajouter manuellement une balise au script jQuery dans votre html SPA. De cette façon, webpack ne vous gênera pas, et vous devriez pouvoir accéder à la même variable globale jQuery dans tous vos scripts.

Fabricio
la source
2

Cela fonctionne pour moi sur le webpack.config.js

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

dans un autre javascript ou en HTML ajouter:

global.jQuery = require('jquery');
JPRLCol
la source
0

Edit: Parfois, vous souhaitez utiliser webpack simplement comme un bundle de modules pour un simple projet web - pour garder votre propre code organisé. La solution suivante est pour ceux qui veulent juste qu'une bibliothèque externe fonctionne comme prévu dans leurs modules - sans passer beaucoup de temps à plonger dans les configurations de webpack. (Modifié après -1)

Solution rapide et simple (es6) si vous rencontrez toujours des difficultés ou si vous voulez éviter la configuration externe / la configuration supplémentaire du plugin webpack:

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

à l'intérieur d'un module:

const { jQuery: $, Underscore: _, etc } = window;
frdnrdb
la source