Webpack verwenden, um deine App so klein wie möglich zu machen
Bei der Optimierung einer Anwendung sollten Sie zunächst möglich. So gehts mit Webpack.
Produktionsmodus verwenden (nur Webpack 4)
Mit Webpack 4 wurde das neue mode
-Flag eingeführt. Sie könnten Folgendes festlegen:
dieses Flag auf 'development'
oder 'production'
setzen, um auf Webpack hinzuweisen, dass du gerade entwickelst
die Anwendung für eine bestimmte Umgebung:
// webpack.config.js
module.exports = {
mode: 'production',
};
Achte darauf, den production
-Modus zu aktivieren, wenn du deine App für die Produktion entwickelst.
Dadurch kann Webpack Optimierungen wie die Reduzierung von Code und die Entfernung von reinem Entwicklungscode anwenden.
in Bibliotheken und mehr.
Weitere Informationen
Reduzierung aktivieren
Bei der Minimierung wird der Code komprimiert, indem Sie zusätzliche Leerzeichen entfernen, Variablennamen kürzen so weiter. Ein Beispiel:
// Original code
function map(array, iteratee) {
let index = -1;
const length = array == null ? 0 : array.length;
const result = new Array(length);
while (++index < length) {
result[index] = iteratee(array[index], index, array);
}
return result;
}
↓
// Minified code
function map(n,r){let t=-1;for(const a=null==n?0:n.length,l=Array(a);++t<a;)l[t]=r(n[t],t,n);return l}
Webpack unterstützt zwei Möglichkeiten zum Reduzieren des Codes: Reduzierung auf Bundle-Ebene und loader-spezifischen Optionen. Sie sollten gleichzeitig verwendet werden.
Komprimierung auf Bundle-Ebene
Bei der Komprimierung auf Bundle-Ebene wird das gesamte Bundle nach der Kompilierung komprimiert. So funktionierts:
Sie schreiben Code wie folgt:
// comments.js import './comments.css'; export function render(data, target) { console.log('Rendered!'); }
Webpack kompiliert sie in ungefähr folgende Elemente:
// bundle.js (part of) "use strict"; Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); /* harmony export (immutable) */ __webpack_exports__["render"] = render; /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__comments_css__ = __webpack_require__(1); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__comments_css_js___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_0__comments_css__); function render(data, target) { console.log('Rendered!'); }
Der Komprimierungsvorgang komprimiert die Datei in etwa so:
// minified bundle.js (part of) "use strict";function t(e,n){console.log("Rendered!")} Object.defineProperty(n,"__esModule",{value:!0}),n.render=t;var o=r(1);r.n(o)
In Webpack 4 ist die Reduzierung auf Bundle-Ebene automatisch aktiviert – beide in der Produktionsphase.
und ohne einen Modus. Sie verwendet den UglifyJS-Minifier.
im Hintergrund. Wenn Sie die Reduzierung deaktivieren möchten, verwenden Sie einfach den Entwicklungsmodus
oder false
an die Option optimization.minimize
übergeben.)
In Webpack 3 müssen Sie das UglifyJS-Plug-in verwenden.
. Das Plug-in ist im Webpack enthalten. Fügen Sie sie zum Aktivieren der plugins
hinzu
der Konfiguration:
// webpack.config.js
const webpack = require('webpack');
module.exports = {
plugins: [
new webpack.optimize.UglifyJsPlugin(),
],
};
Loader-spezifische Optionen
Die zweite Möglichkeit, den Code zu komprimieren, sind loader-spezifische Optionen (was ein Loader
ist. Mit Ladeoptionen können Sie Inhalte komprimieren,
kann der Minifier nicht reduzieren. Wenn Sie beispielsweise eine CSS-Datei mit
css-loader
wird die Datei in einen String kompiliert:
/* comments.css */
.comment {
color: black;
}
// minified bundle.js (part of)
exports=module.exports=__webpack_require__(1)(),
exports.push([module.i,".comment {\r\n color: black;\r\n}",""]);
Der Code kann nicht komprimiert werden, da es sich um einen String handelt. Um den Dateiinhalt zu komprimieren, müssen wir konfigurieren Sie das Ladeprogramm so:
// webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.css$/,
use: [
'style-loader',
{ loader: 'css-loader', options: { minimize: true } },
],
},
],
},
};
Weitere Informationen
- The UglifyJsPlugin-Dokumentation
- Andere beliebte Minifier: Babel Minify, Google-Schließung Compiler
Geben Sie NODE_ENV=production
an
Sie können die Frontend-Größe auch verringern, indem Sie den NODE_ENV
Umgebungsvariable
in Ihrem Code auf den Wert production
.
Bibliotheken lesen die Variable NODE_ENV
, um zu erkennen, in welchem Modus sie arbeiten – in der
oder in der Produktion. Einige Bibliotheken verhalten sich basierend auf dieser Variablen unterschiedlich. Für
Wenn NODE_ENV
beispielsweise nicht auf production
gesetzt ist, führt Vue.js zusätzliche Prüfungen durch und gibt aus
Warnungen:
// vue/dist/vue.runtime.esm.js
// …
if (process.env.NODE_ENV !== 'production') {
warn('props must be strings when using array syntax.');
}
// …
React funktioniert ähnlich: Es wird ein Entwicklungs-Build geladen, der die folgenden Warnungen enthält:
// react/index.js
if (process.env.NODE_ENV === 'production') {
module.exports = require('./cjs/react.production.min.js');
} else {
module.exports = require('./cjs/react.development.js');
}
// react/cjs/react.development.js
// …
warning$3(
componentClass.getDefaultProps.isReactClassApproved,
'getDefaultProps is only used on classic React.createClass ' +
'definitions. Use a static property named `defaultProps` instead.'
);
// …
Solche Prüfungen und Warnungen sind in der Produktion in der Regel nicht erforderlich, verbleiben aber im Code und
um die Bibliothek zu vergrößern. In Webpack 4: Entferne sie,indem du
die Option optimization.nodeEnv: 'production'
:
// webpack.config.js (for webpack 4)
module.exports = {
optimization: {
nodeEnv: 'production',
minimize: true,
},
};
In Webpack 3 verwende stattdessen DefinePlugin
:
// webpack.config.js (for webpack 3)
const webpack = require('webpack');
module.exports = {
plugins: [
new webpack.DefinePlugin({
'process.env.NODE_ENV': '"production"'
}),
new webpack.optimize.UglifyJsPlugin()
]
};
Die Option optimization.nodeEnv
und DefinePlugin
funktionieren auf die gleiche Weise:
Sie ersetzen alle Vorkommen von process.env.NODE_ENV
durch den angegebenen Wert. Mit der
Konfiguration aus:
Webpack ersetzt "
process.env.NODE_ENV
" in allen Vorkommen durch"production"
:// vue/dist/vue.runtime.esm.js if (typeof val === 'string') { name = camelize(val); res[name] = { type: null }; } else if (process.env.NODE_ENV !== 'production') { warn('props must be strings when using array syntax.'); }
↓
// vue/dist/vue.runtime.esm.js if (typeof val === 'string') { name = camelize(val); res[name] = { type: null }; } else if ("production" !== 'production') { warn('props must be strings when using array syntax.'); }
Dann entfernt das Mini-Tool alle
if
Zweige – weil"production" !== 'production'
immer „false“ (falsch) ist, Das Plug-in versteht, dass der Code in diesen Zweigen niemals ausgeführt wird:// vue/dist/vue.runtime.esm.js if (typeof val === 'string') { name = camelize(val); res[name] = { type: null }; } else if ("production" !== 'production') { warn('props must be strings when using array syntax.'); }
↓
// vue/dist/vue.runtime.esm.js (without minification) if (typeof val === 'string') { name = camelize(val); res[name] = { type: null }; }
Weitere Informationen
- Was sind Umgebungsvariablen
- Webpack-Dokumentation zu:
DefinePlugin
,EnvironmentPlugin
ES-Module verwenden
Die nächste Möglichkeit zum Verringern der Frontend-Größe besteht in der Verwendung von ES Module.
Wenn Sie ES-Module verwenden, kann Webpack Tree-Shaking ausführen. Beim Baumwollen wird ein Bundler durchläuft die gesamte Abhängigkeitsstruktur, überprüft, welche Abhängigkeiten verwendet werden, und entfernt ungenutzte Abhängigkeiten. Also: Wenn du die Syntax des ES-Moduls verwendest, kann Webpack den nicht verwendeten Code entfernen:
Sie schreiben eine Datei mit mehreren Exporten, aber die Anwendung verwendet nur einen davon:
// comments.js export const render = () => { return 'Rendered!'; }; export const commentRestEndpoint = '/rest/comments'; // index.js import { render } from './comments.js'; render();
Webpack erkennt, dass
commentRestEndpoint
nicht verwendet wird, und generiert daher kein separaten Exportpunkt im Bundle:// bundle.js (part that corresponds to comments.js) (function(module, __webpack_exports__, __webpack_require__) { "use strict"; const render = () => { return 'Rendered!'; }; /* harmony export (immutable) */ __webpack_exports__["a"] = render; const commentRestEndpoint = '/rest/comments'; /* unused harmony export commentRestEndpoint */ })
Mit dem Reduzierer wird die nicht verwendete Variable entfernt:
// bundle.js (part that corresponds to comments.js) (function(n,e){"use strict";var r=function(){return"Rendered!"};e.b=r})
Das funktioniert auch bei Bibliotheken, die mit ES-Modulen geschrieben wurden.
Sie müssen jedoch nicht unbedingt den integrierten Minifier (UglifyJsPlugin
) von Webpack verwenden.
Jeder Minifier, der die Entfernung veralteter Codes unterstützt
(z.B. Babel Minify-Plug-in)
oder Google Closure Compiler-Plug-in)
wird es helfen.
Weitere Informationen
Webpack-Dokumentation zum Baumschütteln
Bilder optimieren
Bilder machen mehr als eine
die Hälfte der Seitengröße. Während sie
sind nicht so wichtig wie JavaScript (z.B. blockieren nicht das Rendering), verbrauchen dennoch einen großen Teil des
die Bandbreite. Verwenden Sie url-loader
, svg-url-loader
und image-webpack-loader
, um sie in
Webpack.
url-loader
fügt kleine statische Dateien in das
Ohne Konfiguration nimmt er eine übergebene Datei, legt sie neben das kompilierte Bundle ab und gibt
die URL dieser Datei. Wenn wir jedoch die Option limit
angeben, werden Dateien kleiner als
dieses Limit als Base64-Daten-URL angeben und diese URL zurückgeben. Dieses
fügt das Bild in den JavaScript-Code ein und speichert eine HTTP-Anfrage:
// webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.(jpe?g|png|gif)$/,
loader: 'url-loader',
options: {
// Inline files smaller than 10 kB (10240 bytes)
limit: 10 * 1024,
},
},
],
}
};
// index.js
import imageUrl from './image.png';
// → If image.png is smaller than 10 kB, `imageUrl` will include
// the encoded image: 'data:image/png;base64,iVBORw0KGg…'
// → If image.png is larger than 10 kB, the loader will create a new file,
// and `imageUrl` will include its url: `/2fcd56a1920be.png`
svg-url-loader
funktioniert genau wie url-loader
–
Der einzige Unterschied besteht darin, dass er Dateien mit der URL
Codierung anstelle von Base64
eins. Dies ist nützlich für SVG-Bilder. Da es sich bei SVG-Dateien nur um Nur-Text-Dateien handelt, ist diese Codierung
größeneffizienter machen.
module.exports = {
module: {
rules: [
{
test: /\.svg$/,
loader: "svg-url-loader",
options: {
limit: 10 * 1024,
noquotes: true
}
}
]
}
};
Mit image-webpack-loader
werden Bilder komprimiert,
durch sie hindurch. Es unterstützt JPG-, PNG-, GIF- und SVG-Bilder, daher werden wir es für alle diese Typen verwenden.
Dieses Ladeprogramm bettet keine Bilder in die App ein. Es muss also in Kombination mit url-loader
und
svg-url-loader
. Um zu vermeiden, dass der Code in beide Regeln eingefügt wird (eine für JPG-/PNG-/GIF-Bilder und eine andere für JPG-/PNG-/GIF-Bilder und eine weitere
eine für SVG-Dateien), fügen wir diesen Loader als separate Regel in enforce: 'pre'
ein:
// webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.(jpe?g|png|gif|svg)$/,
loader: 'image-webpack-loader',
// This will apply the loader before the other ones
enforce: 'pre'
}
]
}
};
Die Standardeinstellungen des Loaders sind bereits eingerichtet, Sie können sie aber konfigurieren. Weitere Informationen zu den Plug-in-Optionen Bis welche Optionen angegeben werden sollen, schauen Sie sich Addy Osmanis hervorragenden Bildleitfaden Optimierung.
Weitere Informationen
Abhängigkeiten optimieren
Mehr als die Hälfte der durchschnittlichen JavaScript-Größe ist auf Abhängigkeiten zurückzuführen. Ein Teil unnötig sein.
Lodash (ab Version 4.17.4) fügt dem Bundle beispielsweise 72 KB reduzierten Code hinzu. Wenn Sie jedoch nur bei 20 Methoden, dann bewirken etwa 65 KB reduzierten Code einfach nichts.
Ein weiteres Beispiel ist Moment.js. Die Version 2.19.1 benötigt 223 KB reduzierten Code, was enorm ist. lag die durchschnittliche Größe von JavaScript auf einer Seite im Oktober bei 452 KB 2017 170 KB dieser Größe ist Lokalisierung Dateien. Wenn Moment.js nicht mit mehreren Sprachen verwendet wird, blähen diese Dateien das Paket auf, ohne zu verstehen.
Alle diese Abhängigkeiten lassen sich einfach optimieren. Wir haben Optimierungsansätze in ein GitHub-Repository – jetzt ausprobieren
Verkettung von Modulen für ES-Module aktivieren (auch „Scope Hoisting“ genannt)
Wenn Sie ein Bundle erstellen, verpackt Webpack jedes Modul in eine Funktion:
// index.js
import {render} from './comments.js';
render();
// comments.js
export function render(data, target) {
console.log('Rendered!');
}
↓
// bundle.js (part of)
/* 0 */
(function(module, __webpack_exports__, __webpack_require__) {
"use strict";
Object.defineProperty(__webpack_exports__, "__esModule", { value: true });
var __WEBPACK_IMPORTED_MODULE_0__comments_js__ = __webpack_require__(1);
Object(__WEBPACK_IMPORTED_MODULE_0__comments_js__["a" /* render */])();
}),
/* 1 */
(function(module, __webpack_exports__, __webpack_require__) {
"use strict";
__webpack_exports__["a"] = render;
function render(data, target) {
console.log('Rendered!');
}
})
In der Vergangenheit war dies erforderlich, um CommonJS/AMD-Module voneinander zu isolieren. Dadurch wurde jedoch einen Größen- und Leistungsaufwand für jedes Modul.
Durch Webpack 2 werden ES-Module unterstützt, die im Gegensatz zu CommonJS- und AMD-Modulen gebündelt werden können. ohne sie jeweils in eine Funktion zu umschließen. Und Webpack 3 ermöglichte eine solche Bündelung – mit Modulverkettung. Hier finden Sie und welche Funktion die Modulverkettung bewirkt:
// index.js
import {render} from './comments.js';
render();
// comments.js
export function render(data, target) {
console.log('Rendered!');
}
↓
// Unlike the previous snippet, this bundle has only one module
// which includes the code from both files
// bundle.js (part of; compiled with ModuleConcatenationPlugin)
/* 0 */
(function(module, __webpack_exports__, __webpack_require__) {
"use strict";
Object.defineProperty(__webpack_exports__, "__esModule", { value: true });
// CONCATENATED MODULE: ./comments.js
function render(data, target) {
console.log('Rendered!');
}
// CONCATENATED MODULE: ./index.js
render();
})
Sehen Sie den Unterschied? Im einfachen Bundle war für Modul 0 render
von Modul 1 erforderlich. Mit
Modulverkettung. require
wird einfach durch die erforderliche Funktion ersetzt und Modul 1 ist
entfernt. Das Paket umfasst weniger Module – und weniger Modulaufwand.
Um dieses Verhalten zu aktivieren, aktivieren Sie in Webpack 4 die Option optimization.concatenateModules
:
// webpack.config.js (for webpack 4)
module.exports = {
optimization: {
concatenateModules: true
}
};
Verwende in Webpack 3 das ModuleConcatenationPlugin
:
// webpack.config.js (for webpack 3)
const webpack = require('webpack');
module.exports = {
plugins: [
new webpack.optimize.ModuleConcatenationPlugin()
]
};
Weitere Informationen
- Webpack-Dokumentation für die ModuleConcatenationPlugin
- „Kurze Einführung in den Umfang wird hochgezogen“
- Detaillierte Beschreibung des Plug-ins
Verwende externals
, wenn du sowohl Webpack- als auch Nicht-Webpack-Code hast
Sie haben möglicherweise ein großes Projekt, bei dem ein Teil des Codes mit Webpack kompiliert wird, ein anderer Code jedoch nicht. Gefällt mir eine Videohosting-Website, bei der das Player-Widget eventuell mit Webpack erstellt wird, und die umgebende Seite ist möglicherweise nicht:
<ph type="x-smartling-placeholder">Wenn beide Codeabschnitte gemeinsame Abhängigkeiten haben, können Sie sie freigeben, um das Herunterladen des Codes zu vermeiden
und zwar mehrmals. Dies geschieht mithilfe der externals
Option – ersetzt Module durch Variablen oder
andere externe Importe.
Wenn Abhängigkeiten in window
verfügbar sind
Wenn Ihr Code, der nicht aus dem Webpack stammt, auf Abhängigkeiten basiert, die als Variablen in window
verfügbar sind, gilt:
Abhängigkeitsnamen zu Variablennamen:
// webpack.config.js
module.exports = {
externals: {
'react': 'React',
'react-dom': 'ReactDOM'
}
};
Mit dieser Konfiguration bündelt Webpack react
- und react-dom
-Pakete nicht. Stattdessen werden sie
ersetzt durch Folgendes:
// bundle.js (part of)
(function(module, exports) {
// A module that exports `window.React`. Without `externals`,
// this module would include the whole React bundle
module.exports = React;
}),
(function(module, exports) {
// A module that exports `window.ReactDOM`. Without `externals`,
// this module would include the whole ReactDOM bundle
module.exports = ReactDOM;
})
Wenn Abhängigkeiten als AMD-Pakete geladen werden
Wenn Ihr Nicht-Webpack-Code keine Abhängigkeiten in window
offenlegt, ist das Ganze etwas komplizierter.
Sie können jedoch verhindern, dass derselbe Code zweimal geladen wird, wenn der Nicht-Webpack-Code diese
Abhängigkeiten als AMD-Pakete
Dazu kompilieren Sie den Webpack-Code als AMD-Bundle und Aliasmodule für Bibliotheks-URLs:
// webpack.config.js
module.exports = {
output: {
libraryTarget: 'amd'
},
externals: {
'react': {
amd: '/libraries/react.min.js'
},
'react-dom': {
amd: '/libraries/react-dom.min.js'
}
}
};
Webpack umschließt das Bundle in define()
und richtet es von den folgenden URLs abhängig:
// bundle.js (beginning)
define(["/libraries/react.min.js", "/libraries/react-dom.min.js"], function () { … });
Wenn Code, der nicht aus Webpack stammt, dieselben URLs zum Laden seiner Abhängigkeiten verwendet, werden diese Dateien geladen nur einmal – für zusätzliche Anfragen wird der Loader-Cache verwendet.
Weitere Informationen
- Webpack-Dokumente auf
externals
Zusammenfassung
- Produktionsmodus bei Verwendung von Webpack 4 aktivieren
- Code mit den Minifier- und Ladeoptionen auf Bundle-Ebene minimieren
- Entfernen Sie den Entwicklungscode, indem Sie
NODE_ENV
durchproduction
ersetzen - ES-Module zum Aktivieren von Tree Shaking verwenden
- Bilder komprimieren
- Abhängigkeitsspezifische Optimierungen anwenden
- Modulverkettung aktivieren
- Verwende
externals
, wenn dies für dich sinnvoll ist