如何阻止 babel 将“this”转换为“undefined”(并插入“use strict”)

IT技术 javascript node.js amd babeljs commonjs
2021-01-19 20:54:17

编辑:这不是关于胖箭头这也是不是通过一个IIFE这是一个与转译器相关的问题。

所以我为我正在开发的一个小应用程序创建了一个简单的 pub-sub。我在 ES6 中编写它以使用传播/休息并省去一些麻烦。我用 npm 和 gulp 设置它来转译它,但它让我发疯。

我把它变成了一个浏览器库,但意识到它可以在任何地方使用,所以我决定让它兼容 Commonjs 和 AMD。

这是我的代码的精简版本:

(function(root, factory) {
 if(typeof define === 'function' && define.amd) {
    define([], function() {
        return (root.simplePubSub = factory())
    });
  } else if(typeof module === 'object' && module.exports) {
    module.exports = (root.simplePubSub = factory())
  } else {
    root.simplePubSub = root.SPS = factory()
  }
}(this, function() {
 // return SimplePubSub
});

但是,不管我什么(如使这个变量和传递),将其设置到未定义

}(undefined, function() {

这可能与 Babel 不知道将是什么并将其转译有关,但是我可以采取其他任何方法吗?

更新:通过}((window || module || {}), function() {而不是这个似乎有效。我不确定这是最好的方法。

2个回答

对于 Babel >= 7.x

ES6 代码有两种处理方式:

  • “脚本” - 当您通过<script>或任何其他标准 ES5 加载文件方式加载文件时
  • "module" - 当文件作为 ES6 module处理时

在 Babel 7.x 中,文件默认被解析为“module”。给您带来麻烦的是,在 ES6 module中,thisis undefined,而在这种"script"情况下,这取决于环境,例如window在浏览器脚本或exportsCommonJS 代码中。类似地,"module"文件是自动严格的,所以 Babel 会插入"use strict";.

在 Babel 7 中,如果你想避免这种行为,你需要告诉 Babel 你的文件是什么类型。最简单的选择是使用"sourceType"设置sourceType: "unambiguous"在 Babel 选项中的选项,它本质上告诉 Babel 根据importandexport语句的存在来猜测类型(脚本与module)主要的缺点是,拥有一个不使用importor的 ES6 module在技术上没有问题export,并且这些module会被错误地视为脚本。另一方面,这真的不那么常见。

或者,您可以使用 Babel 7 的"overrides"选项将特定文件设置为脚本,例如

overrides: [{
  test: "./vendor/something.umd.js",
  sourceType: "script",
}],

这两种方法都允许 Babel 知道某些文件是script类型,因此不应该this转换为undefined.

对于 Babel < 7.x

ES6 代码有两种处理方式:

  • “脚本” - 当您通过<script>或任何其他标准 ES5 加载文件方式加载文件时
  • "module" - 当文件作为 ES6 module处理时

当使用 Babel 6 和babel-preset-es2015(或 Babel 5)时,Babel 默认假设它处理的文件是 ES6 module。也就是造成你麻烦的事情是,一个ES6module中,thisundefined和文件都是严格的,而在“脚本”的情况下,this取决于环境,比如window在浏览器脚本或exports在CommonJS的代码。

如果您使用 Babel,最简单的选择是在没有 UMD 包装器的情况下编写代码,然后使用 Browserify 之类的工具捆绑您的文件,以自动为您添加 UMD 包装器。Babel 还提供了一个babel-plugin-transform-es2015-modules-umd. 两者都面向简单性,因此如果您想要定制的 UMD 方法,它们可能不适合您。

或者,您需要在babel-preset-es2015 中明确列出所有 Babel 插件,确保排除module处理babel-plugin-transform-es2015-modules-commonjs插件。请注意,这也将停止自动添加,use strict因为这也是 ES6 规范的一部分,您可能需要重新添加babel-plugin-transform-strict-mode以自动保持代码严格。

由于babel-core@6.13预设可以采取选项,因此您也可以这样做

{
  "presets": [
    [ "es2015", { "modules": false } ]
  ]
}

在您的 Babel 配置 ( .babelrc) 中使用babel-preset-es2015禁用module处理。

然后使用babel-preset-es2015-script代替babel-preset-es2015babel-preset-es2015-script已排除babel-plugin-transform-es2015-modules-commonjs
2021-03-13 20:54:17
根据 GitHub 页面babel-preset-es2015-script,该module已弃用,您应该改用它: { "presets": [ [ "es2015", { modules: false } ] ] }
2021-03-13 20:54:17
谢谢!这是有道理的。我选择传递所有可能的this,但我可能会根据您的建议重新审视。
2021-03-22 20:54:17
@Daniel 给我一分钟在这里写更新,然后我们可以关闭您的另一个问题作为重复。
2021-03-25 20:54:17
我在尝试导入一个使用 UMD 语法来包装它的module时遇到了这个问题。我遇到的奇怪的事情是,当我使用 npm3 安装依赖项时,一切正常。但是当我不得不突然退回到 npm2 时,当我的部分代码需要我的module时,我发现它未定义
2021-04-03 20:54:17

默认情况下,“es2015”预设将 Babel 输出包装在 commonJs 包装器中。使用“babel-preset-es2015-script”(必须npm install --save babel-preset-es2015-script先)输出“script”(无module)。这对我使用 Babel 打包的其他库造成了严重破坏。

预设:https : //www.npmjs.com/package/babel-preset-es2015-script

请注意,此方法已被弃用:github.com/Collaborne/babel-preset-es2015-script
2021-04-08 20:54:17