Gestione della dipendenza del plugin jQuery nel webpack


451

Sto usando Webpack nella mia applicazione, in cui creo due punti di ingresso: bundle.js per tutti i miei file / codici JavaScript e vendors.js per tutte le librerie come jQuery e React. Cosa devo fare per utilizzare plugin che hanno jQuery come loro dipendenze e voglio averli anche in vendors.js? Cosa succede se quei plugin hanno dipendenze multiple?

Attualmente sto cercando di utilizzare questo plugin jQuery qui - https://github.com/mbklein/jquery-elastic . Le menzioni della documentazione Webpack forniscono Plugin e caricatore di importazioni. Ho usato fornirePlugin, ma l'oggetto jQuery non è ancora disponibile. Ecco come appare il mio 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;

Ma nonostante ciò, genera ancora un errore nella console del browser:

Errore di riferimento non rilevato: jQuery non è definito

Allo stesso modo, quando utilizzo il caricatore importazioni, viene visualizzato un errore,

requisito non definito '

in questa linea:

var jQuery = require("jquery")

Tuttavia, potrei usare lo stesso plug-in quando non lo aggiungo al mio file vendors.js e invece lo richiedevo nel normale modo AMD come come includo i miei altri file di codice JavaScript, come-

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

});

Ma questo non è quello che voglio fare, poiché ciò significherebbe che jquery.elastic.source.js è raggruppato insieme al mio codice JavaScript in bundle.js e voglio che tutti i miei plugin jQuery siano nel bundle vendors.js. Quindi, come posso fare per raggiungere questo obiettivo?


3
Non sono sicuro se questo è il tuo problema, ma devi assolutamente cambiare windows.jQuery in "window.jQuery": "jquery". C'è un errore di battitura sul sito Web di Webpack in cui suppongo tu abbia ottenuto quel codice.
Alex Hawkins,

@AlexHawkins Oh sì, l'ho notato e risolto. Grazie per segnalarlo!
booleanhunter,

Risposte:


771

Hai mischiato approcci diversi su come includere moduli di fornitori legacy. Ecco come lo affronterei:

1. Preferisci CommonJS / AMD non miniato rispetto a dist

La maggior parte dei moduli collega la distversione nel mainloro campo package.json. Sebbene ciò sia utile per la maggior parte degli sviluppatori, per il webpack è meglio alias la srcversione perché in questo modo il webpack è in grado di ottimizzare meglio le dipendenze (ad esempio quando si utilizza il DedupePlugin).

// webpack.config.js

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

Tuttavia, nella maggior parte dei casi anche la distversione funziona bene.


2. Utilizzare ProvidePluginper iniettare globali impliciti

La maggior parte dei moduli legacy si basano sulla presenza di specifici globi, come fanno i plugin jQuery su $o jQuery. In questo scenario è possibile configurare il webpack, per anteporre var $ = require("jquery")ogni volta che incontra l' $identificatore globale .

var webpack = require("webpack");

    ...

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

3. Utilizzare il caricatore importazioni per configurarethis

Alcuni moduli legacy si basano thissull'essere l' windowoggetto. Questo diventa un problema quando il modulo viene eseguito in un contesto CommonJS dove thisuguale module.exports. In questo caso è possibile eseguire thisl' override con il caricatore importazioni .

Corri npm i imports-loader --save-deve poi

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

Il caricatore importazioni può anche essere utilizzato per iniettare manualmente variabili di ogni tipo. Ma il più delle volte ProvidePluginè più utile quando si tratta di globi impliciti.


4. Utilizzare il caricatore importazioni per disabilitare AMD

Esistono moduli che supportano diversi stili di modulo, come AMD, CommonJS e legacy. Tuttavia, la maggior parte delle volte controllano prima definee quindi usano del codice strano per esportare le proprietà. In questi casi, potrebbe essere utile forzare il percorso CommonJS impostando define = false.

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

5. Utilizzare il caricatore di script per importare gli script a livello globale

Se non ti interessano le variabili globali e vuoi solo che gli script legacy funzionino, puoi anche usare lo script-loader. Esegue il modulo in un contesto globale, proprio come se li avessi inclusi tramite il <script>tag.


6. Utilizzare noParseper includere grandi distanze

Quando non esiste una versione AMD / CommonJS del modulo e si desidera includere il dist, è possibile contrassegnare questo modulo come noParse. Quindi il webpack includerà semplicemente il modulo senza analizzarlo, che può essere utilizzato per migliorare i tempi di compilazione. Ciò significa che qualsiasi funzionalità che richiede l' AST , come la ProvidePlugin, non funzionerà.

module: {
    noParse: [
        /[\/\\]node_modules[\/\\]angular[\/\\]angular\.js$/
    ]
}

3
La ProvidePluginviene applicata su tutte le occorrenze dei identificatori dati in tutti i file. La imports-loaderpuò essere applicato su file specifici, ma non si deve usare sia per le stesse variabili / dipendenze.
Johannes Ewald,

5
Sono confuso da questo. Da dove proviene il jquery? Localmente o un CDN? Tutto dopo 3. non è chiaro se ciò sia necessario. Quali sono i passaggi effettivi per integrare jquery nel tuo progetto usando il webpack. Ignora la versione disponibile tramite CDN?
HelpMeStackOverflowMyOnlyHope

2
Tutto da una CDN non rientra nell'ambito del webpack, quindi si riferisce a un'installazione jquery locale. Jquery può essere richiesto, non ci sono passaggi speciali necessari per integrarlo. Questa domanda riguarda come integrare i plugin jquery che dipendono dalla $variabile globale .
Johannes Ewald,

8
Ha fatto tutto questo, ancora non funzionando; Quindi aggiunto: "module": { "loaders": [ { test: require.resolve("jquery"), loader: "expose?$!expose?jQuery" },e ha funzionato bene.
musicformellons,

5
Fai tutto questo, per includere solo un pacchetto jquery? Che dolore. Tornerò alla mia build gulp
Rahul Gupta

89

Per l'accesso globale a jquery esistono quindi diverse opzioni. Nel mio progetto webpack più recente, volevo l'accesso globale a jquery, quindi ho aggiunto quanto segue alle dichiarazioni dei miei plugin:

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

Ciò significa quindi che jquery è accessibile dal codice sorgente JavaScript tramite riferimenti globali $ e jQuery.

Naturalmente, è necessario aver installato anche jquery tramite npm:

$ npm i jquery --save

Per un esempio funzionante di questo approccio, sentiti libero di fare il fork della mia app su github


2
Per favore, puoi lasciare un commento se declassate un voto che spiega il motivo. Le informazioni di cui sopra sono accurate. Si prega di consultare la mia app funzionante su: github.com/arcseldon/react-babel-webpack-starter-app usando l'approccio sopra.
ArcSeldon,

Non sono il downvoter, ma forse è perché la ProvidePluginsoluzione che suggerisci era già stata proposta?
Léo Lam,

@ LéoLam - grazie per il tuo commento. apprezzo il tuo punto - avevo dedotto la risposta tramite domande separate e ho appena condiviso lo snippet qui che pensavo fosse probabilmente più rilevante per gli altri che desideravano emulare ciò che avevo fatto. Hai ragione però, la risposta ufficiale copre questa opzione.
arcseldon,

1
Funziona ma ricevo 2 avvisi: ./~/jQuery/dist/jquery.js There is another module with an equal name when case is ignored.e lo stesso con./~/jquery/dist/jquery.js
pistou,

7
Ho dovuto aggiungere 'window.jQuery': 'jquery'a quell'elenco per caricare il pacchetto npm ms-signalr-client. Ho anche preso 'window.$': 'jquery'una buona misura :)
Sammi,

57

Non so se capisco molto bene cosa stai cercando di fare, ma ho dovuto usare i plugin jQuery che richiedevano che jQuery fosse nel contesto globale (finestra) e ho inserito quanto segue nel mio entry.js:

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

Devo solo richiedere dove voglio jqueryplugin.min.jse window.$viene esteso con il plug-in come previsto.


2
Fondamentalmente stavo facendo l'errore di utilizzare ProvidePlugin insieme alla condizione noParse. Plugin come ProvidePlugin non funzionano se eseguiamo NoParse, come indicato al punto 6 della risposta. Puoi vedere quell'errore nel codice
booleanhunter

sì, ho scoperto che funziona in modo più coerente tra i plug-in rispetto ai plug-in di fornitura, ecc ... specialmente se stai introducendo 1.x angolare tramite il caricatore di script.
Tracker1,

27

Ho fatto funzionare bene le cose mentre esponevo $e jQuerycome variabili globali con Webpack 3.8.1 e seguenti.

Installa jQuery come dipendenza dal progetto. È possibile omettere @3.2.1di installare l'ultima versione o specificare un'altra versione.

npm install --save jquery@3.2.1

Installa expose-loadercome dipendenza di sviluppo se non è già installato.

npm install expose-loader --save-dev

Configura Webpack per caricare ed esporre jQuery per noi.

// 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
Hai dimenticato di dire che è necessario installare expose-loaderper farlo funzionare correttamente npm install expose-loader --save-dev
Paulo Griiettner,

4
Questo ha funzionato per me 👍. jquery: 3.3.1, esporre-caricatore: 0.7.5, webpack: 4.20.2
AKT

L' expose-loadedho fatto per me. Non ho ricevuto un errore in fase di compilazione, ma negli strumenti di sviluppo di Chrome. Questo è risolto ora.
Johan Vergeer,

Grazie! Funzionava con "jquery": "^ 3.4.1" e "webpack": "^ 4.41.5". Sono solo io o far funzionare jQuery con Webpack non dovrebbe essere così ridicolo?
Carles Alcolea,

18

Aggiungi questo al tuo array di plugin in webpack.config.js

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

quindi richiede jquery normalmente

require('jquery');

Se il dolore persiste nel vedere altri script per vederlo, prova a inserirlo esplicitamente nel contesto globale tramite (nella voce js)

window.$ = jQuery;

18

Nel tuo file webpack.config.js aggiungi qui sotto:

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

Installa jQuery usando npm:

$ npm i jquery --save

Nel file app.js aggiungi le righe seguenti:

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

Questo ha funzionato per me. :)


Come funzionerà se hai per es. app.js e jquery-module.js, che richiedono entrambi jquery ?, per me ottengo jquery13981378127 e jquery12389723198 come istanze sulla finestra?
Martea,

8

Ho provato alcune delle risposte fornite, ma nessuna sembrava funzionare. Quindi ho provato questo:

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

Sembra funzionare indipendentemente dalla versione che sto usando


Il +1 sembra essere un malinteso sul fatto che i globi aggiunti qui verranno automaticamente impostati contro la finestra, non sembra funzionare come se fosse necessario essere espliciti.
James,

Corretto, questo non lo aggiunge all'oggetto window. Crea un alias finestra all'interno del webpack. Quindi, se si tenta di utilizzare $al di fuori di un file richiesto dal webpack, non sarà definito.
Cam Tullos,

7

Funziona con Webpack 3:

nel file webpack.config.babel.js:

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

E usa ProvidePlugin

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

1
Per altri che sono super nuovi nel webpack (come me!) "Resolve" va nel tuo webpack.config.js sotto module.exports = {} proprio come voce, output, plugin, modulo, ecc.
DavGarcia

1
E il nuovo webpack.ProvidePlugin va all'interno dell'array di plugin.
DavGarcia,

2

La migliore soluzione che ho trovato è stata:

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

Fondamentalmente, è necessario includere una variabile fittizia su typings.d.ts, rimuovere qualsiasi "import * * da $ da 'jquery" dal codice e quindi aggiungere manualmente un tag allo script jQuery nel proprio html SPA. In questo modo, il webpack non sarà sulla tua strada e dovresti essere in grado di accedere alla stessa variabile jQuery globale in tutti i tuoi script.


2

Questo funziona per me sul webpack.config.js

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

in un altro javascript o in HTML aggiungere:

global.jQuery = require('jquery');

0

Modifica: a volte si desidera utilizzare il webpack semplicemente come un modulo bundler per un semplice progetto Web - per organizzare il proprio codice. La seguente soluzione è per coloro che desiderano semplicemente che una libreria esterna funzioni come previsto all'interno dei loro moduli, senza impiegare molto tempo a dedicarsi alle configurazioni del webpack. (Modificato dopo -1)

Soluzione rapida e semplice (es6) se stai ancora lottando o vuoi evitare la configurazione esterna / la configurazione aggiuntiva del plug-in webpack:

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

all'interno di un modulo:

const { jQuery: $, Underscore: _, etc } = window;
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.