Správa závislosti zásuvného modulu jQuery v aplikácii Webpack

Vo svojej aplikácii používam Webpack, v ktorom mám vytvorené dva vstupné body - bundle.js pre všetky súbory/kódy JavaScriptu a vendors.js pre všetky knižnice, ako je jQuery a React. Čo mám urobiť, aby som mohol používať zásuvné moduly, ktoré majú ako svoje závislosti jQuery a chcem ich mať aj vo vendors.js? Čo ak majú tieto zásuvné moduly viacero závislostí?

Momentálne sa snažím používať tento plugin jQuery tu - https://github.com/mbklein/jquery-elastic. V dokumentácii Webpack sa spomína providePlugin a imports-loader. Použil som providePlugin, ale objekt jQuery stále nie je k dispozícii. Takto vyzerá môj 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;

Ale napriek tomu to stále hádže chybu do konzoly prehliadača:

Uncaught ReferenceError: jQuery is not defined

Podobne, keď použijem import-loader, vyhodí to chybu,

require is not defined'

v tomto riadku:

var jQuery = require("jquery")

Mohol by som však použiť ten istý zásuvný modul, keď ho nepridám do súboru vendors.js a namiesto toho ho vyžadujem normálnym spôsobom AMD, ako keď zahŕňam svoje ostatné súbory s kódom JavaScript, ako napríklad-

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

});

Ale to nie je to, čo chcem urobiť, pretože by to znamenalo, že jquery.elastic.source.js je spolu s mojím kódom JavaScript v zväzku bundle.js a ja chcem, aby všetky moje zásuvné moduly jQuery boli vo zväzku vendors.js. Ako to mám teda dosiahnuť?

Riešenie

Zmiešali ste rôzne prístupy, ako zahrnúť staršie moduly dodávateľa. Ja by som to riešil takto:

1. Uprednostnite nezminifikovaný CommonJS/AMD pred dist

Väčšina modulov spája verziu dist v poli main svojho súboru package.json. Aj keď je to pre väčšinu vývojárov užitočné, pre webpack je lepšie aliasovať verziu src, pretože takto dokáže webpack lepšie optimalizovať závislosti (napr. pri použití DedupePlugin).

// webpack.config.js

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

Vo väčšine prípadov však rovnako dobre funguje aj verzia dist.


2. Na injektovanie implicitných globálov použite príkaz ProvidePlugin

Väčšina starších modulov sa spolieha na prítomnosť špecifických globálov, ako to robia pluginy jQuery na $ alebo jQuery. V tomto prípade môžete nakonfigurovať webpack tak, aby predvyplnil var $ = require("jquery") vždy, keď narazí na globálny identifikátor $.

var webpack = require("webpack");

    ...

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

3. Pomocou príkazu imports-loader nakonfigurujte this

Niektoré staršie moduly sa spoliehajú na to, že this je objekt window. To sa stáva problémom, keď je modul spustený v kontexte CommonJS, kde sa this rovná module.exports. V takom prípade môžete prepísať this pomocou imports-loader.

Spustite npm i imports-loader --save-dev a potom

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

Import-loader možno použiť aj na ručné injektovanie premenných všetkých druhov. Väčšinou je však ProvidePlugin užitočnejší, keď ide o implicitné globály.


4. Použite imports-loader na vypnutie AMD

Existujú moduly, ktoré podporujú rôzne štýly modulov, napríklad AMD, CommonJS a legacy. Väčšinou však najprv skontrolujú, či je v nich define, a potom použijú nejaký bizarný kód na export vlastností. V týchto prípadoch by mohlo pomôcť vynútiť cestu CommonJS nastavením define = false.

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

5. Použite script-loader na globálny import skriptov

Ak sa nestaráte o globálne premenné a chcete, aby fungovali len staršie skripty, môžete použiť aj skript-loader. Spustí modul v globálnom kontexte, rovnako ako keby ste ich zahrnuli prostredníctvom značky <script>.


6. Použitie noParse na zahrnutie veľkých dist

Ak neexistuje verzia modulu AMD/CommonJS a chcete zahrnúť dist, môžete tento modul označiť ako noParse. Potom webpack len zahrnie modul bez jeho rozboru, čo sa dá použiť na zlepšenie času zostavenia. To znamená, že žiadna funkcia vyžadujúca AST, ako napríklad ProvidePlugin, nebude fungovať.

module: {
    noParse: [
        /[\/\\]node_modules[\/\\]angular[\/\\]angular\.js$/
    ]
}
Komentáre (23)

Pre globálny prístup k jquery existuje niekoľko možností. V mojom najnovšom projekte Webpack som chcel globálny prístup k jquery, takže som do deklarácií zásuvných modulov pridal nasledujúce možnosti:

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

To potom znamená, že jquery je prístupné zo zdrojového kódu JavaScriptu prostredníctvom globálnych odkazov $ a jQuery.

Samozrejme, musíte mať nainštalované aj jquery prostredníctvom npm:

$ npm i jquery --save

Pre funkčný príklad tohto prístupu neváhajte forknúť moju aplikáciu na github.

Komentáre (9)

Neviem, či dobre rozumiem tomu, čo sa snažíte urobiť, ale musel som použiť pluginy jQuery, ktoré vyžadovali, aby jQuery bolo v globálnom kontexte (okno) a do môjho súboru entry.js som vložil nasledujúce:

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

The I just have to require wherever I want the jqueryplugin.min.js a window.$ je rozšírený o plugin podľa očakávania.

Komentáre (3)