Modernen JavaScript-Code für schnellere Anwendungen veröffentlichen, versenden und installieren

Verbessern Sie die Leistung, indem Sie moderne JavaScript-Abhängigkeiten und -Ausgabe aktivieren.

Über 90% der Browser können modernes JavaScript ausführen, Die Verbreitung von veraltetem JavaScript ist nach wie vor eine große Ursache für Leistungsprobleme im Web.

Modernes JavaScript

Modernes JavaScript ist nicht als Code gekennzeichnet, der in einem speziellen ECMAScript geschrieben wurde. Spezifikationsversion, sondern in einer Syntax, die von allen modernen Browser. Moderne Webbrowser wie Chrome, Edge, Firefox und Safari über 90% des Browsermarkts. unterschiedliche Browser, die auf den gleichen Rendering-Modulen basieren, bilden ein weitere 5%. Das bedeutet, dass 95% des weltweiten Web-Traffics von Browsern stammt. die die gängigsten JavaScript-Sprachfunktionen der letzten 10 Jahren, einschließlich:

  • Klassen (ES2015)
  • Pfeilfunktionen (ES2015)
  • Generatoren (ES2015)
  • Block-Bereich (ES2015)
  • Zerstörung (ES2015)
  • Parameter für Ruhe und Streuung (ES2015)
  • Objekt-Abkürzung (ES2015)
  • Async/await (ES2017)

Features in neueren Versionen der Sprachspezifikation haben in der Regel weniger in allen modernen Browsern. Viele ES2020 und ES2021 werden nur von 70% des Browsermarktes unterstützt. aber nicht so sehr, dass man sich direkt auf diese Funktionen verlassen kann. Dieses bedeutet, dass obwohl „modern“ JavaScript ist ein bewegliches Ziel, ES2017 bietet größte Bandbreite an Browserkompatibilität und die meisten der gängigen modernen Syntaxfunktionen enthalten. Mit anderen Worten: ES2017 ist der heutigen Syntax am nächsten.

Altes JavaScript

Legacy-JavaScript ist Code, der ausdrücklich vermeidet, die oben aufgeführten Programmiersprachen zu verwenden. Funktionen. Die meisten Entwickler schreiben ihren Quellcode mit moderner Syntax, aber alles in die Legacy-Syntax zu kompilieren, um die Browserunterstützung zu verbessern. Kompilieren gegenüber der Legacy-Syntax verbessert den Browser-Support, aber das ist oft der Fall. als wir erkennen. In vielen Fällen erhöht sich die Unterstützung von etwa 95 % der auf 98% reduzieren, wobei erhebliche Kosten anfallen:

  • Ältere JavaScript-Versionen sind in der Regel etwa 20% größer und langsamer als entsprechenden modernen Code. Tools-Mängel und Fehlkonfigurationen sind häufig um diese Lücke weiter zu vergrößern.

  • Installierte Bibliotheken machen bis zu 90% der typischen Produktionsversionen JavaScript-Code. Bibliothekscode führt zu einem noch höheren Legacy-JavaScript-Code Overhead aufgrund von Polyfill und Hilfsduplizierung, die vermieden werden könnten indem Sie modernen Code veröffentlichen.

Modernes JavaScript in npm

Seit Kurzem ist in Node.js ein "exports"-Feld standardisiert, Einstiegspunkte für ein Paket:

{
  "exports": "./index.js"
}

Module, auf die im Feld "exports" verwiesen wird, bedeuten eine Knotenversion von mindestens 12.8, unterstützt ES2019. Das bedeutet, dass jedes Modul, auf das mithilfe der Das Feld "exports" kann in modernem JavaScript geschrieben werden. Paketnutzer müssen gehen davon aus, dass Module mit einem "exports"-Feld modernen Code enthalten, und transpilieren, wenn notwendig ist.

Nur modern

Wenn Sie ein Paket mit modernem Code veröffentlichen und es für die Transkription zuständig ist, wenn sie als Abhängigkeit verwendet wird. Verwenden Sie nur die "exports".

{
  "name": "foo",
  "exports": "./modern.js"
}

Modern mit altem Fallback

Verwenden Sie das Feld "exports" zusammen mit "main", um Ihr Paket zu veröffentlichen. mit modernem Code, sondern auch mit einem ES5- und CommonJS-Fallback für ältere Versionen Browser.

{
  "name": "foo",
  "exports": "./modern.js",
  "main": "./legacy.cjs"
}

Modern mit Legacy-Fallback- und ESM-Bundler-Optimierungen

Mit dem Feld "module" kann nicht nur ein CommonJS-Einstiegspunkt für Fallbacks definiert werden, auf ein ähnliches Legacy-Fallback-Bundle verweist, das jedoch Syntax des JavaScript-Moduls (import und export)

{
  "name": "foo",
  "exports": "./modern.js",
  "main": "./legacy.cjs",
  "module": "./module.js"
}

Viele Bundler, z. B. Webpack und Rollup, nutzen dieses Feld, um Funktionen des Moduls Beben von Bäumen. Dies ist immer noch ein Legacy-Bundle, das keinen modernen Code enthält. import/export-Syntax. Verwenden Sie diesen Ansatz, um modernen Code mit einer alte Fallback-Lösung, die immer noch für die Bündelung optimiert ist.

Modernes JavaScript in Anwendungen

Abhängigkeiten von Drittanbietern machen den überwiegenden Teil der typischen Produktionsumgebungen aus. JavaScript-Code in Webanwendungen. Während npm-Abhängigkeiten in der Vergangenheit ES5-Syntax veröffentlicht wurde, gilt dies nicht mehr Risiken Abhängigkeitsupdates zum Ausfall des Browsersupports in Ihrer Anwendung.

Da immer mehr npm-Pakete auf modernes JavaScript umgestellt werden, müssen die Build-Tools entsprechend eingerichtet sein. Es gibt eine gute Wahrscheinlichkeit, dass einige der npm-Pakete, auf die Sie sich verlassen, bereits moderne Sprachfunktionen. Es gibt mehrere Möglichkeiten, modernen Code zu verwenden ohne dass Ihre Anwendung in älteren Browsern unterbrochen wird. dass das Build-System Abhängigkeiten in die gleiche Syntax transpiliert, als Quellcode festlegen.

Webpack

Ab Webpack 5 kann konfiguriert werden, welche Syntax von Webpack verwendet wird wenn Sie Code für Bundles und Module generieren. Dabei wird Ihr oder Abhängigkeiten auswirkt, betrifft nur den „Kleber“ von Webpack generiert. Fügen Sie einen Parameter hinzu, um das Ziel für die Browserunterstützung anzugeben. Konfiguration der Browserliste an Ihr Projekt oder direkt in Ihrer Webpack-Konfiguration:

module.exports = {
  target: ['web', 'es2017'],
};

Webpack kann auch so konfiguriert werden, dass optimierte Bundles generiert werden, Weglassen unnötiger Wrapper-Funktionen beim Targeting auf moderne ES-Module zu verbessern. Dadurch wird Webpack auch so konfiguriert, dass Code-Split-Bundles mit <script type="module">

module.exports = {
  target: ['web', 'es2017'],
  output: {
    module: true,
  },
  experiments: {
    outputModule: true,
  },
};

Es gibt mehrere Webpack-Plug-ins, mit denen modernen JavaScript-Code kompilieren und versenden und gleichzeitig ältere Browser unterstützen, wie das Optimize-Plug-in und BabelEsmPlugin.

Optimize-Plug-in

Das Optimize-Plug-in ist ein Webpack Plug-in, das endgültigen gebündelten Code von modernem in Legacy-JavaScript umwandelt statt auf jede einzelne Quelldatei. Es ist eine eigenständige Einrichtung, die dass alles modernes JavaScript ist, spezielle Verzweigungen für mehrere Ausgaben oder Syntaxen.

Da das Optimize-Plug-in mit Bundles und nicht mit einzelnen Modulen ausgeführt wird, den Code Ihrer Anwendung und Ihre Abhängigkeiten gleichermaßen verarbeitet. So können Sie moderne JavaScript-Abhängigkeiten von npm verwenden, da deren Code gebündelt und in die richtige Syntax transpiliert. Es kann auch schneller sein als herkömmliche Lösungen, bei denen zwei Kompilierungsschritte erforderlich sind, separate Sets für moderne und ältere Browser. Die beiden Sets sind die die mithilfe der Funktion Modul-/nomodule-Muster an.

// webpack.config.js
const OptimizePlugin = require('optimize-plugin');

module.exports = {
  // ...
  plugins: [new OptimizePlugin()],
};

Optimize Plugin kann schneller und effizienter als benutzerdefiniertes Webpack sein Konfigurationen, in denen modernen und Legacy-Code in der Regel separat gebündelt werden. Es kümmert sich auch um die Ausführung von Babel für Sie und reduziert Sets mit Terser mit separaten optimalen Einstellungen für modernen und Legacy-Ausgaben zu synchronisieren. Polyfills, die für die generierten Legacy-Bundles werden in ein dediziertes Skript extrahiert, damit sie dupliziert oder in neueren Browsern unnötigerweise geladen werden.

<ph type="x-smartling-placeholder">
</ph>
Vergleich: Quellmodule zweimal im Vergleich zum Transpilieren generierter Bundles.

BabelEsmPlugin

BabelEsmPlugin ist ein Webpack. Plug-in, das mit @babel/preset-env zum Generieren moderner Versionen vorhandener Bundles, um weniger transpilierten Code an moderne Browser. Es ist die beliebteste Standardlösung für Module/nomodule, verwendet von Next.js und Preact-Befehlszeile.

// webpack.config.js
const BabelEsmPlugin = require('babel-esm-plugin');

module.exports = {
  //...
  module: {
    rules: [
      // your existing babel-loader configuration:
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: ['@babel/preset-env'],
          },
        },
      },
    ],
  },
  plugins: [new BabelEsmPlugin()],
};

BabelEsmPlugin unterstützt eine Vielzahl von Webpack-Konfigurationen, zwei größtenteils separate Builds Ihrer Anwendung ausführt. Zweimal kompilieren für große Anwendungen etwas mehr Zeit. Mit dieser Technik BabelEsmPlugin zur nahtlosen Integration in vorhandene Webpack-Konfigurationen und macht sie zu einer der bequemsten Optionen, die es gibt.

Babel-Loader zum Transpilieren von node_modules konfigurieren

Wenn Sie babel-loader ohne eines der beiden vorherigen Plug-ins verwenden, ist ein wichtiger Schritt erforderlich, um modernes JavaScript npm zu nutzen. Module. Das Definieren von zwei separaten babel-loader-Konfigurationen ermöglicht zur automatischen Kompilierung moderner Sprachfunktionen in node_modules, um ES2017, während Sie mit dem Babel-Tool Ihren eigenen Code Plug-ins und Voreinstellungen, die Sie in der Konfiguration Ihres Projekts definiert haben. Das ist nicht Generieren moderner und Legacy-Bundles für eine Modul-/Nomodule-Einrichtung ermöglichen die Installation und Verwendung von npm-Paketen, die modernes JavaScript ohne dass dabei ältere Browser beeinträchtigt werden.

webpack-plugin-modern-npm verwendet dieses Verfahren, um npm-Abhängigkeiten zu kompilieren, die das Feld "exports" haben in package.json enthalten, da diese moderne Syntax enthalten können:

// webpack.config.js
const ModernNpmPlugin = require('webpack-plugin-modern-npm');

module.exports = {
  plugins: [
    // auto-transpile modern stuff found in node_modules
    new ModernNpmPlugin(),
  ],
};

Alternativ kannst du das Verfahren manuell in deinem Webpack implementieren. Konfiguration, indem Sie nach einem "exports"-Feld in package.json von sobald er abgeschlossen ist. Der Einfachheit halber wird das Caching könnte wie folgt aussehen:

// webpack.config.js
module.exports = {
  module: {
    rules: [
      // Transpile for your own first-party code:
      {
        test: /\.js$/i,
        loader: 'babel-loader',
        exclude: /node_modules/,
      },
      // Transpile modern dependencies:
      {
        test: /\.js$/i,
        include(file) {
          let dir = file.match(/^.*[/\\]node_modules[/\\](@.*?[/\\])?.*?[/\\]/);
          try {
            return dir && !!require(dir[0] + 'package.json').exports;
          } catch (e) {}
        },
        use: {
          loader: 'babel-loader',
          options: {
            babelrc: false,
            configFile: false,
            presets: ['@babel/preset-env'],
          },
        },
      },
    ],
  },
};

Wenn Sie diesen Ansatz verwenden, müssen Sie sicherstellen, dass die moderne Syntax von den den Minifier an. Beide Terser und uglify-es können Sie {ecma: 2017} angeben, um die Generieren der ES2017-Syntax während der Komprimierung und Formatierung.

Auf einen Blick

Rollup bietet integrierte Unterstützung für das Generieren mehrerer Sets von Bundles als Teil eines und generiert standardmäßig modernen Code. Dadurch kann Sammel-Property können so konfiguriert werden, dass mit den offiziellen Plug-ins moderne und Legacy-Bundles generiert werden. die Sie wahrscheinlich bereits nutzen.

@rollup/plugin-babel

Wenn Sie Rollup verwenden, getBabelOutputPlugin()-Methode (bereitgestellt vom Rollup-Dienst offizielles Babel-Plug-in) wandelt den Code in generierten Bundles statt in einzelnen Quellmodulen um. Rollup bietet integrierte Unterstützung für das Generieren mehrerer Sets von Bundles als Teil eines einen einzelnen Build mit jeweils eigenen Plug-ins erstellen. Damit können Sie verschiedene Bundles für moderne und Legacy-Anwendungen. Konfiguration des Babel-Ausgabe-Plug-ins:

// rollup.config.js
import {getBabelOutputPlugin} from '@rollup/plugin-babel';

export default {
  input: 'src/index.js',
  output: [
    // modern bundles:
    {
      format: 'es',
      plugins: [
        getBabelOutputPlugin({
          presets: [
            [
              '@babel/preset-env',
              {
                targets: {esmodules: true},
                bugfixes: true,
                loose: true,
              },
            ],
          ],
        }),
      ],
    },
    // legacy (ES5) bundles:
    {
      format: 'amd',
      entryFileNames: '[name].legacy.js',
      chunkFileNames: '[name]-[hash].legacy.js',
      plugins: [
        getBabelOutputPlugin({
          presets: ['@babel/preset-env'],
        }),
      ],
    },
  ],
};

Zusätzliche Build-Tools

Rollup und Webpack sind hoch konfigurierbar. Das bedeutet in der Regel, dass jedes Projekt muss seine Konfiguration aktualisieren, um moderne JavaScript-Syntax in Abhängigkeiten zu ermöglichen. Es gibt auch übergeordnete Build-Tools, die Konventionen und Standardeinstellungen wie Parcel, Snowpack, Vite und WMR. Die meisten dieser Tools gehen davon aus, dass npm-Abhängigkeiten moderne Syntax enthalten können, und übertragen sie in die entsprechenden Syntaxebenen beim Erstellen für die Produktion.

Neben den speziellen Plug-ins für Webpack und Rollup Sets mit alten Fallbacks können jedem Projekt mit devolution. Devolution ist ein eigenständiges Tool, das die Ausgabe eines Build-Systems in Legacy-Umgebungen JavaScript-Varianten, wodurch Bündelung und Transformationen eine moderne Ausgabeziel.