Как не дать Вавилону перенести "это" в "неопределенное"

РЕДАКТИРОВАТЬ: Это не о толстых стрелах. Это также не о передаче этого в IIFE. Это вопрос, связанный с транспортом.

Итак, я создал простой паб-саб для небольшого приложения, над которым я работаю. Я написал это в ES6, чтобы использовать распространение / отдых и сохранить некоторые головные боли. Я настроил это с помощью npm и глотнул, чтобы пропустить это, но это сводит меня с ума.

Я сделал это библиотекой браузера, но понял, что ее можно использовать где угодно, поэтому решил сделать ее совместимой с 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() {

Возможно, это как-то связано с тем, что Бабель не знает, что это будет, и не переносит это, но есть ли другой способ, которым я могу воспользоваться?

ОБНОВЛЕНИЕ: Проход }((window || module || {}), function() { вместо этого похоже на работу. Я не уверен, что это лучший подход.

2 ответа

Решение

Для Вавилона>= 7.x

Код ES6 имеет два режима обработки:

  • "скрипт" - при загрузке файла через <script> или любой другой стандартный способ загрузки файла ES5
  • "модуль" - когда файл обрабатывается как модуль ES6

В Babel 7.x файлы по умолчанию анализируются как "модуль". Проблема в том, что в модуле ES6 this является undefined тогда как в "script" случай, это варьируется в зависимости от окружающей среды, как window в скрипте браузера или exports в коде CommonJS.

В Babel 7 вам нужно будет указать Babel, какой у вас тип файла, если вы хотите избежать такого поведения. Самый простой вариант - использовать "sourceType" возможность установить sourceType: "unambiguous" в ваших опциях Babel, которые по сути говорят Babel угадывать тип (scripts vs module), основываясь на наличии import а также export заявления. Основным недостатком является то, что технически нормально иметь модуль ES6, который не использует import или же export и они будут неправильно рассматриваться как сценарии. С другой стороны, это действительно не так часто.

Кроме того, вы можете использовать Babel 7's "overrides" возможность установить конкретные файлы в качестве сценариев, например,

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

Любой подход позволяет Babel знать, что некоторые файлы script типы, и, следовательно, не должны иметь this конвертировано в undefined,

Для Вавилона < 7.x

Код ES6 имеет два режима обработки:

  • "скрипт" - при загрузке файла через <script> или любой другой стандартный способ загрузки файла ES5
  • "модуль" - когда файл обрабатывается как модуль ES6

При использовании Babel 6 и babel-preset-es2015 (или Babel 5), Babel по умолчанию предполагает, что файлы, которые он обрабатывает, являются модулями ES6. Проблема в том, что в модуле ES6 this является undefined в то время как в случае "сценария", this варьируется в зависимости от окружающей среды, как window в скрипте браузера или exports в коде CommonJS.

Если вы используете Babel, самый простой вариант - написать свой код без оболочки UMD, а затем связать файл, используя что-то вроде Browserify, чтобы автоматически добавить оболочку UMD для вас. Бабель также обеспечивает babel-plugin-transform-es2015-modules-umd, Оба ориентированы на простоту, поэтому, если вам нужен индивидуальный подход UMD, они могут не подойти вам.

В качестве альтернативы вам нужно было бы явно перечислить все плагины Babel в babel-preset-es2015, убедившись, что исключена обработка модулей 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 с отключенной обработкой модуля.

Предустановка "es2015" по умолчанию упаковывает вывод Babel в оболочку commonJs. Используйте "babel-preset-es2015-script" (вы должны npm install --save babel-preset-es2015-script сначала) вывести на "скрипт" (без модулей). Это наносило ущерб другим библиотекам, которые я упаковывал с помощью Babel.

Предустановка: https://www.npmjs.com/package/babel-preset-es2015-script

Другие вопросы по тегам