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


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.


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}

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!


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);
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.