ist jetzt verfügbar! Lesen Sie über die neuen Funktionen und Fehlerbehebungen vom November.

Erweiterungen bündeln

Der erste Grund, Ihre Visual Studio Code-Erweiterung zu bündeln, ist die Gewährleistung ihrer Funktionalität für alle Benutzer von VS Code auf jeder Plattform. Nur gebündelte Erweiterungen können in VS Code für Web-Umgebungen wie github.dev und vscode.dev verwendet werden. Wenn VS Code im Browser ausgeführt wird, kann es nur eine Datei für Ihre Erweiterung laden, daher muss der Erweiterungscode zu einer einzigen, webfreundlichen JavaScript-Datei gebündelt werden. Dies gilt auch für Notebook-Ausgaberenderer, bei denen VS Code ebenfalls nur eine Datei für Ihre Renderer-Erweiterung lädt.

Darüber hinaus können Erweiterungen schnell an Größe und Komplexität gewinnen. Sie können in mehreren Quelldateien verfasst und von Modulen aus npm abhängen. Dekomposition und Wiederverwendung sind bewährte Entwicklungspraktiken, haben aber bei der Installation und Ausführung von Erweiterungen ihren Preis. Das Laden von 100 kleinen Dateien ist wesentlich langsamer als das Laden einer großen Datei. Deshalb empfehlen wir das Bündeln. Bündeln ist der Prozess, bei dem mehrere kleine Quelldateien zu einer einzigen Datei zusammengefasst werden.

Für JavaScript stehen verschiedene Bundler zur Verfügung. Beliebte sind rollup.js, Parcel, esbuild und webpack.

Verwendung von esbuild

esbuild ist ein schneller JavaScript-Bundler, der einfach zu konfigurieren ist. Um esbuild zu erhalten, öffnen Sie das Terminal und geben Sie ein

npm i --save-dev esbuild

esbuild ausführen

Sie können esbuild von der Befehlszeile ausführen, aber um Wiederholungen zu reduzieren und die Fehlerberichterstattung zu ermöglichen, ist die Verwendung eines Build-Skripts, esbuild.js, hilfreich.

const esbuild = require('esbuild');

const production = process.argv.includes('--production');
const watch = process.argv.includes('--watch');

async function main() {
  const ctx = await esbuild.context({
    entryPoints: ['src/extension.ts'],
    bundle: true,
    format: 'cjs',
    minify: production,
    sourcemap: !production,
    sourcesContent: false,
    platform: 'node',
    outfile: 'dist/extension.js',
    external: ['vscode'],
    logLevel: 'warning',
    plugins: [
      /* add to the end of plugins array */
      esbuildProblemMatcherPlugin
    ]
  });
  if (watch) {
    await ctx.watch();
  } else {
    await ctx.rebuild();
    await ctx.dispose();
  }
}

/**
 * @type {import('esbuild').Plugin}
 */
const esbuildProblemMatcherPlugin = {
  name: 'esbuild-problem-matcher',

  setup(build) {
    build.onStart(() => {
      console.log('[watch] build started');
    });
    build.onEnd(result => {
      result.errors.forEach(({ text, location }) => {
        console.error(`✘ [ERROR] ${text}`);
        if (location == null) return;
        console.error(`    ${location.file}:${location.line}:${location.column}:`);
      });
      console.log('[watch] build finished');
    });
  }
};

main().catch(e => {
  console.error(e);
  process.exit(1);
});

Das Build-Skript führt Folgendes aus

  • Es erstellt einen Build-Kontext mit esbuild. Der Kontext wird konfiguriert, um
    • Den Code in src/extension.ts in eine einzige Datei dist/extension.js zu bündeln.
    • Den Code zu minimieren, wenn das Flag --production übergeben wurde.
    • Quellkarten zu generieren, es sei denn, das Flag --production wurde übergeben.
    • Das Modul 'vscode' vom Bundle auszuschließen (da es von der VS Code-Laufzeitumgebung bereitgestellt wird).
  • Das esbuildProblemMatcherPlugin zu verwenden, um Fehler zu melden, die den Bundler daran gehindert haben, abzuschließen. Dieses Plugin gibt die Fehler in einem Format aus, das vom esbuild-Problem-Matcher erkannt wird, der ebenfalls als Erweiterung installiert werden muss.
  • Wenn das Flag --watch übergeben wurde, beginnt es mit der Überwachung der Quelldateien auf Änderungen und baut das Bundle neu auf, wenn eine Änderung erkannt wird.

esbuild kann direkt mit TypeScript-Dateien arbeiten. esbuild entfernt jedoch einfach alle Typdeklarationen, ohne Typüberprüfungen durchzuführen. Nur Syntaxfehler werden gemeldet und können dazu führen, dass esbuild fehlschlägt.

Aus diesem Grund führen wir separat den TypeScript-Compiler (tsc) aus, um die Typen zu überprüfen, aber ohne Code auszugeben (Flag --noEmit).

Der Abschnitt scripts in package.json sieht nun so aus

"scripts": {
    "compile": "npm run check-types && node esbuild.js",
    "check-types": "tsc --noEmit",
    "watch": "npm-run-all -p watch:*",
    "watch:esbuild": "node esbuild.js --watch",
    "watch:tsc": "tsc --noEmit --watch --project tsconfig.json",
    "vscode:prepublish": "npm run package",
    "package": "npm run check-types && node esbuild.js --production"
}

npm-run-all ist ein Node-Modul, das Skripte parallel ausführt, deren Namen mit einem bestimmten Präfix übereinstimmen. Für uns führt es die Skripte watch:esbuild und watch:tsc aus. Sie müssen npm-run-all zu den devDependencies in package.json hinzufügen.

Die Skripte compile und watch sind für die Entwicklung gedacht und erstellen die Bundle-Datei mit Quellkarten. Das Skript package wird vom Skript vscode:prepublish verwendet, das von vsce, dem Pack- und Veröffentlichungstool von VS Code, verwendet wird und vor der Veröffentlichung einer Erweiterung ausgeführt wird. Das Übergeben des Flags --production an das esbuild-Skript führt dazu, dass der Code komprimiert und ein kleines Bundle erstellt wird, aber das Debugging erschwert, daher werden während der Entwicklung andere Flags verwendet. Um die obigen Skripte auszuführen, öffnen Sie ein Terminal und geben Sie npm run watch ein oder wählen Sie Tasks: Run Task aus der Befehlspalette (⇧⌘P (Windows, Linux Ctrl+Shift+P)).

Wenn Sie .vscode/tasks.json wie folgt konfigurieren, erhalten Sie für jede Watch-Aufgabe ein separates Terminal.

{
  "version": "2.0.0",
  "tasks": [
    {
      "label": "watch",
      "dependsOn": ["npm: watch:tsc", "npm: watch:esbuild"],
      "presentation": {
        "reveal": "never"
      },
      "group": {
        "kind": "build",
        "isDefault": true
      }
    },
    {
      "type": "npm",
      "script": "watch:esbuild",
      "group": "build",
      "problemMatcher": "$esbuild-watch",
      "isBackground": true,
      "label": "npm: watch:esbuild",
      "presentation": {
        "group": "watch",
        "reveal": "never"
      }
    },
    {
      "type": "npm",
      "script": "watch:tsc",
      "group": "build",
      "problemMatcher": "$tsc-watch",
      "isBackground": true,
      "label": "npm: watch:tsc",
      "presentation": {
        "group": "watch",
        "reveal": "never"
      }
    }
  ]
}

Diese Watch-Aufgabe hängt von der Erweiterung connor4312.esbuild-problem-matchers für die Problembehandlung ab, die Sie installieren müssen, damit die Aufgabe Probleme in der Problemansicht meldet. Diese Erweiterung muss installiert sein, damit der Start abgeschlossen werden kann.

Um dies nicht zu vergessen, fügen Sie eine Datei .vscode/extensions.json zum Arbeitsbereich hinzu

{
  "recommendations": ["connor4312.esbuild-problem-matchers"]
}

Schließlich möchten Sie Ihre Datei .vscodeignore aktualisieren, damit kompilierte Dateien in die veröffentlichte Erweiterung aufgenommen werden. Weitere Details finden Sie im Abschnitt Veröffentlichung.

Springen Sie zum Abschnitt Tests, um weiterzulesen.

Verwendung von webpack

Webpack ist ein Entwicklungswerkzeug, das von npm verfügbar ist. Um webpack und seine Befehlszeilenschnittstelle zu erhalten, öffnen Sie das Terminal und geben Sie ein

npm i --save-dev webpack webpack-cli

Dadurch werden webpack installiert und Ihre Erweiterungsdatei package.json aktualisiert, um webpack in die devDependencies aufzunehmen.

Webpack ist ein JavaScript-Bundler, aber viele VS Code-Erweiterungen sind in TypeScript geschrieben und werden nur zu JavaScript kompiliert. Wenn Ihre Erweiterung TypeScript verwendet, können Sie den Loader ts-loader verwenden, damit webpack TypeScript versteht. Verwenden Sie Folgendes, um ts-loader zu installieren

npm i --save-dev ts-loader

Alle Dateien sind im Beispiel webpack-extension verfügbar.

Webpack konfigurieren

Nach der Installation aller Tools kann webpack nun konfiguriert werden. Konventionell enthält eine Datei webpack.config.js die Konfiguration, um webpack anzuweisen, Ihre Erweiterung zu bündeln. Die folgende Beispielkonfiguration ist für VS Code-Erweiterungen gedacht und sollte einen guten Ausgangspunkt bieten.

//@ts-check

'use strict';

const path = require('path');
const webpack = require('webpack');

/**@type {import('webpack').Configuration}*/
const config = {
  target: 'webworker', // vscode extensions run in webworker context for VS Code web 📖 -> https://webpack.js.org/configuration/target/#target

  entry: './src/extension.ts', // the entry point of this extension, 📖 -> https://webpack.js.org/configuration/entry-context/
  output: {
    // the bundle is stored in the 'dist' folder (check package.json), 📖 -> https://webpack.js.org/configuration/output/
    path: path.resolve(__dirname, 'dist'),
    filename: 'extension.js',
    libraryTarget: 'commonjs2',
    devtoolModuleFilenameTemplate: '../[resource-path]'
  },
  devtool: 'source-map',
  externals: {
    vscode: 'commonjs vscode' // the vscode-module is created on-the-fly and must be excluded. Add other modules that cannot be webpack'ed, 📖 -> https://webpack.js.org/configuration/externals/
  },
  resolve: {
    // support reading TypeScript and JavaScript files, 📖 -> https://github.com/TypeStrong/ts-loader
    mainFields: ['browser', 'module', 'main'], // look for `browser` entry point in imported node modules
    extensions: ['.ts', '.js'],
    alias: {
      // provides alternate implementation for node module and source files
    },
    fallback: {
      // Webpack 5 no longer polyfills Node.js core modules automatically.
      // see https://webpack.js.org/configuration/resolve/#resolvefallback
      // for the list of Node.js core module polyfills.
    }
  },
  module: {
    rules: [
      {
        test: /\.ts$/,
        exclude: /node_modules/,
        use: [
          {
            loader: 'ts-loader'
          }
        ]
      }
    ]
  }
};
module.exports = config;

Die Datei ist als Teil des Beispiels webpack-extension verfügbar. Webpack-Konfigurationsdateien sind normale JavaScript-Module, die ein Konfigurationsobjekt exportieren müssen.

Im obigen Beispiel werden folgende Punkte definiert

  • Das target gibt den Kontext an, in dem Ihre Erweiterung ausgeführt wird. Wir empfehlen die Verwendung von webworker, damit Ihre Erweiterung sowohl in VS Code für Web als auch in VS Code Desktop-Versionen funktioniert.
  • Der Einstiegspunkt, den webpack verwenden soll. Dies ist ähnlich wie die Eigenschaft main in package.json, außer dass Sie webpack einen "Source"-Einstiegspunkt bereitstellen, normalerweise src/extension.ts, und keinen "Output"-Einstiegspunkt. Der webpack-Bundler versteht TypeScript, sodass ein separater TypeScript-Kompilierungsschritt überflüssig ist.
  • Die output-Konfiguration teilt webpack mit, wo die generierte Bundle-Datei platziert werden soll. Konventionell ist dies der Ordner dist. In diesem Beispiel erstellt webpack eine Datei dist/extension.js.
  • Die Konfigurationen resolve und module/rules dienen zur Unterstützung von TypeScript- und JavaScript-Eingabedateien.
  • Die Konfiguration externals wird verwendet, um Ausschlüsse zu deklarieren, z. B. Dateien und Module, die nicht in das Bundle aufgenommen werden sollen. Das Modul vscode sollte nicht gebündelt werden, da es nicht auf der Festplatte vorhanden ist, sondern von VS Code bei Bedarf im laufenden Betrieb erstellt wird. Abhängig von den von einer Erweiterung verwendeten Node-Modulen können weitere Ausschlüsse erforderlich sein.

Schließlich möchten Sie Ihre Datei .vscodeignore aktualisieren, damit kompilierte Dateien in die veröffentlichte Erweiterung aufgenommen werden. Weitere Details finden Sie im Abschnitt Veröffentlichung.

Webpack ausführen

Mit der erstellten Datei webpack.config.js kann webpack aufgerufen werden. Sie können webpack von der Befehlszeile aus ausführen, aber um Wiederholungen zu reduzieren, ist die Verwendung von npm-Skripten hilfreich.

Fügen Sie diese Einträge zum Abschnitt scripts in package.json zusammen

"scripts": {
    "compile": "webpack --mode development",
    "watch": "webpack --mode development --watch",
    "vscode:prepublish": "npm run package",
    "package": "webpack --mode production --devtool hidden-source-map",
},

Die Skripte compile und watch sind für die Entwicklung und erstellen die Bundle-Datei. vscode:prepublish wird von vsce, dem Pack- und Veröffentlichungstool von VS Code, verwendet und vor der Veröffentlichung einer Erweiterung ausgeführt. Der Unterschied liegt im Modus, der den Optimierungsgrad steuert. Die Verwendung von production liefert das kleinste Bundle, dauert aber auch länger, daher wird stattdessen development verwendet. Um die obigen Skripte auszuführen, öffnen Sie ein Terminal und geben Sie npm run compile ein oder wählen Sie Tasks: Run Task aus der Befehlspalette (⇧⌘P (Windows, Linux Ctrl+Shift+P)).

Erweiterung ausführen

Bevor Sie die Erweiterung ausführen können, muss die Eigenschaft main in package.json auf das Bundle verweisen, das für die obige Konfiguration "./dist/extension" ist. Mit dieser Änderung kann die Erweiterung nun ausgeführt und getestet werden.

Tests

Erweiterungsautoren schreiben oft Unit-Tests für ihren Erweiterungsquellcode. Mit der richtigen architektonischen Schichtung, bei der der Erweiterungsquellcode nicht von Tests abhängt, sollte das von webpack und esbuild erstellte Bundle keinen Testcode enthalten. Zum Ausführen von Unit-Tests ist nur eine einfache Kompilierung erforderlich.

Fügen Sie diese Einträge zum Abschnitt scripts in package.json zusammen

"scripts": {
    "compile-tests": "tsc -p . --outDir out",
    "pretest": "npm run compile-tests",
    "test": "vscode-test"
}

Das Skript compile-tests verwendet den TypeScript-Compiler, um die Erweiterung in den Ordner out zu kompilieren. Mit diesem zwischenzeitlich verfügbaren JavaScript ist der folgende Ausschnitt für launch.json ausreichend, um Tests auszuführen.

{
  "name": "Extension Tests",
  "type": "extensionHost",
  "request": "launch",
  "runtimeExecutable": "${execPath}",
  "args": [
    "--extensionDevelopmentPath=${workspaceFolder}",
    "--extensionTestsPath=${workspaceFolder}/out/test"
  ],
  "outFiles": ["${workspaceFolder}/out/test/**/*.js"],
  "preLaunchTask": "npm: compile-tests"
}

Diese Konfiguration zum Ausführen von Tests ist für nicht gebündelte Erweiterungen gleich. Es gibt keinen Grund, Unit-Tests zu bündeln, da sie nicht Teil des veröffentlichten Teils einer Erweiterung sind.

Veröffentlichung

Vor der Veröffentlichung sollten Sie die Datei .vscodeignore aktualisieren. Alles, was jetzt in die Datei dist/extension.js gebündelt ist, kann ausgeschlossen werden, normalerweise der Ordner out (falls Sie ihn noch nicht gelöscht haben) und am wichtigsten der Ordner node_modules.

Eine typische Datei .vscodeignore sieht so aus

.vscode
node_modules
out/
src/
tsconfig.json
webpack.config.js
esbuild.js

Vorhandene Erweiterung migrieren

Die Migration einer vorhandenen Erweiterung zur Verwendung von esbuild oder webpack ist einfach und ähnelt dem obigen Leitfaden für den Einstieg. Ein realweltliches Beispiel, das webpack übernommen hat, ist die Referenzansicht von VS Code durch diesen Pull Request.

Dort sehen Sie

  • esbuild bzw. webpack, webpack-cli und ts-loader als devDependencies hinzufügen.
  • npm-Skripte aktualisieren, um die Bundler wie oben gezeigt zu verwenden.
  • Die Task-Konfiguration tasks.json aktualisieren.
  • Die Build-Datei esbuild.js oder webpack.config.js hinzufügen und optimieren.
  • .vscodeignore aktualisieren, um node_modules und Zwischenausgabedateien auszuschließen.
  • Genießen Sie eine Erweiterung, die viel schneller installiert und geladen wird!

Fehlerbehebung

Minimierung

Das Bündeln im production-Modus führt auch eine Code-Minimierung durch. Minifizierung komprimiert Quellcode, indem Leerzeichen und Kommentare entfernt und Variablennamen und Funktionsnamen in etwas Hässliches, aber Kurzes umgewandelt werden. Quellcode, der Function.prototype.name verwendet, funktioniert anders und daher müssen Sie möglicherweise die Minifizierung deaktivieren.

Webpack kritische Abhängigkeiten

Wenn Sie webpack ausführen, stoßen Sie möglicherweise auf eine Warnung wie Kritische Abhängigkeiten: Die Anforderung einer Abhängigkeit ist ein Ausdruck. Solche Warnungen müssen ernst genommen werden und Ihr Bundle wird wahrscheinlich nicht funktionieren. Die Meldung bedeutet, dass webpack statisch nicht ermitteln kann, wie eine bestimmte Abhängigkeit gebündelt werden soll. Dies wird normalerweise durch eine dynamische require-Anweisung verursacht, z. B. require(someDynamicVariable).

Um die Warnung zu beheben, sollten Sie entweder

  • Versuchen, die Abhängigkeit statisch zu machen, damit sie gebündelt werden kann.
  • Diese Abhängigkeit über die externals-Konfiguration ausschließen. Stellen Sie außerdem sicher, dass diese JavaScript-Dateien nicht aus der gepackten Erweiterung ausgeschlossen werden, indem Sie ein negiertes Glob-Muster in .vscodeignore verwenden, z. B. !node_modules/mySpecialModule.

Nächste Schritte

  • Extension Marketplace - Erfahren Sie mehr über den öffentlichen Extension Marketplace von VS Code.
  • Erweiterungen testen - Fügen Sie Ihrem Erweiterungsprojekt Tests hinzu, um eine hohe Qualität zu gewährleisten.
  • Continuous Integration - Erfahren Sie, wie Sie CI-Builds für Erweiterungen auf Azure Pipelines ausführen.
© . This site is unofficial and not affiliated with Microsoft.