使用 webpack 定义全局变量

IT技术 javascript webpack webpack-2 webpack-3
2021-01-12 14:02:18

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

var myvar = {};

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

6个回答

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

  1. 把你的变量放在一个module中。

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

配置文件

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(它使module可用作每个module中的变量,并且仅在您实际使用它的那些module中可用)。当您不想import Bar from 'foo'一次又一次地输入时,这很有用或者,您可以在此处引入像 jQuery 或 lodash 这样的全局包(尽管您可能会查看 Webpack 的Externals)。

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

实用程序.js

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

步骤 2) 为module添加别名并添加到 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/

你会看到这通常用于 polyfills,例如: 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,如果你想从你的构建包中排除一些module,请使用它。Webpack 将使module全局可用,但不会将其放入您的包中。这对于像 jQuery 这样的大型库很方便(因为摇树外部包在 Webpack 中不起作用),在这些库中,您已经在单独的脚本标签(可能来自 CDN)中将这些加载到页面上。

你知道我如何在 TypeScript 中使用这种方法吗?在那里,如果您使用未声明的变量,则会引发错误...
2021-03-14 14:02:18
+1。我正在重新构建一个应用程序以利用 webpack 作为构建工具,这最初对我不起作用,因为我没有utils在目标文件中包含对我自己的命名空间的任何引用- 最初我只是在浏览器中放置了一个断点源窗口,我一直对为什么utils没有定义感到困惑最后我发现 webpack(相当聪明)包含一个module,如果它的命名空间至少被引用一次。因此,一旦我以 开头的目标文件的实用程序功能之一utils,该module就被包含在内。
2021-03-15 14:02:18
@programhammer 实际上,我已经找到了解决方案。在您的应用程序的根目录中,通常是您的tsconfig.json所在的位置,您需要添加一个名为global.d.ts的定义文件您可以在其中声明全局变量,如下所示:declare const isProduction: bool;作为参考,请查看typescriptlang.org/docs/handbook/declaration-files/templates/...
2021-03-23 14:02:18
请注意,ProvidePlugin 实际上加载module,如果您只需要一个变量,它就不会那样工作。只要使用externals,如果你需要创建一个全局变量来代替。示例:externals: { 'webpackVariables': `{ serverUrl: '${ env.server }', cordovaBuild: '${ env.cordova }', }`, }, 然后将其用作const webpackVariables = require('webpackVariables');
2021-03-26 14:02:18
是的,只有在您使用它的地方,它才能使它可用。我把它放在答案的第一行,但我做了一点调整,所以也许它读起来更好。感谢您的 +1!
2021-04-09 14:02:18

我正要问同样的问题。进一步搜索了一下,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从其他脚本中的任何位置访问

在我的情况下,myLibrary 在另一个文件中给出了 undefined 。你能帮我么
2021-03-14 14:02:18
我认为这是export { foo }index.js?
2021-03-19 14:02:18

使用定义插件

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

new webpack.DefinePlugin(definitions)

例子:

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

用法:

console.log(`Environment is in production: ${PRODUCTION}`);
DefinePlugin 具有欺骗性。它不会创建全局变量。相反,它用其他代码字符串替换代码字符串,并且它只对您的包进行操作。因此,对于需要真实window.*变量(例如外部脚本)的人来说,DefinePlugin 将不起作用。
2021-04-02 14:02:18

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

这有效,不幸的是我遇到的问题是我需要在 CKEditor 之前将它加载到包中,但是 Webpack 坚持将它放在之后,无论我将它放在我的导入/js 中的什么位置。:/
2021-03-19 14:02:18
这不适用于 EMCAScript 6。在之后产生var window.CKEDITOR_BASEPATH = {};错误为“Unexpected Token”window.
2021-03-27 14:02:18
对不起。我刚刚更新了我的答案。你应该var关键字。 window.CKEDITOR_BASEPATH = {};
2021-03-27 14:02:18

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

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