web-dev-qa-db-fra.com

Comment empêcher babel de transpiler «this» en «undefined» (et en insérant «use strict»)

MODIFIER : Il s'agit pas de grosses flèches. Il ne s'agit pas non plus de passer ceci à un IIFE . C'est une question liée au transpilateur.

J'ai donc créé un sous-pub simple pour une petite application sur laquelle je travaille. Je l'ai écrit dans ES6 pour utiliser spread/rest et éviter quelques maux de tête. Je l'ai installé avec npm et gulp pour le transpiler mais ça me rend fou.

J'en ai fait une bibliothèque de navigateur mais j'ai réalisé qu'elle pouvait être utilisée n'importe où, j'ai donc décidé de la rendre compatible Commonjs et AMD.

Voici une version réduite de mon code:

(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
});

Mais peu importe ce que j'essaye (comme faire cette une variable et la passer), elle la définit undefined .

}(undefined, function() {

Cela a probablement quelque chose à voir avec Babel ne sachant pas ce que cela sera et le transpiler, mais y a-t-il une autre approche que je peux adopter?

UPDATE : En passant }((window || module || {}), function() { au lieu de cela semble travail. Je ne suis pas sûr que ce soit la meilleure approche.

47
JR Halchak

Pour Babel> = 7.x

Le code ES6 a deux modes de traitement:

  • "script" - Lorsque vous chargez un fichier via un <script>, ou tout autre moyen standard ES5 de charger un fichier
  • "module" - Lorsqu'un fichier est traité comme un module ES6

Dans Babel 7.x, les fichiers sont analysés comme "module" par défaut. Ce qui vous pose problème, c'est que dans un module ES6, this est undefined, tandis que dans le "script" cas, cela varie selon l'environnement, comme window dans un script de navigateur ou exports dans le code CommonJS. De même, "module" les fichiers sont automatiquement stricts, Babel insérera donc "use strict";.

Dans Babel 7, vous devrez indiquer à Babel de quel type est votre fichier si vous souhaitez éviter ce comportement. L'option la plus simple serait d'utiliser le "sourceType" option pour définir sourceType: "unambiguous" dans vos options Babel, qui indique essentiellement à Babel de deviner le type (scripts vs module), en fonction de la présence des instructions import et export. Le principal inconvénient étant qu'il est techniquement correct d'avoir un module ES6 qui n'utilise pas import ou export, et ceux-ci seraient traités à tort comme des scripts. D'un autre côté, ce n'est vraiment pas si courant.

Vous pouvez également utiliser Babel 7 "overrides" option pour définir des fichiers spécifiques en tant que scripts, par exemple.

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

L'une ou l'autre approche permet à Babel de savoir que certains fichiers sont de type script et ne devraient donc pas avoir this convertis en undefined.

Pour Babel <7.x

Le code ES6 a deux modes de traitement:

  • "script" - Lorsque vous chargez un fichier via un <script>, ou tout autre moyen standard ES5 de charger un fichier
  • "module" - Lorsqu'un fichier est traité comme un module ES6

Lorsque vous utilisez Babel 6 et babel-preset-es2015 (ou Babel 5), Babel suppose par défaut que les fichiers qu'il traite sont des modules ES6. Ce qui vous pose problème, c'est que dans un module ES6, this est undefined et les fichiers sont tous stricts, tandis que dans le cas "script", this varie selon l'environnement, comme window dans un script de navigateur ou exports dans le code CommonJS.

Si vous utilisez Babel, l'option la plus simple consiste à écrire votre code sans le wrapper UMD, puis à regrouper votre fichier à l'aide de quelque chose comme Browserify pour ajouter automatiquement le wrapper UMD pour vous. Babel fournit également un babel-plugin-transform-es2015-modules-umd. Les deux sont orientés vers la simplicité, donc si vous voulez une approche UMD personnalisée, ils peuvent ne pas être pour vous.

Alternativement, vous devrez lister explicitement tous les plugins Babel dans babel-preset-es2015 , en veillant à exclure le module-processing babel-plugin-transform-es2015-modules-commonjs brancher. Notez que cela arrêtera également l'ajout automatique de use strict puisque cela fait également partie de la spécification ES6, vous voudrez peut-être rajouter babel-plugin-transform-strict-mode pour garder votre code strict automatiquement.

À partir du [email protected] les préréglages peuvent prendre des options, vous pouvez donc

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

dans votre configuration Babel (.babelrc) utiliser babel-preset-es2015 avec le traitement du module désactivé.

60
loganfsmyth

Le préréglage "es2015" encapsule la sortie Babel dans un wrapper commonJs par défaut. Utilisez le "babel-preset-es2015-script" (vous devez npm install --save babel-preset-es2015-script premier) pour sortir pour "script" (pas de modules). Cela faisait des ravages sur d'autres bibliothèques que je terminais en utilisant Babel.

Le préréglage: https://www.npmjs.com/package/babel-preset-es2015-script

2
user2503764