Front-End-Größe verringern

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:

  1. Sie schreiben Code wie folgt:

    // comments.js
    import './comments.css';
    export function render(data, target) {
      console.log('Rendered!');
    }
    
  2. 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!');
    }
    
  3. 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

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:

  1. 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.');
    }
    
  2. 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

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:

  1. 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();
    
  2. 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 */
    })
    
  3. 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

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

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">
</ph> Screenshot einer Videohosting-Website
(Eine komplett zufällige Videohosting-Website)

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

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 durch production 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