使用webpack定义全局变量

时间:2016-06-06 11:44:54

标签: javascript webpack webpack-2 webpack-3

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

var myvar = {};

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

6 个答案:

答案 0 :(得分:194)

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

1)将变量放入模块中。

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

注意:如果您希望每次实例都为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,请确保重新启动您的开发服务器。

注意:不要忘记告诉你的关于全球的信息,所以它不会抱怨。例如,请参阅我的answer for ESLint here

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/

您会看到这通常用于填充,例如: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,如果要排除某些模块包含在构建的bundle中,请使用它。 Webpack将使该模块在全球范围内可用,但不会将其放入您的捆绑包中。这对于像jQuery这样的大型库(因为树摇动外部包doesn't work in Webpack)非常方便,您可以在页面中加载这些库,这些脚本已经在单独的脚本标记中(可能来自CDN)。

答案 1 :(得分:35)

我正要问同样的问题。在进一步搜索并解密webpack文档的一部分之后,我认为您想要的是output.library文件中的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'
   ...
}

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

答案 2 :(得分:13)

使用DefinePlugin

  

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

@SuppressWarnings("deprecation")
public void actionPerformed(ActionEvent e) { 
    int buttonNumber = 0;
    String buttonName;
    openJob = true;

    JButton myButton = (JButton)e.getSource();

    buttonName = myButton.getLabel();
    buttonNumber = Arrays.asList(jobs).indexOf(buttonName);

    JFrame jobFrame = new JFrame(jobs[buttonNumber]);
    JPanel panel = new JPanel();
    MyButton backButton = new MyButton();
    JTextField field = new JTextField();

    if (Arrays.asList(jobs).contains(buttonName)){      
        jobFrame.getContentPane().setLayout(new FlowLayout());
        backButton.setText("Back");
        field.setText(jobDescription[buttonNumber]);
        field.setEditable(false);

        panel.add(field);
        panel.add(backButton);

        jobFrame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
        jobFrame.getContentPane().add (panel);
        jobFrame.pack();   
        jobFrame.setVisible(true);
        jobFrame.setSize(500, 500);

    }else if(buttonName.contains("Back")){
        jobFrame.setVisible(false);
        System.out.println("This is the back button");
    }
}

实施例

new webpack.DefinePlugin(definitions)

用法:

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

答案 3 :(得分:10)

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

答案 4 :(得分: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 具有误导性名称的原因。

答案 5 :(得分:0)

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

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