使用 webpack 定义全局变量

Define global variable with webpack

是否可以用 webpack 定义一个全局变量来产生这样的结果:

var myvar = {};

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

您可以使用定义window.myvar = {}。 想用的时候可以用like window.myvar = 1

我正要问同样的问题。在进一步搜索并解密了 webpack 文档的一部分之后,我认为你想要的是 webpack.config.js 文件中的 output.libraryoutput.libraryTarget

例如:

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

现在,如果您 link 在 html 脚本标签中生成的 www/js/index.js 文件,您可以从其他脚本中的任何位置访问 myLibrary.foo

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


1。将变量放入模块中。

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

config.js

export default {
    FOO: 'bar'
}

somefile.js

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

注意:如果你希望实例每次都是new,那么使用一个ES6 class。传统上,在 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'
    })
  ]  

}

现在只要在任何 js 文件中调用 utils.sayHello() 就可以了。如果您将开发服务器与 Webpack 一起使用,请确保重启您的开发服务器。

注意:不要忘记告诉你的 linter 关于全局的,所以它不会抱怨。比如看我的.


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。使用全局 window 对象(或 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 keys/credentials)并将你的配置变量添加到 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 这样的大型库来说很方便(因为 tree shaking 外部包 在 Webpack 中不起作用),你已经在单独的脚本标签中将它们加载到你的页面上(也许来自 CDN)。

使用DefinePlugin.

The DefinePlugin allows you to create global constants which can be configured at compile time.

new webpack.DefinePlugin(definitions)

示例:

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

用法:

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

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

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

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 有一个误导性的名字。