7.7.0 Rilasciato: Ripristino degli errori e TypeScript 3.7
Questa pagina è stata tradotta da PageTurner AI (beta). Non ufficialmente approvata dal progetto. Hai trovato un errore? Segnala problema →
Oggi rilasciamo Babel 7.7.0!
Questa versione include nuove funzionalità del parser come l'await di primo livello (await x(), Stage 3) e le dichiarazioni enum di Flow (proposta Flow). Inoltre, @babel/parser offre ora la possibilità di ripristinarsi da determinati errori di sintassi!
Abbiamo inoltre aggiunto il supporto per TypeScript 3.7: Babel può analizzare e trasformare campi privati di classe con annotazioni di tipo, annotazioni di campi pubblici definite tramite la parola chiave declare, firme di funzioni di asserzione di tipo e template literal nelle dichiarazioni enum.
Babel supporta ora tre nuovi file di configurazione: babel.config.json, babel.config.cjs e .babelrc.cjs, che si comportano esattamente come i file babel.config.js e .babelrc.js.
Infine, Babel 7.7.0 utilizza il 20% di memoria in meno rispetto alla versione 7.6.0.
Puoi consultare l'intero changelog su GitHub.
Un ringraziamento speciale a Alejandro Sánchez, Chris Garrett, 彭驰, Daniel Arthur Gallagher, ExE-Boss, Eugene Myunster, Georgii Dolzhykov, Gerald, Linus Unnebäck, Martin Forsgren, Matthew Whitworth, Micah Zoltu, Mohammad Ahmadi e Samuel Kwok per i loro primi PR!
Questa release è stata possibile anche grazie alla collaborazione con team di altri progetti open source: grazie a Devon Govett (Parcel) per aver implementato il supporto per i file babel.config.json, e a George Zahariev (Flow) per aver aggiunto le dichiarazioni enum di Flow a @babel/parser!
Un ulteriore ringraziamento speciale va a Bloomberg per aver organizzato un Hackathon Open Source per incoraggiare i propri ingegneri a contribuire alla comunità! In particolare, Robin Ricard e Jaideep Bhoosreddy che stanno lavorando attivamente all'automazione dei test delle trasformazioni di Babel tramite la suite Test262.
Se tu o la tua azienda desiderate supportare Babel e l'evoluzione di JavaScript, ma non siete sicuri su come farlo, potete donare tramite OpenCollective o, ancora meglio, collaborare direttamente con noi all'implementazione di nuove proposte ECMAScript! Essendo un progetto guidato da volontari, contiamo sul supporto della comunità sia per finanziare i nostri sforzi nell'assistere la vasta gamma di utenti JavaScript, sia per assumere la proprietà del codice. Contatta Henry all'indirizzo henry@babeljs.io per maggiori informazioni!
Analisi di await di livello superiore (#10449)
La proposta di await di livello superiore consente di utilizzare await sulle promise nei moduli come se fossero racchiuse in una grande funzione asincrona. Ciò è utile, ad esempio, per caricare condizionalmente una dipendenza o per eseguire l'inizializzazione dell'applicazione:
// Dynamic dependency path
const strings = await import(`./i18n/${navigator.language}.mjs`);
// Resource initialization
const connection = await dbConnector();
@babel/parser supporta l'utilizzo di await al di fuori delle funzioni asincrone tramite l'opzione allowAwaitOutsideFunction a partire dalla versione 7.0.0.
La versione 7.7.0 introduce un nuovo plugin del parser topLevelAwait, che presenta alcune differenze chiave:
-
Consente
awaitdi livello superiore solo all'interno dei moduli e non all'interno degli script, come richiesto dalla proposta. Ciò è necessario perché i sistemi di moduli sincroni basati su script (come CommonJS) non possono supportare una dipendenza asincrona. -
Permette di rilevare il corretto
sourceTypequando viene utilizzatosourceType: "unambiguous". Nota che, poichéawaitè un identificatore valido negli script, molte strutture che potrebbero sembrare inequivocabilmente moduli sono in realtà ambigue e Babel le analizzerà come script. Ad esempio,await -1potrebbe essere un'espressione await che attende-1, oppure una differenza traawaite1.
Se stai utilizzando @babel/parser direttamente, puoi abilitare il plugin topLevelAwait:
parser.parse(inputCode, {
plugins: ["topLevelAwait"]
});
Abbiamo anche creato il pacchetto @babel/plugin-syntax-top-level-await, che puoi aggiungere alla tua configurazione Babel:
module.exports = {
plugins: [
"@babel/plugin-syntax-top-level-await"
]
}
Nota che l'utilizzo di await di livello superiore presuppone il supporto nel tuo module bundler. Babel stesso non esegue trasformazioni: se stai usando Rollup puoi abilitare l'opzione experimentalTopLevelAwait, mentre webpack 5 supporta l'opzione experiments.topLevelAwait.
A partire da questa release, @babel/preset-env abiliterà automaticamente @babel/plugin-syntax-top-level-await se il caller lo supporta. Nota: babel-loader e rollup-plugin-babel non comunicano ancora a Babel di supportare questa sintassi, ma stiamo collaborando con i rispettivi maintainer.
Recupero degli errori del parser (#10363)
Come molti altri parser JavaScript, @babel/parser genera un errore ogni volta che incontra una sintassi non valida. Questo comportamento funziona bene per Babel, poiché per trasformare un programma JavaScript in un altro programma dobbiamo prima essere certi che l'input sia valido.
Data la popolarità di Babel, molti altri strumenti si affidano a @babel/parser: soprattutto babel-eslint e Prettier. Per entrambi questi strumenti, un parser che si interrompe al primo errore non è ottimale.
Considera questo codice, non valido a causa della proprietà __proto__ duplicata:
let a = {
__proto__: x,
__proto__: y
}
let a = 2;
L'attuale flusso di lavoro con ESLint e Prettier è il seguente:
-
Prettier non può formattare il file
-
ESLint segnala un errore del parser
Redefinition of __proto__ property -
Rimuovi la seconda proprietà
__proto__ -
Prettier non può formattare il file
-
ESLint segnala un errore
Identifier 'a' has already been declared -
Rimuovi la seconda parola chiave
let -
Prettier formatta il file
Non sarebbe meglio se funzionasse così?
-
Prettier formatta il file
-
ESLint segnala due errori:
Redefinition of __proto__ propertyeIdentifier 'a' has already been declared -
Rimuovi la seconda proprietà
__proto__e la seconda parola chiavelet
In questa release, introduciamo una nuova opzione in @babel/parser: errorRecovery. Quando impostata su true, l'AST risultante conterrà una proprietà errors con tutti gli errori da cui @babel/parser è riuscito a riprendersi:
const input = `
let a = {
__proto__: x,
__proto__: y
}
let a = 2;
`;
parser.parse(input); // Throws "Redefinition of __proto__ property"
const ast = parser.parse(input, { errorRecovery: true });
ast.errors == [
SyntaxError: "Redefinition of __proto__ property",
SyntaxError: "Identifier 'a' has already been declared",
];
@babel/parser potrebbe ancora generare eccezioni poiché non tutti gli errori sono attualmente recuperabili. Continueremo a migliorare questi casi!
Nuove estensioni per file di configurazione (#10501, #10599)
Babel 6 supportava un solo file di configurazione: .babelrc, il cui contenuto doveva essere specificato in JSON.
Babel 7 ha cambiato il significato dei .babelrc e ha introdotto due nuovi file di configurazione: babel.config.js e .babelrc.js (leggi le differenze nella documentazione). Abbiamo aggiunto file di configurazione JavaScript per consentire la definizione di logiche personalizzate nell'abilitazione/disabilitazione di plugin/opzioni.
Tuttavia, un grande vantaggio dei file JSON è la migliore cacheabilità. Lo stesso file JavaScript può produrre valori diversi quando eseguito due volte, mentre un file JSON garantisce sempre lo stesso oggetto. Inoltre, le configurazioni JSON sono facilmente serializzabili, a differenza di valori JavaScript come funzioni o oggetti con dati/relazioni implicite.
Nota che Babel memorizza nella cache anche le trasformazioni con configurazioni JavaScript, ma il file di configurazione deve essere valutato (per verificare la validità della cache) e la cache configurata manualmente.
Per questi motivi, Babel 7.7.0 introduce il supporto per un nuovo file di configurazione: babel.config.json, con comportamento identico a babel.config.js.
Abbiamo anche aggiunto supporto per due nuovi file: babel.config.cjs e .babelrc.cjs, da usare con l'opzione "type": "module" di Node.js in package.json (poiché Babel non supporta moduli ECMAScript nei file di configurazione). A parte questa differenza "type": "module", si comportano esattamente come babel.config.js e .babelrc.js.
TypeScript 3.7 (#10543, #10545)
TypeScript 3.7 RC include supporto per optional chaining, nullish coalescing operator, funzioni di asserzione, dichiarazioni di campi solo tipo e molte altre funzionalità relative ai tipi.
L'optional chaining (a?.b) e il nullish coalescing (a ?? b) sono supportati in Babel dalla 7.0.0 tramite @babel/plugin-proposal-optional-chaining e @babel/plugin-proposal-nullish-coalescing-operator.
In Babel 7.7.0, ora puoi usare funzioni di asserzione e declare nei campi classe:
function assertString(x): assert x is string {
if (typeof x !== "string") throw new Error("It must be a string!");
}
class Developer extends Person {
declare usingBabel: boolean;
}
Per evitare breaking changes, abbiamo introdotto il supporto per declare nei campi classe dietro un flag: "allowDeclareFields", supportato sia da @babel/plugin-transform-typescript che @babel/preset-typescript. Probabilmente diventerà il comportamento predefinito, quindi ti consigliamo di migrare la tua configurazione:
{
"presets": [
["@babel/preset-typescript", {
"allowDeclareFields": true
}]
]
}
Usare object spread nel JSX compilato (#10572)
Quando si usano proprietà spread negli elementi JSX, Babel per impostazione predefinita inserisce un helper runtime:
<a x {...y} />
// 🡇 🡇 🡇
function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
React.createElement("a", _extends({
x: true
}, y));
Nel 2016, con il migliorato supporto per ES6 nativo, abbiamo aggiunto l'opzione useBuiltIns a @babel/plugin-transform-react-jsx, consentendo all'output compilato di usare direttamente Object.assign rimuovendo codice superfluo:
<a x {...y} />
// 🡇 🡇 🡇
React.createElement("a", Object.assign({
x: true
}, y));
Tuttavia, grazie al supporto nativo per lo spread di oggetti, possiamo generare un codice ancora più ottimizzato:
<a x {...y} />
// 🡇 🡇 🡇
React.createElement("a", { x: true, ...y });
Puoi abilitarlo utilizzando l'opzione useSpread con @babel/preset-react o @babel/plugin-transform-react-jsx:
{
presets: [
["@babel/react", { useSpread: true }]
]
}
Miglioramenti nell'utilizzo della memoria (#10480)
Fin dall'inizio, abbiamo compiuto sforzi (#433, #3475, #7028, etc.) per migliorare le prestazioni. Babel 7.7.0 utilizza ora il 20% di memoria in meno e trasforma file di grandi dimensioni l'8% più velocemente rispetto alla versione 7.6.0.
Per ottenere questi risultati, abbiamo ottimizzato diverse operazioni eseguite durante il ciclo di vita degli oggetti NodePath (utilizzati per incapsulare ogni nodo AST):
-
Ora evitiamo di inizializzare alcune proprietà di oggetti raramente utilizzate finché non sono necessarie, consentendoci di evitare un'allocazione
Object.create(null)per quasi ogni nodo AST. -
Abbiamo ridotto il carico di lavoro di contabilità per ogni visita di nodo, sostituendo alcune proprietà non comuni con dei getter in modo che
@babel/traversepossa saltarne l'aggiornamento. -
Abbiamo ottimizzato l'utilizzo della memoria comprimendo diverse proprietà booleane utilizzate per rappresentare lo stato di una traversata di nodi (ad esempio, saltato, fermato o rimosso) in un bit array.
Tutti questi miglioramenti si sommano nella seguente differenza nelle prestazioni di trasformazione e nell'utilizzo della memoria:
| Performance | Memory usage |
|---|---|
![]() | ![]() |
Puoi anche consultare i dati grezzi dei grafici sopra. Se desideri approfondire l'argomento, puoi leggere la dettagliata relazione di Jùnliàng sulle modifiche apportate per ottenere questi miglioramenti!

