Babel 6 change la façon dont il exporte par défaut

195

Avant, babel ajoutait la ligne module.exports = exports["default"]. Il ne fait plus cela. Ce que cela signifie, c'est avant que je puisse faire:

var foo = require('./foo');
// use foo

Maintenant, je dois faire ceci:

var foo = require('./foo').default;
// use foo

Pas une grosse affaire (et je suppose que c'est ce que cela aurait dû être tout au long). Le problème est que j'ai beaucoup de code qui dépend de la façon dont les choses fonctionnaient (je peux en convertir la plupart en importations ES6, mais pas en totalité). Quelqu'un peut-il me donner des conseils sur la façon de faire fonctionner l'ancienne méthode sans avoir à passer par mon projet et à résoudre ce problème (ou même des instructions sur la façon d'écrire un codemod pour le faire seraient assez simples).

Merci!

Exemple:

Contribution:

const foo = {}
export default foo

Sortie avec Babel 5

"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
var foo = {};
exports["default"] = foo;
module.exports = exports["default"];

Sortie avec Babel 6 (et le plugin es2015):

"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
var foo = {};
exports["default"] = foo;

Notez que la seule différence dans la sortie est le module.exports = exports["default"].


Éditer

Vous pouvez être intéressé par cet article de blog que j'ai écrit après avoir résolu mon problème spécifique: les malentendus des modules ES6, la mise à niveau de Babel, les larmes et une solution

kentcdodds
la source
Je suis curieux, quels sont les cas où besoin requiresi vous travaillez dans une base de code qui utilise Babel? Il y a de fortes chances qu'il existe d'autres approches qui vous permettraient d'éviter cela de toute façon.
loganfsmyth
J'utilise une fonctionnalité de Webpack qui ne nécessitera pas de code s'il se trouve dans un code mort comme: if (false) { require('./foo') }avec webpack, il serait en fait ignoré, y compris foo.jsdans le bundle résultant.
kentcdodds
Qu'est-ce qui finit par être votre falsebascule là-bas? Si c'est une condition qui est disponible dans votre configuration de webpack, il peut y avoir une autre option.
loganfsmyth
Celui-là aussi m'a mordu. Merci @kentcdodds.
Tyler McGinnis
1
Celui-ci m'a causé des problèmes pendant des heures avant de trouver ce post. J'ai fini par remplacer tout le mien export default {foo, bar}par module.exports = {foo, bar}. J'ai bien aimé la méthode incorrecte qui n'est plus prise en charge.
stumct

Réponses:

90

Vous pouvez également utiliser ce plugin pour récupérer l'ancien exportcomportement.

SimenB
la source
1
Je savais que quelqu'un écrirait un plugin pour tôt ou tard. Merci!
kentcdodds
malheureusement, babel-plugin-add-module-exports ne prend pas (encore) en charge les modules de style amd
zowers
3
J'ai utilisé le babel-plugin-transform-es2015-modules-simple-amd pour résoudre ce même problème dans mon projet qui a des modules AMD
Tom Wayson
Je pense que l'utilisation d'UMD et de ce plugin est la voie à suivre! Merci
electronix384128
Très très utile.
Jovica Aleksic
105

Si vous voulez un comportement d'exportation CommonJS, vous devrez utiliser CommonJS directement (ou utiliser le plugin dans l'autre réponse). Ce comportement a été supprimé car il a causé de la confusion et conduit à une sémantique ES6 non valide, sur laquelle certaines personnes se sont penchées, par exemple

export default {
  a: 'foo'
};

puis

import {a} from './foo';

qui n'est pas valide ES6 mais qui a fonctionné en raison du comportement d'interopérabilité CommonJS que vous décrivez. Malheureusement, la prise en charge des deux cas n'est pas possible, et permettre aux gens d'écrire ES6 non valide est un problème pire que de vous obliger à le faire .default.

L'autre problème était qu'il était inattendu pour les utilisateurs s'ils ajoutaient une exportation nommée à l'avenir, par exemple

export default 4;

puis

require('./mod');
// 4

mais

export default 4;
export var foo = 5;

puis

require('./mod')
// {'default': 4, foo: 5}
loganfsmyth
la source
Je suis d'accord avec vous (et j'ai noté) que le comportement précédent était incorrect, mais ma question était de savoir comment contourner le problème. Je comptais beaucoup sur le comportement incorrect (je n'ai pas réalisé qu'il était incorrect jusqu'à ce matin). Je préférerais ne pas avoir à tout mettre à jour en même temps ...
kentcdodds
Le seul correctif pour obtenir le comportement actuel serait de changer votre code pour utiliser CommonJS directement, ou de rester sur Babel 5 jusqu'à ce que vous ayez le temps de mettre à jour.
loganfsmyth
4
@kentcdodds nous pouvons écrire un chargeur de webpack pour que cela fonctionne (ou un plugin babel). Je suis surpris qu'ils n'en fournissent pas (ou ne
fassent pas
Je suis confus par cela ... si je le fais export default function () {}dans le module A puis import a from 'a'dans le module B, avec Babel 6, ce aserait { default: function () {} }... D'après ce que je peux comprendre d' explorerjs.com/es6/… cela devrait fonctionner et je devrais obtenir l'export fonction en B, pas l'objet.
mamapitufo
@mamapitufo Cela devrait fonctionner, mais il est difficile de dire ce qui ne va pas sans un exemple à regarder. N'hésitez pas à passer par le canal d'assistance de Babel sur Slack si vous souhaitez discuter.
loganfsmyth
33

Pour les auteurs de bibliothèque, vous pourrez peut-être contourner ce problème.

J'ai généralement un point d'entrée index.js, qui est le fichier vers lequel je pointe depuis le champ principal package.json. Il ne fait rien d'autre que de réexporter le point d'entrée réel de la lib:

export { default } from "./components/MyComponent";

Pour contourner le problème babel, j'ai changé cela en une importdéclaration, puis attribue la valeur par défaut à module.exports:

import MyComponent from "./components/MyComponent";
module.exports = MyComponent;

Tous mes autres fichiers restent des modules ES6 purs, sans solution de contournement. Donc, seul le point d'entrée a besoin d'un léger changement :)

Cela fonctionnera pour commonjs nécessite, et aussi pour les importations ES6 car babel ne semble pas avoir abandonné l'interopérabilité inverse (commonjs -> es6). Babel injecte la fonction suivante pour corriger les commonjs:

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 

J'ai passé des heures à lutter contre cela, alors j'espère que cela fera économiser de l'effort à quelqu'un d'autre!

WickyNilliams
la source
Pour une raison quelconque, je n'ai jamais vraiment tourné la tête module.exportset tout export defaultça. Maintenant, nous sommes de retour à la case départ?
windmaomao
@windmaomao que voulez-vous dire? C'est une astuce pour que les utilisateurs de commonjs n'aient pas à le faire require("whatever").default. Si vous n'êtes pas un auteur de bibliothèque, cela n'est probablement pas pertinent
WickyNilliams
1

J'ai eu ce genre de problème. Et voici ma solution:

//src/arithmetic.js

export var operations = {
  add: function (a, b) {
      return a + b;
  },

  subtract: function (a, b) {
      return a - b;
  }
};

//src/main.js

import { operations }  from './arithmetic';

let result = operations.add(1, 1);

console.log(result);
Ihor Pavlyk
la source