Quản lý phụ thuộc plugin jQuery trong gói webpack


451

Tôi đang sử dụng Webpack trong ứng dụng của mình, trong đó tôi tạo hai điểm nhập - bundle.js cho tất cả các tệp / mã JavaScript của mình và nhà cung cấp.js cho tất cả các thư viện như jQuery và React. Tôi phải làm gì để sử dụng các plugin có jQuery làm phụ thuộc của chúng và tôi muốn có chúng trong nhà cung cấp? Điều gì xảy ra nếu các plugin đó có nhiều phụ thuộc?

Hiện tại tôi đang cố gắng sử dụng plugin jQuery này tại đây - https://github.com/mbklein/jquery-elastic . Tài liệu Webpack đề cập đến cung cấpPlugin và trình tải nhập. Tôi đã sử dụng cung cấpPlPlugin, nhưng vẫn không có đối tượng jQuery. Đây là cách webpack.config.js của tôi trông như thế nào-

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;

Nhưng mặc dù vậy, nó vẫn gây ra lỗi trong bảng điều khiển trình duyệt:

Uncaught ReferenceError: jQuery không được xác định

Tương tự, khi tôi sử dụng trình tải nhập, nó sẽ báo lỗi,

yêu cầu không được xác định '

trong dòng này:

var jQuery = require("jquery")

Tuy nhiên, tôi có thể sử dụng cùng một plugin khi tôi không thêm nó vào tệp nhà cung cấp của mình và thay vào đó yêu cầu nó theo cách AMD thông thường như cách tôi bao gồm các tệp mã JavaScript khác của mình, như-

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

});

Nhưng đây không phải là điều tôi muốn làm, vì điều này có nghĩa là jquery.elastic.source.js được gói cùng với mã JavaScript của tôi trong bundle.js và tôi muốn tất cả các trình cắm jQuery của mình nằm trong gói nhà cung cấp. Vì vậy, làm thế nào để tôi đạt được điều này?


3
Không chắc đây có phải là vấn đề của bạn không nhưng bạn chắc chắn cần thay đổi windows.jQuery thành "window.jQuery": "jquery". Có một lỗi đánh máy trên trang web của webpack nơi tôi cho rằng bạn đã nhận được mã đó từ đó.
Alex Hawkins

@AlexHawkins Oh yeah, tôi nhận thấy điều đó và đã sửa nó. Cảm ơn đã chỉ ra điều đó!
booleanhunter

Câu trả lời:


770

Bạn đã pha trộn các cách tiếp cận khác nhau làm thế nào để bao gồm các mô-đun nhà cung cấp cũ. Đây là cách tôi giải quyết nó:

1. Thích CommonJS / AMD chưa hoàn thành hơn dist

Hầu hết các mô-đun liên kết distphiên bản trong mainlĩnh vực của họ package.json. Mặc dù điều này hữu ích cho hầu hết các nhà phát triển, nhưng đối với webpack thì tốt hơn là đặt bí danh cho srcphiên bản vì cách này webpack có thể tối ưu hóa các phụ thuộc tốt hơn (ví dụ như khi sử dụng DedupePlugin).

// webpack.config.js

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

Tuy nhiên, trong hầu hết các trường hợp, distphiên bản cũng hoạt động tốt.


2. Sử dụng ProvidePluginđể tiêm toàn cầu ngầm

Hầu hết các mô-đun kế thừa đều dựa vào sự hiện diện của các quả cầu cụ thể, như các plugin jQuery làm trên $hoặc jQuery. Trong kịch bản này, bạn có thể định cấu hình gói web, để trả trước var $ = require("jquery")mỗi khi nó gặp mã $định danh toàn cầu .

var webpack = require("webpack");

    ...

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

3. Sử dụng trình tải nhập để định cấu hìnhthis

Một số mô-đun kế thừa dựa trên thisviệc là windowđối tượng. Điều này trở thành một vấn đề khi mô-đun được thực thi trong bối cảnh CommonJS trong đó thisbằng module.exports. Trong trường hợp này, bạn có thể ghi đè thisbằng trình tải nhập .

Chạy npm i imports-loader --save-devrồi

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

Trình tải nhập khẩu cũng có thể được sử dụng để chèn thủ công các biến. Nhưng hầu hết thời gian ProvidePluginlà hữu ích hơn khi nói đến toàn cầu ngầm.


4. Sử dụng trình tải nhập để tắt AMD

Có các mô-đun hỗ trợ các kiểu mô-đun khác nhau, như AMD, CommonJS và di sản. Tuy nhiên, hầu hết thời gian đầu tiên họ kiểm tra definevà sau đó sử dụng một số mã kỳ quặc để xuất các thuộc tính. Trong những trường hợp này, nó có thể giúp buộc đường dẫn CommonJS bằng cách cài đặt define = false.

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

5. Sử dụng trình tải tập lệnh để nhập tập lệnh toàn cầu

Nếu bạn không quan tâm đến các biến toàn cục và chỉ muốn các tập lệnh kế thừa hoạt động, bạn cũng có thể sử dụng trình tải tập lệnh. Nó thực thi mô-đun trong bối cảnh toàn cầu, giống như bạn đã đưa chúng qua <script>thẻ.


6. Sử dụng noParseđể bao gồm các dists lớn

Khi không có phiên bản AMD / CommonJS của mô-đun và bạn muốn bao gồm dist, bạn có thể gắn cờ mô-đun này là noParse. Sau đó, webpack sẽ chỉ bao gồm các mô-đun mà không phân tích cú pháp, có thể được sử dụng để cải thiện thời gian xây dựng. Điều này có nghĩa là bất kỳ tính năng nào yêu cầu AST , như ProvidePlugin, sẽ không hoạt động.

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

3
Điều ProvidePluginnày được áp dụng trên tất cả các lần xuất hiện của các định danh đã cho trong tất cả các tệp. Chỉ imports-loadercó thể được áp dụng trên các tệp cụ thể, nhưng bạn không nên sử dụng cả hai cho cùng một biến / phụ thuộc.
Julian Ewald

5
Tôi bối rối vì điều này. Jquery thực sự đến từ đâu? Địa phương hay CDN? Tất cả mọi thứ sau 3. nó không rõ liệu điều đó là cần thiết. Các bước thực tế để tích hợp jquery vào dự án của bạn bằng cách sử dụng webpack. Nó có bỏ qua phiên bản có sẵn thông qua CDN không?
HelpMeStackOverflowMyOnlyITH

2
Mọi thứ từ CDN đều nằm ngoài phạm vi của gói webpack, vì vậy điều này đề cập đến cài đặt jquery cục bộ. Jquery chỉ có thể được yêu cầu, không có các bước đặc biệt cần thiết để tích hợp nó. Câu hỏi này là về cách tích hợp các plugin jquery phụ thuộc vào $biến toàn cục.
Julian Ewald

8
Đã làm tất cả điều này, vẫn không làm việc; Sau đó thêm: "module": { "loaders": [ { test: require.resolve("jquery"), loader: "expose?$!expose?jQuery" },và nó hoạt động tốt.
nhạc nền

5
Làm tất cả những điều này, chỉ bao gồm một gói jquery?, Thật là một nỗi đau. Tôi sẽ quay trở lại bản dựng của mình
Rahul Gupta

89

Để truy cập toàn cầu vào jquery thì một số tùy chọn tồn tại. Trong dự án webpack gần đây nhất của tôi, tôi muốn truy cập toàn cầu vào jquery vì vậy tôi đã thêm các phần sau vào khai báo bổ trợ của mình:

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

Điều này có nghĩa là jquery có thể truy cập được từ bên trong mã nguồn JavaScript thông qua các tham chiếu toàn cầu $ và jQuery.

Tất nhiên, bạn cũng cần phải cài đặt jquery qua npm:

$ npm i jquery --save

Để có một ví dụ hoạt động của phương pháp này, xin vui lòng rẽ nhánh ứng dụng của tôi trên github


2
Xin vui lòng bạn có thể để lại nhận xét nếu bạn hạ cấp một phiếu bầu giải thích lý do. Các thông tin trên là chính xác. Vui lòng xem ứng dụng làm việc của tôi tại: github.com/arcseldon/react-babel-webpack-starter-app bằng cách sử dụng phương pháp trên.
arcseldon

Tôi không phải là downvoter, nhưng có lẽ điều này là do ProvidePlugingiải pháp bạn đề xuất đã được đề xuất?
Léo Lâm

@ LéoLam - cảm ơn bình luận của bạn. đánh giá cao quan điểm của bạn - tôi đã suy luận câu trả lời thông qua các câu hỏi riêng biệt và chỉ chia sẻ đoạn trích ở đây tôi nghĩ có khả năng phù hợp nhất với những người khác muốn mô phỏng những gì tôi đã làm. Mặc dù bạn đúng, câu trả lời chính thức bao gồm tùy chọn này.
arcseldon

1
Nó hoạt động nhưng tôi nhận được 2 cảnh báo: ./~/jQuery/dist/jquery.js There is another module with an equal name when case is ignored.và cùng một cảnh báo với./~/jquery/dist/jquery.js
pistou

7
Tôi cần thêm 'window.jQuery': 'jquery'vào danh sách đó để tải gói npm ms-signalr-client. Tôi cũng đưa ra 'window.$': 'jquery'biện pháp tốt :)
Sammi

57

Tôi không biết nếu tôi hiểu rất rõ những gì bạn đang cố gắng làm, nhưng tôi đã phải sử dụng các plugin jQuery yêu cầu jQuery phải ở trong bối cảnh toàn cầu (cửa sổ) và tôi đặt những điều sau đây vào entry.js:

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

Tôi chỉ cần yêu cầu bất cứ nơi nào tôi muốn jqueryplugin.min.jswindow.$được mở rộng với plugin như mong đợi.


2
Về cơ bản, tôi đã phạm sai lầm khi sử dụng ProvPlugin cùng với điều kiện noPude. Các plugin như ProvPlugin không hoạt động nếu chúng tôi thực hiện NoPude, như đã nêu ở điểm số 6 của câu trả lời. Bạn có thể thấy lỗi đó trong mã
booleanhunter

vâng, tôi đã thấy rằng hoạt động ổn định hơn trên các plugin so với các plugin cung cấp, v.v ... đặc biệt nếu bạn mang trong mình 1.x thông qua trình tải tập lệnh.
Tracker1

27

Tôi đã làm mọi thứ hoạt động tốt trong khi phơi bày $jQuerynhư các biến toàn cục với Webpack 3.8.1 và sau đây.

Cài đặt jQuery như một phụ thuộc dự án. Bạn có thể bỏ qua @3.2.1để cài đặt phiên bản mới nhất hoặc chỉ định phiên bản khác.

npm install --save jquery@3.2.1

Cài đặt expose-loadernhư một phụ thuộc phát triển nếu chưa được cài đặt.

npm install expose-loader --save-dev

Cấu hình Webpack để tải và hiển thị jQuery cho chúng tôi.

// 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
Bạn đã quên đề cập rằng bạn cần cài đặt expose-loaderđể nó hoạt động bình thường npm install expose-loader --save-dev
Paulo Griiettner

4
Điều này làm việc cho tôi. jquery: 3.3.1, bộ tải lộ: 0.7.5, gói web: 4.20.2
AKT

expose-loadedđã làm điều đó cho tôi. Tôi đã không gặp lỗi khi biên dịch, nhưng trong các công cụ dành cho nhà phát triển Chrome. Điều đó đã được giải quyết ngay bây giờ.
Johan Vergeer

Cảm ơn bạn! Điều này hoạt động với "jquery": "^ 3.4.1" và "webpack": "^ 4.41.5". Có phải tôi hay bắt jQuery làm việc với Webpack không phải là điều vô lý này?
Carles Alcolea

18

Thêm phần này vào mảng plugin của bạn trong webpack.config.js

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

sau đó yêu cầu jquery bình thường

require('jquery');

Nếu nỗi đau vẫn còn để các kịch bản khác nhìn thấy nó, hãy thử đặt nó một cách rõ ràng trong bối cảnh toàn cầu thông qua (trong mục js)

window.$ = jQuery;

18

Trong tệp webpack.config.js của bạn thêm vào bên dưới:

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

Cài đặt jQuery bằng npm:

$ npm i jquery --save

Trong tệp app.js thêm dòng dưới đây:

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

Điều này làm việc cho tôi. :)


Làm thế nào điều này sẽ hành động nếu bạn có cho ex. app.js và jquery-module.js, cả hai đều yêu cầu jquery?, đối với tôi, tôi nhận jquery13981378127 và jquery12389723198 làm ví dụ trên cửa sổ?
Martea

8

Tôi đã thử một số câu trả lời được cung cấp nhưng dường như không có câu trả lời nào hoạt động. Sau đó, tôi đã thử điều này:

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

Có vẻ như hoạt động cho dù tôi đang sử dụng phiên bản nào


+1 dường như là một sự hiểu lầm rằng các quả cầu được thêm vào đây sẽ tự động được đặt trên cửa sổ, dường như không hoạt động như bạn cần phải rõ ràng.
James

Chính xác, điều này không thêm nó vào đối tượng cửa sổ. Nó tạo ra một bí danh cửa sổ bên trong webpack. Vì vậy, nếu bạn cố gắng sử dụng $bên ngoài tệp webpack yêu cầu, nó sẽ không được xác định.
Cam Tullos

7

Điều này hoạt động trong webpack 3:

trong tệp webpack.config.babel.js:

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

Và sử dụng ProvPlugin

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

1
(! Như tôi) Đối với những người khác mà là siêu mới tại webpack "quyết tâm" đi trong webpack.config.js của bạn dưới module.exports = {} giống như nhập cảnh, đầu ra, plugin, module, vv ..
DavGarcia

1
Và webpack mới.ProvidePlugin đi vào bên trong mảng plugin.
DavGarcia

2

Giải pháp tốt nhất tôi tìm thấy là:

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

Về cơ bản, bạn cần bao gồm một biến giả trên typings.d.ts, xóa mọi "nhập * dưới dạng $ từ 'jquery" khỏi mã của bạn, sau đó thêm một thẻ vào tập lệnh jQuery vào html html của bạn theo cách thủ công. Theo cách này, webpack sẽ không theo cách của bạn và bạn sẽ có thể truy cập cùng một biến jQuery toàn cầu trong tất cả các tập lệnh của mình.


2

Điều này hoạt động với tôi trên webpack.config.js

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

trong một javascript khác hoặc vào HTML thêm:

global.jQuery = require('jquery');

0

Chỉnh sửa: Đôi khi bạn muốn sử dụng gói web đơn giản như một gói mô-đun cho một dự án web đơn giản - để giữ cho mã của riêng bạn được tổ chức. Giải pháp sau đây dành cho những người chỉ muốn một thư viện bên ngoài hoạt động như mong đợi bên trong các mô-đun của họ - mà không cần sử dụng nhiều thời gian để thiết lập webpack. (Đã chỉnh sửa sau -1)

Giải pháp nhanh chóng và đơn giản (es6) nếu bạn vẫn đang gặp khó khăn hoặc muốn tránh cấu hình bên ngoài / cấu hình plugin webpack bổ sung:

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

bên trong một mô-đun:

const { jQuery: $, Underscore: _, etc } = window;
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.