Zarządzanie zależnością wtyczki jQuery w pakiecie internetowym

451

Używam Webpack w mojej aplikacji, w której tworzę dwa punkty wejścia - bundle.js dla wszystkich moich plików / kodów JavaScript i vendors.js dla wszystkich bibliotek takich jak jQuery i React. Co mam zrobić, aby korzystać z wtyczek, które mają zależności jQuery i chcę mieć je również w vendors.js? Co jeśli te wtyczki mają wiele zależności?

Obecnie próbuję użyć tej wtyczki jQuery tutaj - https://github.com/mbklein/jquery-elastic . Dokumentacja pakietu Webpack wspomina o opcji Plugin i moduł ładujący import. Korzystałem z programu enablePlugin, ale obiekt jQuery wciąż nie jest dostępny. Oto jak wygląda mój plik 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;

Mimo to nadal wyświetla błąd w konsoli przeglądarki:

Uncaught ReferenceError: jQuery nie jest zdefiniowany

Podobnie, gdy używam modułu ładującego import, zgłasza błąd,

wymaganie nie jest zdefiniowane ”

w tej linii:

var jQuery = require("jquery")

Mogę jednak użyć tej samej wtyczki, jeśli nie dodam jej do mojego pliku vendors.js i zamiast tego wymagam jej w normalny sposób AMD, ponieważ dołączam inne pliki kodu JavaScript, takie jak-

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

});

Ale nie chcę tego robić, ponieważ oznaczałoby to, że plik jquery.elastic.source.js znajduje się w pakiecie wraz z moim kodem JavaScript w pakiecie.js i chcę, aby wszystkie moje wtyczki jQuery znajdowały się w pakiecie vendors.js. Jak mam to osiągnąć?

booleanhunter
źródło
3
Nie jestem pewien, czy to jest twój problem, ale zdecydowanie musisz zmienić windows.jQuery na „window.jQuery”: „jquery”. Na stronie internetowej paczki jest literówka, z której zakładam, że masz ten kod.
Alex Hawkins
@AlexHawkins O tak, zauważyłem to i naprawiłem. Dzięki za wskazanie tego!
booleanhunter

Odpowiedzi:

771

Mieszałeś różne podejścia do włączania starszych modułów dostawców. Oto jak sobie z tym poradzę:

1. Preferuj niezminimalizowane CommonJS / AMD dist

Większość modułów łączy distwersję w swoim mainpolu package.json. Chociaż jest to przydatne dla większości programistów, w przypadku pakietu WWW lepiej jest dokonać aliasu srcwersji, ponieważ w ten sposób pakiet może lepiej zoptymalizować zależności (np. Podczas korzystania z DedupePlugin).

// webpack.config.js

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

Jednak w większości przypadków distwersja działa również dobrze.


2. Użyj ProvidePlugindo wstrzyknięcia niejawnych globałów

Większość starszych modułów polega na obecności określonych globałów, takich jak wtyczki jQuery na $lub jQuery. W tym scenariuszu możesz skonfigurować pakiet WWW, aby był var $ = require("jquery")on przygotowywany za każdym razem, gdy napotka globalny $identyfikator.

var webpack = require("webpack");

    ...

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

3. Skorzystaj z modułu ładującego import, aby skonfigurowaćthis

Niektóre starsze moduły polegają na thisbyciu windowobiektem. Staje się to problemem, gdy moduł jest wykonywany w kontekście CommonJS, gdzie thisjest równy module.exports. W takim przypadku możesz zastąpić thisprogram ładujący import .

Uruchom npm i imports-loader --save-devi wtedy

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

Moduł importujący może także służyć do ręcznego wstrzykiwania zmiennych wszelkiego rodzaju. Ale przez większość czasu ProvidePluginjest to bardziej przydatne, jeśli chodzi o ukryte globale.


4. Użyj modułu importującego, aby wyłączyć AMD

Istnieją moduły obsługujące różne style modułów, takie jak AMD, CommonJS i starsze wersje. Jednak przez większość czasu najpierw sprawdzają, definea następnie używają dziwnego kodu do eksportowania właściwości. W takich przypadkach może pomóc wymusić ścieżkę CommonJS przez ustawienie define = false.

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

5. Użyj programu ładującego skrypty do globalnego importowania skryptów

Jeśli nie interesują Cię zmienne globalne i po prostu chcesz, aby starsze skrypty działały, możesz także użyć programu ładującego skrypty. Wykonuje moduł w kontekście globalnym, tak jakbyś umieścił je za pomocą <script>znacznika.


6. Użyj, noParseaby uwzględnić duże odległości

Jeśli nie ma wersji modułu AMD / CommonJS i chcesz dołączyć dist, możesz oflagować ten moduł jako noParse. Następnie webpack po prostu obejmie moduł bez analizowania go, co można wykorzystać do poprawy czasu kompilacji. Oznacza to, że żadna funkcja wymagająca AST , taka jak ProvidePlugin, nie będzie działać.

module: {
    noParse: [
        /[\/\\]node_modules[\/\\]angular[\/\\]angular\.js$/
    ]
}
Johannes Ewald
źródło
3
ProvidePluginJest stosowana na wszystkich wystąpień podanych identyfikatorów we wszystkich plikach. imports-loaderMogą być stosowane tylko w określonych plików, ale nie powinno się używać zarówno do tych samych zmiennych / zależnościami.
Johannes Ewald
5
Jestem tym zmieszany. Skąd faktycznie pochodzi jquery? Lokalnie czy CDN? Wszystko po 3. nie jest jasne, czy jest to konieczne. Jakie są rzeczywiste kroki w celu zintegrowania jquery z twoim projektem za pomocą webpacka. Czy pomija wersję dostępną za pośrednictwem CDN?
HelpMeStackOverflowMyOnlyHope
2
Wszystko z CDN nie wchodzi w zakres pakietu WWW, więc odnosi się to do lokalnej instalacji jquery. Jquery może być po prostu wymagane, nie ma specjalnych kroków niezbędnych do jego zintegrowania. To pytanie dotyczy sposobu integracji wtyczek jquery zależnych od $zmiennej globalnej .
Johannes Ewald
8
Czy to wszystko, wciąż nie działa; Następnie dodał: "module": { "loaders": [ { test: require.resolve("jquery"), loader: "expose?$!expose?jQuery" },i działało dobrze.
musicformellons
5
Czy to wszystko, aby po prostu dołączyć pakiet jquery? Co za ból. Wracam do mojej wersji łyka
Rahul Gupta
89

Aby uzyskać globalny dostęp do jquery, istnieje kilka opcji. W moim najnowszym projekcie pakietu internetowego chciałem globalnego dostępu do jquery, więc do moich deklaracji wtyczek dodałem następujące elementy:

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

Oznacza to, że jquery jest dostępne z poziomu kodu źródłowego JavaScript poprzez globalne odwołania $ i jQuery.

Oczywiście musisz także zainstalować jquery za pośrednictwem npm:

$ npm i jquery --save

Przykładem takiego podejścia jest rozwidlenie mojej aplikacji na github

arcseldon
źródło
2
Czy możesz zostawić komentarz, jeśli obniżysz głos wyjaśniający przyczynę. Powyższe informacje są dokładne. Proszę zobaczyć moją działającą aplikację na: github.com/arcseldon/react-babel-webpack-starter-app przy użyciu powyższego podejścia.
arcseldon
Nie jestem zwycięzcą, ale może dlatego, że ProvidePluginproponowane przez Ciebie rozwiązanie zostało już zaproponowane?
Léo Lam
@ LéoLam - dziękuję za komentarz. doceniam twój punkt - wydedukowałem odpowiedź poprzez osobne zapytania i po prostu podzieliłem się fragmentem, który moim zdaniem był najbardziej odpowiedni dla innych, którzy chcą naśladować to, co zrobiłem. Masz rację, oficjalna odpowiedź obejmuje tę opcję.
arcseldon
1
Działa, ale dostaję 2 ostrzeżenia: ./~/jQuery/dist/jquery.js There is another module with an equal name when case is ignored.i to samo z./~/jquery/dist/jquery.js
pistou
7
Musiałem dodać 'window.jQuery': 'jquery'do tej listy, aby załadować pakiet npm ms-signalr-client. Włożyłem również 'window.$': 'jquery'dla dobrego :)
Sammi
57

Nie wiem, czy dobrze rozumiem, co próbujesz zrobić, ale musiałem użyć wtyczek jQuery, które wymagały, aby jQuery znajdowało się w kontekście globalnym (okno) i umieściłem w moim entry.js:

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

Muszę tylko wymagać, gdziekolwiek chcę jqueryplugin.min.jsi window.$jest rozszerzony o wtyczkę zgodnie z oczekiwaniami.

sanfilippopablo
źródło
2
Zasadniczo popełniłem błąd przy użyciu ProvidePlugin wraz z warunkiem noParse. Wtyczki takie jak ProvidePlugin nie działają, jeśli wykonujemy NoParse, jak stwierdzono w punkcie 6 odpowiedzi. Możesz zobaczyć ten błąd w kodzie
booleanhunter
tak, znalazłem, że działa to bardziej konsekwentnie we wszystkich wtyczkach niż w przypadku dostarczania wtyczek itp., szczególnie jeśli wprowadzasz kątowy 1.x za pomocą programu ładującego skrypty.
Tracker1
27

Sprawiłem, że wszystko działało ładnie podczas wyświetlania $i jQueryjako zmienne globalne w Webpack 3.8.1 i następnych.

Zainstaluj jQuery jako zależność projektu. Możesz pominąć @3.2.1instalację najnowszej wersji lub podać inną wersję.

npm install --save jquery@3.2.1

Zainstaluj expose-loaderjako zależność programistyczną, jeśli jeszcze nie została zainstalowana.

npm install expose-loader --save-dev

Skonfiguruj Webpack, aby ładował i ujawniał dla nas jQuery.

// 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'
    })
  ]
}
Harlem Wiewiórka
źródło
5
Zapomniałeś wspomnieć, że musisz zainstalować expose-loader, aby działał poprawnie npm install expose-loader --save-dev
Paulo Griiettner
4
To działało dla mnie 👍. jquery: 3.3.1, expose-loader: 0.7.5, webpack: 4.20.2
AKT
expose-loadedZrobił to dla mnie. W czasie kompilacji nie wystąpił błąd, ale w narzędziach dla programistów Chrome. To już rozwiązane.
Johan Vergeer,
Dziękuję Ci! Działa to z „jquery”: „^ 3.4.1” i „webpack”: „^ 4.41.5”. Czy to tylko ja, czy zmuszenie jQuery do pracy z Webpackiem nie powinno być aż tak śmieszne?
Carles Alcolea
18

Dodaj to do tablicy wtyczek w webpack.config.js

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

następnie normalnie wymagaj jquery

require('jquery');

Jeśli ból nadal występuje, aby inne skrypty go widziały, spróbuj jawnie umieścić go w kontekście globalnym za pośrednictwem (w pozycji js)

window.$ = jQuery;
KhaledMohamedP
źródło
18

W pliku webpack.config.js dodaj poniżej:

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

Zainstaluj jQuery przy użyciu npm:

$ npm i jquery --save

W pliku app.js dodaj poniższe wiersze:

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

To zadziałało dla mnie. :)

ashwini
źródło
Jak to będzie działać, jeśli masz na przykład. app.js i jquery-module.js, które wymagają zarówno jquery ?, dla mnie dostaję jquery13981378127 i jquery12389723198 jako wystąpienia w oknie?
Martea,
8

Wypróbowałem niektóre z dostarczonych odpowiedzi, ale żadna z nich nie działała. Potem spróbowałem:

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

Wydaje się działać bez względu na to, której wersji używam

Cam Tullos
źródło
+1 wydaje się nieporozumieniem, że dodane tutaj globały zostaną automatycznie ustawione na oknie, nie wydaje się, aby działało tak, że musisz być jawny.
James
Prawidłowo, to nie dodaje go do obiektu okna. Tworzy alias okna w pakiecie internetowym. Jeśli więc spróbujesz użyć $pliku wymaganego poza pakietem WWW, zostanie on niezdefiniowany.
Cam Tullos,
7

Działa to w pakiecie internetowym 3:

w pliku webpack.config.babel.js:

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

I użyj ProvidePlugin

new webpack.ProvidePlugin({
        '$': 'jquery',
        'jQuery': 'jquery',
    })
SharpCoder
źródło
1
Dla innych, którzy są nowi na webpacku (jak ja!) „Resolver” wchodzi do twojego webpack.config.js w module.exports = {} podobnie jak wejście, wyjście, wtyczki, moduł itp.
DavGarcia
1
Nowy webpack.ProvidePlugin wchodzi do tablicy wtyczek.
DavGarcia
2

Najlepsze rozwiązanie, jakie znalazłem, to:

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

Zasadniczo musisz dołączyć zmienną fikcyjną do typings.d.ts, usunąć wszelkie „import * as $ z„ jquery ”z kodu, a następnie ręcznie dodać znacznik do skryptu jQuery do html SPA. W ten sposób webpack nie będzie na twojej drodze i powinieneś mieć dostęp do tej samej globalnej zmiennej jQuery we wszystkich swoich skryptach.

Fabricio
źródło
2

Działa to dla mnie na webpack.config.js

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

w innym javascript lub w HTML dodaj:

global.jQuery = require('jquery');
JPRLCol
źródło
0

Edycja: Czasami chcesz używać pakietu web po prostu jako programu pakującego moduły do ​​prostego projektu internetowego - w celu uporządkowania własnego kodu. Poniższe rozwiązanie jest przeznaczone dla tych, którzy chcą tylko, aby biblioteka zewnętrzna działała zgodnie z oczekiwaniami w swoich modułach - bez poświęcania dużo czasu na konfigurowanie pakietu WWW. (Edytowane po -1)

Szybkie i proste rozwiązanie (es6), jeśli nadal masz problemy lub chcesz uniknąć konfiguracji zewnętrznej / dodatkowej konfiguracji wtyczki pakietu sieciowego:

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

wewnątrz modułu:

const { jQuery: $, Underscore: _, etc } = window;
frdnrdb
źródło