Definir variável global com o webpack

138

É possível definir uma variável global com o webpack para resultar em algo como isto:

var myvar = {};

Todos os exemplos que eu vi estavam usando arquivo externo require("imports?$=jquery!./file.js")

Teneff
fonte

Respostas:

272

Existem várias maneiras de abordar os globais:

1) Coloque suas variáveis ​​em um módulo.

O Webpack avalia os módulos apenas uma vez, para que sua instância permaneça global e faça alterações de módulo para módulo. Portanto, se você criar algo como globals.jsae exportar um objeto de todos os seus globais, poderá import './globals'e ler / gravar nesses globais. Você pode importar para um módulo, fazer alterações no objeto de uma função e importar para outro módulo e ler essas alterações em uma função. Lembre-se também da ordem em que as coisas acontecem. O Webpack primeiro pegará todas as importações e as carregará na ordem em que você começar entry.js. Então ele será executado entry.js. Então, onde você lê / escreve para globais é importante. É do escopo raiz de um módulo ou de uma função chamada posteriormente?

Nota : Se você deseja que a instância seja newsempre, use uma classe ES6 . Tradicionalmente, em JS, você capitaliza classes (em oposição à minúscula para objetos) como
import FooBar from './foo-bar' // <-- Usage: myFooBar = new FooBar()

2) ProvidePlugin do Webpack

Veja como você pode fazê-lo usando o ProvidePlugin do Webpack (que disponibiliza um módulo como variável em todos os módulos e apenas nos módulos em que você realmente o usa). Isso é útil quando você não deseja continuar digitando import Bar from 'foo'repetidamente. Ou você pode trazer em um pacote como jQuery ou lodash tão global aqui (embora você pode dar uma olhada de Webpack Externals ).

Etapa 1) Crie qualquer módulo. Por exemplo, um conjunto global de utilitários seria útil:

utils.js

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

Etapa 2) Alias ​​o módulo e adicione ao 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'
    })
  ]  

}

Agora basta chamar utils.sayHello()qualquer arquivo js e ele deve funcionar. Certifique-se de reiniciar o servidor dev se estiver usando isso com o Webpack.

Nota: Não esqueça de informar o seu interlocutor sobre o global, para que não se queixe. Por exemplo, veja minha resposta para ESLint aqui .

3) Use o DefinePlugin do Webpack

Se você quiser apenas usar const com valores de string para seus globais, adicione este plug-in à sua lista de plug-ins do Webpack:

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

Use-o como:

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

4) Use o objeto de janela global (ou o nó 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/

Você verá isso comumente usado em polyfills, por exemplo: window.Promise = Bluebird

5) Use um pacote como dotenv

(Para projetos do lado do servidor) O pacote dotenv pega um arquivo de configuração local (que você pode adicionar ao seu .gitignore se houver alguma chave / credencial) e adiciona suas variáveis ​​de configuração ao objeto process.env do Node .

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

Crie um .envarquivo no diretório raiz do seu projeto. Adicione variáveis ​​específicas do ambiente em novas linhas na forma de NAME=VALUE. Por exemplo:

DB_HOST=localhost
DB_USER=root
DB_PASS=s1mpl3

É isso aí.

process.envagora tem as chaves e os valores que você definiu no seu .envarquivo.

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

Notas:

Em relação aos externos do Webpack , use-o se desejar excluir alguns módulos da inclusão em seu pacote configurável. O Webpack disponibilizará o módulo globalmente, mas não o colocará em seu pacote. Isso é útil para grandes bibliotecas como o jQuery (porque pacotes externos de agitação de árvore não funcionam no Webpack ), onde você já os carregou em sua página em tags de script separadas (talvez de uma CDN).

programador
fonte
3
+1. Estou reestruturando um aplicativo para alavancar o webpack como uma ferramenta de construção, e isso inicialmente não funcionou para mim porque não havia incluído nenhuma referência ao meu próprio utilsespaço para nome no arquivo de destino - inicialmente, acabei de colocar um ponto de interrupção no navegador janela de origem e eu fiquei intrigado sobre o porquê utilsnão foi definido. Finalmente, descobri que o webpack (de maneira bastante inteligente) inclui apenas um módulo se o seu espaço para nome for referenciado pelo menos uma vez. Portanto, uma vez que eu prefácio uma das funções utilitárias do arquivo de destino utils, o módulo foi incluído.
Nb1987
Sim, apenas onde você o usa, ele o torna disponível. Coloquei isso na primeira linha da resposta, mas fiz um pequeno ajuste para que talvez pareça melhor. Obrigado pelo +1!
prograhammer
1
Observe que o ProvidePlugin realmente carrega módulos e, se você precisar apenas de uma variável, não funciona dessa maneira. Basta usar externalsse você precisar criar uma variável global. Exemplo: externals: { 'webpackVariables': `{ serverUrl: '${ env.server }', cordovaBuild: '${ env.cordova }', }`, }, Em seguida, use-o comoconst webpackVariables = require('webpackVariables');
Brian Haak 26/02
1
E você sabe como posso usar essa abordagem com o TypeScript? Não se você usar uma variável não declarada ele lança um erro ...
knaos
2
@prograhammer Na verdade, eu já encontrei a solução. Na raiz do seu aplicativo, geralmente onde está o seu tsconfig.json , você precisa adicionar um arquivo de definição chamado global.d.ts . Nele, você pode declarar variáveis ​​globais, como esta: declare const isProduction: bool;Para referência, consulte typescriptlang.org/docs/handbook/declaration-files/templates/…
knaos
45

Eu estava prestes a fazer a mesma pergunta. Depois de pesquisar um pouco mais e decyphering parte da documentação do Webpack Eu acho que o que você quer é o output.librarye output.libraryTargetno webpack.config.jsarquivo.

Por exemplo:

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

Agora, se você vincular o www/js/index.jsarquivo gerado em uma tag de script html, poderá acessar myLibrary.foode qualquer lugar em seus outros scripts.

OriolBG
fonte
3
Eu acho que isso está faltando export { foo }no index.js?
LondonAppDev 27/0618
myLibrary dá indefinido em outro arquivo no meu caso. Você pode por favor me ajude
RVCoder
17

Use DefinePlugin .

O DefinePlugin permite criar constantes globais que podem ser configuradas em tempo de compilação.

new webpack.DefinePlugin(definitions)

Exemplo:

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

Uso:

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

Você pode usar define window.myvar = {}. Quando você quiser usá-lo, você pode usar comowindow.myvar = 1

Anh Nguyen
fonte
Isso não funciona com EMCAScript 6. Produz erro com var window.CKEDITOR_BASEPATH = {};erro é "token inesperado" depoiswindow.
Routhinator
1
Desculpe. Acabei de atualizar minha resposta. Você deve varpalavra - chave. window.CKEDITOR_BASEPATH = {};
Anh Nguyen
Isso funciona, infelizmente, o problema que estou tendo é que preciso que ele seja carregado no pacote antes do CKEditor; no entanto, o Webpack insiste em colocá-lo depois, não importa onde eu o coloquei em minhas importações / js. : /
Routhinator
2

Resolvi esse problema definindo as variáveis ​​globais como propriedades estáticas nas classes para as quais elas são mais relevantes. No ES5, fica assim:

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