Come ridurre al minimo le dimensioni del pacchetto Webpack?

Sto scrivendo un’app Web utilizzando react e webpack come il mio modulo bundler. Il mio codice jsx è davvero leggero finora, la dimensione dell’intera cartella è 25 kb.

Il mio bundle.js creato da webpack è 2.2 MB. Dopo aver eseguito l’ottimizzazione con il flag -p , riduce il bundle a 700kb, che è ancora estremamente grande.

Ho esaminato il file react.min.js e la sua dimensione è 130kb.

È ansible che il webpack produca file così grandi o sto facendo qualcosa di sbagliato?

webpack.config.js

 var path = require('path'); var webpack = require('webpack'); module.exports = { entry: './public/components/main.jsx', output: { path: __dirname + "/public", filename: 'bundle.js' }, module: { loaders: [{ test: /.jsx?$/, loader: 'babel-loader', exclude: /node_modules/, query: { presets: ['es2015', 'react'] } }, { test: /\.css$/, loader: "style!css" }] } }; 

MODIFICARE

package.json:

 { "name": "XChange", "version": "0.0.0", "private": true, "scripts": { "start": "node ./bin/www" }, "main": "./bin/www", "devDependencies": { "body-parser": "~1.13.2", "cookie-parser": "~1.3.5", "debug": "~2.2.0", "express": "~4.13.1", "jade": "~1.11.0", "morgan": "~1.6.1", "serve-favicon": "~2.3.0", "react-dom": "~0.14.3", "react": "~0.14.3", "webpack": "~1.12.9", "babel-loader": "~6.2.0", "babel-core": "~6.2.1", "babel-preset-react": "~6.1.18", "babel-preset-es2015": "~6.1.18", "react-bootstrap": "~0.28.1", "material-ui": "~0.14.0-rc1", "history": "~1.13.1", "react-router": "~1.0.2", "style-loader": "~0.13.0", "css-loader": "~0.18.0" }, "dependencies": { "express-validator": "~2.18.0", "mongoose": "~4.2.9", "kerberos": "~0.0.17", "bcrypt": "~0.8.5" } } 

Secondo i tuoi commenti stai usando material-ui e react-bootstrap . Queste dipendenze sono raggruppate in pacchetti web insieme ai tuoi pacchetti react e react-dom . Ogni volta che require o import un pacchetto, questo viene raggruppato come parte del tuo file bundle.

E qui arriva la mia ipotesi. Probabilmente stai importando i componenti react-bootstrap e material-ui usando la modalità libreria :

 import { Button } from 'react-bootstrap'; import { FlatButton } from 'material-ui'; 

Questo è utile e pratico, ma non raggruppa solo Button e FlatButton (e le loro dipendenze) ma le intere librerie.

Un modo per alleviarlo è cercare di import o require ciò che è necessario, diciamo la via del componente . Utilizzando lo stesso esempio:

 import Button from 'react-bootstrap/lib/Button'; import FlatButton from 'material-ui/lib/flat-button'; 

Questo raggrupperà solo Button , FlatButton e le loro rispettive dipendenze. Ma non l’intera biblioteca. Quindi proverei a sbarazzarmi di tutte le importazioni della tua libreria e invece userò la modalità componente .

Se non si utilizzano molti componenti, è necessario ridurre notevolmente le dimensioni del file in dotazione.

Come ulteriore spiegazione:

Quando si utilizza la libreria in modo in cui si stanno importando tutti questi react-bootstrap e tutti questi componenti del materiale-ui , indipendentemente da quelli che si stanno effettivamente utilizzando.

EDIZIONE 01/2017 – Da allora ho imparato un po ‘di più sui diversi Webpack Plugin e ho voluto aggiornarlo. Si scopre che UglifyJS ha un po ‘di opzioni di configurazione che non sembrano essere molto diffuse, ma possono avere un effetto drammatico sulle dimensioni del bundle. Questa è la mia attuale configurazione con alcune annotazioni (i documenti sul sito sono fantastici):

  new webpack.optimize.UglifyJsPlugin({ comments: false, // remove comments compress: { unused: true, dead_code: true, // big one--strip code that will never execute warnings: false, // good for prod apps so users can't peek behind curtain drop_debugger: true, conditionals: true, evaluate: true, drop_console: true, // strips console statements sequences: true, booleans: true, } }) 

Una volta ho riscontrato un oscuro problema con uglify ugolarizzazione di caratteri unicode sfuggiti, quindi sii consapevole che se usi queste trasformazioni è ansible che cose del genere siano così.

Puoi leggere ulteriori informazioni sulle opzioni specifiche supportate dal webpack nei documenti webpack con alcuni link di follow-on per ulteriori letture.


(sidenote: Penso che il tuo pacchetto.json sia confuso … almeno alcuni di questi dipendono da dipendenze in ogni pacchetto. json che ho visto (ad esempio, il kit di avvio reattivo )

Se ti stai preparando per la produzione, ci sono ancora alcuni passi da fare per ridurre le dimensioni del tuo file. Ecco uno snip del mio webpack.config.js:

  plugins: [ new webpack.optimize.UglifyJsPlugin(), new webpack.optimize.DedupePlugin(), new webpack.DefinePlugin({ 'process.env': { 'NODE_ENV': JSON.stringify('production') } }) ], 

1) minimizza / migliora il tuo codice

2) sostituisce il codice duplicato per ridurre al minimo le dimensioni del file

3) dice al webpack di omettere alcune cose che usa per le build dell’ambiente del nodo

Infine, se usi una mappa sorgente (che probabilmente dovresti), ti consigliamo di aggiungere la linea appropriata. Sentry ha scritto un bel post sul blog su questo .

Nella mia build, uso devtool: 'source-map' per la produzione

AGGIORNAMENTO 05/18: aggiorna l’impostazione UglifyJsPlugin per una migliore minificazione

Io uso sotto la configurazione per la minificazione nel codice di produzione.

  plugins: [ new webpack.DefinePlugin({ 'process.env': { // This has effect on the react lib size 'NODE_ENV': JSON.stringify('production'), } }), new ExtractTextPlugin("bundle.css", {allChunks: false}), new webpack.optimize.AggressiveMergingPlugin(), new webpack.optimize.OccurrenceOrderPlugin(), new webpack.optimize.DedupePlugin(), new webpack.optimize.UglifyJsPlugin({ mangle: true, compress: { warnings: false, // Suppress uglification warnings pure_getters: true, unsafe: true, unsafe_comps: true, screw_ie8: true, conditionals: true, unused: true, comparisons: true, sequences: true, dead_code: true, evaluate: true, if_return: true, join_vars: true }, output: { comments: false, }, exclude: [/\.min\.js$/gi] // skip pre-minified libs }), new webpack.IgnorePlugin(/^\.\/locale$/, [/moment$/]), new CompressionPlugin({ asset: "[path].gz[query]", algorithm: "gzip", test: /\.js$|\.css$|\.html$/, threshold: 10240, minRatio: 0 }) ], 

Hai esaminato il modo in cui gli script vengono inviati tramite il filo … Ho avuto alcuni componenti di reazione molto semplici, con una risoluzione di circa 300kb ciascuno, e ciò dopo le ottimizzazioni del webpack. Dopo che sono stati compressi con gz, sono scesi a 38kb. Ancora considerevole – ma è quello che otteniamo oggi con le funzionalità di Tomorrow. Se stai usando node / express per servire risorse statiche, incluso il tuo javascript, guarda alla compressione ( https://github.com/expressjs/compression ). Suggerirei anche di consultare la guida alle best practice del nodo per la produzione https://expressjs.com/en/advanced/best-practice-performance.html Se non stai servendo i file attraverso il nodo, quindi apache (o altro server web) avrà opzioni per la compressione di file basati su testo.

Trovo utile menzionare l’utilità source-map-explorer che aiuta a sapere cosa si trova esattamente nel file bundle.js. Può aiutarti a identificare se ci sono cose inutili in bundle js. puoi installare source-map-explorer da npm e usarlo come

 source-map-explorer yourBundle.js 

Oltre a ciò, come menzionato da @kimmiju, controlla se il tuo server sta usando una certa compressione.

Scheda di rete in Chrome

Puoi anche provare a caricare in modo asincrono percorsi (caricamento lazy nel webpack), in modo che l’intero file bundlejs non venga inviato in una volta sola, ma viene inviato in blocchi quando l’utente naviga verso tali percorsi.