{"id":7001120,"date":"2019-06-24T09:58:00","date_gmt":"2019-06-24T09:58:00","guid":{"rendered":"https:\/\/alistapart.com\/it\/?post_type=article&#038;p=7001120"},"modified":"2020-06-03T10:29:52","modified_gmt":"2020-06-03T10:29:52","slug":"javascript-responsabile-parte-ii","status":"publish","type":"article","link":"https:\/\/alistapart.com\/it\/article\/javascript-responsabile-parte-ii\/","title":{"rendered":"JavaScript Responsabile, Parte II"},"content":{"rendered":"\n<p>Supponiamo che insieme a tutto il dev team abbiate fatto pressione con entusiasmo per un remake totale dell&#8217;architettura del sito web aziendale, che comincia a mostrare i suoi anni. Le vostre preghiere sono state ascoltate dal management &#8211; su su fino alla C-suite &#8211; che ha dato il via libera. Tutti euforici, voi e il team avete cominciato subito a lavorare con i team di design, copy e IA e nel giro di poco tempo, avete sfornato il nuovo codice.<\/p>\n\n\n\n<p>\u00c8 cominciato tutto con un innocente <code>npm install<\/code> qui e un <code>npm install<\/code> l\u00e0. Prima che ve ne rendeste conto, per\u00f2, stavate installando delle dependencies in produzione come uno studente della triennale che fa <a href=\"https:\/\/it.wikipedia.org\/wiki\/Keg_stand\">keg stand<\/a> senza curarsi di cosa succeder\u00e0 il giorno dopo.<\/p>\n\n\n\n<p>Poi avete lanciato.<\/p>\n\n\n\n<p>In questo caso per\u00f2, a differenza delle conseguenze delle peggiori bevute, l&#8217;agonia non inizia la mattina dopo. <em>Oh<\/em> no. Succede mesi dopo, sotto l&#8217;agghiacciante forma di debole nausea e mal di testa da parte dei product owner e del middle management che si chiedono come mai le conversion e le revenue si sono entrambe abbassate dal momento del lancio. Poi si tocca la frenesia quando il CTO di ritorno da un week-end nei boschi si chiede come mai il sito si caricasse cos\u00ec lentamente sul suo telefono &#8211; ammesso che si caricasse.<\/p>\n\n\n\n<p>Prima erano tutti contenti. Adesso <em>nessuno<\/em> \u00e8 contento. Benvenuti al vostro primo hangover da JavaScript.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Non \u00e8 colpa vostra<\/h2>\n\n\n\n<p>Quando vi ritrovate con un terribile hangover, vi meritereste un bel \u201cVe l&#8217;avevo detto\u201d, anche se potrebbe scaturirne una litigata\u2026 Ammesso che riusciate a litigare nel miserabile stato in cui vi trovate.<\/p>\n\n\n\n<p>Quando abbiamo a che fare con un hangover da JavaScript, c&#8217;\u00e8 un sacco di colpa da distribuire. Ma puntare il dito \u00e8 una perdita di tempo. Il panorama del web attuale richiede iterazioni pi\u00f9 rapide di quelle dei nostri competitor. Questo tipo di pressione significa che probabilmente dovremo trarre vantaggio da qualunque mezzo a nostra disposizione per essere il pi\u00f9 produttivi possibile. <em>Ci\u00f2<\/em> significa che \u00e8 pi\u00f9 probabile creare app con pi\u00f9 overhead e magari usare pattern che possono ledere la performance e l&#8217;accessibilit\u00e0, ma che non sar\u00e0 necessariamente un insuccesso.<\/p>\n\n\n\n<p>Lo sviluppo web non \u00e8 facile. \u00c8 un lungo lavoro duro che raramente facciamo bene al primo tentativo. La parte migliore del lavorare sul web, per\u00f2, \u00e8 che non <em>dobbiamo<\/em> essere perfetti fin dall&#8217;inizio. Possiamo fare dei miglioramenti dopo il lancio e questo \u00e8 proprio l&#8217;argomento di questa seconda parte di <a href=\"https:\/\/alistapart.com\/article\/responsible-javascript-part-1\/\">questa serie<\/a>. La perfezione \u00e8 molto lontana. Per ora, liberiamoci dell&#8217;hangover di JavaScript migliorando la <em>scriptuation<\/em> a breve termine del vostro sito.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Radunate i soliti sospetti<\/h2>\n\n\n\n<p>Potrebbe sembrare un futile esercizio, ma vale la pena scorrere l&#8217;elenco delle ottimizzazioni di base. Non \u00e8 insolito che i grandi team di sviluppo, particolarmente per quelli che lavorano su molti repository o che non usano boilerplate ottimizzati, le ignorino.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Scuotete quegli alberi<\/h3>\n\n\n\n<p>Per prima cosa, assicuratevi che la vostra toolchain sia configurata per fare <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Glossary\/Tree_shaking\"><em>tree shaking<\/em><\/a>. Se il tree shaking \u00e8 un concetto nuovo per voi, l&#8217;anno scorso ho scritto <a href=\"https:\/\/developers.google.com\/web\/fundamentals\/performance\/optimizing-javascript\/tree-shaking\/\">una guida sull&#8217;argomento<\/a>. In poche parole, il tree shaking \u00e8 un processo nel quale gli export non utilizzati nella vostra codebase non vengono impacchettati nel vostro bundle in produzione.<\/p>\n\n\n\n<p>Il tree shaking \u00e8 disponibile \u201cout of the box\u201d con i moderni bundlers come <a href=\"https:\/\/webpack.js.org\/\">webpack<\/a>, <a href=\"https:\/\/rollupjs.org\/\">Rollup<\/a> o <a href=\"https:\/\/parceljs.org\/\">Parcel<\/a>. <a href=\"https:\/\/gruntjs.com\/\">Grunt<\/a> o <a href=\"https:\/\/gulpjs.com\/\">gulp<\/a>, che non sono <em>bundlers<\/em> ma piuttosto <em>task runner<\/em>, non lo faranno per voi. Un task runner non crea un <a href=\"https:\/\/webpack.js.org\/concepts\/dependency-graph\/\">dependency graph<\/a> come invece fa un bundler. Al contrario, fanno dei task discreti sui files che date loro in pasto con un qualsiasi numero di plugin. I task runner <em>possono<\/em> essere estesi con plugin che usino dei bundler per processare JavaScript. Se estendere cos\u00ec i task runner \u00e8 per voi un problema, probabilmente dovrete fare un audit manuale e rimuovere il codice inutilizzato.<\/p>\n\n\n\n<p>Perch\u00e9 il tree shaking sia efficace, devono essere vere le seguenti condizioni:<\/p>\n\n\n\n<ol class=\"wp-block-list\"><li>La logica della vostra app e i package che installate nel vostro progetto devono essere creati come <a href=\"https:\/\/ponyfoo.com\/articles\/es6-modules-in-depth\">moduli ES6<\/a>. Fare tree shaking di moduli <a href=\"https:\/\/en.wikipedia.org\/wiki\/CommonJS\">CommonJS<\/a> non \u00e8 praticamente possibile.<\/li><li>Il vostro bundler <em>non<\/em> deve trasformare i moduli ES6 in un altro formato di modulo durante il build time. Se succede in una toolchain che usa Babel, <a href=\"https:\/\/babeljs.io\/docs\/en\/babel-preset-env\">@babel\/preset-env configuration<\/a> deve specificare <a href=\"https:\/\/babeljs.io\/docs\/en\/babel-preset-env#modules\"><code>modules: false<\/code><\/a> per impedire che il codice ES6 venga convertito a CommonJS.<\/li><\/ol>\n\n\n\n<p>Nella remota possibilit\u00e0 in cui il tree shaking non avvenga durante il build, potrebbe essere utile farlo funzionare. Ovviamente, la sua efficacia varia caso per caso. Dipende anche dal fatto che i moduli che importate introducano degli <a href=\"https:\/\/en.wikipedia.org\/wiki\/Side_effect_(computer_science)\">effetti collaterali<\/a>, che potrebbero influenzare la capacit\u00e0 del bundler di fare shaking degli export inutilizzati.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Suddividete quel codice<\/h3>\n\n\n\n<p>Ci sono delle buone possibilit\u00e0 che stiate usando una qualche forma di <a href=\"https:\/\/developers.google.com\/web\/fundamentals\/performance\/optimizing-javascript\/code-splitting\/\">code splitting<\/a>, ma vale la pena rivalutare come lo state facendo. Indipendentemente da <em>come<\/em> state suddividendo il codice, ci sono due domande che vale sempre la pena porsi:<\/p>\n\n\n\n<ol class=\"wp-block-list\"><li>State <a href=\"https:\/\/developers.google.com\/web\/fundamentals\/performance\/optimizing-javascript\/code-splitting\/#removing_duplicate_code\">de-duplicando il codice comune<\/a> tra gli <a href=\"https:\/\/webpack.js.org\/concepts\/entry-points\/\">entry point<\/a>?<\/li><li>State facendo lazy loading di tutte le funzionalit\u00e0 che potete ragionevolmente con <a href=\"https:\/\/developers.google.com\/web\/updates\/2017\/11\/dynamic-import\">dynamic <code>import()<\/code><\/a>?<\/li><\/ol>\n\n\n\n<p>Queste cose sono importanti perch\u00e9 ridurre il codice ridondante \u00e8 fondamentale per la performance. Anche la funzionalit\u00e0 lazy loading migliora la performance abbassando l&#8217;impronta iniziale di JavaScript su una data pagina. Sul fronte della ridondanza, usare un tool di analisi come <a href=\"https:\/\/github.com\/samccone\/bundle-buddy\">Bundle Buddy<\/a> pu\u00f2 aiutarvi a scoprire se avete un problema.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/alistapart.com\/wp-content\/uploads\/2019\/06\/figure-6-2x.png?w=435\" alt=\"The Bundle Buddy utility demonstrating how much code is shared between bundles of JavaScript.\" class=\"wp-image-7171674\" \/><figcaption>Bundle Buddy esamina le statistiche di compilazione del vostro webpack e determina quanto codice sia condiviso tra i vostri bundle.<\/figcaption><\/figure>\n\n\n\n<p>Quando c&#8217;\u00e8 in ballo il lazy loading, pu\u00f2 essere un po&#8217; difficile sapere da dove cominciare a cercare delle opportunit\u00e0. Quando le cerco in un progetto esistente, cercher\u00f2 i punti di interazione dell&#8217;utente in tutta la codebase, come gli eventi click e keyboard e candidati simili. Ogni codice che richiede un&#8217;interazione con l&#8217;utente per girare \u00e8 un potenziale buon candidato per l&#8217;<code>import()<\/code> dinamico.<\/p>\n\n\n\n<p>Ovviamente, caricare gli script on demand porta con s\u00e9 la possibilit\u00e0 che l&#8217;interattivit\u00e0 possa essere sensibilmente ritardata, dal momento che lo script necessario per l&#8217;interazione deve essere prima caricato. Se l&#8217;uso dei dati non \u00e8 un problema, prendete in considerazione l&#8217;uso del <a href=\"https:\/\/www.w3.org\/TR\/resource-hints\/#prefetch\">resource hint<code>rel=prefetch<\/code><\/a> per caricare tali script con una priorit\u00e0 minore, cos\u00ec non si contenderanno la banda con le risorse critiche. <a href=\"https:\/\/caniuse.com\/#feat=link-rel-prefetch\">Il supporto per <code>rel=prefetch<\/code><\/a> \u00e8 buono, ma non far\u00e0 danni se non \u00e8 supportato, dal momento che quei browser che non lo supportano ignoreranno il markup che non comprendono.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Esternalizzate il codice di terze parti hosted<\/h3>\n\n\n\n<p>Idealmente, dovreste fare self-hosting di quante pi\u00f9 dipendenze del vostro sito possibile. Se per qualche ragione <em>dovete<\/em> caricare le dipendenze da una terza parte, <a href=\"https:\/\/webpack.js.org\/configuration\/externals\/\">segnatele come esterne<\/a> nella configurazione del vostro bundler. Se non riuscite a farlo, potrebbe significare che i visitatori del vostro sito scaricheranno sia il codice ospitato localmente <em>sia<\/em> lo stesso codice da terze parti.<\/p>\n\n\n\n<p>Osserviamo un&#8217;ipotetica situazione in cui questo potrebbe danneggiarvi. Supponiamo che il vostro sito carichi Lodash da un CDN pubblico. Per\u00f2 avete anche installato Lodash nel vostro progetto per lo sviluppo locale. Tuttavia, se non riuscite a marcare Lodash come esterno, il vostro codice di produzione finir\u00e0 col caricarne una copia di terze parti <em>oltre<\/em> alla copia bundled, ospitata localmente.<\/p>\n\n\n\n<p>Potrebbe <em>sembrare<\/em> cosa nota se sapete come muovervi tra i bundler, ma ho visto che viene sottovalutata. Vale la pena controllare due volte.<\/p>\n\n\n\n<p>Se non siete convinti della necessit\u00e0 di ospitare sul vostro hosting le dipendenze di terze parti, allora prendete in considerazione l&#8217;opzione di aggiungere per loro <a href=\"https:\/\/css-tricks.com\/prefetching-preloading-prebrowsing\/#article-header-id-0\"><code>dns-prefetch<\/code><\/a>, <a href=\"https:\/\/css-tricks.com\/prefetching-preloading-prebrowsing\/#article-header-id-1\"><code>preconnect<\/code><\/a> o addirittura <a href=\"https:\/\/www.smashingmagazine.com\/2016\/02\/preload-what-is-it-good-for\/\"><code>preload<\/code><\/a>. In questo modo abbasserete il <a href=\"https:\/\/developers.google.com\/web\/tools\/lighthouse\/audits\/time-to-interactive\">Time to Interactive<\/a> del vostro sito e, se JavaScript \u00e8 cruciale per la resa del contenuto, lo <a href=\"https:\/\/sites.google.com\/a\/webpagetest.org\/docs\/using-webpagetest\/metrics\/speed-index\">Speed Index<\/a> del vostro sito.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Alternative pi\u00f9 piccole per minori overhead<\/h2>\n\n\n\n<p><a href=\"https:\/\/nodejs.org\/en\/knowledge\/getting-started\/what-is-node-core-verus-userland\/\"><a href=\"https:\/\/nodejs.org\/en\/knowledge\/getting-started\/what-is-node-core-verus-userland\/\">Userland JavaScript<\/a> \u00e8 come un negozio di caramelle esageratamente grande e noi sviluppatori siamo stupefatti dall&#8217;incredibile quantit\u00e0 di offerte open source. I framework e le librerie ci permettono di estendere le nostre applicazioni per fare tutta una serie di cose che altrimenti richiederebbero tonnellate di tempo e lavoro.<\/a><\/p>\n\n\n\n<p>Sebbene io personalmente preferisca minimizzare aggressivamente i framework e le librerie client-side dei miei progetti, il loro valore \u00e8 inestimabile. Tuttavia, noi <em>abbiamo<\/em> la responsabilit\u00e0 di essere un po&#8217; aggressivi quando si tratta di decidere cosa installare. Quando abbiamo gi\u00e0 realizzato e spedito qualcosa che dipende da un sacco di codice per funzionare, abbiamo accettato il fatto che solo i maintainer di quel codice lo possono gestire in pratica. Giusto?<\/p>\n\n\n\n<p>Forse, o forse no. Dipende dalle dipendenze che abbiamo usato. Per esempio, React \u00e8 estremamente popolare ma <a href=\"https:\/\/preactjs.com\/\">Preact<\/a> \u00e8 un&#8217;alternativa <a href=\"https:\/\/bundlephobia.com\/result?p=preact@8.4.2\">ultra-piccola<\/a> che condivide ampiamente la stessa API e mantiene la compatibilit\u00e0 con molti degli add-on di React. <a href=\"https:\/\/moment.github.io\/luxon\/\">Luxon<\/a> e <a href=\"https:\/\/date-fns.org\/\">date-fns<\/a> sono alternative molto pi\u00f9 compatte di <a href=\"https:\/\/momentjs.com\/\">moment.js<\/a>, che <a href=\"https:\/\/bundlephobia.com\/result?p=moment\">non \u00e8 esattamente piccolo<\/a>.<\/p>\n\n\n\n<p>Librerie come <a href=\"https:\/\/lodash.com\/\">Lodash<\/a> offrono molti metodi utili. tuttavia, alcuni di essi sono facilmente sostituibili con ES6 nativo. <a href=\"https:\/\/lodash.com\/docs\/4.17.11#compact\">Il metodo <code>compact<\/code> di Lodash<\/a>, per esempio, \u00e8 sostituibile con il <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/JavaScript\/Reference\/Global_Objects\/Array\/filter\">metodo array <code>filter<\/code><\/a>. <a href=\"https:\/\/github.com\/you-dont-need\/You-Dont-Need-Lodash-Underscore#_chunk\">Molti altri sono sostituibili<\/a> senza troppa fatica e senza il bisogno di richiamare una grande libreria di utility.<\/p>\n\n\n\n<p>Quali che siano i vostri tool preferiti, l&#8217;idea \u00e8 la stessa: fate delle ricerche per vedere se ci sono alternative pi\u00f9 piccole o se le feature del linguaggio nativo possono andare bene. Potreste rimanere stupiti da quanto poco ci voglia per ridurre seriamente l&#8217;overhead della vostra app.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Fate invio differenziato degli script<\/h2>\n\n\n\n<p>C&#8217;\u00e8 una buona possibilit\u00e0 che stiate usando Babel nella vostra toolchain per trasformare il vostro sorgente ES6 in codice che possa girare sui browser pi\u00f9 vecchi. Questo implica che siete costretti a inviare giganti bundle anche ai browser a cui non servono, finch\u00e9 non ci saranno pi\u00f9 i browser pi\u00f9 vecchi? <a href=\"https:\/\/philipwalton.com\/articles\/deploying-es2015-code-in-production-today\/\">Ovviamente no<\/a>! L&#8217;invio in maniera differenziata ci aiuta ad aggirare questo problema generando due diverse build del vostro sorgente ES6:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Bundle uno, che contiene tutte le transform e i polyfill richiesti dal vostro sito per funzionare sui browser pi\u00f9 vecchi. Probabilmente inviate gi\u00e0 questo bundle.<\/li><li>Bundle due, che contiene <em>pochi o nessun<\/em> transform e polyfill perch\u00e9 ha come obiettivo i browser moderni. Questo \u00e8 il bundle che forse non state <em>ancora<\/em> inviando.<\/li><\/ul>\n\n\n\n<p>Realizzare ci\u00f2 \u00e8 un po complicato. <a href=\"https:\/\/calendar.perfplanet.com\/2018\/doing-differential-serving-in-2019\/\">Ho scritto una guida riguardante un modo per farlo<\/a>, quindi non c&#8217;\u00e8 bisogno di entrare nei dettagli qui. Il succo della questione \u00e8 che potete modificare la configurazione della vostra build per generare una versione aggiuntiva ma pi\u00f9 piccola del codice JavaScript del sito e inviarla solo ai browser moderni. La parte migliore \u00e8 che risparmiate senza dover sacrificare alcuna feature o funzionalit\u00e0 che gi\u00e0 offrite. A seconda del codice della vostra applicazione, i risparmi potrebbero essere piuttosto significativi.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/alistapart.com\/wp-content\/uploads\/2019\/06\/diff-serving-bundles.jpg?w=960\" alt=\"\" class=\"wp-image-7171677\" \/><figcaption>Un&#8217;analisi di webpack-bundle-analyzer di un bundle legacy di un progetto (a sinistra) rispetto a una per un bundle moderno (destra). <a rel=\"noreferrer noopener\" href=\"https:\/\/alistapart.com\/wp-content\/uploads\/2019\/06\/diff-serving-bundles.jpg\" target=\"_blank\">Vedi immagine a dimensione reali<\/a>.<\/figcaption><\/figure>\n\n\n\n<p>Il <a href=\"https:\/\/developers.google.com\/web\/fundamentals\/primers\/modules#browser\">pattern pi\u00f9 semplice<\/a> per inviare questi bundle alle rispettive piattaforme \u00e8 breve. Inoltre, funziona benissimo nei browser moderni:<\/p>\n\n\n\n<pre id=\"snippet1\" class=\"wp-block-code language-html\"><code class=\"language-html\">&lt;!-- Modern browsers load this file: --&gt;\n<a href=\"\/js\/app.mjs\">\/js\/app.mjs<\/a>\n&lt;!-- Legacy browsers load this file: --&gt;\n<a href=\"\/js\/app.js\">\/js\/app.js<\/a><\/code><\/pre>\n\n\n\n<p>Sfortunatamente, c&#8217;\u00e8 una puntualizzazione riguardo a questo pattern: i browser legacy come IE 11, ma anche quelli relativamente moderni come Edge dalla versione 15 alla 18, scaricheranno <em>entrambe<\/em> i bundle. Se per voi questa cosa non \u00e8 un problema, allora siete a posto.<\/p>\n\n\n\n<p>D&#8217;altro canto, vi servir\u00e0 una soluzione temporanea se siete preoccupati <a href=\"https:\/\/gist.github.com\/jakub-g\/5fc11af85a061ca29cc84892f1059fec\">delle conseguenze sulla performance del download di entrambe i set di bundle da parte dei browser pi\u00f9 vecchi<\/a>. Ecco una soluzione potenziale che usa lo script injection (invece dei tag <code>script<\/code> di cui sopra) per evitare un download doppio che danneggi i browser:<\/p>\n\n\n\n<pre id=\"snippet2\" class=\"wp-block-code language-javascript\"><code class=\"language-javascript\">var scriptEl = document.createElement(\"script\");\n\nif (\"noModule\" in scriptEl) {\n  \/\/ Set up modern script\n  scriptEl.src = \"\/js\/app.mjs\";\n  scriptEl.type = \"module\";\n} else {\n  \/\/ Set up legacy script\n  scriptEl.src = \"\/js\/app.js\";\n  scriptEl.defer = true; \/\/ type=\"module\" defers by default, so set it here.\n}\n\n\/\/ Inject!\ndocument.body.appendChild(scriptEl);<\/code><\/pre>\n\n\n\n<p>Questo script deduce che se un browser supporta <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/HTML\/Element\/script#attr-nomodule\">l&#8217;attributo <code>nomodule<\/code><\/a> nell&#8217;elemento <code>script<\/code>, allora comprende <code>type=\"module\"<\/code>. Questo assicura che i browser legacy ottengano solo gli script legacy e i browser moderni ottengano solo quelli moderni. Attenti, per\u00f2! Gli script inviati dinamicamente si caricano in maniera asincrona di default, quindi impostate l&#8217;attributo <code>&lt;a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/HTML\/Element\/script#attr-async\"&gt;async&lt;\/a&gt;<\/code> a <code>false<\/code> se l&#8217;ordine delle dipendenze \u00e8 di cruciale importanza.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Fate meno transpiling<\/h2>\n\n\n\n<p class=\"has-text-align-left\">Non sono qui per devastare Babel. \u00c8 indispensabile, ma diamine, aggiunge <em>un sacco<\/em> di altre robe senza che nemmeno lo sappiate. Conviene guardare meglio dietro le quinte per vedere cosa fa. Alcuni cambiamenti minori nelle vostre abitudini di programmazione possono avere un impatto positivo su quello che butta fuori Babel.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/alistapart.com\/wp-content\/uploads\/2019\/06\/twete.png?w=306\" alt=\"\" class=\"wp-image-7171676\" \/><figcaption><a href=\"https:\/\/twitter.com\/_developit\/status\/1110229993999777793\">https:\/\/twitter.com\/_developit\/status\/1110229993999777793<\/a><\/figcaption><\/figure>\n\n\n\n<p>Per intenderci, <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/JavaScript\/Reference\/Functions\/Default_parameters\">i parametri di default<\/a> sono una feature <em>molto<\/em> pratica di ES6 che probabilmente usate gi\u00e0:<\/p>\n\n\n\n<pre id=\"snippet3\" class=\"wp-block-code language-javascript\"><code class=\"language-javascript\">function logger(message, level = \"log\") {\n  console[level](message);\n}<\/code><\/pre>\n\n\n\n<p>La cosa a cui prestare attenzione qui \u00e8 il parametro <code>level<\/code>, che ha come default \u201clog\u201d. Questo significa che se vogliamo invocare <code>console.log<\/code> con questa wrapper function, non dobbiamo specificare <code>level<\/code>. Ottimo, no? Tranne che quando Babel trasforma questa funzione, l&#8217;output appare cos\u00ec:<\/p>\n\n\n\n<pre id=\"snippet4\" class=\"wp-block-code language-javascript\"><code class=\"language-javascript\">function logger(message) {\n  var level = arguments.length &gt; 1 &amp;&amp; arguments[1] !== undefined ? arguments[1] : \"log\";\n\n  console[level](message);\n}<\/code><\/pre>\n\n\n\n<p>Questo \u00e8 un esempio di come, nonostante le nostre migliori intenzioni, la comodit\u00e0 dello sviluppatore possa ritorcerglisi contro. Quello che nel nostro sorgente era poco pi\u00f9 di una manciata di byte adesso \u00e8 stato trasformato in qualcosa di <em>molto<\/em> pi\u00f9 grosso nel codice in produzione. Neanche l&#8217;uglification pu\u00f2 farci granch\u00e9, dal momento che gli argomenti non possono essere ridotti. Oh e se state pensando che i <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/JavaScript\/Reference\/Functions\/rest_parameters\">rest parameter<\/a> potrebbero essere un valido antidoto, le trasformazioni che vi opera Babel sono ancora pi\u00f9 grosse:<\/p>\n\n\n\n<pre id=\"snippet5\" class=\"wp-block-code language-javascript\"><code class=\"language-javascript\">\/\/ Source\nfunction logger(...args) {\n  const [level, message] = args;\n\n  console[level](message);\n}\n\n\/\/ Babel output\nfunction logger() {\n  for (var _len = arguments.length, args = new Array(_len), _key = 0; _key &lt; _len; _key++) {\n    args[_key] = arguments[_key];\n  }\n\n  const level = args[0],\n        message = args[1];\n  console[level](message);\n}<\/code><\/pre>\n\n\n\n<p>Peggio ancora, Babel trasforma questo codice anche per progetti con una configurazione <a href=\"https:\/\/babeljs.io\/docs\/en\/babel-preset-env\">@babel\/preset-env<\/a> <a href=\"https:\/\/babeljs.io\/docs\/en\/babel-preset-env#targetsesmodules\">indirizzata ai browser moderni<\/a>, il che significa che saranno interessati anche i bundle moderni nel vostro JavaScript inviato in maniera differenziata! <em>Potreste<\/em> usare una <a href=\"https:\/\/babeljs.io\/docs\/en\/babel-preset-env#loose\">loose transforms<\/a> per attutire il colpo &#8211; ed \u00e8 una buona idea, dal momento che sono spesso un po&#8217; pi\u00f9 piccoli delle loro controparti pi\u00f9 spec-compliant &#8211; <a href=\"http:\/\/2ality.com\/2015\/12\/babel6-loose-mode.html\">ma abilitare le loose transform pu\u00f2 causare problemi se in seguito rimuoverete Babel dalla vostra build pipeline<\/a>.<\/p>\n\n\n\n<p>Indipendentemente se decidiate di abilitare le loose transform o meno, ecco un modo per tagliare il cruft (codice progettato male, inutilmente complicato, ndt) dei parametri di default trasnpiled.<\/p>\n\n\n\n<pre id=\"snippet6\" class=\"wp-block-code language-javascript\"><code class=\"language-javascript\"><pre id=\"snippet2\" class=\"wp-block-code language-javascript\"><code class=\"language-javascript\">\/\/ Babel won't touch this\nfunction logger(message, level) {\n  console[level || \"log\"](message);\n}<\/code><\/pre><\/code><\/pre>\n\n\n\n<p>Ovviamente, i parametri di default non sono l&#8217;<em>unica<\/em> feature a cui prestare attenzione. Per esempio, la <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/JavaScript\/Reference\/Operators\/Spread_syntax\">spread syntax<\/a> viene trasformata, cos\u00ec come le <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/JavaScript\/Reference\/Functions\/Arrow_functions\">arrow function<\/a> e tutto un insieme di <a href=\"https:\/\/babeljs.io\/repl\/#?babili=false&amp;browsers=%3E%200.25%25%2C%20ie%20%3E%2010%2C%20Firefox%20ESR%2C%20not%20dead&amp;build=&amp;builtIns=false&amp;spec=false&amp;loose=false&amp;code_lz=MYGwhgzhAECyYDsCuAzMwAuSBOBTb0A3gFDTTAD2CEG2SmFBAFALaKrpZ7YA05FSBLQCeASiKky0DAAsAlhAB0bZGkw580ALzQVHddwDcksrIWLKgkdv5Xsw42QC-xF8VCQYAYTAFcADwxcBAATGHhVTg0CEjJKalp6DEZoVgoQ3BA-YVxfPkoQRj5FEt8AcwhxWKkIJAAHfCYSxXLKxykTaXklFnTMm16MkHbTbsUc3xsJ7BGu8wKUnQWZyRcySTw6sDkhVOWqzrMlZZtl9pc3eJpoNBY5EGEfAh0EXAB3aCemACIfFntvnxvgAmAAMoOBgOg3wAMoJJrAFBg4LgMGAQCA5MAod8ACoUYQUNE4gBSYC2CG-okMQA&amp;debug=false&amp;forceAllTransforms=false&amp;shippedProposals=false&amp;circleciRepo=&amp;evaluate=true&amp;fileSize=true&amp;timeTravel=false&amp;sourceType=module&amp;lineWrap=true&amp;presets=env&amp;prettier=false&amp;targets=&amp;version=7.4.5&amp;externalPlugins=\">altre cose<\/a>.<\/p>\n\n\n\n<p>Se non volete evitare queste features in toto, ci sono un paio di modi per ridurne l&#8217;impatto:<\/p>\n\n\n\n<ol class=\"wp-block-list\"><li>se state scrivendo una libreria, prendete in considerazione l&#8217;utilizzo di <a href=\"https:\/\/babeljs.io\/docs\/en\/babel-runtime\">@babel\/runtime<\/a> insieme a <a href=\"https:\/\/babeljs.io\/docs\/en\/babel-plugin-transform-runtime\">@babel\/plugin-transform-runtime<\/a> per de-duplicare le helper function che Babel mette nel vostro codice.<\/li><li>Per le feature a cui sono applicati polyfill nelle app, potete includerli selettivamente con <a href=\"https:\/\/babeljs.io\/docs\/en\/babel-polyfill\">@babel\/polyfill<\/a> attraverso l&#8217;opzione <a href=\"https:\/\/babeljs.io\/docs\/en\/babel-preset-env#usebuiltins\">useBuiltIns: &#8220;usage&#8221; di @babel\/preset-env<\/a>.<\/li><\/ol>\n\n\n\n<p>\u00c8 solo la mia opinione, ma io credo che la scelta migliore sia quella di evitare completamente la transpilation nei bundle generati per i browser moderni. Non \u00e8 sempre possibile, specialmente se usate <a href=\"https:\/\/reactjs.org\/docs\/introducing-jsx.html\">JSX<\/a>, che deve essere trasformato per <em>tutti<\/em> i browser, o se state usando delle feature davvero all&#8217;avanguardia che non sono ampiamente supportate. In quest&#8217;ultimo caso, potrebbe valere la pena chiedersi se queste feature siano veramente necessarie per realizzare una buona user experience (e raramente lo sono). Se arrivate alla conclusione che Babel deve far parte della vostra toolchain, allora vale la pena osservare pi\u00f9 in profondit\u00e0, di tanto in tanto, per trovare le cose sub-ottimali che Babel sta facendo che potete migliorare.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Il miglioramento non \u00e8 una gara<\/h2>\n\n\n\n<p>Mentre vi massaggiate le tempie chiedendovi quando finir\u00e0 questo orribile hungover da JavaScript, dovete capire che \u00e8 esattamente quando ci affrettiamo a mandare fuori qualcosa il prima possibile che la user experience soffre. Mentre la web development community si ossessiona sulle iterazioni sempre pi\u00f9 rapide in nome della competizione, vale la pena <a href=\"https:\/\/en.wikipedia.org\/wiki\/Thinking,_Fast_and_Slow\"><em>rallentare un po&#8217;<\/em><\/a>. Scoprirete che facendo cos\u00ec potreste non iterare tanto velocemente quanto i vostri competitor, ma <em>il vostro prodotto<\/em> sar\u00e0 <em>pi\u00f9 veloce<\/em> del loro.<\/p>\n\n\n\n<p>Dovete sapere che se applicate questi suggerimenti alla vostra codebase, non avanzerete spontaneamente dalla sera alla mattina. Il web development \u00e8 un lavoro. Il vostro lavoro di maggior impatto verr\u00e0 fatto quando vi sarete dedicati in maniera ponderata a questo mestiere per un lungo periodo. Concentratevi su miglioramenti continui. Misurate, testate, ripete e la user experience del vostro sito migliorer\u00e0 e diventerete sempre pi\u00f9 veloci.<\/p>\n\n\n\n<p><em><em>Un ringraziamento speciale va a <\/em><a href=\"https:\/\/twitter.com\/_developit\"><em>Jason Miller<\/em><\/a><em> per il tech editing di questo articolo. Jason \u00e8 il creatore e uno dei tanti maintainer di <\/em><a href=\"https:\/\/preactjs.com\/\"><em>Preact<\/em><\/a>, un&#8217;alternativa enormemente pi\u00f9 piccola di React, con la stessa API. Se usate Preact, <a href=\"https:\/\/opencollective.com\/preact\"><em>, per favore, prendete in considerazione di supportarlo via Open Collective<\/em><\/a>.<\/em><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Lo sviluppo web \u00e8 difficile. Non sempre si riesce al primo tentativo. Fortunatamente, non dobbiamo fare tutto perfetto fin dall&#8217;inizio. Jeremy Wagner delinea alcuni modi utili per cominciare a riprenderci dal nostro hangover collettivo da JavaScript.<\/p>\n","protected":false},"author":22,"featured_media":7001121,"comment_status":"closed","ping_status":"closed","template":"","categories":[269,242,271],"tags":[546],"coauthors":[500],"class_list":["post-7001120","article","type-article","status-publish","has-post-thumbnail","hentry","category-application-development","category-browser","category-javascript","tag-featured"],"jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/alistapart.com\/it\/wp-json\/wp\/v2\/article\/7001120","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/alistapart.com\/it\/wp-json\/wp\/v2\/article"}],"about":[{"href":"https:\/\/alistapart.com\/it\/wp-json\/wp\/v2\/types\/article"}],"author":[{"embeddable":true,"href":"https:\/\/alistapart.com\/it\/wp-json\/wp\/v2\/users\/22"}],"replies":[{"embeddable":true,"href":"https:\/\/alistapart.com\/it\/wp-json\/wp\/v2\/comments?post=7001120"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/alistapart.com\/it\/wp-json\/wp\/v2\/media\/7001121"}],"wp:attachment":[{"href":"https:\/\/alistapart.com\/it\/wp-json\/wp\/v2\/media?parent=7001120"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/alistapart.com\/it\/wp-json\/wp\/v2\/categories?post=7001120"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/alistapart.com\/it\/wp-json\/wp\/v2\/tags?post=7001120"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/alistapart.com\/it\/wp-json\/wp\/v2\/coauthors?post=7001120"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}