Babel 6 меняет способ экспорта по умолчанию

195

Раньше Бабель добавлял строчку module.exports = exports["default"]. Это больше не делает это. Что это значит, прежде чем я смог сделать:

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

Теперь я должен сделать это:

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

Не огромная сделка (и я предполагаю, что так и должно быть). Проблема в том, что у меня много кода, который зависел от того, как все работало раньше (я могу преобразовать большую часть его в импорт ES6, но не все). Может кто-нибудь дать мне советы о том, как заставить старый способ работать без необходимости проходить через мой проект и исправлять это (или даже некоторую инструкцию о том, как написать codemod, чтобы сделать это, было бы довольно гладко).

Спасибо!

Пример:

Входные данные:

const foo = {}
export default foo

Выход с Вавилоном 5

"use strict";

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

Вывод с Babel 6 (и плагином es2015):

"use strict";

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

Обратите внимание, что единственная разница в выводе - это module.exports = exports["default"].


редактировать

Возможно, вас заинтересует этот пост, который я написал после решения моей конкретной проблемы: недопонимание модулей ES6, обновление Babel, слезы и решение

kentcdodds
источник
Мне любопытно, в каких случаях это нужно, requireесли вы работаете в кодовой базе, которая использует Babel? Скорее всего, есть и другие подходы, которые в любом случае позволят вам избежать этого.
loganfsmyth
Я использую функцию Webpack, которая не будет требовать кода, если он найден в мертвом коде, например: if (false) { require('./foo') }с webpack пропустил бы фактическое включение foo.jsв получившийся пакет.
kentcdodds
Что в итоге становится твоим falseтумблером? Если это условие доступно в вашей конфигурации веб-пакета, может быть другой вариант.
loganfsmyth
Этот тоже меня укусил. Спасибо @kentcdodds.
Тайлер МакГиннис
1
Этот вызвал у меня проблемы в течение нескольких часов, прежде чем я нашел этот пост. Я в конечном итоге заменить все мое export default {foo, bar}с module.exports = {foo, bar}. Мне очень понравился неправильный метод, который сейчас не поддерживается.
спотыкаюсь

Ответы:

90

Вы также можете использовать этот плагин, чтобы вернуть старое exportповедение.

SimenB
источник
1
Я знал, что кто-то напишет плагин рано или поздно. Спасибо!
kentcdodds
к сожалению, babel-plugin-add-module-exports не поддерживает модули в стиле amd (пока)
zowers
3
Я использовал babel-plugin-transform-es2015-modules-simple-amd для решения этой же проблемы в моем проекте с модулями AMD
Том Уэйсон,
Я думаю, что с помощью UMD и этот плагин это путь! Спасибо
Electronix
Очень очень полезно
Йовица Алексик
105

Если вам нужно поведение экспорта CommonJS, вам нужно использовать CommonJS напрямую (или использовать плагин в другом ответе). Это поведение было удалено, потому что оно вызывало путаницу и приводило к неверной семантике ES6, на которую, например, полагались некоторые люди.

export default {
  a: 'foo'
};

а потом

import {a} from './foo';

который является недопустимым ES6, но работал из-за поведения совместимости CommonJS, которое вы описываете. К сожалению, поддержка обоих случаев невозможна, и позволить людям писать недействительные ES6 - проблема хуже, чем заставлять вас делать это .default.

Другая проблема заключалась в том, что пользователи неожиданно добавили именованный экспорт, например, в будущем.

export default 4;

затем

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

но

export default 4;
export var foo = 5;

затем

require('./mod')
// {'default': 4, foo: 5}
loganfsmyth
источник
Я согласен с вами (и отметил), что предыдущее поведение было неверным, но мой вопрос заключался в том, как обойти эту проблему. Я сильно полагался на неправильное поведение (не понимал, что это было неправильно до сегодняшнего утра). Я бы предпочел не обновлять все сразу ...
kentcdodds
Единственным исправлением для текущего поведения было бы переключение вашего кода на использование CommonJS напрямую или сохранение Babel 5 до тех пор, пока у вас не будет времени на обновление.
loganfsmyth
4
@kentcdodds мы можем написать загрузчик веб-пакетов, чтобы он работал (или плагин babel). Я удивлен, что они не предоставляют (или обнародуют изменения более сильно!)
Джамунд Фергюсон
Я смущен этим ... если я делаю export default function () {}в модуле A, а затем import a from 'a'в модуле B, с Babel 6 aбудет { default: function () {} }... Из того, что я могу понять из exploringjs.com/es6/… это должно работать, и я должен получить экспортированный функция в B, а не объект.
mamapitufo
@mamapitufo Это должно сработать, но трудно сказать, что не так, без примера, чтобы посмотреть. Не стесняйтесь заходить на канал поддержки Babel на Slack, если вы хотите пообщаться.
loganfsmyth
33

Для авторов библиотеки вы можете обойти эту проблему.

У меня обычно есть точка входа, то index.jsесть файл, на который я указываю из основного поля package.json. Он ничего не делает, кроме как реэкспортирует фактическую точку входа в lib:

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

Чтобы обойти проблему babel, я изменил это на importутверждение и затем назначил по умолчанию module.exports:

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

Все остальные мои файлы остаются чистыми модулями ES6, без каких-либо обходных путей. Так что только точка входа нуждается в небольшом изменении :)

Это будет работать для потребностей commonjs, а также для импорта ES6, потому что babel, похоже, не сбросил обратное взаимодействие (commonjs -> es6). Бабель вводит следующую функцию для исправления commonjs:

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

Я потратил часы на борьбу с этим, поэтому я надеюсь, что это спасет кого-то еще от усилий!

WickyNilliams
источник
По какой-то причине у меня никогда не получалось крутить головы module.exportsи export defaultвсе такое. Теперь мы вернулись на круги своя?
windmaomao
@windmaomao что ты имеешь в виду? Это хитрость, так что обычным пользователям это не нужно require("whatever").default. Если вы не автор библиотеки, это, вероятно, не имеет значения
WickyNilliams
1

У меня была такая проблема. И это мое решение:

//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);
Игорь Павлык
источник