Babel 6 cambia la forma en que exporta el valor predeterminado

195

Antes, Babel agregaba la línea module.exports = exports["default"]. Ya no hace esto. Lo que esto significa es antes de que pueda hacer:

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

Ahora tengo que hacer esto:

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

No es un gran problema (y supongo que esto es lo que debería haber sido todo el tiempo). El problema es que tengo mucho código que depende de la forma en que funcionaban las cosas (puedo convertir la mayor parte a importaciones de ES6, pero no todas). ¿Alguien puede darme consejos sobre cómo hacer que la vieja forma funcione sin tener que pasar por mi proyecto y arreglar esto (o incluso alguna instrucción sobre cómo escribir un codemod para hacer esto sería bastante ingenioso).

¡Gracias!

Ejemplo:

Entrada:

const foo = {}
export default foo

Salida con Babel 5

"use strict";

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

Salida con Babel 6 (y el complemento es2015):

"use strict";

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

Tenga en cuenta que la única diferencia en la salida es el module.exports = exports["default"].


Editar

Puede que le interese esta publicación de blog que escribí después de resolver mi problema específico: malentendidos módulos ES6, actualización de Babel, lágrimas y una solución

kentcdodds
fuente
Tengo curiosidad, ¿cuáles son los casos donde se necesita requiresi está trabajando en una base de código que usa Babel? Lo más probable es que haya otros enfoques que le permitan evitar eso de todos modos.
loganfsmyth
Estoy aprovechando una característica de Webpack que no requerirá código si se encuentra en un código muerto como: if (false) { require('./foo') }con webpack omitiría realmente incluirlo foo.jsen el paquete resultante.
kentcdodds 03 de
¿Qué termina siendo tu falsepalanca allí? Si es una condición que está disponible en su configuración de paquete web, puede haber otra opción.
loganfsmyth
Este también me mordió. Gracias @kentcdodds.
Tyler McGinnis
1
Este me causó problemas durante horas antes de encontrar esta publicación. Terminé reemplazando todo mi export default {foo, bar}con module.exports = {foo, bar}. Me gustó bastante el método incorrecto que ahora no es compatible.
stumct

Respuestas:

90

También puede usar este complemento para recuperar el exportcomportamiento anterior.

SimenB
fuente
1
Sabía que alguien escribiría un complemento para tarde o temprano. ¡Gracias!
kentcdodds
módulos tristemente babel-plugin-add-módulo de exportaciones no es compatible con AMD-estilo (todavía)
zowers
3
He usado babel-plugin-transform-es2015-modules-simple-amd para resolver este mismo problema en mi proyecto que tiene módulos AMD
Tom Wayson
¡Creo que usar UMD y este complemento es el camino a seguir! Gracias
electronix384128
Muy muy útil
Jovica Aleksic
105

Si desea un comportamiento de exportación de CommonJS, deberá usar CommonJS directamente (o usar el complemento en la otra respuesta). Este comportamiento se eliminó porque causó confusión y condujo a una semántica ES6 no válida, en la que algunas personas habían confiado, por ejemplo

export default {
  a: 'foo'
};

y entonces

import {a} from './foo';

que es ES6 no válido pero funcionó debido al comportamiento de interoperabilidad de CommonJS que está describiendo. Desafortunadamente, no es posible admitir ambos casos, y permitir que las personas escriban ES6 no válidas es un problema peor que obligarlo a hacerlo.default .

El otro problema era que era inesperado para los usuarios si agregaban una exportación con nombre en el futuro, por ejemplo

export default 4;

luego

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

pero

export default 4;
export var foo = 5;

luego

require('./mod')
// {'default': 4, foo: 5}
loganfsmyth
fuente
Estoy de acuerdo con usted (y noté) que el comportamiento anterior era incorrecto, pero mi pregunta era cómo solucionar el problema. Estaba confiando mucho en el comportamiento incorrecto (no me di cuenta de que era incorrecto hasta esta mañana). Preferiría no tener que actualizar todo de una vez ...
kentcdodds 03 de
La única solución para obtener el comportamiento actual sería cambiar su código para usar CommonJS directamente o permanecer en Babel 5 hasta que tenga tiempo para actualizar.
loganfsmyth
44
@kentcdodds podemos escribir un cargador de paquetes web para mantenerlo funcionando (o un complemento de babel). Me sorprende que no están proporcionando una (o dar a conocer el cambio en mayor medida!)
Jamund Ferguson
Estoy confundido por esto ... si lo hago export default function () {}en el módulo A y luego import a from 'a'en el módulo B, con Babel 6 asería { default: function () {} }... Por lo que puedo entender de explorejs.com/es6/... esto debería funcionar y debería exportarlo funcionan en B, no en el objeto.
mamapitufo
@mamapitufo Eso debería funcionar, pero es difícil decir qué está mal sin un ejemplo para mirar. No dude en visitar el canal de soporte de Babel en Slack si desea chatear.
loganfsmyth
33

Para los autores de la biblioteca, puede solucionar este problema.

Por lo general, tengo un punto de entrada index.js, que es el archivo al que apunto desde el campo principal package.json. No hace nada más que reexportar el punto de entrada real de la lib:

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

Para solucionar el problema de babel, cambié esto a una importdeclaración y luego asigné el valor predeterminado a module.exports:

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

Todos mis otros archivos permanecen como módulos ES6 puros, sin soluciones. Entonces, solo el punto de entrada necesita un cambio ligeramente :)

Esto funcionará para los requisitos de commonjs, y también para las importaciones de ES6 porque babel no parece haber eliminado la interoperabilidad inversa (commonjs -> es6). Babel inyecta la siguiente función para parchear commonjs:

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

¡He pasado horas luchando contra esto, así que espero que esto le ahorre el esfuerzo a otra persona!

WickyNilliams
fuente
Por alguna razón, nunca me dieron vueltas module.exportsy eso export default. ¿Ahora volvemos al punto de partida?
windmaomao
@windmaomao, ¿qué quieres decir? Este es un truco para que los usuarios de commonjs no tengan que hacerlo require("whatever").default. Si no eres autor de una biblioteca, esto probablemente sea irrelevante
WickyNilliams
1

He tenido ese tipo de problema. Y esta es mi solución:

//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
fuente