การจัดการการพึ่งพาปลั๊กอิน jQuery ใน webpack


451

ฉันใช้ Webpack ในแอปพลิเคชันของฉันซึ่งฉันสร้างจุดเข้าใช้งานสองจุด - bundle.js สำหรับไฟล์ / รหัส JavaScript ทั้งหมดของฉันและผู้ขาย.jsสำหรับห้องสมุดทั้งหมดเช่น jQuery และ React ฉันจะทำอย่างไรเพื่อใช้ปลั๊กอินที่มี jQuery เป็นการอ้างอิงของพวกเขาและฉันต้องการให้พวกเขายังอยู่ใน vendor.js? เกิดอะไรขึ้นถ้าปลั๊กอินเหล่านั้นมีการขึ้นต่อกันหลายอย่าง?

ขณะนี้ฉันกำลังพยายามที่จะใช้ jQuery นี้ปลั๊กอินที่นี่ - https://github.com/mbklein/jquery-elastic เอกสารประกอบ Webpack ระบุถึงPluginและimport -loader ฉันใช้ 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 ไม่ได้ถูกกำหนดไว้

ในทำนองเดียวกันเมื่อฉันใช้ import-loader มันจะพ่นข้อผิดพลาด

ไม่จำเป็นต้องมีการกำหนด '

ในบรรทัดนี้:

var jQuery = require("jquery")

อย่างไรก็ตามฉันสามารถใช้ปลั๊กอินตัวเดียวกันเมื่อฉันไม่ได้เพิ่มลงในไฟล์ผู้ขายของฉันและใช้วิธีการปกติของ 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 ทั้งหมดของฉันอยู่ในมัดผู้ขาย.jpg ดังนั้นฉันจะไปเกี่ยวกับการบรรลุเป้าหมายนี้ได้อย่างไร


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เพื่อฉีด globals โดยนัย

ส่วนใหญ่โมดูลมรดกพึ่งพาการปรากฏตัวของ Globals ที่เฉพาะเจาะจงเช่นปลั๊กอิน 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ด้วยการนำเข้า-loader

เรียกใช้npm i imports-loader --save-devแล้ว

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

import-loader ยังสามารถใช้เพื่อฉีดตัวแปรด้วยตนเองทุกชนิด แต่เวลาส่วนใหญ่นั้นProvidePluginมีประโยชน์มากกว่าเมื่อพูดถึงการบอกเป็นนัย ๆ


4. ใช้import-loaderเพื่อปิดการใช้งาน 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เพื่อรวม dists ขนาดใหญ่

เมื่อไม่มีรุ่นเอเอ็มดี / CommonJS ของโมดูลและคุณต้องการที่จะรวมคุณสามารถตั้งค่าสถานะโมดูลนี้เป็นdist noParseจากนั้น webpack จะรวมโมดูลโดยไม่ต้องแยกวิเคราะห์ซึ่งสามารถใช้ในการปรับปรุงเวลาสร้างได้ ซึ่งหมายความว่าคุณลักษณะใด ๆ ที่ต้องใช้เอเอสทีเหมือนProvidePluginจะไม่ทำงาน

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

3
ProvidePluginถูกนำไปใช้ในเหตุการณ์ที่เกิดขึ้นทั้งหมดของตัวบ่งชี้ที่กำหนดในไฟล์ทั้งหมด imports-loaderสามารถนำไปใช้กับไฟล์เฉพาะ แต่คุณไม่ควรใช้ทั้งสำหรับตัวแปรเดียวกัน / อ้างอิง
Johannes Ewald

5
ฉันสับสนกับสิ่งนี้ jquery มาจากไหนจริงหรือ ในประเทศหรือ CDN ทุกอย่างหลังจาก 3. มันไม่ชัดเจนว่าจำเป็น ขั้นตอนการรวม jquery เข้ากับโครงการของคุณโดยใช้ webpack คืออะไร มันข้ามรุ่นที่มีให้ผ่านทาง CDN หรือไม่
HelpMeStackOverflowMyOnlyHope

2
ทุกอย่างจาก CDN อยู่นอกขอบเขตสำหรับ webpack ดังนั้นนี่หมายถึงการติดตั้ง jquery ในเครื่อง jquery สามารถทำได้เพียงแค่ไม่มีขั้นตอนพิเศษที่จำเป็นในการรวมเข้าด้วยกัน คำถามนี้เกี่ยวกับวิธีรวมปลั๊กอิน jquery ที่ขึ้นอยู่กับ$ตัวแปรโกลบอล
Johannes Ewald

8
ทั้งหมดนี้ยังใช้งานไม่ได้ เพิ่มแล้ว: "module": { "loaders": [ { test: require.resolve("jquery"), loader: "expose?$!expose?jQuery" },และมันก็ใช้ได้ดี
musicformellons

5
ทำทั้งหมดนี้เพื่อรวมแพ็คเกจ jquery หรือไม่ช่างเป็นความเจ็บปวด ฉันจะกลับไปสร้างอึกของฉัน
Rahul Gupta

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éo Lam

@ 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'การวัดที่ดี :)
Sammi

57

ฉันไม่ทราบว่าฉันเข้าใจสิ่งที่คุณพยายามทำดีหรือไม่ แต่ฉันต้องใช้ปลั๊กอิน jQuery ที่ต้องการให้ jQuery อยู่ในบริบทของโลก (หน้าต่าง) และฉันใส่สิ่งต่อไปนี้ในของฉันentry.js:

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

ฉันแค่ต้องต้องการทุกที่ที่ฉันต้องการjqueryplugin.min.jsและwindow.$ขยายด้วยปลั๊กอินตามที่คาดไว้


2
โดยทั่วไปฉันทำผิดพลาดในการใช้ ProviderPlugin พร้อมกับเงื่อนไข noParse ปลั๊กอินเช่น ProvidePlugin ไม่ทำงานหากเราทำ NoParse ตามที่ระบุไว้ในข้อ 6 ของคำตอบ คุณสามารถเห็นความผิดพลาดนั้นในรหัส
booleanhunter

ใช่ฉันพบว่าทำงานได้อย่างต่อเนื่องข้ามปลั๊กอินมากกว่าปลั๊กอินเสริม ฯลฯ ... โดยเฉพาะถ้าคุณกำลังนำแองกูลาร์ 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
Paulo Griiettner

4
สิ่งนี้ใช้ได้สำหรับฉัน👍 jquery: 3.3.1, ตัวโหลดเปิดเผย: 0.7.5, webpack: 4.20.2
AKT

expose-loadedมันสำหรับฉัน ฉันไม่ได้รับข้อผิดพลาดในเวลารวบรวม แต่ในเครื่องมือสำหรับนักพัฒนาซอฟต์แวร์ของ Chrome แก้ไขแล้วตอนนี้
Johan Vergeer

ขอบคุณ! สิ่งนี้ใช้ได้กับ "jquery": "^ 3.4.1" และ "webpack": "^ 4.41.5" เป็นเพียงฉันหรือได้รับ jQuery เพื่อทำงานร่วมกับ Webpack ไม่ควรจะไร้สาระนี้หรือไม่?
Carles Alcolea

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 เป็นอินสแตนซ์บนหน้าต่าง
Martea

8

ฉันลองคำตอบที่ให้มา แต่ดูเหมือนว่าไม่มีคำตอบใด ๆ เลย จากนั้นฉันลองทำสิ่งนี้:

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

ดูเหมือนว่าจะทำงานไม่ว่าฉันจะใช้เวอร์ชันใด


+1 ดูเหมือนจะเป็นความเข้าใจผิดที่ว่าดาวที่เพิ่มที่นี่จะถูกตั้งค่าโดยอัตโนมัติกับหน้าต่างดูเหมือนจะไม่ทำงานอย่างที่คุณต้องการชัดเจน
James

ถูกต้องจะไม่เพิ่มลงในวัตถุหน้าต่าง มันสร้างชื่อแทนหน้าต่างภายใน webpack ดังนั้นหากคุณพยายามใช้$นอกไฟล์ที่ต้องการ webpack ไฟล์นั้นจะไม่ถูกกำหนด
Cam Tullos

7

ใช้งานได้ในwebpack 3:

ในไฟล์ webpack.config.babel.js:

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

และใช้ProviderPlugin

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/issues/5139#issuecomment-283634059

โดยทั่วไปคุณจะต้องรวมตัวแปรจำลองใน typings.d.ts ลบ "import * as $ จาก 'jquery" ออกจากรหัสของคุณแล้วเพิ่มแท็กลงในสคริปต์ jQuery ใน SPA html ของคุณด้วยตนเอง ด้วยวิธีนี้ webpack จะไม่เป็นไปในแบบของคุณและคุณควรจะสามารถเข้าถึงตัวแปร jQuery ทั่วโลกที่เหมือนกันในสคริปต์ทั้งหมดของคุณ


2

สิ่งนี้ใช้ได้กับฉันใน webpack.config.js

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

ใน javascript อื่นหรือเพิ่ม HTML:

global.jQuery = require('jquery');

0

แก้ไข: บางครั้งคุณต้องการใช้ webpack เพียงแค่เป็นโมดูลบันเดิลสำหรับโครงการเว็บอย่างง่าย - เพื่อให้รหัสของคุณเป็นระเบียบ วิธีแก้ไขปัญหาต่อไปนี้สำหรับผู้ที่ต้องการให้ห้องสมุดภายนอกทำงานตามที่คาดไว้ในโมดูลของพวกเขา - โดยไม่ต้องใช้เวลามากมายในการตั้งค่า webpack (แก้ไขหลังจาก -1)

วิธีแก้ปัญหาที่ง่ายและรวดเร็ว (es6) หากคุณยังคงดิ้นรนหรือต้องการหลีกเลี่ยงการกำหนดค่าภายนอก / การกำหนดค่าปลั๊กอิน webpack เพิ่มเติม:

<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;
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.