Управління залежністю від плагінів jQuery у вебпаку


451

Я використовую Webpack у своїй програмі, в якій створюю дві точки входу - bundle.js для всіх моїх файлів / кодів JavaScript та vendors.js для всіх бібліотек, таких як jQuery та React. Що робити для використання плагінів, у яких залежність jQuery має, і я хочу їх мати також у vendors.js? Що робити, якщо ці плагіни мають декілька залежностей?

На даний момент я намагаюся тут використовувати цей плагін jQuery - https://github.com/mbklein/jquery-elastic . У документації на Webpack згадується плагін та завантажувач імпорту. Я використовував providePlugin, але все ще об’єкт jQuery недоступний. Ось як виглядає мій 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;

Але, незважаючи на це, він все ще видає помилку в консолі браузера:

Uncaught ReferenceError: jQuery не визначено

Так само, коли я використовую навантажувач імпорту, він видає помилку,

вимагати не визначено "

у цьому рядку:

var jQuery = require("jquery")

Однак я міг би використовувати той самий плагін, коли не додаю його до файлу vendors.js, а замість цього вимагаю його звичайним способом AMD, як я включаю інші файли коду JavaScript, як-от

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

});

Але це не те, що я хочу робити, оскільки це означатиме, що jquery.elastic.source.js постачається разом із моїм кодом JavaScript у bundle.js, і я хочу, щоб усі мої плагіни jQuery знаходились у пакеті vendors.js. Тож як я можу досягти цього?


3
Не впевнений, чи це ваша проблема, але вам обов'язково потрібно змінити windows.jQuery на "window.jQuery": "jquery". На веб-сайті webpack є помилка друку, де я припускаю, що ви отримали цей код.
Алекс Хокінс

@AlexHawkins О так, я помітив це і виправив це. Дякуємо, що вказали на це!
booleanhunter

Відповіді:


771

Ви змішали різні підходи щодо включення застарілих модулів постачальників. Ось як я вирішував це:

1. Віддавайте перевагу немініфікованому CommonJS / AMD над dist

Більшість модулів пов'язують distверсію в mainобласті їх package.json. Хоча це корисно для більшості розробників, для webpack краще псевдонім srcверсії, оскільки таким чином webpack здатний краще оптимізувати залежності (наприклад, при використанні DedupePlugin).

// webpack.config.js

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

Однак у більшості випадків distверсія працює також чудово.


2. Використовуйте ProvidePluginдля введення неявних глобалів

Більшість застарілих модулів покладатися на наявність специфічних глобальний, як JQuery плагіни роблять на $або jQuery. У цьому сценарії ви можете налаштувати webpack, щоб передбачити var $ = require("jquery")кожен раз, коли він стикається з глобальним $ідентифікатором.

var webpack = require("webpack");

    ...

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

3. Використовуйте навантажувач імпорту для налаштуванняthis

Деякі застарілі модулі покладаються на thisбути windowоб'єктом. Це стає проблемою, коли модуль виконується в контексті CommonJS, де thisдорівнює module.exports. В цьому випадку ви можете перевизначити thisз імпортом-навантажувачем .

Біжи npm i imports-loader --save-devі тоді

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

Імпорт-завантажувач також може бути використаний для введення вручну змінних усіх типів. Але більшу частину часу ProvidePluginце корисніше, коли мова йде про неявні глобалі.


4. Використовуйте навантажувач імпорту, щоб відключити AMD

Є модулі, які підтримують різні стилі модулів, як AMD, CommonJS та застарілі. Однак більшість часу вони спочатку перевіряють, defineа потім використовують якийсь химерний код для експорту властивостей. У цих випадках це може допомогти встановити шлях CommonJS шляхом встановлення define = false.

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

5. Використовуйте завантажувач сценаріїв для глобального імпорту скриптів

Якщо ви не переймаєтесь глобальними змінними та просто хочете, щоб застарілі сценарії працювали, ви також можете використовувати завантажувач скриптів. Він виконує модуль у глобальному контексті так само, як якщо б ви включили їх через <script>тег.


6. Використовуйте noParseдля включення великих дистів

Коли немає версії модуля AMD / CommonJS і ви хочете включити distмодуль, ви можете позначити цей модуль як noParse. Тоді вебпакет буде просто включати модуль без його розбору, який можна використовувати для покращення часу збирання. Це означає, що будь-яка функція, яка вимагає AST , як, наприклад ProvidePlugin, не працюватиме.

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

3
ProvidePluginЗастосовуються на все входження даних ідентифікаторів у всіх файлах. Це imports-loaderможе застосовуватися лише для певних файлів, але ви не повинні використовувати обидва для однакових змінних / залежностей.
Йоханнес Евальд

5
Мене це бентежить. Звідки насправді береться jquery? Місцево чи CDN? Все після 3. його незрозуміло, чи потрібно це. Які фактичні кроки для інтеграції jquery у ваш проект за допомогою webpack. Чи він обходить версію, доступну через CDN?
HelpMeStackOverflowMyOnlyHope

2
Все з CDN виходить за межі веб-пакету, тому це стосується локальної установки jquery. Jquery може просто вимагати, немає ніяких спеціальних кроків, необхідних для його інтеграції. Це питання стосується інтеграції плагінів jquery, які залежать від глобальної $змінної.
Йоханнес Евальд

8
Зробив усе це, все ще не працюючи; Потім додав: "module": { "loaders": [ { test: require.resolve("jquery"), loader: "expose?$!expose?jQuery" },і це спрацювало чудово.
musicformellons

5
Зроби все це, щоб просто включити пакет jquery ?, який біль. Я повертаюсь до свого складання глотків
Рахул Гупта

89

Для глобального доступу до jquery існує кілька варіантів. У своєму останньому проекті webpack я хотів отримати глобальний доступ до jquery, тому я додав у свої декларації плагінів наступне:

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

Тоді це означає, що jquery доступний з вихідного коду JavaScript через глобальні посилання $ та jQuery.

Звичайно, вам також потрібно встановити jquery через npm:

$ npm i jquery --save

Для робочого прикладу такого підходу, будь ласка, розпрощайте моє додаток на github


2
Будь ласка, можете залишити коментар, якщо ви зменшите голос із поясненням причини. Наведена вище інформація є точною. Перегляньте мій робочий додаток за адресою: github.com/arcseldon/react-babel-webpack-starter-app, використовуючи вищезазначений підхід.
arcseldon

Я не прихильник, але, можливо, це тому, що ProvidePluginрішення, яке ви пропонуєте, вже було запропоновано?
Лео Лам

@ LéoLam - дякую за ваш коментар. оцінюю вашу думку - я вивів відповідь за допомогою окремих запитів і просто поділився фрагментом тут, на який я подумав, що, мабуть, є найбільш відповідним для інших, бажаючих наслідувати тому, що я зробив. Ти прав, хоча офіційна відповідь стосується цього варіанту.
arcseldon

1
Це працює, але я отримую 2 попередження: ./~/jQuery/dist/jquery.js There is another module with an equal name when case is ignored.і те саме з./~/jquery/dist/jquery.js
pistou

7
Мені потрібно було додати 'window.jQuery': 'jquery'до цього списку, щоб завантажити пакет ms-signalr-client npm. Я також ставлюся 'window.$': 'jquery'на гарну міру :)
Саммі

57

Я не знаю, чи я дуже добре розумію, що ви намагаєтеся зробити, але мені довелося використовувати плагіни jQuery, які вимагають, щоб jQuery знаходився в глобальному контексті (вікно), і я помістив у своєму entry.js:

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

Мені просто потрібно вимагати, де я хочу, jqueryplugin.min.jsі window.$розширений плагін, як очікувалося.


2
В основному я робив помилку використання ProvidePlugin разом із умовою noParse. Плагіни на зразок ProvidePlugin не працюють, якщо ми робимо NoParse, як зазначено в пункті 6 відповіді. Ви можете побачити цю помилку в коді
booleanhunter

так, я виявив, що він працює більш послідовно у плагінах, ніж додатки тощо ... esp, якщо ви вводите кут 1.x через завантажувач скриптів.
Tracker1

27

У мене все добре працює під час викриття $та jQueryглобальних змінних за допомогою Webpack 3.8.1 та наступного.

Встановіть jQuery як залежність від проекту. Ви можете пропустити @3.2.1встановлення останньої версії або вказати іншу.

npm install --save jquery@3.2.1

Встановіть expose-loaderяк залежність від розробки, якщо вона вже не встановлена.

npm install expose-loader --save-dev

Налаштуйте Webpack для завантаження та виставлення 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'
    })
  ]
}

5
Ви забули згадати, що вам потрібно встановити expose-loader, щоб вона працювала належним чином npm install expose-loader --save-dev
Пауло Гриеттнер

4
Це працювало для мене 👍. jquery: 3.3.1, expose-loader: 0.7.5, webpack: 4.20.2
AKT

expose-loadedЗробив це для мене. Я не отримав помилку під час компіляції, але в інструментах для розробників Chrome. Це вирішено зараз.
Йоган

Дякую! Це працювало з "jquery": "^ 3.4.1" та "webpack": "^ 4.41.5". Це тільки я, або примушення jQuery працювати з Webpack не повинно бути таким смішним?
Карлес Алколія

18

Додайте це до масиву плагінів у webpack.config.js

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

то вимагають jquery нормально

require('jquery');

Якщо біль зберігає отримання інших сценаріїв, щоб побачити це, спробуйте явно розмістити його у глобальному контексті через (у записі js)

window.$ = jQuery;

18

У свій файл webpack.config.js додайте нижче:

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

Встановіть jQuery за допомогою npm:

$ npm i jquery --save

У файл app.js додайте рядки нижче:

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

Це працювало для мене. :)


Як буде діяти, якщо у вас є екс. app.js та jquery-module.js, для яких обох потрібен jquery?, для мене я отримую jquery13981378127 та jquery12389723198 як екземпляри у вікні?
Мартея

8

Я спробував деякі з наданих відповідей, але жодна з них, здавалося, не спрацювала. Потім я спробував це:

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

Здається, працює незалежно від того, яку версію я використовую


+1, здається, є непорозумінням, що додані тут глобалі будуть автоматично встановлені проти вікна, але, здається, не працюють так, як потрібно чітко.
Джеймс

Правильно, це не додає його до об’єкта вікна. Він створює псевдонім вікна всередині webpack. Отже, якщо ви намагаєтесь використовувати $поза потрібним файлом веб-пакету, він буде невизначений.
Cam Tullos

7

Це працює в webpack 3:

у файлі webpack.config.babel.js:

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

І використовуйте ProvidePlugin

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

1
Для інших, які є надзвичайно новими в webpack (як я!), "Вирішується" йде у ваш webpack.config.js під module.exports = {} так само, як запис, вихід, плагіни, модуль тощо.
DavGarcia,

1
І новий webpack.ProvidePlugin знаходиться всередині масиву плагінів.
DavGarcia

2

Найкраще рішення, яке я знайшов:

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

В основному вам потрібно включити фіктивну змінну на typings.d.ts, видалити будь-який "імпорт * як $ з 'jquery" зі свого коду, а потім вручну додати тег до сценарію jQuery до свого HTML HTML. Таким чином, webpack не заважатиме вам, і ви повинні мати доступ до тієї ж глобальної змінної jQuery у всіх своїх сценаріях.


2

Це працює для мене на webpack.config.js

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

в інший javascript або в HTML додати:

global.jQuery = require('jquery');

0

Редагувати: Іноді ви хочете використовувати веб-пакет просто як постачальник модулів для простого веб-проекту - щоб організувати власний код. Наступне рішення - для тих, хто просто хоче, щоб зовнішня бібліотека працювала, як очікувалося, у своїх модулях - не використовуючи багато часу, щоб зануритися в налаштування веб-пакету. (Відредаговано після -1)

Швидке та просте рішення (es6), якщо ви все ще боретеся або хочете уникнути зовнішньої конфігурації / додаткової конфігурації плагіна веб-пакету:

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

всередині модуля:

const { jQuery: $, Underscore: _, etc } = window;
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.