Un insieme di note per la configurazione di un ambiente di sviluppo per ES6, sia frontend che backend. Perché per quanto Webpack sia un labirinto, con un filo di arianna la strada si può trovare.
Per utilizzare ES6 nel config di Webpack è necessario:
-
Chiamare il file
webpack.config.babel.js
(per far riconoscere a webpack che è necessario chiamare ilbabel-loader
). -
Installare
babel-loader
(npm i --save-dev babel-core babel-loader
) -
Installare i plugin e i preset necessari, ad esempio:
"devDependencies": { "babel-plugin-transform-flow-strip-types": "^6.7.0", "babel-preset-es2015": "^6.6.0", "babel-preset-react": "^6.5.0", "babel-preset-stage-0": "^6.5.0" }
-
Creare un file
.babelrc
per far riconoscere a webpack quali opzioni utilizzare per ilwebpack.config.babel.js
{ "presets": ["react", "es2015", "stage-0"], "plugins": [ "transform-flow-strip-types" ] }
Le entry sono sempre percorsi 'relativi'. Utilizzare ad esempio ./index.js
al posto di index.js
.
export default {
entry: './index.js'
// ..
}
Target
di default èweb
(Front-End), mentre invece per il Back-end bisogna specificarenode
output.libraryTarget
specificare'commonjs2'
in caso il codice debba essere utilizzato da node.
export default {
// ..
target: 'node', // Di default è 'web' ed è ok per il front-end
output: {
filename: 'server.js', // Oppure [name].js in caso di più entry
path: distPath, // Path Assoluta
publicPath: publicPath, // Path relativa i.e. `dist/`
libraryTarget: 'commonjs2' // Necessario in caso il codice sia per un server, quindi Node.
}
}
Gli external
permettono di far ignorare a WebPack degli import
specifici, in modo tale che vengano presi dall'Environment e non debbano essere cercati all'interno dei file dell'applicazione.
E' necessario specialmente lato backend, per evitare che vengano compressi all'interno del Bundle finale le dipendenze, che invece rimangono gestite dal sistema di import di Node.js.
// Più semplice, ma in realtà meno corretto:
externals: /^[a-z\-0-9]+$/,
...
// Più preciso ma lungo
let nodeModules = fs.readdirSync('node_modules')
.filter((x) => ['.bin'].indexOf(x) === -1 });
export default {
...
externals: (context, request, callback) => {
var pathStart = request.split('/')[0];
if(nodeModules.indexOf(pathStart) >= 0 && request != 'webpack/hot/signal.js') {
return callback(null, "commonjs " + request);
};
callback();
}
}
Per supportare le SourceMap, è necessario utilizzare (lato server) la libreria source-map-support
(su npm). Quindi eseguire npm i source-map-support --save-dev
, e poi aggiungere nel config di Webpack:
export default {
...
devtool: 'source-map',
plugins: [
new webpack.BannerPlugin('require("source-map-support").install();',
{ raw: true, entryOnly: false }),
...
]
}
Le lambda
, o arrow function
permettono di utilizzare una sintassi più semplice per la definizione di funzioni:
let fun = (param, other) => {
...
}
In caso di un solo parametro, le parentesi possono essere omesse:
let squared = n => {
return n * n
}
Inoltre, in caso il corpo della funzione sia composto da un solo statement, è possibile omettere le parentesi graffe e l'istruzione di return
.
let squared = n => n * n
Caratteristica fondamentale delle Lambda è quella di catturare il this
del contesto in cui vengono definite, senza definirne uno nuovo come accade per le function(){}
, ad esempio:
let heroDisplay = {
name: 'Luke Skywalker',
displayLater: function() {
/**
* Senza il `lexical this`, `this.name` sarebbe stato 'undefined'
*/
setTimeout(() => console.log('Il mio eroe è ' + this.name));
}
}
heroDisplay.displayLater(); // stampa 'Il mio eroe è Luke Skywalker'
// Definizione classe
class Hero {
// Costruttore chiamato con la keyword new
constructor(name) {
this.name = name;
}
// Metodo definito senza utilizzare la keyword `function`
displayName() {
console.log(this.name);
}
}
let hero = new Hero('Michael Jordan');
hero.displayName();