Zdefiniuj zmienną globalną za pomocą pakietu internetowego

138

Czy można zdefiniować zmienną globalną za pomocą pakietu webpack, aby uzyskać coś takiego:

var myvar = {};

Wszystkie przykłady, które widziałem, używały pliku zewnętrznego require("imports?$=jquery!./file.js")

Teneff
źródło

Odpowiedzi:

272

Istnieje kilka sposobów podejścia do globalnych:

1) Umieść swoje zmienne w module.

Webpack ocenia moduły tylko raz, więc Twoja instancja pozostaje globalna i przenosi zmiany z modułu na moduł. Więc jeśli utworzysz coś takiego jak a globals.jsi wyeksportujesz obiekt ze wszystkich swoich globalnych, możesz import './globals'i czytać / zapisywać w tych globalnych. Możesz importować do jednego modułu, wprowadzać zmiany w obiekcie z funkcji i importować do innego modułu i odczytywać te zmiany w funkcji. Pamiętaj również o kolejności rzeczy. Webpack najpierw pobierze wszystkie importy i załaduje je, aby rozpocząć w Twoim entry.js. Wtedy to się wykona entry.js. Dlatego ważne jest, gdzie czytasz / piszesz do globali. Czy pochodzi z głównego zakresu modułu, czy z funkcji wywoływanej później?

Uwaga : jeśli chcesz, aby instancja występowała za newkażdym razem, użyj klasy ES6 . Tradycyjnie w JS można zapisywać klasy z wielkich liter (w przeciwieństwie do małych liter w przypadku obiektów), jak
import FooBar from './foo-bar' // <-- Usage: myFooBar = new FooBar()

2) ProvidePlugin pakietu Webpack

Oto, jak możesz to zrobić za pomocą ProvidePlugin Webpacka (który udostępnia moduł jako zmienną w każdym module i tylko w tych modułach, w których faktycznie go używasz). Jest to przydatne, gdy nie chcesz ciągle pisać import Bar from 'foo'. Możesz też przynieść pakiet taki jak jQuery lub lodash jako globalny tutaj (chociaż możesz rzucić okiem na zewnętrzne elementy Webpack ).

Krok 1) Utwórz dowolny moduł. Na przykład przydałby się globalny zestaw narzędzi:

utils.js

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

Krok 2) Utwórz alias moduł i dodaj do 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'
    })
  ]  

}

Teraz po prostu wywołaj utils.sayHello()dowolny plik js i powinno działać. Upewnij się, że zrestartowałeś swój dev-server, jeśli używasz go z Webpack.

Uwaga: nie zapomnij powiedzieć linterowi o globalnym, aby nie narzekał. Na przykład zobacz moją odpowiedź dla ESLint tutaj .

3) Użyj wtyczki DefinePlugin Webpack

Jeśli chcesz po prostu użyć const z wartościami ciągów dla twoich globali, możesz dodać tę wtyczkę do swojej listy wtyczek Webpack:

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

Używaj go jak:

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

4) Użyj globalnego obiektu okna (lub globalnego obiektu 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/

Zobaczysz to często używane w przypadku wypełniaczy, na przykład: window.Promise = Bluebird

5) Użyj pakietu takiego jak dotenv

(Dla projektów po stronie serwera) Pakiet dotenv weźmie lokalny plik konfiguracyjny (który możesz dodać do swojego .gitignore, jeśli są jakieś klucze / poświadczenia) i doda twoje zmienne konfiguracyjne do obiektu process.env Node .

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

Utwórz .envplik w katalogu głównym projektu. Dodaj zmienne specyficzne dla środowiska w nowych wierszach w postaci NAME=VALUE. Na przykład:

DB_HOST=localhost
DB_USER=root
DB_PASS=s1mpl3

Otóż ​​to.

process.envma teraz klucze i wartości zdefiniowane w .envpliku.

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

Uwagi:

Jeśli chodzi o zewnętrzne elementy Webpacka , użyj go, jeśli chcesz wykluczyć niektóre moduły z wbudowanego pakietu. Webpack sprawi, że moduł będzie dostępny globalnie, ale nie umieści go w pakiecie. Jest to przydatne dla dużych bibliotek, takich jak jQuery (ponieważ zewnętrzne pakiety wstrząsające drzewem nie działają w Webpack ), w których masz je już załadowane na swojej stronie w osobnych tagach skryptów (być może z CDN).

prograhammer
źródło
3
+1. Zmieniam strukturę aplikacji, aby wykorzystać pakiet WebPack jako narzędzie do kompilacji i początkowo nie działało to dla mnie, ponieważ nie umieściłem żadnego odniesienia do mojej własnej utilsprzestrzeni nazw w pliku docelowym - początkowo po prostu wstawiłem punkt przerwania w przeglądarce okno źródłowe i ciągle zastanawiałem się, dlaczego utilsnie zostało zdefiniowane. Wreszcie odkryłem, że WebPACK (raczej elegancko) tylko zawiera moduł jeśli jego nazw odwołuje się co najmniej raz. Dlatego też, gdy poprzedziłem jedną z funkcji narzędziowych pliku docelowego utils, moduł został dołączony.
nb1987
Tak, tylko tam, gdzie go używasz, udostępnia. Umieściłem to w pierwszym wierszu odpowiedzi, ale dokonałem niewielkiej korekty, więc może lepiej czyta. Dzięki za +1!
prograhammer
1
Zauważ, że ProvidePlugin faktycznie ładuje moduły i jeśli potrzebujesz tylko zmiennej, to nie działa w ten sposób. Po prostu użyj externalszamiast tego, jeśli chcesz utworzyć zmienną globalną. Przykład: externals: { 'webpackVariables': `{ serverUrl: '${ env.server }', cordovaBuild: '${ env.cordova }', }`, }, użyj go jakoconst webpackVariables = require('webpackVariables');
Brian Haak
1
Czy wiesz, jak mogę zastosować to podejście w przypadku języka TypeScript? Tam, jeśli użyjesz niezadeklarowanej zmiennej, wyrzuca błąd ...
knaos
2
@prograhammer Właściwie to już znalazłem rozwiązanie. W katalogu głównym aplikacji, zwykle tam, gdzie znajduje się plik tsconfig.json , należy dodać plik definicji o nazwie global.d.ts . W nim można zadeklarować zmienne globalne, jak poniżej: declare const isProduction: bool;Dla porównania, to sprawdzić typescriptlang.org/docs/handbook/declaration-files/templates/...
knaos
45

Właśnie miałem zadać to samo pytanie. Po dalszych poszukiwaniach i rozszyfrowaniu części dokumentacji webpacka myślę, że to czego potrzebujesz to output.libraryi output.libraryTargetw webpack.config.jspliku.

Na przykład:

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

Teraz, jeśli połączysz wygenerowany www/js/index.jsplik w tagu skryptu html, do którego możesz uzyskać dostęp myLibrary.fooz dowolnego miejsca w innych skryptach.

OriolBG
źródło
3
Myślę, że brakuje export { foo }z index.js?
LondonAppDev
myLibrary w moim przypadku daje undefined w innym pliku. Czy możesz mi pomóc
RVCoder
17

Użyj DefinePlugin .

DefinePlugin umożliwia tworzenie stałych globalnych, które można konfigurować w czasie kompilacji.

new webpack.DefinePlugin(definitions)

Przykład:

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

Stosowanie:

console.log(`Environment is in production: ${PRODUCTION}`);
Ricky
źródło
14

Możesz użyć funkcji define window.myvar = {}. Jeśli chcesz go użyć, możesz użyć likewindow.myvar = 1

Anh Nguyen
źródło
To nie działa z EMCAScript 6. Powoduje błąd z var window.CKEDITOR_BASEPATH = {};błędem „Nieoczekiwany token” powindow.
Routhinator
1
Przepraszam. Właśnie zaktualizowałem moją odpowiedź. Powinieneś varsłowo kluczowe. window.CKEDITOR_BASEPATH = {};
Anh Nguyen
To działa, niestety problem, który mam, polega na tym, że muszę go załadować do pakietu przed CKEditorem, jednak Webpack nalega na umieszczenie go bez względu na to, gdzie umieściłem go w moim Import / js. : /
Routhinator
2

Rozwiązałem ten problem, ustawiając zmienne globalne jako statyczne właściwości klas, do których są najbardziej odpowiednie. W ES5 wygląda to tak:

var Foo = function(){...};
Foo.globalVar = {};
pasx
źródło