Babel 6 zmienia domyślny sposób eksportu

197

Wcześniej babel dodawał linię module.exports = exports["default"]. Już tego nie robi. Co to oznacza, zanim będę mógł:

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

Teraz muszę to zrobić:

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

Nie jest to wielka sprawa (i myślę, że tak powinno być przez cały czas). Problem polega na tym, że mam dużo kodu, który zależał od sposobu, w jaki rzeczy działały (większość mogę przekonwertować na import z ES6, ale nie całość). Czy ktoś może mi dać wskazówki, jak sprawić, by stary sposób działał bez konieczności przechodzenia przez mój projekt i naprawiania tego (lub nawet instrukcja, jak napisać codemod, aby to zrobić, byłaby całkiem sprytna).

Dzięki!

Przykład:

Wejście:

const foo = {}
export default foo

Wyjście z Babel 5

"use strict";

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

Wyjście z Babel 6 (i wtyczką es2015):

"use strict";

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

Zauważ, że jedyną różnicą w danych wyjściowych jest module.exports = exports["default"].


Edytować

Możesz być zainteresowany tym postem na blogu, który napisałem po rozwiązaniu mojego konkretnego problemu: Niezrozumienie modułów ES6, Uaktualnienie Babel, Łzy i rozwiązanie

kentcdodds
źródło
Jestem ciekawy, jakie są przypadki, w których potrzebujesz, requirejeśli pracujesz w bazie kodu, która używa Babel? Są szanse, że istnieją inne podejścia, które i tak pozwolą ci tego uniknąć.
loganfsmyth
Korzystam z funkcji Webpacka, która nie będzie wymagała kodu, jeśli zostanie znaleziona w martwym kodzie, na przykład: if (false) { require('./foo') }z webpackiem pominie się faktyczne włączenie foo.jsdo wynikowego pakietu.
kentcdodds
Co kończy się falsetam twoim przełącznikiem? Jeśli jest to warunek dostępny w konfiguracji Twojego pakietu internetowego, może istnieć inna opcja.
loganfsmyth
1
Ten powodował mi problemy na wiele godzin, zanim znalazłem ten post. Skończyło się na zastąpieniu wszystkich moich export default {foo, bar}plików module.exports = {foo, bar}. Bardzo podobała mi się niewłaściwa metoda, która nie jest teraz obsługiwana.
stumct
@loganfsmyth Jest to bardzo przydatne do przekazywania całych modułów bez zbytniego powtarzania w kodzie. Spójrz na to sedno gist.github.com/loopmode/3eeaf0764c30439add1d8008e39d0267
Jovica Aleksic

Odpowiedzi:

92

Możesz także użyć tej wtyczki, aby przywrócić stare exportzachowanie.

SimenB
źródło
1
Wiedziałem, że ktoś prędzej czy później napisze wtyczkę. Dzięki!
kentcdodds
niestety babel-plugin-add-module-export nie obsługuje modułów w stylu AMD (jeszcze)
zowers
3
Użyłem babel-plugin-transform-es2015-modules-simple-amd, aby rozwiązać ten sam problem w moim projekcie, który zawiera moduły AMD
Tom Wayson,
Myślę, że użycie UMD i tej wtyczki jest drogą do zrobienia! Dzięki
electronix384128
Bardzo pomocna.
Jovica Aleksic
105

Jeśli chcesz zachować zachowanie eksportu CommonJS, musisz użyć bezpośrednio CommonJS (lub użyć wtyczki w drugiej odpowiedzi). To zachowanie zostało usunięte, ponieważ powodowało zamieszanie i prowadziło do nieprawidłowej semantyki ES6, na której niektórzy polegali np

export default {
  a: 'foo'
};

i wtedy

import {a} from './foo';

który jest nieprawidłowy ES6, ale działał z powodu opisywanego zachowania współdziałania CommonJS. Niestety obsługa obu przypadków nie jest możliwa, a zezwolenie ludziom na pisanie nieprawidłowego ES6 jest gorszym problemem niż zmuszanie do tego .default.

Innym problemem było to, że było to nieoczekiwane dla użytkowników, jeśli na przykład dodali nazwany eksport w przyszłości

export default 4;

następnie

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

ale

export default 4;
export var foo = 5;

następnie

require('./mod')
// {'default': 4, foo: 5}
loganfsmyth
źródło
Zgadzam się z tobą (i zauważyłem), że zachowanie przed było niepoprawne, ale moje pytanie dotyczyło tego, jak obejść ten problem. W dużej mierze polegałem na niewłaściwym zachowaniu (nie zdawałem sobie sprawy, że było to nieprawidłowe do dzisiejszego ranka). Wolałbym nie musieć aktualizować wszystkiego naraz ...
kentcdodds
Jedyną poprawką, aby uzyskać bieżące zachowanie, byłoby przełączenie kodu do bezpośredniego korzystania z CommonJS lub pozostanie na Babel 5 do czasu aktualizacji.
loganfsmyth
4
@kentcdodds możemy napisać program ładujący webpack, który będzie działał (lub wtyczkę Babel). Jestem zaskoczony, że ich nie udostępniają (lub
głośniej
Jestem zdezorientowany ... jeśli zrobię export default function () {}w module A, a następnie import a from 'a'w module B, z Babel 6 abędzie { default: function () {} }... Z tego, co mogę zrozumieć z explorejs.com/es6/ ... to powinno działać i powinienem dostać wyeksportowany funkcja w B, a nie obiekt.
mamapitufo
@mamapitufo To powinno działać, ale trudno powiedzieć, co jest nie tak, bez przykładu. Jeśli chcesz porozmawiać, odwiedź kanał wsparcia Babel na Slacku.
loganfsmyth
33

W przypadku autorów bibliotecznych możesz obejść ten problem.

Zwykle mam punkt wejścia index.js, czyli plik, na który wskazuję z głównego pola w package.json. Nie robi nic poza reeksportowaniem rzeczywistego punktu wejścia biblioteki:

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

Aby obejść problem z babel, zmieniłem to na importinstrukcję, a następnie przypisałem wartość domyślną do module.exports:

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

Wszystkie moje inne pliki pozostają jako czyste moduły ES6, bez żadnych obejść. Więc tylko punkt wejścia wymaga nieznacznej zmiany :)

To zadziała dla wymagań commonjs, a także dla importu z ES6, ponieważ babel nie wydaje się porzucić odwrotnej interop (commonjs -> es6). Babel wprowadza następującą funkcję, aby załatać commonjs:

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

Spędziłem godziny walcząc z tym, więc mam nadzieję, że zaoszczędzi to komuś innemu wysiłku!

WickyNilliams
źródło
Z jakiegoś powodu nigdy nie odwróciłem się od głowy module.exportsi export defaulttakie tam. Teraz wróciliśmy do punktu wyjścia?
windmaomao,
@windmaomao co masz na myśli? Jest to sztuczka, której użytkownicy commonjs nie muszą tego robić require("whatever").default. Jeśli nie jesteś autorem biblioteki, to prawdopodobnie nie ma znaczenia
WickyNilliams,
2

Miałem taki problem. A oto moje rozwiązanie:

//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
źródło