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, слезы и решение


Мне любопытно, в каких случаях это нужно, 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поведение.


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}

Я согласен с вами (и отметил), что предыдущее поведение было неверным, но мой вопрос заключался в том, как обойти эту проблему. Я сильно полагался на неправильное поведение (не понимал, что это было неправильно до сегодняшнего утра). Я бы предпочел не обновлять все сразу ...
— 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 }; } 

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


По какой-то причине у меня никогда не получалось крутить головы 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);
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.