กำหนดตัวแปรส่วนกลางด้วย webpack


149

เป็นไปได้ไหมที่จะกำหนดตัวแปรส่วนกลางด้วย webpack เพื่อให้ได้ผลลัพธ์ดังนี้:

var myvar = {};

ตัวอย่างทั้งหมดที่ฉันเห็นใช้ไฟล์ภายนอก require("imports?$=jquery!./file.js")

คำตอบ:


288

มีหลายวิธีในการเข้าใกล้โลก:

1) ใส่ตัวแปรของคุณในโมดูล

Webpack จะประเมินโมดูลเพียงครั้งเดียวดังนั้นอินสแตนซ์ของคุณจึงยังคงเป็นสากลและดำเนินการเปลี่ยนแปลงจากโมดูลไปยังโมดูล ดังนั้นหากคุณสร้างบางสิ่งเช่นglobals.jsและส่งออกวัตถุของโลกทั้งหมดของคุณคุณก็สามารถimport './globals'อ่าน / เขียนไปยังโลกเหล่านี้ได้ คุณสามารถนำเข้าในโมดูลเดียวทำการเปลี่ยนแปลงวัตถุจากฟังก์ชันและนำเข้าสู่โมดูลอื่นและอ่านการเปลี่ยนแปลงเหล่านั้นในฟังก์ชัน นอกจากนี้ยังจำคำสั่งซื้อที่เกิดขึ้น Webpack จะนำเข้าทั้งหมดก่อนและโหลดขึ้นตามลำดับโดยเริ่มต้นในentry.jsไฟล์. entry.jsจากนั้นก็จะดำเนินการ ดังนั้นตำแหน่งที่คุณอ่าน / เขียนถึงคนทั่วโลกจึงมีความสำคัญ มาจากขอบเขตรากของโมดูลหรือในฟังก์ชันที่เรียกในภายหลังหรือไม่?

หมายเหตุ : หากคุณต้องการเช่นที่จะเป็นnewทุกครั้งที่แล้วใช้ระดับ ES6 ตามเนื้อผ้าใน JS คุณจะใช้ตัวพิมพ์ใหญ่ในชั้นเรียน (เมื่อเทียบกับตัวพิมพ์เล็กสำหรับวัตถุ) เช่น
import FooBar from './foo-bar' // <-- Usage: myFooBar = new FooBar()

2) ProviderPlugin ของWebpack

ต่อไปนี้เป็นวิธีที่คุณสามารถทำได้โดยใช้ GivePlugin ของ Webpack (ซึ่งทำให้โมดูลพร้อมใช้งานเป็นตัวแปรในทุกโมดูลและเฉพาะโมดูลที่คุณใช้งานจริง) สิ่งนี้มีประโยชน์เมื่อคุณไม่ต้องการพิมพ์import Bar from 'foo'ซ้ำแล้วซ้ำอีก หรือคุณสามารถนำแพ็คเกจเช่น jQuery หรือ lodash เป็น global ได้ที่นี่ (แม้ว่าคุณจะดูExternalsของ Webpack )

ขั้นตอนที่ 1) สร้างโมดูลใด ๆ ตัวอย่างเช่นชุดยูทิลิตี้ส่วนกลางจะสะดวก:

utils.js

export function sayHello () {
  console.log('hello')
}

ขั้นตอนที่ 2) ตั้งชื่อโมดูลและเพิ่มลงใน GivePlugin:

webpack.config.js

var webpack = require("webpack");
var path = require("path");

// ...

module.exports = {

  // ...

  resolve: {
    extensions: ['', '.js'],
    alias: {
      'utils': path.resolve(__dirname, './utils')  // <-- When you build or restart dev-server, you'll get an error if the path to your utils.js file is incorrect.
    }
  },

  plugins: [

    // ...

    new webpack.ProvidePlugin({
      'utils': 'utils'
    })
  ]  

}

ตอนนี้แค่โทร utils.sayHello()ในไฟล์ js ใดก็ได้และควรใช้งานได้ ตรวจสอบให้แน่ใจว่าคุณรีสตาร์ทเซิร์ฟเวอร์ dev ของคุณหากคุณใช้กับ Webpack

หมายเหตุ: อย่าลืมบอกคนของคุณเกี่ยวกับคนทั่วโลกจะได้ไม่บ่น ตัวอย่างเช่นดูฉันตอบสำหรับ ESLint ที่นี่

3) ใช้ DefinePlugin ของWebpack

หากคุณต้องการใช้ const กับค่าสตริงสำหรับ globals ของคุณคุณสามารถเพิ่มปลั๊กอินนี้ในรายการปลั๊กอิน Webpack ของคุณ:

new webpack.DefinePlugin({
  PRODUCTION: JSON.stringify(true),
  VERSION: JSON.stringify("5fa3b9"),
  BROWSER_SUPPORTS_HTML5: true,
  TWO: "1+1",
  "typeof window": JSON.stringify("object")
})

ใช้มันเช่น:

console.log("Running App version " + VERSION);
if(!BROWSER_SUPPORTS_HTML5) require("html5shiv");

4) ใช้วัตถุหน้าต่างส่วนกลาง (หรือส่วนกลางของโหนด)

window.foo = 'bar'  // For SPA's, browser environment.
global.foo = 'bar'  // Webpack will automatically convert this to window if your project is targeted for web (default), read more here: https://webpack.js.org/configuration/node/

คุณจะเห็นสิ่งนี้ที่ใช้กันทั่วไปสำหรับ polyfills ตัวอย่างเช่น: window.Promise = Bluebird

5) ใช้แพ็คเกจเช่นdotenv

(สำหรับโปรเจ็กต์ฝั่งเซิร์ฟเวอร์) แพ็กเกจ dotenv จะใช้ไฟล์คอนฟิกูเรชันภายในเครื่อง (ซึ่งคุณสามารถเพิ่มลงใน. gitignore ของคุณได้หากมีคีย์ / ข้อมูลรับรอง) และเพิ่มตัวแปรคอนฟิกูเรชันของคุณไปยังอ็อบเจ็กต์ process.envของโหนด

// As early as possible in your application, require and configure dotenv.    
require('dotenv').config()

สร้าง.envไฟล์ในไดเร็กทอรีรากของโปรเจ็กต์ของคุณ เพิ่มตัวแปรเฉพาะสภาพแวดล้อมในบรรทัดใหม่ในรูปแบบNAME=VALUE . ตัวอย่างเช่น:

DB_HOST=localhost
DB_USER=root
DB_PASS=s1mpl3

แค่นั้นแหละ.

process.envตอนนี้มีคีย์และค่าที่คุณกำหนดไว้ใน.envไฟล์ของคุณ

var db = require('db')
db.connect({
  host: process.env.DB_HOST,
  username: process.env.DB_USER,
  password: process.env.DB_PASS
})

หมายเหตุ:

เกี่ยวกับExternalsของ Webpack ให้ใช้หากคุณต้องการแยกโมดูลบางส่วนไม่ให้รวมอยู่ในบันเดิลที่สร้างขึ้นของคุณ Webpack จะทำให้โมดูลพร้อมใช้งานทั่วโลก แต่จะไม่ใส่ไว้ในบันเดิลของคุณ สิ่งนี้มีประโยชน์สำหรับไลบรารีขนาดใหญ่เช่น jQuery (เนื่องจากทรีเขย่าแพ็กเกจภายนอกไม่ทำงานใน Webpack ) ซึ่งคุณได้โหลดสิ่งเหล่านี้บนเพจของคุณแล้วในแท็กสคริปต์แยกต่างหาก (อาจมาจาก CDN)


3
+1. ฉันกำลังจัดโครงสร้างแอพใหม่เพื่อใช้ประโยชน์จาก webpack เป็นเครื่องมือสร้างและในตอนแรกสิ่งนี้ไม่ได้ผลสำหรับฉันเพราะฉันไม่ได้รวมการอ้างอิงถึงutilsเนมสเปซของตัวเองในไฟล์เป้าหมาย - ตอนแรกฉันเพิ่งใส่เบรกพอยต์ในเบราว์เซอร์ หน้าต่างแหล่งที่มาและฉันยังคงงงว่าทำไมutilsไม่ได้กำหนดไว้ ในที่สุดฉันก็ค้นพบว่า webpack (ค่อนข้างฉลาด) มีเฉพาะโมดูลหากมีการอ้างอิงเนมสเปซอย่างน้อยหนึ่งครั้ง ดังนั้นเมื่อฉันได้นำหน้าหนึ่งในฟังก์ชันยูทิลิตี้ของไฟล์เป้าหมายไปด้วยutilsโมดูลก็จะรวม
nb1987

ใช่เฉพาะที่ที่คุณใช้เท่านั้นที่ทำให้มันพร้อมใช้งาน ฉันใส่ไว้ในบรรทัดแรกของคำตอบ แต่ฉันได้ปรับเปลี่ยนเล็กน้อยเพื่อให้อ่านได้ดีขึ้น ขอบคุณสำหรับ +1!
prograhammer

1
โปรดทราบว่า GivePlugin โหลดโมดูลและหากคุณต้องการเพียงแค่ตัวแปรก็จะไม่ทำงานเช่นนั้น เพียงใช้externalsแทนหากคุณต้องการสร้างตัวแปรส่วนกลาง ตัวอย่าง: externals: { 'webpackVariables': `{ serverUrl: '${ env.server }', cordovaBuild: '${ env.cordova }', }`, }, จากนั้นใช้เป็นconst webpackVariables = require('webpackVariables');
Brian Cannard

1
และคุณรู้หรือไม่ว่าฉันจะใช้แนวทางนี้กับ TypeScript ได้อย่างไร? หากคุณใช้ตัวแปรที่ไม่ได้ประกาศจะแสดงข้อผิดพลาด ...
knaos

2
@prograhammer จริงๆแล้วฉันพบวิธีแก้ปัญหาแล้ว ในรากของแอพลิเคชันของคุณมักจะที่คุณtsconfig.jsonคือคุณต้องเพิ่มไฟล์การกำหนดชื่อglobal.d.ts ในนั้นคุณสามารถประกาศตัวแปรส่วนกลางได้ดังนี้: declare const isProduction: bool;สำหรับการอ้างอิงโปรดดูที่typescriptlang.org/docs/handbook/declaration-files/templates/…
knaos

47

ฉันกำลังจะถามคำถามเดียวกันนี้ หลังจากค้นหาเพิ่มเติมและถอดรหัสส่วนหนึ่งของเอกสารของ webpack ฉันคิดว่าสิ่งที่คุณต้องการคือoutput.libraryและoutput.libraryTargetในwebpack.config.jsไฟล์

ตัวอย่างเช่น:

js / index.js:

var foo = 3;
var bar = true;

webpack.config.js

module.exports = {
   ...
   entry: './js/index.js',
   output: {
      path: './www/js/',
      filename: 'index.js',
      library: 'myLibrary',
      libraryTarget: 'var'
   ...
}

ตอนนี้ถ้าคุณเชื่อมโยงwww/js/index.jsไฟล์ที่สร้างในแท็กสคริปต์ html คุณสามารถเข้าถึงได้myLibrary.fooจากทุกที่ในสคริปต์อื่น ๆ ของคุณ


3
ฉันคิดว่าสิ่งนี้หายไปexport { foo }จากindex.js?
LondonAppDev

myLibrary ให้ undefined ในไฟล์อื่นในกรณีของฉัน คุณช่วยฉันได้ไหม
RVCoder

17

ใช้DefinePlugin

DefinePlugin ช่วยให้คุณสร้างค่าคงที่ส่วนกลางซึ่งสามารถกำหนดค่าได้ในเวลาคอมไพล์

new webpack.DefinePlugin(definitions)

ตัวอย่าง:

plugins: [
  new webpack.DefinePlugin({
    PRODUCTION: JSON.stringify(true)
  })
  //...
]

การใช้งาน:

console.log(`Environment is in production: ${PRODUCTION}`);

15

window.myvar = {}คุณสามารถใช้กำหนด ต้องการใช้เมื่อใดก็สามารถใช้ likewindow.myvar = 1


สิ่งนี้ใช้ไม่ได้กับ EMCAScript 6 ข้อผิดพลาดที่เกิดขึ้นพร้อมกับvar window.CKEDITOR_BASEPATH = {};ข้อผิดพลาดคือ "โทเค็นที่ไม่คาดคิด" หลังจากwindow.
Routhinator

1
ขออภัย. ฉันเพิ่งอัปเดตคำตอบของฉัน คุณควรvarคีย์เวิร์ด window.CKEDITOR_BASEPATH = {};
Anh Nguyen

สิ่งนี้ใช้งานได้น่าเสียดายที่ปัญหาที่ฉันพบคือฉันต้องการให้โหลดลงในบันเดิลก่อน CKEditor อย่างไรก็ตาม Webpack ยืนยันที่จะวางมันหลังจากนั้นไม่ว่าฉันจะวางไว้ที่ใดในการนำเข้า / js ของฉัน : /
Routhinator

2

ฉันแก้ไขปัญหานี้โดยการตั้งค่าตัวแปรส่วนกลางเป็นคุณสมบัติคงที่ในคลาสที่เกี่ยวข้องมากที่สุด ใน ES5 จะมีลักษณะดังนี้:

var Foo = function(){...};
Foo.globalVar = {};
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.