Tentukan variabel global dengan webpack


149

Apakah mungkin untuk mendefinisikan variabel global dengan webpack untuk menghasilkan sesuatu seperti ini:

var myvar = {};

Semua contoh yang saya lihat menggunakan file eksternal require("imports?$=jquery!./file.js")

Jawaban:


288

Ada beberapa cara untuk mendekati global:

1) Masukkan variabel Anda ke dalam modul.

Webpack mengevaluasi modul hanya sekali, jadi instance Anda tetap global dan membawa perubahan dari modul ke modul. Jadi jika Anda membuat sesuatu seperti globals.jsdan mengekspor objek dari semua global Anda, maka Anda bisa import './globals'dan membaca / menulis ke global ini. Anda dapat mengimpor ke dalam satu modul, membuat perubahan pada objek dari suatu fungsi dan mengimpor ke modul lain dan membaca perubahan tersebut dalam suatu fungsi. Juga ingat urutan sesuatu terjadi. Webpack pertama-tama akan mengambil semua impor dan memuatnya secara berurutan di file entry.js. Kemudian itu akan dieksekusi entry.js. Jadi di mana Anda membaca / menulis ke global itu penting. Apakah itu dari lingkup akar modul atau dalam fungsi yang dipanggil nanti?

Catatan : Jika Anda ingin instance menjadi newsetiap kali, gunakan kelas ES6 . Secara tradisional di JS Anda akan menggunakan huruf besar (berlawanan dengan huruf kecil untuk objek) seperti
import FooBar from './foo-bar' // <-- Usage: myFooBar = new FooBar()

2) ProvidPlugin dari Webpack

Berikut cara melakukannya menggunakan ProvidPlugin Webpack (yang membuat modul tersedia sebagai variabel di setiap modul dan hanya modul tempat Anda benar-benar menggunakannya). Ini berguna saat Anda tidak ingin terus mengetik import Bar from 'foo'lagi dan lagi. Atau Anda dapat membawa paket seperti jQuery atau lodash sebagai global di sini (meskipun Anda mungkin melihat Eksternal Webpack ).

Langkah 1) Buat modul apa saja. Misalnya, seperangkat utilitas global akan berguna:

utils.js

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

Langkah 2) Alias ​​modul dan tambahkan ke ProvidPlugin:

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'
    })
  ]  

}

Sekarang panggil utils.sayHello()saja file js apa saja dan itu akan berfungsi. Pastikan Anda me-restart dev-server Anda jika Anda menggunakannya dengan Webpack.

Catatan: Jangan lupa memberi tahu linter Anda tentang global, jadi tidak akan ada keluhan. Misalnya, lihat jawaban saya untuk ESLint di sini .

3) Gunakan DefinePlugin dari Webpack

Jika Anda hanya ingin menggunakan const dengan nilai string untuk global Anda, maka Anda dapat menambahkan plugin ini ke daftar plugin Webpack Anda:

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

Gunakan seperti:

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

4) Gunakan objek jendela global (atau global Node)

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/

Anda akan melihat ini biasanya digunakan untuk polyfill, misalnya: window.Promise = Bluebird

5) Gunakan paket seperti dotenv

(Untuk proyek sisi server) Paket dotenv akan mengambil file konfigurasi lokal (yang dapat Anda tambahkan ke .gitignore Anda jika ada kunci / kredensial) dan menambahkan variabel konfigurasi Anda ke objek process.env Node .

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

Buat .envfile di direktori root proyek Anda. Tambahkan variabel khusus lingkungan pada baris baru dalam bentuk NAME=VALUE. Sebagai contoh:

DB_HOST=localhost
DB_USER=root
DB_PASS=s1mpl3

Itu dia.

process.envsekarang memiliki kunci dan nilai yang Anda tentukan di .envfile Anda .

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

Catatan:

Terkait Eksternal Webpack , gunakan jika Anda ingin mengecualikan beberapa modul agar tidak disertakan dalam bundel bawaan Anda. Webpack akan membuat modul tersedia secara global tetapi tidak akan dimasukkan ke dalam bundel Anda. Ini berguna untuk pustaka besar seperti jQuery (karena paket eksternal yang mengguncang pohon tidak berfungsi di Webpack ) di mana Anda telah memuatnya di halaman Anda dalam tag skrip terpisah (mungkin dari CDN).


3
+1. Saya menyusun ulang aplikasi untuk memanfaatkan webpack sebagai alat build dan ini awalnya tidak berfungsi untuk saya karena saya tidak menyertakan referensi apa pun ke utilsnamespace saya sendiri di file target - awalnya saya baru saja meletakkan breakpoint di browser jendela sumber dan saya terus bingung mengapa utilstidak ditentukan. Akhirnya saya menemukan bahwa webpack (agak cerdas) hanya menyertakan modul jika namespace-nya direferensikan setidaknya sekali. Oleh karena itu, setelah saya melakukan pengantar salah satu fungsi utilitas file target dengan utils, modul itu disertakan.
nb1987

Yup, hanya di tempat Anda menggunakannya, apakah itu membuatnya tersedia. Saya letakkan di baris pertama jawaban, tetapi saya membuat sedikit penyesuaian jadi mungkin hasilnya lebih baik. Terima kasih atas +1!
prograhammer

1
Perhatikan bahwa ProvidPlugin sebenarnya memuat modul dan jika Anda hanya membutuhkan variabel, itu tidak berfungsi seperti itu. Gunakan externalssaja jika Anda perlu membuat variabel global. Contoh: externals: { 'webpackVariables': `{ serverUrl: '${ env.server }', cordovaBuild: '${ env.cordova }', }`, }, Kemudian gunakan sebagaiconst webpackVariables = require('webpackVariables');
Brian Cannard

1
Dan tahukah Anda bagaimana saya dapat menggunakan pendekatan ini dengan TypeScript? Di sana jika Anda menggunakan variabel yang tidak dideklarasikan itu membuat kesalahan ...
knaos

2
@prograhammer Sebenarnya, saya sudah menemukan solusinya. Di root aplikasi Anda, biasanya tempat tsconfig.json berada, Anda perlu menambahkan file definisi bernama global.d.ts . Di dalamnya Anda dapat mendeklarasikan variabel global, seperti ini: declare const isProduction: bool;Untuk referensi, lihat ini typescriptlang.org/docs/handbook/declaration-files/templates/…
knaos

47

Saya akan menanyakan pertanyaan yang sama. Setelah mencari sedikit lebih jauh dan decyphering bagian dari dokumentasi webpack, saya pikir yang Anda inginkan adalah output.librarydan output.libraryTargetdi dalam webpack.config.jsfile.

Sebagai contoh:

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'
   ...
}

Sekarang jika Anda menautkan www/js/index.jsfile yang dihasilkan dalam tag skrip html, Anda dapat mengaksesnya myLibrary.foodari mana saja di skrip Anda yang lain.


3
Saya pikir ini hilang export { foo }dari index.js?
LondonAppDev

myLibrary memberikan undefined di file lain dalam kasus saya. Bisakah Anda membantu saya
RVCoder

17

Gunakan DefinePlugin .

DefinePlugin memungkinkan Anda membuat konstanta global yang dapat dikonfigurasi pada waktu kompilasi.

new webpack.DefinePlugin(definitions)

Contoh:

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

Pemakaian:

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

15

Anda dapat menggunakan definisikan window.myvar = {}. Saat Anda ingin menggunakannya, Anda bisa menggunakan likewindow.myvar = 1


Ini tidak bekerja dengan EMCAScript 6. Menghasilkan kesalahan dengan var window.CKEDITOR_BASEPATH = {};Kesalahan adalah "Token Tak Terduga" setelahwindow.
Routhinator

1
Maaf. Saya baru saja memperbarui jawaban saya. Anda harus varkata kunci. window.CKEDITOR_BASEPATH = {};
Anh Nguyen

Ini berfungsi, sayangnya masalah yang saya hadapi adalah saya membutuhkannya untuk dimuat ke dalam bundel sebelum CKEditor, namun Webpack bersikeras untuk meletakkannya setelah di mana pun saya meletakkannya ke dalam import / js saya. : /
Routhinator

2

Saya memecahkan masalah ini dengan menetapkan variabel global sebagai properti statis pada kelas yang paling relevan. Di ES5 terlihat seperti ini:

var Foo = function(){...};
Foo.globalVar = {};
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.