Управління залежністю від плагінів 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.