Babel 6 muda como exporta o padrão

195

Antes, babel adicionava a linha module.exports = exports["default"]. Não faz mais isso. O que isso significa é antes que eu pudesse fazer:

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

Agora eu tenho que fazer isso:

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

Não é um grande negócio (e acho que é isso que deveria ter sido o tempo todo). O problema é que tenho um monte de código que dependia da maneira como as coisas funcionavam (posso converter a maioria delas em importações do ES6, mas não todas). Alguém pode me dar dicas de como fazer a maneira antiga funcionar sem ter que passar pelo meu projeto e consertar isso (ou até mesmo algumas instruções sobre como escrever um codemod para fazer isso seriam bem lisas).

Obrigado!

Exemplo:

Entrada:

const foo = {}
export default foo

Saída com Babel 5

"use strict";

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

Saída com Babel 6 (e plugin es2015):

"use strict";

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

Observe que a única diferença na saída é a module.exports = exports["default"].


Editar

Você pode estar interessado neste post do blog que escrevi depois de resolver meu problema específico: Entendendo mal os módulos ES6, atualizando o Babel, as lágrimas e uma solução

kentcdodds
fonte
Estou curioso, quais são os casos em requireque você precisa se estiver trabalhando em uma base de código que usa Babel? Provavelmente, existem outras abordagens que permitiriam evitar isso de qualquer maneira.
Loganfsmyth 3/11
Estou aproveitando um recurso do Webpack que não exigirá código se for encontrado em código morto, como: o if (false) { require('./foo') }webpack ignoraria realmente foo.jso pacote resultante.
precisa saber é o seguinte
O que acaba sendo sua falsealternância lá? Se houver uma condição disponível na sua configuração do webpack, pode haver outra opção.
Loganfsmyth 3/11
Este também me mordeu. Obrigado @kentcdodds.
Tyler McGinnis
1
Este me causou problemas por horas antes de encontrar este post. Acabei substituindo todo o meu export default {foo, bar}com module.exports = {foo, bar}. Gostei bastante do método incorreto , que agora não é suportado.
stumct

Respostas:

90

Você também pode usar este plugin para recuperar o exportcomportamento antigo .

SimenB
fonte
1
Eu sabia que alguém iria escrever um plugin para mais cedo ou mais tarde. Obrigado!
kentcdodds
módulos infelizmente babel-plugin-add-module-exportações não suporta AMD-estilo (ainda)
zowers
3
Eu usei o babel-plugin-transformam-es2015-modules-simple-amd para resolver este mesmo problema no meu projeto que tem módulos AMD
Tom Wayson
Eu acho que usando UMD e este plugin é o caminho a seguir! Graças
electronix384128
Muito, muito útil.
Jovica Aleksic
105

Se você deseja um comportamento de exportação do CommonJS, precisará usar o CommonJS diretamente (ou usar o plug-in na outra resposta). Esse comportamento foi removido porque causou confusão e levou a semântica ES6 inválida, na qual algumas pessoas confiaram, por exemplo

export default {
  a: 'foo'
};

e depois

import {a} from './foo';

que é ES6 inválido, mas funcionou devido ao comportamento de interoperabilidade CommonJS que você está descrevendo. Infelizmente, não é possível suportar os dois casos, e permitir que as pessoas escrevam ES6 inválido é um problema pior do que fazer você.default .

O outro problema era que era inesperado para os usuários se eles adicionassem uma exportação nomeada no futuro, por exemplo

export default 4;

então

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

mas

export default 4;
export var foo = 5;

então

require('./mod')
// {'default': 4, foo: 5}
loganfsmyth
fonte
Concordo com você (e observei) que o comportamento anterior estava incorreto, mas minha pergunta era como solucionar o problema. Eu estava confiando muito no comportamento incorreto (não percebi que estava incorreto até esta manhã). Eu preferiria não ter que atualizar tudo de uma vez ...
kentcdodds
A única correção para obter o comportamento atual seria alternar seu código para usar o CommonJS diretamente ou permanecer no Babel 5 até que você tenha tempo para atualizar.
Loganfsmyth 3/11
4
@kentcdodds, podemos escrever um carregador de webpack para manter esse funcionamento (ou um plugin babel). Eu estou surpreso que eles não estão fornecendo um (ou divulgando a mudança mais pesadamente!)
Jamund Ferguson
Estou confuso com isso ... se eu fizer export default function () {}no módulo A e, import a from 'a'em seguida, no módulo B, com Babel 6 aseria { default: function () {} }... Pelo que eu posso entender em explorejs.com/es6/…, isso deve funcionar e eu devo exportar função em B, não o objeto.
Mamapitufo
@mamapitufo Isso deve funcionar, mas é difícil dizer o que há de errado sem um exemplo. Sinta-se à vontade para visitar o canal de suporte de Babel no Slack se quiser conversar.
Loganfsmyth
33

Para os autores da biblioteca, você pode solucionar esse problema.

Normalmente, tenho um ponto de entrada index.js, que é o arquivo para o qual aponto no campo principal package.json. Ele não faz nada além de reexportar o ponto de entrada real da lib:

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

Para solucionar o problema do babel, alterei isso para uma importinstrução e atribua o padrão a module.exports:

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

Todos os meus outros arquivos permanecem como módulos ES6 puros, sem soluções alternativas. Portanto, apenas o ponto de entrada precisa ser ligeiramente alterado :)

Isso funcionará para os requisitos do commonjs e também para as importações do ES6 porque o babel não parece ter descartado a interoperabilidade inversa (commonjs -> es6). Babel injeta a seguinte função para corrigir os commonjs:

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

Passei horas lutando contra isso, então espero que isso poupe o esforço de outra pessoa!

WickyNilliams
fonte
Por alguma razão, eu nunca tive minhas cabeças giradas module.exportse export defaultcoisas assim. Agora estamos de volta à estaca zero?
windmaomao
@windmaomao o que você quer dizer? Esse é um truque para que os usuários do commonjs não precisem require("whatever").default. Se você não é um autor biblioteca, esta é provavelmente irrelevante
WickyNilliams
1

Eu tive esse tipo de problema. E esta é a minha solução:

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