NodeJS中全局变量无法正常工作

3

我正在尝试在node.js中使用全局变量,但似乎我并不真正理解这个概念,即使我的理解与文档相符。

最小示例

我的main.js文件,使用rollup编译:

global.a = 1;
require('./core/test.js');

core/test.js 文件只是这样的:

console.log(a);

这导致了错误:

未捕获的引用错误:a未定义

完全编译输出为:
(function (exports) {
'use strict';

var commonjsGlobal = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};

console.log(a);

commonjsGlobal.a = 1;

}((this.LaravelElixirBundle = this.LaravelElixirBundle || {})));
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjpudWxsLCJzb3VyY2VzIjpbIkM6L3dhbXAvd3d3L3V1YmMvcmVzb3VyY2VzL2Fzc2V0cy9qcy9jb3JlL3Rlc3QuanMiLCJDOi93YW1wL3d3dy91dWJjL3Jlc291cmNlcy9hc3NldHMvanMvYXBwLmpzIl0sInNvdXJjZXNDb250ZW50IjpbImNvbnNvbGUubG9nKGEpO1xyXG4iLCJnbG9iYWwuYSA9IDE7XHJcbnJlcXVpcmUoJy4vY29yZS90ZXN0LmpzJyk7XHJcbiJdLCJuYW1lcyI6WyJnbG9iYWwiXSwibWFwcGluZ3MiOiI7Ozs7O0FBQUEsT0FBTyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQzs7QUNBZkEsY0FBTSxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUM7OyJ9

似乎aconsole.log(a);之后才被定义。我不确定这在JS中是否重要,但可能会导致错误。
我的问题是:是什么导致了这个问题,我在这里做错了什么?
可能相关的信息:我正在使用Laravel Elixir编译所有内容。
注:请不要讨论是否在node.js或通常情况下使用全局变量。我知道这通常是一个坏主意,但在这种情况下我有一个非常好的理由这样做。
编辑:额外的上下文
我真正想做的是通过node.js使Zurb Foundation与Laravel Elixir配合使用。我通过NPM安装了foundation-sitesfoundation-sites依赖于jquery,它自己拉取。然而,Foundation似乎没有遵循像在自己的js文件中只使用var jquery = require('jquery');这样的惯例。它实际上依赖于全局jQuery变量可用。因此,我必须确保某种方式。
我的实际文件看起来像这样:
global.jQuery = global.$ = require('jquery');
require('foundation-sites');

所以如果有任何与Foundation/Laravel相关的答案,我会非常乐意听取。是我没有理解到位,还是Foundation只是没有以“正确”的方式创建他们的包?


@T.J.Crowder 好的,已经编辑到底部了。 - Wouter Florijn
似乎全局变量只是另一个对象,恰好被命名为“global”。如果您在其中放置了某些内容:global.a = 1,那么您应该能够通过console.log(global.a)将其取出。 - Kokodoko
@Kokodoko:不是的。NodeJS 为了这个目的而定义了global - T.J. Crowder
5个回答

4

我觉得这可能是您的捆绑器没有尊重您执行这两行代码的顺序所导致的问题。您的源代码显然是:

global.a = 1;
require('./core/test.js');

...但捆绑的结果显然是相反的:

console.log(a);
commonjsGlobal.a = 1;

似乎它将require调用提升了。通常,需要在执行控制流的特定点进行require调用不是最佳实践(事实上,在为ES2015定义模块时,明确指定import不会在模块的逐步控制流中执行)。
因此,如果您需要这样做,您可能需要查看另一个打包程序。但请检查它是否支持除依赖关系解析顺序以外的其他顺序。

这正是我所想的。你有文档链接吗?说明import明确定义为不在模块的逐步控制流中执行吗? - Wouter Florijn
顺便说一下,我在问题中添加了一些额外的上下文。也许你对此更了解? - Wouter Florijn

3

您说得对,它应该可以工作。这是一个可行的例子:

// file1.js
global.a = 'hello';
require('./file2');

// file2.js
console.log(a);

运行node file1.js,你会在控制台中看到打印出'hello'
看起来你正在使用其他工具(Laravel / Elixir)。直接使用node看看会发生什么。

0

好的,我用browserify代替rollup解决了这个问题。感谢其他答案指引我正确的方向。虽然这不是一个完美的解决方案,而且我仍然不完全理解两者之间的区别,但对于这个项目来说已经足够了。

我的gulpfile相关部分:

mix.browserify('app.js','public/js/app.js');

要在 Laravel Elixir 中使用 browserify,我使用了以下方法:

npm install laravel-elixir-browserify-official --save-dev

0

我通过提供一个设置所需变量的output.intro来解决了rollup的问题。在你的情况下,这将是:

// rollup.config.js
export default {
  // ...
  output: {
    // ...
    intro: `let a = 1;`
  }
};

诚然,这算是一种黑客方式,但在我的情况下解决了捆绑问题(转换到其他选项不可行)。


0

同样的问题,仅在使用 import 时。我这样解决了这个问题:

// main.js
import './globals.js';
import './file.js';

// globals.js
global.a = 123;

// file.js
console.log(a);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接