Définir une variable globale avec webpack

138

Est-il possible de définir une variable globale avec webpack pour obtenir quelque chose comme ceci:

var myvar = {};

Tous les exemples que j'ai vus utilisaient un fichier externe require("imports?$=jquery!./file.js")

Teneff
la source

Réponses:

272

Il existe plusieurs façons d'aborder les globaux:

1) Mettez vos variables dans un module.

Webpack évalue les modules une seule fois, de sorte que votre instance reste globale et effectue les modifications d'un module à l'autre. Donc, si vous créez quelque chose comme a globals.jset exportez un objet de tous vos globals, vous pouvez import './globals'et lire / écrire dans ces globals. Vous pouvez importer dans un module, apporter des modifications à l'objet à partir d'une fonction et importer dans un autre module et lire ces modifications dans une fonction. Souvenez-vous également de l'ordre dans lequel les choses se passent. Webpack prendra d'abord toutes les importations et les chargera dans l'ordre en commençant dans votre entry.js. Ensuite, il s'exécutera entry.js. Donc, où vous lisez / écrivez dans les globaux est important. Est-ce de la portée racine d'un module ou dans une fonction appelée plus tard?

Remarque : si vous souhaitez que l'instance soit à newchaque fois, utilisez une classe ES6 . Traditionnellement dans JS, vous mettriez les classes en majuscules (par opposition aux minuscules pour les objets) comme
import FooBar from './foo-bar' // <-- Usage: myFooBar = new FooBar()

2) FournirPlugin de Webpack

Voici comment vous pouvez le faire en utilisant le ProviderPlugin de Webpack (qui rend un module disponible en tant que variable dans chaque module et uniquement les modules où vous l'utilisez réellement). Ceci est utile lorsque vous ne voulez pas continuer à taper import Bar from 'foo'encore et encore. Ou vous pouvez apporter un package comme jQuery ou lodash en tant que global ici (bien que vous puissiez jeter un oeil à Webpack's Externals ).

Étape 1) Créez n'importe quel module. Par exemple, un ensemble global d'utilitaires serait pratique:

utils.js

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

Étape 2) Alias ​​le module et ajouter à FournirPlugin:

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

}

Maintenant, appelez simplement utils.sayHello()n'importe quel fichier js et cela devrait fonctionner. Assurez-vous de redémarrer votre serveur de développement si vous l'utilisez avec Webpack.

Remarque: n'oubliez pas de parler à votre linter du global pour qu'il ne se plaigne pas. Par exemple, voir ma réponse pour ESLint ici .

3) Utilisez DefinePlugin de Webpack

Si vous souhaitez simplement utiliser const avec des valeurs de chaîne pour vos globals, vous pouvez ajouter ce plugin à votre liste de plugins Webpack:

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

Utilisez-le comme:

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

4) Utilisez l'objet de fenêtre global (ou global de 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/

Vous verrez ceci couramment utilisé pour les polyfills, par exemple: window.Promise = Bluebird

5) Utilisez un package comme dotenv

(Pour les projets côté serveur) Le package dotenv prendra un fichier de configuration local (que vous pouvez ajouter à votre .gitignore s'il y a des clés / informations d'identification) et ajoute vos variables de configuration à l' objet process.env de Node .

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

Créez un .envfichier dans le répertoire racine de votre projet. Ajoutez des variables spécifiques à l'environnement sur de nouvelles lignes sous la forme de NAME=VALUE. Par exemple:

DB_HOST=localhost
DB_USER=root
DB_PASS=s1mpl3

C'est tout.

process.enva maintenant les clés et les valeurs que vous avez définies dans votre .envfichier.

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

Remarques:

En ce qui concerne les externes de Webpack , utilisez-le si vous souhaitez exclure certains modules d'être inclus dans votre bundle construit. Webpack rendra le module disponible dans le monde entier mais ne le mettra pas dans votre bundle. C'est pratique pour les grandes bibliothèques comme jQuery (car les paquets externes qui secouent les arbres ne fonctionnent pas dans Webpack ) où vous les avez déjà chargés sur votre page dans des balises de script séparées (peut-être à partir d'un CDN).

prograhammer
la source
3
+1. Je restructure une application pour tirer parti de Webpack en tant qu'outil de construction et cela n'a pas fonctionné pour moi au départ car je n'avais inclus aucune référence à mon propre utilsespace de noms dans le fichier cible - au départ, je venais de mettre un point d'arrêt dans le navigateur. fenêtre source et je n'arrêtais pas de me demander pourquoi utilsn'était pas définie. Enfin j'ai découvert que webpack (plutôt intelligemment) ne comprend un module si son espace de noms est référencé au moins une fois. Par conséquent, une fois que j'ai fait la préface de l'une des fonctions utilitaires du fichier cible avec utils, le module a été inclus.
nb1987
Oui, seulement là où vous l'utilisez, cela le rend disponible. J'ai mis cela dans la première ligne de la réponse, mais j'ai fait un léger ajustement, donc peut-être que cela se lit mieux. Merci pour le +1!
prograhammer
1
Notez que ProvidePlugin charge en fait les modules et si vous avez juste besoin d'une variable, cela ne fonctionne pas de cette façon. Utilisez simplement à la externalsplace si vous devez créer une variable globale. Exemple: externals: { 'webpackVariables': `{ serverUrl: '${ env.server }', cordovaBuild: '${ env.cordova }', }`, }, Ensuite, utilisez-le commeconst webpackVariables = require('webpackVariables');
Brian Haak
1
Et savez-vous comment puis-je utiliser cette approche avec TypeScript? Là, si vous utilisez une variable non déclarée, cela génère une erreur ...
knaos
2
@prograhammer En fait, j'ai déjà trouvé la solution. À la racine de votre application, généralement là où se trouve votre tsconfig.json , vous devez ajouter un fichier de définition nommé global.d.ts . Vous pouvez y déclarer des variables globales, comme ceci: declare const isProduction: bool;Pour référence, consultez typescriptlang.org/docs/handbook/declaration-files/templates
...
45

J'étais sur le point de poser la même question. Après avoir cherché un peu plus loin et déchiffré une partie de la documentation de Webpack, je pense que ce que vous voulez, c'est le output.libraryet output.libraryTargetdans le webpack.config.jsfichier.

Par exemple:

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

Maintenant, si vous liez le www/js/index.jsfichier généré dans une balise de script html, vous pouvez accéder à myLibrary.foopartir de n'importe où dans vos autres scripts.

OriolBG
la source
3
Je pense que cela manque export { foo }dans le index.js?
LondonAppDev
myLibrary donne undefined dans un autre fichier dans mon cas. Pouvez-vous s'il vous plaît m'aider
RVCoder
17

Utilisez DefinePlugin .

Le DefinePlugin vous permet de créer des constantes globales qui peuvent être configurées au moment de la compilation.

new webpack.DefinePlugin(definitions)

Exemple:

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

Usage:

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

Vous pouvez utiliser define window.myvar = {}. Lorsque vous souhaitez l'utiliser, vous pouvez utiliser commewindow.myvar = 1

Anh Nguyen
la source
Cela ne fonctionne pas avec EMCAScript 6. Produit une erreur avec var window.CKEDITOR_BASEPATH = {};Erreur est "Jeton inattendu" aprèswindow.
Routhinator
1
Désolé. Je viens de mettre à jour ma réponse. Vous devez varmot-clé. window.CKEDITOR_BASEPATH = {};
Anh Nguyen
Cela fonctionne, malheureusement, le problème que j'ai est que j'ai besoin qu'il soit chargé dans le paquet avant CKEditor, mais Webpack insiste pour le mettre après, peu importe où je le place dans mes importations / js. : /
Routhinator
2

J'ai résolu ce problème en définissant les variables globales en tant que propriétés statiques sur les classes pour lesquelles elles sont les plus pertinentes. Dans ES5, cela ressemble à ceci:

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