Vai al contenuto principale

Aggiornamento a Babel 7

Traduzione Beta Non Ufficiale

Questa pagina è stata tradotta da PageTurner AI (beta). Non ufficialmente approvata dal progetto. Hai trovato un errore? Segnala problema →

Fai riferimento a questo documento durante l'aggiornamento a Babel 7. Consulta qui per le modifiche alle API/integrazioni.

Poiché non ogni modifica incompatibile influenzerà ogni progetto, abbiamo organizzato le sezioni in base alla probabilità che una modifica interrompa i test durante l'aggiornamento.

Tutte le parti di Babel

Il supporto per Node.js 0.10, 0.12, 4 e 5 è stato rimosso #5025, #5041, #7755, #5186

Ti consigliamo vivamente di utilizzare una versione più recente di Node.js (LTS v8) poiché le versioni precedenti non sono più mantenute. Consulta nodejs/LTS per maggiori informazioni.

Questo significa semplicemente che Babel stesso non verrà eseguito su versioni precedenti di Node, ma può comunque produrre codice eseguibile su vecchie versioni di Node.

Modifiche alla ricerca della configurazione

Per maggiori dettagli, leggi il nostro confronto tra 6.x e 7.x.

Babel aveva precedentemente problemi con la gestione di node_modules, collegamenti simbolici e monorepo. Abbiamo apportato modifiche per risolverli: Babel interromperà la ricerca al confine di package.json invece di risalire la catena. Per i monorepo abbiamo introdotto un nuovo file babel.config.js che centralizza la configurazione tra tutti i pacchetti (in alternativa puoi creare una configurazione per pacchetto). Nella versione 7.1, abbiamo introdotto l'opzione rootMode per ricerche aggiuntive se necessario.

Deprecazione dei preset annuali

Il preset "env" esiste da oltre un anno e sostituisce completamente alcuni preset che avevamo suggerito in precedenza.

  • babel-preset-es2015

  • babel-preset-es2016

  • babel-preset-es2017

  • babel-preset-latest

  • Una combinazione dei precedenti ^

Questi preset dovrebbero essere sostituiti con il preset "env".

Deprecazione dei preset stage

Stiamo rimuovendo i preset stage a favore dell'utilizzo esplicito delle proposte. Consulta il README di stage-0 per ulteriori passaggi sulla migrazione.

Per automatizzare questa operazione, esegui npx babel-upgrade (PR aggiunto qui).

Rimozione dei polyfill per le proposte in @babel/polyfill

Seguendo lo stesso ragionamento, abbiamo rimosso i polyfill per le proposte da @babel/polyfill.

Attualmente @babel/polyfill è principalmente un alias di core-js v2. Fonte

In precedenza erano solo 2 import:

JavaScript
import "core-js/shim"; // included < Stage 4 proposals
import "regenerator-runtime/runtime";

Se desideri utilizzare le proposte, dovrai importarle indipendentemente. Dovresti importarle direttamente dal pacchetto core-js o da un altro pacchetto su npm.

ad esempio:

JavaScript
// for core-js v2:
import "core-js/fn/array/flat-map";

// for core-js v3:
import "core-js/features/array/flat-map";

Di seguito è riportato un elenco di polyfill per proposte in Stage < 3 in core-js v2.

Details
JavaScript
// core-js v2

// Stage 3
import "core-js/fn/string/trim-left";
import "core-js/fn/string/trim-right";
import "core-js/fn/string/match-all";
import "core-js/fn/array/flat-map";
import "core-js/fn/array/flatten"; // RENAMED
import "core-js/fn/global";

// Stage 1
import "core-js/fn/symbol/observable";
import "core-js/fn/promise/try";
import "core-js/fn/observable";

// Stage 1 Math Extensions
import "core-js/fn/math/clamp";
import "core-js/fn/math/deg-per-rad";
import "core-js/fn/math/degrees";
import "core-js/fn/math/fscale";
import "core-js/fn/math/iaddh";
import "core-js/fn/math/isubh";
import "core-js/fn/math/imulh";
import "core-js/fn/math/rad-per-deg";
import "core-js/fn/math/radians";
import "core-js/fn/math/scale";
import "core-js/fn/math/umulh";
import "core-js/fn/math/signbit";

// Stage 1 "of and from on collection constructors"
import "core-js/fn/map/of";
import "core-js/fn/set/of";
import "core-js/fn/weak-map/of";
import "core-js/fn/weak-set/of";
import "core-js/fn/map/from";
import "core-js/fn/set/from";
import "core-js/fn/weak-map/from";
import "core-js/fn/weak-set/from";

// Stage 0
import "core-js/fn/string/at";

// Nonstandard
import "core-js/fn/object/define-getter";
import "core-js/fn/object/define-setter";
import "core-js/fn/object/lookup-getter";
import "core-js/fn/object/lookup-setter";
// import "core-js/fn/map/to-json"; // Not available standalone
// import "core-js/fn/set/to-json"; // Not available standalone

import "core-js/fn/system/global";
import "core-js/fn/error/is-error";
import "core-js/fn/asap";

// Decorator metadata? Not sure of stage/proposal
import "core-js/fn/reflect/define-metadata";
import "core-js/fn/reflect/delete-metadata";
import "core-js/fn/reflect/get-metadata";
import "core-js/fn/reflect/get-metadata-keys";
import "core-js/fn/reflect/get-own-metadata";
import "core-js/fn/reflect/get-own-metadata-keys";
import "core-js/fn/reflect/has-metadata";
import "core-js/fn/reflect/has-own-metadata";
import "core-js/fn/reflect/metadata";

Versioning/Dipendenze

La maggior parte dei plugin e pacchetti di primo livello ora ha una peerDependency su @babel/core.

Ridenominazione dei pacchetti

  • babylon è ora @babel/parser

Puoi ancora utilizzare la versione abbreviata del nome di un pacchetto (rimuovendo preset- o plugin-) nella configurazione, ma scelgo di usare il nome completo per chiarezza (forse dovremmo semplicemente rimuoverla, dato che non fa risparmiare molto tempo di digitazione).

{
- "presets": ["@babel/preset-react"],
+ "presets": ["@babel/react"], // this is equivalent
- "plugins": ["@babel/transform-runtime"],
+ "plugins": ["@babel/plugin-transform-runtime"], // same
}

Pacchetti con ambito (Scoped Packages)

La modifica più importante è il passaggio definitivo a pacchetti con ambito (i nomi delle cartelle nel monorepo non cambiano, ma il nome nel suo package.json sì).

Ciò significa nessun problema di name squatting accidentale/intenzionale, separazione chiara dai plugin della comunità e convenzione di denominazione più semplice.

Le tue dipendenze dovranno essere modificate come segue:

babel-cli@babel/cli. Sostanzialmente abbiamo sostituito babel- con @babel/.

Utilizzo nella configurazione

Puoi ancora usare la forma abbreviata per specificare preset o plugin. Tuttavia, a causa del passaggio ai pacchetti con ambito, devi comunque specificare @babel/ come se avessi un tuo preset da aggiungere alla configurazione.

babel.config.js
module.exports = {
presets: ["@babel/env"], // "@babel/preset-env"
plugins: ["@babel/transform-arrow-functions"], // same as "@babel/plugin-transform-arrow-functions"
};

Passaggio a -proposal- per le proposte TC39

Ciò significa che qualsiasi plugin non incluso in una release annuale (ES2015, ES2016, ecc.) dovrebbe essere rinominato in -proposal. Così indichiamo chiaramente che una proposta non è ufficialmente in JavaScript.

Esempi:

  • @babel/plugin-transform-function-bind è ora @babel/plugin-proposal-function-bind (Stage 0)

  • @babel/plugin-transform-class-properties è ora @babel/plugin-proposal-class-properties (Stage 3)

Ciò significa anche che quando una proposta raggiunge lo Stage 4, dovremmo rinominare il pacchetto.

Rimozione dell'anno dai nomi dei pacchetti

Alcuni plugin avevano -es3- o -es2015- nei nomi, ma erano superflui.

@babel/plugin-transform-es2015-classes è diventato @babel/plugin-transform-classes.

"use strict" e this in CommonJS

Le trasformazioni di Babel 6 per i moduli ES6 venivano applicate indiscriminatamente a qualsiasi file, senza verificare la presenza effettiva di import/export ES6. Ciò riscriveva i riferimenti a this nell'ambito del file in undefined e inseriva "use strict" in tutti i moduli CommonJS elaborati.

JavaScript
// input.js
this;
JavaScript
// output.js v6
"use strict"; // assumed strict modules
undefined; // changed this to undefined
JavaScript
// output.js v7
this;

In Babel 7 questo comportamento è stato limitato: per la trasformazione transform-es2015-modules-commonjs, il file viene modificato solo se contiene importazioni o esportazioni ES6. (Nota della redazione: Questo potrebbe cambiare nuovamente se implementiamo https://github.com/babel/babel/issues/6242, quindi sarà necessario rivederlo prima della pubblicazione).

JavaScript
// input2.js
import "a";
JavaScript
// output.js v6 and v7
"use strict";
require("a");

Se facevi affidamento su Babel per iniettare automaticamente "use strict" in tutti i tuoi moduli CommonJS, dovrai utilizzare esplicitamente il plugin transform-strict-mode nella tua configurazione Babel.

Separazione dei preset React e Flow

babel-preset-react ha sempre incluso il plugin flow. Ciò ha causato numerosi problemi agli utenti che utilizzavano accidentalmente la sintassi flow a causa di refusi, o che la aggiungevano senza effettuare il controllo dei tipi con flow stesso, generando errori.

Questo problema si è aggravato quando abbiamo deciso di supportare TypeScript. Per utilizzare i preset React e TypeScript insieme, avremmo dovuto trovare un modo per attivare/disattivare la sintesi automaticamente, tramite tipo di file o direttiva. Alla fine, è risultato più semplice separare completamente i preset.

I preset consentono a Babel di analizzare i tipi forniti da Flow / TypeScript (e altri dialetti/linguaggi), per poi rimuoverli durante la compilazione in JavaScript.

{
- "presets": ["@babel/preset-react"]
+ "presets": ["@babel/preset-react", "@babel/preset-flow"] // parse & remove flow types
+ "presets": ["@babel/preset-react", "@babel/preset-typescript"] // parse & remove typescript types
}

Analisi delle opzioni

Le opzioni di configurazione di Babel sono più rigorose rispetto a Babel 6. Mentre in passato un elenco separato da virgole per i preset, ad esempio "presets": 'es2015, es2016', tecnicamente funzionava, ora fallirà e dovrà essere convertito in un array #5463.

Nota: ciò non si applica alla CLI, dove --presets es2015,es2016 continuerà sicuramente a funzionare.

{
- "presets": "@babel/preset-env, @babel/preset-react"
+ "presets": ["@babel/preset-env", "@babel/preset-react"]
}

Esportazione di plugin e preset

Tutti i plugin/preset dovrebbero ora esportare una funzione anziché un oggetto per coerenza (tramite babel/babel#6494). Questo ci aiuterà con la memorizzazione nella cache.

Risoluzione dei valori di configurazione basati su stringhe

In Babel 6, i valori passati direttamente a Babel (non da un file di configurazione) venivano risolti relativamente ai file in compilazione, causando molta confusione.

In Babel 7, i valori vengono risolti in modo coerente rispetto al file di configurazione che li ha caricati o rispetto alla directory di lavoro.

Per i valori presets e plugins, questo cambiamento significa che la CLI si comporterà correttamente in casi come

Shell
babel --presets @babel/preset-env ../file.js

Supponendo che la tua cartella node_modules si trovi in ., in Babel 6 questo fallirebbe perché il preset non veniva trovato.

Questo cambiamento influisce anche su only e ignore, che verranno approfonditi in seguito.

Pattern only e ignore basati su percorsi

In Babel 6, only e ignore venivano trattati come stringhe di corrispondenza generiche anziché come glob di percorsi. Ciò significava che ad esempio *.foo.js corrispondeva a ./**/*.foo.js, risultando confuso e inaspettato per la maggior parte degli utenti.

In Babel 7, questi sono ora trattati come pattern glob basati su percorsi, relativi o assoluti. Ciò significa che se utilizzavi questi pattern, probabilmente dovrai aggiungere almeno un prefisso **/ per garantire la corrispondenza profonda nelle directory.

I pattern only e ignore funzionano comunque anche per le directory: puoi usare only: './tests' per compilare solo i file nella tua directory tests, senza bisogno di usare **/*.js per corrispondere a tutti i file annidati.

Comandi CLI di Babel

L'argomento --copy-files per il comando babel, che indica a Babel di copiare tutti i file in una directory che non sa gestire, ora copierà anche i file che non superano i controlli only/ignore, mentre in precedenza saltava silenziosamente tutti i file ignorati.

@babel/node

Il comando babel-node in Babel 6 faceva parte del pacchetto babel-cli. In Babel 7, questo comando è stato separato nel proprio pacchetto @babel/node, quindi se lo utilizzi, dovrai aggiungere questa nuova dipendenza.

@babel/runtime, @babel/plugin-transform-runtime

Abbiamo separato gli helper di Babel dal comportamento di "polyfilling" nel runtime. Maggiori dettagli nella PR.

@babel/runtime ora contiene solo gli helper. Se hai bisogno di core-js, puoi usare @babel/runtime-corejs2 con l'opzione fornita nella trasformazione. Per entrambi è comunque necessario @babel/plugin-transform-runtime

Solo helper

Shell
# install the runtime as a dependency
npm install @babel/runtime
# install the plugin as a devDependency
npm install @babel/plugin-transform-runtime --save-dev
babel.config.json
{
"plugins": ["@babel/plugin-transform-runtime"]
}

Helper + polyfill da core-js

Quindi se hai bisogno del supporto core-js con transform-runtime, dovrai ora passare l'opzione corejs e usare la dipendenza @babel/runtime-corejs2 invece di @babel/runtime.

Shell
# install the runtime as a dependency
npm install @babel/runtime-corejs2
# install the plugin as a devDependency
npm install @babel/plugin-transform-runtime --save-dev
{
"plugins": [
- ["@babel/plugin-transform-runtime"],
+ ["@babel/plugin-transform-runtime", {
+ "corejs": 2,
+ }],
]
}

Conformità alle specifiche

@babel/plugin-proposal-object-rest-spread

Una virgola finale non può seguire un RestElement negli oggetti #290 medium

var {
- ...y, // trailing comma is a SyntaxError
+ ...y
} = { a: 1 };

Poiché Object Spread definisce nuove proprietà mentre Object.assign le imposta semplicemente, Babel ha modificato il comportamento predefinito per essere più conforme alle specifiche.

JavaScript
// input
z = { x, ...y };
JavaScript
// v7 default behavior: ["proposal-object-rest-spread"]
function _objectSpread(target) { ... }

z = _objectSpread({
x
}, y);
JavaScript
// Old v6 behavior: ["proposal-object-rest-spread", { "loose": true }]
function _extends(target) { ... }

z = _extends({
x
}, y);
JavaScript
// Substitute for Object.assign: ["proposal-object-rest-spread", { "loose": true, "useBuiltIns": true }]
z = Object.assign(
{
x,
},
y
);

@babel/plugin-proposal-class-properties

Il comportamento predefinito è stato cambiato a ciò che precedentemente era "spec" di default

JavaScript
// input
class Bork {
static a = "foo";
y;
}
JavaScript
// v7 default behavior: ["@babel/plugin-proposal-class-properties"]
var Bork = function Bork() {
Object.defineProperty(this, "y", {
enumerable: true,
writable: true,
value: void 0,
});
};

Object.defineProperty(Bork, "a", {
enumerable: true,
writable: true,
value: "foo",
});
JavaScript
// old v6 behavior: ["@babel/plugin-proposal-class-properties", { "loose": true }]
var Bork = function Bork() {
this.y = void 0;
};

Bork.a = "foo";

Suddivisione di @babel/plugin-transform-export-extensions nelle due proposte rinominate

Questa modiera era attesa da tempo ed è finalmente stata implementata.

@babel/plugin-proposal-export-default-from

JavaScript
export v from "mod";

@babel/plugin-proposal-export-namespace-from

JavaScript
export * as ns from "mod";

@babel/plugin-transform-template-literals

Aggiornamento di Template Literals Revision #5523 low

Vedi la proposta per Template Literals Revision.

Causava in Babel 6 l'errore Bad character escape sequence (5:6).

JavaScript
tag`\unicode and \u{55}`;

Questo problema è stato risolto in Babel 7 che genera qualcosa simile a:

JavaScript
// default
function _taggedTemplateLiteral(strings, raw) {
return Object.freeze(
Object.defineProperties(strings, { raw: { value: Object.freeze(raw) } })
);
}
var _templateObject = /*#__PURE__*/ _taggedTemplateLiteral(
[void 0],
["\\unicode and \\u{55}"]
);
tag(_templateObject);
JavaScript
// loose mode
function _taggedTemplateLiteralLoose(strings, raw) {
strings.raw = raw;
return strings;
}
var _templateObject = /*#__PURE__*/ _taggedTemplateLiteralLoose(
[void 0],
["\\unicode and \\u{55}"]
);
tag(_templateObject);

Comportamento predefinito impostato alla precedente modalità "spec" per i template literal regolari

JavaScript
// input
`foo${bar}`;
JavaScript
// default v7 behavior: ["@babel/plugin-transform-template-literals"]
"foo".concat(bar);
JavaScript
// old v6 behavior: ["@babel/plugin-transform-template-literals", { "loose": true }]
"foo" + bar;

@babel/plugin-proposal-decorators

In previsione dell'implementazione della nuova proposta per i decoratori, abbiamo deciso di renderla il comportamento predefinito. Ciò significa che per continuare a utilizzare la sintassi/il comportamento attuale dei decoratori, devi impostare l'opzione legacy su true.

 {
"plugins": [
- "@babel/plugin-proposal-decorators"
+ ["@babel/plugin-proposal-decorators", { "legacy": true }]
]
}

NOTA: Se stai utilizzando @babel/preset-stage-0 o @babel/preset-stage-1, che includono questo plugin, devi passare loro l'opzione decoratorsLegacy.

@babel/plugin-proposal-pipeline-operator

Le proposte più recenti in fase di evoluzione genereranno errori per impostazione predefinita e richiederanno a tutti di aderire a una proposta specifica finché non raggiungono almeno lo Stage 2. Maggiori dettagli in questo articolo.

{
"plugins": [
- "@babel/plugin-proposal-pipeline-operator"
+ ["@babel/plugin-proposal-pipeline-operator", { "proposal": "minimal" }]
]
}

Rimosso babel-plugin-transform-class-constructor-call

babel-plugin-transform-class-constructor-call è stato rimosso #5119 low

TC39 ha deciso di abbandonare questa proposta. Puoi spostare la tua logica nel costruttore o in un metodo statico.

Consulta /docs/plugins/transform-class-constructor-call/ per maggiori informazioni.

  class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}

- call constructor(x, y) {
+ static secondConstructor(x, y) {
return new Point(x, y);
}
}

let p1 = new Point(1, 2);
- let p2 = Point(3, 4);
+ let p2 = Point.secondConstructor(3, 4);

@babel/plugin-async-to-generator

Abbiamo unito babel-plugin-transform-async-to-module-method nel plugin async regolare rendendolo semplicemente un'opzione.

{
"plugins": [
- ["@babel/transform-async-to-module-method"]
+ ["@babel/transform-async-to-generator", {
+ "module": "bluebird",
+ "method": "coroutine"
+ }]
]
}

babel

Rimozione del pacchetto babel #5293 low

Attualmente questo pacchetto restituisce un messaggio di errore che invita a installare babel-cli nella v6. Pensiamo comunque si possa fare qualcosa di interessante con questo nome.

@babel/register

babel-core/register.js è stato rimosso #5132 low

L'utilizzo deprecato di babel-core/register è stato rimosso in Babel 7; utilizza invece il pacchetto autonomo @babel/register.

Installa @babel/register come nuova dipendenza:

npm install --save-dev @babel/register

Aggiornamento con Mocha:

- mocha --require babel-core/register
+ mocha --require @babel/register

@babel/register compilerà ora solo i file nella directory di lavoro corrente (modifica apportata per risolvere problemi con i symlink).

Le opzioni di @babel/register ora vengono sostituite invece che unite

@babel/generator

Rimozione dell'opzione quotes #5154] none

Se desideri formattare l'output compilato puoi usare recast/prettier/escodegen/fork babel-generator.

Questa opzione era disponibile solo tramite babel-generator esplicitamente fino alla v6.18.0, quando abbiamo esposto parserOpts e generatorOpts. Dato che c'era un bug in quella release, nessuno avrebbe dovuto usare questa opzione in Babel stesso.

Rimozione dell'opzione flowUsesCommas #5123 none

Attualmente sono supportate due sintassi (, e ;) per i Flow Object Types.

Questa modifica fa sì che babel-generator produca , invece di ;.

@babel/core

Rimozione di babel-core/src/api/browser.js #5124 none

babel-browser era già stato rimosso nella versione 6.0. Se devi utilizzare Babel nel browser o in un ambiente non Node, usa @babel/standalone.

Babel restituirà filename come percorso assoluto #8044

@babel/preset-env

La modalità loose escluderà automaticamente la trasformazione typeof-symbol (molti progetti che utilizzavano la modalità loose lo facevano già).