175

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

var myvar = {};

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

4

6 回答 6

336

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

  1. 将变量放入模块中。

Webpack 只评估模块一次,因此您的实例保持全局并在模块之间进行更改。因此,如果您创建类似 aglobals.js并导出所有全局变量的对象,那么您可以import './globals'读取/写入这些全局变量。您可以导入一个模块,从一个函数对对象进行更改,然后导入另一个模块并在函数中读取这些更改。还要记住事情发生的顺序。Webpack 将首先获取所有导入并按顺序加载它们,从您的entry.js. 然后它会执行entry.js。所以你在哪里读/写全局变量很重要。它是来自模块的根范围还是在稍后调用的函数中?

配置.js

export default {
    FOO: 'bar'
}

一些文件.js

import CONFIG from './config.js'
console.log(`FOO: ${CONFIG.FOO}`)

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

  1. Webpack 的ProvidePlugin

以下是使用 Webpack 的 ProvidePlugin 的方法(它使模块在每个模块中作为变量可用,并且仅在您实际使用它的那些模块中可用)。当您不想import Bar from 'foo'一次又一次地输入时,这很有用。或者你可以在这里引入一个像 jQuery 或 lodash 这样的包作为全局包(尽管你可以看看 Webpack 的Externals)。

步骤 1) 创建任何模块。例如,一组全局实用程序会很方便:

实用程序.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 的回答

  1. 使用 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");
  1. 使用全局窗口对象(或 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

  1. 使用像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)中将这些加载到页面上。

于 2016-11-04T06:47:15.443 回答
50

我正要问同样的问题。在进一步搜索并解密 webpack 文档的一部分后,我认为您想要的是文件中的output.libraryand 。output.libraryTargetwebpack.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从其他脚本中的任何位置访问。

于 2016-08-26T12:39:59.850 回答
23

使用DefinePlugin

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

new webpack.DefinePlugin(definitions)

例子:

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

用法:

console.log(`Environment is in production: ${PRODUCTION}`);
于 2017-04-20T01:23:51.890 回答
18

您可以使用定义window.myvar = {}。当你想使用它时,你可以使用likewindow.myvar = 1

于 2016-06-28T08:06:45.630 回答
2

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

var Foo = function(){...};
Foo.globalVar = {};
于 2018-09-20T15:35:55.540 回答
1

DefinePlugin 实际上并没有定义任何东西。它的作用是替换捆绑代码中存在的变量。如果您的代码中不存在该变量,则它不会执行任何操作。所以它不会创建全局变量。

为了创建一个全局变量,把它写在你的代码中:

window.MyGlobal = MY_GLOBAL; 

并使用 DefinePlugin 替换MY_GLOBAL一些代码:

new webpack.DefinePlugin({
    'MY_GLOBAL': `'foo'`,
    // or
    'MY_GLOBAL': `Math.random()`,
}),

那么你的输出 JS 会是这样的:

window.MyGlobal = 'foo';
// or
window.MyGlobal = Math.random(); 

MY_GLOBAL在运行时永远不会真正存在,因为它从未被定义。这就是DefinePlugin 有一个误导性名称的原因。

于 2021-06-14T22:51:53.747 回答