简体   繁体   English

使用 webpack 定义全局变量

[英]Define global variable with webpack

Is it possible to define a global variable with webpack to result something like this:是否可以用 webpack 定义一个全局变量来产生这样的结果:

var myvar = {};

All of the examples I saw were using external file require("imports?$=jquery!./file.js")我看到的所有示例都使用外部文件require("imports?$=jquery!./file.js")

There are several way to approach globals:有几种方法可以处理全局变量:

  1. Put your variables in a module.把你的变量放在一个模块中。

Webpack evaluates modules only once, so your instance remains global and carries changes through from module to module. Webpack 只对模块进行一次评估,因此您的实例保持全局并在模块之间进行更改。 So if you create something like a globals.js and export an object of all your globals then you can import './globals' and read/write to these globals.因此,如果您创建类似globals.js并导出所有全局变量的对象,那么您可以import './globals'并读取/写入这些全局变量。 You can import into one module, make changes to the object from a function and import into another module and read those changes in a function.您可以导入一个模块,从一个函数更改对象,然后导入另一个模块并读取函数中的这些更改。 Also remember the order things happen.还要记住事情发生的顺序。 Webpack will first take all the imports and load them up in order starting in your entry.js . Webpack 将首先获取所有导入并从entry.js开始按顺序加载它们。 Then it will execute entry.js .然后它将执行entry.js So where you read/write to globals is important.所以你在哪里读/写全局变量很重要。 Is it from the root scope of a module or in a function called later?它是来自模块的根范围还是在稍后调用的函数中?

config.js配置文件

export default {
    FOO: 'bar'
}

somefile.js一些文件.js

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

Note : If you want the instance to be new each time, then use an ES6 class .注意:如果您希望实例每次都是new ,请使用ES6 类 Traditionally in JS you would capitalize classes (as opposed to the lowercase for objects) like传统上,在 JS 中,您会大写类(而不是小写的对象),例如
import FooBar from './foo-bar' // <-- Usage: myFooBar = new FooBar()

  1. Webpack's ProvidePlugin的WebPack的ProvidePlugin

Here's how you can do it using Webpack's ProvidePlugin (which makes a module available as a variable in every module and only those modules where you actually use it).以下是如何使用 Webpack 的 ProvidePlugin(它使模块可用作每个模块中的变量,并且仅在您实际使用它的那些模块中可用)。 This is useful when you don't want to keep typing import Bar from 'foo' again and again.当您不想一次又一次地输入import Bar from 'foo'时,这很有用。 Or you can bring in a package like jQuery or lodash as global here (although you might take a look at Webpack's Externals ).或者,您可以在此处引入像 jQuery 或 lodash 这样的全局包(尽管您可能会查看 Webpack 的Externals )。

Step 1) Create any module.步骤 1) 创建任何模块。 For example, a global set of utilities would be handy:例如,一组全局实用程序会很方便:

utils.js实用程序.js

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

Step 2) Alias the module and add to ProvidePlugin:步骤 2) 为模块添加别名并添加到 ProvidePlugin:

webpack.config.js 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'
    })
  ]  

}

Now just call utils.sayHello() in any js file and it should work.现在只需在任何 js 文件中调用utils.sayHello()就可以了。 Make sure you restart your dev-server if you are using that with Webpack.如果您在 Webpack 中使用它,请确保重新启动您的开发服务器。

Note: Don't forget to tell your linter about the global, so it won't complain.注意:不要忘记告诉你的 linter 关于全局,这样它就不会抱怨。 For example, see my answer for ESLint here .例如,请在此处查看我对 ESLint 的回答

  1. Use Webpack's DefinePlugin使用 Webpack 的DefinePlugin

If you just want to use const with string values for your globals, then you can add this plugin to your list of Webpack plugins:如果您只想将 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")
})

Use it like:像这样使用它:

console.log("Running App version " + VERSION);
if(!BROWSER_SUPPORTS_HTML5) require("html5shiv");
  1. Use the global window object (or Node's global)使用全局窗口对象(或 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/

You'll see this commonly used for polyfills, for example: window.Promise = Bluebird你会看到这通常用于 polyfills,例如: window.Promise = Bluebird

  1. Use a package like dotenv使用像dotenv这样的包

(For server side projects) The dotenv package will take a local configuration file (which you could add to your .gitignore if there are any keys/credentials) and adds your configuration variables to Node's process.env object. (对于服务器端项目) dotenv 包将采用本地配置文件(如果有任何密钥/凭据,您可以将其添加到 .gitignore 中)并将您的配置变量添加到 Node 的process.env对象。

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

Create a .env file in the root directory of your project.在项目的根目录中创建一个.env文件。 Add environment-specific variables on new lines in the form of NAME=VALUE .NAME=VALUE的形式在新行上添加特定于环境的变量。 For example:例如:

DB_HOST=localhost
DB_USER=root
DB_PASS=s1mpl3

That's it.就是这样。

process.env now has the keys and values you defined in your .env file. process.env现在具有您在.env文件中定义的键和值。

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

Notes:笔记:

Regarding Webpack's Externals , use it if you want to exclude some modules from being included in your built bundle.关于 Webpack 的Externals ,如果您想从构建的包中排除某些模块,请使用它。 Webpack will make the module globally available but won't put it in your bundle. Webpack 将使模块全局可用,但不会将其放入您的包中。 This is handy for big libraries like jQuery (because tree shaking external packages doesn't work in Webpack ) where you have these loaded on your page already in separate script tags (perhaps from a CDN).这对于像 jQuery 这样的大型库很方便(因为摇树外部包在 Webpack 中不起作用),在这些库中,您已经在单独的脚本标签(可能来自 CDN)中将这些加载到页面上。

I was about to ask the very same question.我正要问同样的问题。 After searching a bit further and decyphering part of webpack's documentation I think that what you want is the output.library and output.libraryTarget in the webpack.config.js file.在进一步搜索并解密 webpack 文档的一部分后,我认为您想要的是webpack.config.js文件output.libraryTargetoutput.libraryoutput.libraryTarget

For example:例如:

js/index.js: js/index.js:

var foo = 3;
var bar = true;

webpack.config.js webpack.config.js

module.exports = {
   ...
   entry: './js/index.js',
   output: {
      path: './www/js/',
      filename: 'index.js',
      library: 'myLibrary',
      libraryTarget: 'var'
   ...
}

Now if you link the generated www/js/index.js file in a html script tag you can access to myLibrary.foo from anywhere in your other scripts.现在,如果您将生成的www/js/index.js文件链接到 html 脚本标记中,您可以从其他脚本中的任何位置访问myLibrary.foo

Use DefinePlugin .使用定义插件

The DefinePlugin allows you to create global constants which can be configured at compile time. DefinePlugin 允许您创建可以在编译时配置的全局常量。

new webpack.DefinePlugin(definitions)

Example:例子:

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

Usage:用法:

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

You can use define window.myvar = {} .您可以使用定义window.myvar = {} When you want to use it, you can use like window.myvar = 1当你想使用它时,你可以使用 like window.myvar = 1

I solved this issue by setting the global variables as a static properties on the classes to which they are most relevant.我通过将全局变量设置为与它们最相关的类的静态属性来解决这个问题。 In ES5 it looks like this:在 ES5 中,它看起来像这样:

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

DefinePlugin doesn't actually define anything. DefinePlugin 实际上并没有定义任何东西。 What it does is replace variables that exist in your bundle code.它所做的是替换包代码中存在的变量。 If the variable doesn't exist in your code, it will do nothing.如果您的代码中不存在该变量,则它什么也不做。 So it doesn't create global variables.所以它不会创建全局变量。

In order to create a global variable, write it in your code:为了创建一个全局变量,将它写在你的代码中:

window.MyGlobal = MY_GLOBAL; 

And use DefinePlugin to replace MY_GLOBAL with some code:并使用 DefinePlugin 用一些代码替换MY_GLOBAL

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

Then your output JS will be like this:那么你的输出 JS 将是这样的:

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

But MY_GLOBAL will never actually exist at runtime, because it is never defined.但是MY_GLOBAL永远不会在运行时实际存在,因为它永远不会被定义。 So that's why DefinePlugin has a misleading name.所以这就是 DefinePlugin 有一个误导性名称的原因。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM