使用webpack定义全局变量


138

是否可以使用webpack定义全局变量以产生如下所示的结果:

var myvar = {};

我看到的所有示例都使用外部文件 require("imports?$=jquery!./file.js")

Answers:


272

有几种方法可以处理全局变量:

1)将变量放入模块中。

Webpack仅对模块进行一次评估,因此您的实例保持全局性,并在模块之间进行更改。因此,如果您创建像a之类的东西globals.js并导出所有全局变量的对象,则可以import './globals'对这些全局变量进行读/写操作。您可以导入一个模块,从功能中对对象进行更改,然后导入另一个模块,并读取功能中的更改。还记得事情发生的顺序。Webpack首先将所有导入并按顺序从您的加载它们entry.js。然后它将执行entry.js。因此,读取/写入全局变量的位置很重要。是从模块的根作用域还是在稍后调用的函数中?

注意:如果您希望实例new每次出现,请使用ES6类。传统上,在JS中,您会大写类(相对于对象的小写字母),例如
import FooBar from './foo-bar' // <-- Usage: myFooBar = new FooBar()

2)的WebPack的ProvidePlugin

这是使用Webpack的ProvidePlugin(将模块作为变量在每个模块中以及仅在实际使用它们的那些模块中可用)提供的方式。当您不想import Bar from 'foo'一次又一次地键入内容时,这很有用。或者,您可以在此处引入像jQuery或lodash这样的全局包(尽管您可以看看Webpack的Externals)。

步骤1)创建任何模块。例如,可以使用一组全局实用程序:

utils.js

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

步骤2)别名模块并添加到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'
    })
  ]  

}

现在只需调用utils.sayHello()任何js文件,它就可以正常工作。如果与Webpack一起使用,请确保重新启动开发服务器。

注意:不要忘了告诉您的linter有关全局的信息,因此它不会抱怨。例如,在此处查看我对ESLint的回答

3)使用Webpack的DefinePlugin

如果只想将const和字符串值用于全局变量,则可以将此插件添加到Webpack插件列表中:

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

像这样使用它:

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

4)使用全局窗口对象(或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/

您将看到通常用于polyfill的内容,例如: window.Promise = Bluebird

5)使用像dotenv这样的包

(对于服务器端项目)dotenv软件包将获取本地配置文件(如果有任何键/凭据,则可以将其添加到.gitignore中),并将配置变量添加到Node的process.env对象中。

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

.env在项目的根目录中创建一个文件。以形式在新行上添加特定于环境的变量NAME=VALUE。例如:

DB_HOST=localhost
DB_USER=root
DB_PASS=s1mpl3

而已。

process.env现在具有您在.env文件中定义的键和值。

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

笔记:

关于Webpack的Externals,如果要排除某些模块不包含在内置包中,请使用它。Webpack将使该模块在全球范围内可用,但不会将其放入您的捆绑包中。这对于jQuery之类的大型库非常方便(因为摇晃外部软件包在Webpack中不起作用),在这些库中,这些库已经以单独的脚本标记(可能是CDN)加载到了页面上。


3
+1。我正在重组一个应用程序以利用webpack作为构建工具,这最初对我不起作用,因为我没有utils在目标文件中包含对我自己的名称空间的任何引用-最初我只是在浏览器的目录中放置了一个断点源代码窗口,我一直在困惑为什么utils未定义。最终我发现,如果webpack 的命名空间至少被引用了一次,则webpack(更聪明地)包括一个模块。因此,一旦我用标记了目标文件的实用程序功能之一utils包括了该模块。
nb1987

是的,只有在使用它的地方,它才可用。我把它放在答案的第一行,但是我做了一点调整,所以也许它读起来更好。感谢您的+1!
prograhammer

1
请注意,ProvidePlugin实际上是加载模块,如果您只需要一个变量,则它不能那样工作。只要使用externals,如果你需要创建一个全局变量来代替。示例:externals: { 'webpackVariables': `{ serverUrl: '${ env.server }', cordovaBuild: '${ env.cordova }', }`, }, 然后将其用作const webpackVariables = require('webpackVariables');
Brian Haak

1
而且您知道如何在TypeScript中使用这种方法吗?在那里,如果您使用未声明的变量,则会引发错误...
knaos

2
@prograhammer实际上,我已经找到了解决方案。在应用程序的根目录(通常是tsconfig.json所在的位置)中,您需要添加一个名为global.d.ts的定义文件。在这里面,你可以声明全局变量,像这样:declare const isProduction: bool;作为参考,看看这个typescriptlang.org/docs/handbook/declaration-files/templates/...
knaos

45

我正要问同样的问题。进一步搜索了一下,decyphering的WebPack的文档的一部分之后,我认为,你想要什么output.library,并output.libraryTarget在在webpack.config.js文件中。

例如:

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

现在,如果您将生成的www/js/index.js文件链接到html脚本标记中,则可以myLibrary.foo从其他脚本中的任何位置进行访问。


3
我认为这是缺少export { foo }index.js吗?
LondonAppDev

在我的情况下,myLibrary在另一个文件中给出了undefined。您能帮我吗
RVCoder

17

使用DefinePlugin

DefinePlugin允许您创建可以在编译时配置的全局常量。

new webpack.DefinePlugin(definitions)

例:

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

用法:

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

14

您可以使用define window.myvar = {}。当您想使用它时,可以使用window.myvar = 1


这不适用于EMCAScript6。var window.CKEDITOR_BASEPATH = {};window.
Routhinator

1
抱歉。我刚刚更新了答案。您应该使用var关键字。 window.CKEDITOR_BASEPATH = {};
Anh Nguyen

可行,不幸的是,我遇到的问题是我需要在CKEditor之前将其加载到捆绑软件中,但是Webpack坚持将其放置在无论我将其放置在import / js中的位置之后。:/
Routhinator

2

我通过将全局变量设置为与它们最相关的类的静态属性来解决了这个问题。在ES5中,它看起来像这样:

var Foo = function(){...};
Foo.globalVar = {};
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.