Definir variable global con webpack

138

¿Es posible definir una variable global con webpack para obtener algo como esto:

var myvar = {};

Todos los ejemplos que vi estaban usando un archivo externo require("imports?$=jquery!./file.js")

Teneff
fuente

Respuestas:

272

Hay varias formas de acercarse a los globales:

1) Pon tus variables en un módulo.

Webpack evalúa los módulos solo una vez, por lo que su instancia permanece global y lleva los cambios de un módulo a otro. Entonces, si crea algo como a globals.jsy exporta un objeto de todas sus globales, puede import './globals'leer y escribir en estas globales. Puede importar en un módulo, realizar cambios en el objeto desde una función e importar en otro módulo y leer esos cambios en una función. También recuerda el orden en que suceden las cosas. Webpack primero tomará todas las importaciones y las cargará en orden comenzando en su entry.js. Entonces se ejecutará entry.js. Entonces, donde lees / escribes a los globales es importante ¿Es del alcance raíz de un módulo o en una función llamada más tarde?

Nota : Si desea que la instancia sea newcada vez, use una clase ES6 . Tradicionalmente, en JS, se capitalizaban las clases (en lugar de las minúsculas para los objetos) como
import FooBar from './foo-bar' // <-- Usage: myFooBar = new FooBar()

2) ProvidePlugin de Webpack

A continuación, le mostramos cómo puede hacerlo utilizando ProvidePlugin de Webpack (que hace que un módulo esté disponible como variable en cada módulo y solo en aquellos módulos donde realmente lo usa). Esto es útil cuando no desea seguir escribiendo import Bar from 'foo'una y otra vez. O puede traer un paquete como jQuery o lodash como global aquí (aunque puede echar un vistazo a los elementos externos de Webpack ).

Paso 1) Crea cualquier módulo. Por ejemplo, un conjunto global de utilidades sería útil:

utils.js

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

Paso 2) Alias ​​el módulo y agregar a ProvidePlugin:

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

}

Ahora solo llame utils.sayHello()a cualquier archivo js y debería funcionar. Asegúrese de reiniciar su servidor de desarrollo si lo está usando con Webpack.

Nota: No olvides decirle a tu linter sobre lo global, para que no se queje. Por ejemplo, vea mi respuesta para ESLint aquí .

3) Use el DefinePlugin de Webpack

Si solo desea usar const con valores de cadena para sus globales, entonces puede agregar este complemento a su lista de complementos de Webpack:

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

Úselo como:

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

4) Use el objeto de ventana global (o el Nodo global)

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/

Verá esto comúnmente utilizado para polyfills, por ejemplo: window.Promise = Bluebird

5) Use un paquete como dotenv

(Para proyectos del lado del servidor) El paquete dotenv tomará un archivo de configuración local (que podría agregar a su .gitignore si hay claves / credenciales) y agregará sus variables de configuración al objeto process.env de Node .

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

Cree un .envarchivo en el directorio raíz de su proyecto. Agregue variables específicas del entorno en nuevas líneas en forma de NAME=VALUE. Por ejemplo:

DB_HOST=localhost
DB_USER=root
DB_PASS=s1mpl3

Eso es.

process.envahora tiene las claves y los valores que definió en su .envarchivo.

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

Notas:

Con respecto a los elementos externos de Webpack, úselo si desea excluir algunos módulos de su paquete integrado. Webpack hará que el módulo esté disponible globalmente, pero no lo incluirá en su paquete. Esto es útil para grandes bibliotecas como jQuery (porque los paquetes externos de sacudidas de árboles no funcionan en Webpack ) donde ya los ha cargado en su página en etiquetas de script separadas (tal vez de un CDN).

martillo programador
fuente
3
+1. Estoy reestructurando una aplicación para aprovechar el paquete web como herramienta de compilación y esto inicialmente no funcionó para mí porque no había incluido ninguna referencia a mi propio utilsespacio de nombres en el archivo de destino; inicialmente solo había puesto un punto de interrupción en el navegador ventana de origen y seguí pensando por qué utilsno se definió. Finalmente descubrí que webpack (de manera inteligente) solo incluye un módulo si su espacio de nombres se hace referencia al menos una vez. Por lo tanto, una vez que introduje una de las funciones de utilidad del archivo de destino utils, se incluyó el módulo .
nb1987
Sí, solo donde lo usas, lo hace disponible. Puse eso en la primera línea de la respuesta, pero hice un pequeño ajuste, por lo que tal vez se lea mejor. Gracias por el +1!
prograhammer
1
Tenga en cuenta que ProvidePlugin en realidad carga módulos y si solo necesita una variable, no funciona de esa manera. Solo use externalsen su lugar si necesita crear una variable global. Ejemplo: externals: { 'webpackVariables': `{ serverUrl: '${ env.server }', cordovaBuild: '${ env.cordova }', }`, }, luego usarlo comoconst webpackVariables = require('webpackVariables');
Brian Haak
1
¿Y sabes cómo puedo usar este enfoque con TypeScript? Allí, si utiliza una variable no declarada, arroja un error ...
knaos
2
@prograhammer En realidad, ya encontré la solución. En la raíz de su aplicación, generalmente donde está su tsconfig.json , debe agregar un archivo de definición llamado global.d.ts . En ella se puede declarar variables globales, así: declare const isProduction: bool;Como referencia, mira esto typescriptlang.org/docs/handbook/declaration-files/templates/...
knaos
45

Estaba a punto de hacer la misma pregunta. Después de buscar un poco más y descifrar parte de la documentación del paquete web, creo que lo que quieres es el output.libraryy output.libraryTargeten el webpack.config.jsarchivo.

Por ejemplo:

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

Ahora, si vincula el www/js/index.jsarchivo generado en una etiqueta de script html, puede acceder myLibrary.foodesde cualquier otro lugar en sus otros scripts.

OriolBG
fuente
3
Creo que esto falta export { foo }en el index.js?
LondonAppDev
myLibrary da indefinido en otro archivo en mi caso. ¿Puede usted por favor me ayude
RVCoder
17

Use DefinePlugin .

DefinePlugin le permite crear constantes globales que se pueden configurar en tiempo de compilación.

new webpack.DefinePlugin(definitions)

Ejemplo:

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

Uso:

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

Puedes usar define window.myvar = {}. Cuando quieras usarlo, puedes usar comowindow.myvar = 1

Anh Nguyen
fuente
Esto no funciona con EMCAScript 6. Produce un error con var window.CKEDITOR_BASEPATH = {};Error es "Token inesperado" despuéswindow.
Routhinator
1
Lo siento. Acabo de actualizar mi respuesta. Usted debe la varpalabra clave window.CKEDITOR_BASEPATH = {};
Anh Nguyen
Esto funciona, desafortunadamente, el problema que tengo es que necesito que se cargue en el paquete antes de CKEditor, sin embargo, Webpack insiste en ponerlo después, sin importar dónde lo coloque en mis importaciones / js. : /
Routhinator
2

Resolví este problema estableciendo las variables globales como propiedades estáticas en las clases para las que son más relevantes. En ES5 se ve así:

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