Definieren Sie die globale Variable mit dem Webpack

137

Ist es möglich, eine globale Variable mit Webpack zu definieren, um so etwas zu erhalten:

var myvar = {};

Alle Beispiele, die ich sah, verwendeten externe Dateien require("imports?$=jquery!./file.js")

Teneff
quelle

Antworten:

271

Es gibt verschiedene Möglichkeiten, sich den Globalen zu nähern:

1) Fügen Sie Ihre Variablen in ein Modul ein.

Webpack wertet Module nur einmal aus, sodass Ihre Instanz global bleibt und Änderungen von Modul zu Modul durchführt. Wenn Sie also so etwas wie a erstellen globals.jsund ein Objekt aller Ihrer Globals exportieren, können Sie import './globals'diese Globals lesen und schreiben. Sie können in ein Modul importieren, Änderungen am Objekt von einer Funktion vornehmen und in ein anderes Modul importieren und diese Änderungen in einer Funktion lesen. Denken Sie auch an die Reihenfolge, in der die Dinge passieren. Webpack nimmt zuerst alle Importe und lädt sie in der Reihenfolge ab Ihrem entry.js. Dann wird es ausgeführt entry.js. Es ist also wichtig, wo Sie in Globals lesen / schreiben. Ist es aus dem Stammbereich eines Moduls oder in einer später aufgerufenen Funktion?

Hinweis : Wenn die Instanz newjedes Mal sein soll, verwenden Sie eine ES6-Klasse . Traditionell würden Sie in JS Klassen (im Gegensatz zu Kleinbuchstaben für Objekte) wie groß schreiben
import FooBar from './foo-bar' // <-- Usage: myFooBar = new FooBar()

2) ProvidePlugin von Webpack

So können Sie dies mit dem ProvidePlugin von Webpack tun (das ein Modul als Variable in jedem Modul und nur in den Modulen zur Verfügung stellt, in denen Sie es tatsächlich verwenden). Dies ist nützlich, wenn Sie nicht immer import Bar from 'foo'wieder tippen möchten . Oder Sie können in einem Paket wie jQuery bringen oder als globale lodash hier (auch wenn Sie einen Blick auf Webpack die nehmen könnte Externals ).

Schritt 1) ​​Erstellen Sie ein beliebiges Modul. Zum Beispiel wäre eine globale Reihe von Dienstprogrammen praktisch:

utils.js

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

Schritt 2) Aliasen Sie das Modul und fügen Sie es zu ProvidePlugin hinzu:

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

}

Rufen Sie jetzt einfach eine utils.sayHello()beliebige js-Datei auf und es sollte funktionieren. Stellen Sie sicher, dass Sie Ihren Dev-Server neu starten, wenn Sie dies mit Webpack verwenden.

Hinweis: Vergessen Sie nicht, Ihrem Linter das Globale mitzuteilen, damit er sich nicht beschwert. Siehe zum Beispiel meine Antwort für ESLint hier .

3) Verwenden Sie das DefinePlugin von Webpack

Wenn Sie nur const mit Zeichenfolgenwerten für Ihre Globals verwenden möchten, können Sie dieses Plugin zu Ihrer Liste der Webpack-Plugins hinzufügen:

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

Verwenden Sie es wie:

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

4) Verwenden Sie das globale Fensterobjekt (oder das globale des Knotens).

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/

Sie werden sehen, dass dies häufig für Polyfills verwendet wird, zum Beispiel: window.Promise = Bluebird

5) Verwenden Sie ein Paket wie dotenv

(Für serverseitige Projekte) Das dotenv-Paket verwendet eine lokale Konfigurationsdatei (die Sie zu Ihrem .gitignore hinzufügen können, wenn Schlüssel / Anmeldeinformationen vorhanden sind) und fügt Ihre Konfigurationsvariablen dem process.env- Objekt von Node hinzu .

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

Erstellen Sie eine .envDatei im Stammverzeichnis Ihres Projekts. Fügen Sie in neuen Zeilen umgebungsspezifische Variablen in Form von hinzu NAME=VALUE. Beispielsweise:

DB_HOST=localhost
DB_USER=root
DB_PASS=s1mpl3

Das ist es.

process.envhat jetzt die Schlüssel und Werte, die Sie in Ihrer .envDatei definiert haben .

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

Anmerkungen:

Verwenden Sie Webpacks Externals , wenn Sie einige Module von der Aufnahme in Ihr erstelltes Bundle ausschließen möchten. Webpack stellt das Modul global zur Verfügung, fügt es jedoch nicht in Ihr Bundle ein. Dies ist praktisch für große Bibliotheken wie jQuery (da das Schütteln externer Pakete in Webpack nicht funktioniert ), bei denen diese bereits in separaten Skript-Tags (möglicherweise von einem CDN) auf Ihre Seite geladen sind.

Programmierer
quelle
3
+1. Ich strukturiere eine App neu, um Webpack als Build-Tool zu nutzen, und dies funktionierte zunächst nicht für mich, da ich keinen Verweis auf meinen eigenen utilsNamespace in die Zieldatei aufgenommen hatte - anfangs hatte ich nur einen Haltepunkt in den Browser eingefügt Quellfenster und ich rätselten immer wieder, warum utilsnicht definiert wurde. Schließlich entdeckte ich, dass Webpack (ziemlich intelligent) nur dann ein Modul enthält, wenn auf seinen Namespace mindestens einmal verwiesen wird. Deshalb, sobald ich mit Vorwort einer der Utility - Funktionen der Zieldatei haben utils, das Modul wurde eingeschlossen.
nb1987
Ja, nur dort, wo Sie es verwenden, wird es verfügbar gemacht. Ich habe das in die erste Zeile der Antwort eingefügt, aber ich habe eine leichte Anpassung vorgenommen, damit es vielleicht besser liest. Danke für die +1!
Programmierer
1
Beachten Sie, dass ProvidePlugin tatsächlich Module lädt. Wenn Sie nur eine Variable benötigen, funktioniert dies nicht. Verwenden Sie externalsstattdessen einfach, wenn Sie eine globale Variable erstellen müssen. Beispiel: externals: { 'webpackVariables': `{ serverUrl: '${ env.server }', cordovaBuild: '${ env.cordova }', }`, }, Dann verwenden Sie es alsconst webpackVariables = require('webpackVariables');
Brian Haak
1
Und wissen Sie, wie ich diesen Ansatz mit TypeScript verwenden kann? Wenn Sie dort eine nicht deklarierte Variable verwenden, wird ein Fehler
ausgegeben
2
@prograhammer Eigentlich habe ich die Lösung schon gefunden. Im Stammverzeichnis Ihrer Anwendung, normalerweise dort, wo sich Ihre Datei tsconfig.json befindet, müssen Sie eine Definitionsdatei mit dem Namen global.d.ts hinzufügen . Darin können Sie globale Variablen, wie dies erklären: declare const isProduction: bool;Als Referenz check this out typescriptlang.org/docs/handbook/declaration-files/templates/...
knaos
45

Ich wollte gerade die gleiche Frage stellen. Nachdem ich ein bisschen weiter gesucht und einen Teil der Dokumentation des Webpacks entschlüsselt habe, denke ich, dass Sie das output.libraryund output.libraryTargetin der webpack.config.jsDatei wollen.

Beispielsweise:

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

Wenn Sie nun die generierte www/js/index.jsDatei in einem HTML-Skript-Tag verknüpfen , können Sie myLibrary.foovon überall in Ihren anderen Skripten darauf zugreifen .

OriolBG
quelle
3
Ich denke das fehlt export { foo }im index.js?
LondonAppDev
myLibrary gibt in meinem Fall undefiniert in einer anderen Datei. Können Sie mir bitte helfen
RVCoder
17

Verwenden Sie DefinePlugin .

Mit dem DefinePlugin können Sie globale Konstanten erstellen, die zur Kompilierungszeit konfiguriert werden können.

new webpack.DefinePlugin(definitions)

Beispiel:

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

Verwendung:

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

Sie können define verwenden window.myvar = {}. Wenn Sie es verwenden möchten, können Sie like verwendenwindow.myvar = 1

Anh Nguyen
quelle
Dies funktioniert nicht mit EMCAScript 6. Erzeugt Fehler mit var window.CKEDITOR_BASEPATH = {};Fehler ist "Unerwartetes Token" nachwindow.
Routhinator
1
Es tut uns leid. Ich habe gerade meine Antwort aktualisiert. Sie sollten varSchlüsselwort. window.CKEDITOR_BASEPATH = {};
Anh Nguyen
Dies funktioniert, leider besteht das Problem darin, dass ich es vor CKEditor in das Bundle laden muss. Webpack besteht jedoch darauf, es nach dem Einfügen in meine Importe / js zu platzieren. : /
Routhinator
2

Ich habe dieses Problem gelöst, indem ich die globalen Variablen als statische Eigenschaften für die Klassen festgelegt habe, für die sie am relevantesten sind. In ES5 sieht es so aus:

var Foo = function(){...};
Foo.globalVar = {};
pasx
quelle