javascript - 使用 ES6 模块重新导出全局变量

标签 javascript ecmascript-6

我正在将 JS 脚本迁移到 ES6 模块。客户端代码的一种常见模式是将跟踪信息推送到 window 对象上的全局数组。一个具体的例子是 GTM window.dataLayer 数组。

我想将这些全局变量抽象到 ES6 模块中,而不是使用 /* global dataLayer */ 指示 linter 忽略它们,因为它使代码更容易理解。我的第一次尝试是创建这样的垫片:

export default window.dataLayer;

但是,正如解释的here在“实现 View ”部分,上述代码等同于:

const *default* = window.dataLayer; // *not* legal JavaScript
export { *default* as default };

因此,每个模块中的 window.dataLayer 数组将是原始 window.dataLater 数组的副本:当 GTM 异步引导时,从它不会看到模块,因为只有本地 *default* 才会有这些事件。

使用 ES6 模块处理此类全局变量的推荐方法是什么,它不涉及像使用代理这样的重量级解决方案?在模块化系统中有很多全局变量确实让人感觉很糟糕。

最佳答案

与您在问题中描述的相反,处理此问题的正确方法是:

/* data-layer.js */
window.dataLayer = [];
export default window.dataLayer;

...以及任何需要推送到“dataLayer”数组的模块,只需要像这样的东西:

import dataLayer from 'data-layer';

// ... some code I assume

dataLayer.push({
  'pageCategory': 'signup',
  'visitorType': 'high-value'
});

因为 ES6 导入将只读引用传递给导出,所以它不是您正在导入的数组的副本,而是在 data-layer.js 中创建和导出的数组。

但棘手的部分是,您必须修改 Google 跟踪代码管理器容器代码段,使其不会在加载后立即运行,而是仅在加载完所有脚本后运行可以修改已经运行的dataLayer

如果您要将 GTM Container Snippet 作为一个模块单独加载,您可能需要先导入所有可能会修改数据的脚本(并确保该部分实际运行),然后再导入调用代码段。

类似于:

/* gtm-container.js */
import 'this';
import 'that';
import otherThing from 'the-other-thing'; // lets assume it returns a promise
import dataLayer from 'data-layer'l

otherThing.then(value => {
   invokeSnippet()
})
.catch(err => {
   handleError(err);
});

function invokeSnippet() {
(function(w,d,s,i){dataLayer.push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'//www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','GTM-XXXX')
}

但是,你知道这并不是对如何做到这一点的真正解释,只是一个想法,我不知道可以向数据层添加什么不同的东西,并且因为你正在转向异步模块模式,你将拥有了解异步运行所有这些脚本将如何改变您使用 GTM 系统的方式,清楚地编写该系统是为了使用全局变量同步运行。

我想知道 Google 是否会很快用现代 JavaScript 更新这些东西,或者是否有更模块化的选项可用。

如果您不知道,我应该提一下:

许多(大多数)ES6/ES2015 功能,包括模块,截至今天(2016 年 1 月)在浏览器中不可用,因此您需要某种构建或加载器来制作这些东西在浏览器中工作(比如 webpack、browserify、stealjs、jspm,或者带有 babel 或 tracuer 的东西)

http://stealjs.com/可能是最容易上手的。

关于javascript - 使用 ES6 模块重新导出全局变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34862340/

相关文章:

Javascript表单提交问题

javascript - 从可折叠标题内的按钮调用函数而不展开

Javascript RegExp 量词问题

javascript - 如何从 Firefox 插件在网页中插入图像?

javascript - 引入一个单独的微任务队列的动机是什么,事件循环优先于任务队列?

javascript - 多级菜单

javascript - ES6 javascript 如何处理一系列 async/await 函数中的错误

reactjs - `circle: (null : ?{ setNativeProps(props: Object): void })` 是什么意思

javascript - Firefox 插件面板可以确定何时显示和隐藏吗?

javascript - 提取对单独文件的 ReactDOM.render() 调用