本站点文档内容均翻译自code.visualstudio.com,仅供个人学习,如有差异请以官网为准。

捆绑扩展

捆绑您的 Visual Studio Code 扩展的第一个原因是确保它在任何平台上使用 VS Code 时都能正常工作。只有捆绑的扩展才能在像 github.devvscode.dev 这样的 VS Code 网页环境中使用。当 VS Code 在浏览器中运行时,它只能加载一个文件来加载您的扩展,因此扩展代码需要被捆绑成一个单一的、对网页友好的 JavaScript 文件。这也适用于 Notebook Output Renderers,VS Code 也将只加载您的渲染器扩展的一个文件。

此外,扩展可以迅速增长到规模和复杂性。它们可能由多个源文件编写,并依赖于 npm 的模块。模块分解和代码重用是开发的最佳实践,但在安装和运行扩展时会带来成本。加载100个小文件比加载一个大文件慢得多。这就是为什么我们建议进行打包。打包是将多个小源文件合并成一个文件的过程。

对于JavaScript,有不同类型的打包器。流行的有rollup.jsParcelesbuildwebpack

使用 esbuild

esbuild是一个快速的JavaScript打包器,配置简单。要获取esbuild,请打开终端并输入:

npm i --save-dev esbuild

运行 esbuild

你可以从命令行运行esbuild,但为了减少重复并能够报告问题,使用构建脚本是有帮助的。esbuild.js输入:

常量 esbuild = 需要('esbuild');

常量 生产 = 过程.argv.包括('--production');
常量 监视 = 过程.argv.包括('--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);
});

构建脚本执行以下操作:

  • 它使用esbuild创建一个构建上下文。该上下文被配置为:
    • 将代码打包在src/extension.ts合并成一个文件dist/extension.js输入:.
    • 如果需要,请压缩代码--生产旗帜已通过。
    • 生成源映射,除非--生产旗帜已通过。
    • 从包中排除'vscode'模块(因为它是由VS Code运行时提供的)。
  • 使用esbuildProblemMatcherPlugin插件来报告阻止打包器完成的错误。此插件以一种被检测的格式发出错误。esbuild问题匹配器也需要安装为扩展。
  • 如果--观察当传递标志时,它开始监视源文件的变化,并在检测到变化时重新构建包。

esbuild 可以直接处理 TypeScript 文件。然而,esbuild 会直接去除所有的类型声明,而不进行任何类型检查。 只报告语法错误,这可能会导致 esbuild 失败。

出于这个原因,我们单独运行TypeScript编译器 (翻译结果:tsc) 检查类型,但不生成任何代码(标志--不输出)。

脚本部分在package.json现在看起来是那样

"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运行所有是一个节点模块,可以并行运行与给定前缀匹配的脚本。对我们来说,它运行的是watch:esbuild手表: tsc脚本。你需要添加npm运行所有开发依赖项部分在package.json输入:.

编译手表脚本用于开发,并生成带有源映射的包文件。包裹脚本被使用vscode:预发布脚本,它被使用一切, VS Code 打包和发布工具,在发布扩展之前运行。通过--生产将 flag 添加到 esbuild 脚本将使其压缩代码并创建一个小型包,但也会使调试变得困难,因此在开发过程中使用其他 flag。要运行上述脚本,请打开终端并输入npm 运行 监控 或选择 任务:运行任务 从命令面板 (⇧⌘P (Windows, Linux Ctrl+Shift+P))。

如果你配置.vscode/tasks.json以这种方式,每个手表任务将获得一个单独的终端。

{
  "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"
      }
    }
  ]
}

这个手表任务取决于扩展connor4312.esbuild-问题-匹配器用于问题匹配,该任务需要在问题视图中报告问题时安装。此扩展需要安装以完成启动。

不要忘记这一点,添加一个.vscode/extensions.json将文件添加到工作区:

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

最后,您将希望更新您的.vscodeignore 文件以便将编译文件包含在发布的扩展中。查看 发布 部分以获取更多详细信息。

跳到 测试 部分继续阅读。

使用webpack

Webpack 是一个开发工具,可以从 npm获取。要获取 webpack 及其命令行界面,请打开终端并输入:

npm i --save-dev webpack webpack-cli

这将安装webpack并更新您的扩展package.json文件包含webpack开发依赖项输入:.

Webpack 是一个 JavaScript 打包器,但许多 VS Code 扩展是用 TypeScript 编写的,并且只编译成 JavaScript。如果你的扩展使用了 TypeScript,你可以使用这个加载器ts-loader,以便webpack可以理解TypeScript。使用以下命令进行安装ts-loader输入:

npm i --save-dev ts-loader

所有文件都可以在webpack-extension示例中找到。

配置 webpack

安装所有工具后,现在可以配置webpack了。按照约定,一个webpack.config.js文件包含用于指示webpack打包你的扩展的配置。以下示例配置是针对VS Code扩展的,应该可以作为一个良好的起点:

//@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'
          }
        ]
      }
    ]
  }
};
模块.导出 = 配置;

该文件 可用 作为 webpack-extension 示例的一部分。Webpack 配置文件是普通的 JavaScript 模块,必须导出一个配置对象。

在上面的示例中,定义了以下内容:

  • 目标指示您的扩展将在哪个上下文中运行。我们建议使用网页工作者这样你的扩展将在 VS Code 网页版和 VS Code 桌面版中都能正常工作。
  • webpack 应该使用的入口点。这类似于主要物业在package.json 除了向webpack提供一个“源”入口点,通常src/extension.ts, 并且不是一个“输出”入口点。Webpack 打包器理解 TypeScript,因此不需要单独的 TypeScript 编译步骤。
  • 输出配置告诉webpack生成的包文件放置在哪里。按照惯例,这是距离文件夹。在这个示例中,webpack 将生成一个dist/extension.js文件。
  • 解决模块/规则配置用于支持TypeScript和JavaScript输入文件。
  • 外部配置用于声明排除项,例如不应包含在捆绑包中的文件和模块。Visual Studio Code模块不应被打包,因为它不存在于磁盘上,而是由 VS Code 在需要时动态创建。根据扩展程序使用的 node 模块,可能需要更多的排除。

最后,您将希望更新您的.vscodeignore 文件以便将编译文件包含在发布的扩展中。查看 发布 部分以获取更多详细信息。

运行webpack

随着webpack.config.js文件已创建,可以调用webpack。您可以从命令行运行webpack,但为了减少重复,使用npm脚本很有帮助。

将这些条目合并到脚本部分在package.json输入:

"脚本": {
    "编译": "webpack --模式 development",
    "监控": "webpack --模式 development --watch",
    "vscode:预发布": "npm run package",
    "打包": "webpack --模式 production --devtool hidden-source-map",
},

编译手表脚本用于开发,并生成捆绑文件。vscode:预发布被使用一切,VS Code 打包和发布工具,在发布扩展之前运行。区别在于模式,它控制优化的级别。使用生产产生最小的捆绑,但也会花费更长时间,所以其他发展使用。要运行上述脚本,请打开终端并输入npm 运行 compile 或选择 任务:运行任务 从命令面板 (⇧⌘P (Windows, Linux Ctrl+Shift+P))。

运行扩展

在您运行扩展之前,主要物业在package.json必须指向该包,对于上面的配置是"./dist/extension". 有了这个更改,现在可以执行和测试这个扩展。

测试

扩展作者通常为他们的扩展源代码编写单元测试。通过正确的架构分层,扩展源代码不依赖于测试,webpack 和 esbuild 生成的包不应包含任何测试代码。要运行单元测试,只需进行简单的编译。

将这些条目合并到脚本部分在package.json输入:

"脚本": {
    "编译测试": "tsc -p . --outDir out",
    "预测试": "npm run compile-tests",
    "测试": "vscode-test"
}

编译测试脚本使用TypeScript编译器将扩展编译成输出文件夹。有了中间的JavaScript,以下片段用于launch.json这足以进行测试。

{
  "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"
}

这种用于运行测试的配置对于非捆绑扩展是一样的。没有捆绑单元测试的原因,因为它们不是扩展发布部分的一部分。

发布

发布前,您应该更新.vscodeignore文件。现在捆绑在一起的所有内容dist/extension.js文件可以被排除,通常是输出文件夹(如果你还没有删除它的话)和最重要的是,节点模块文件夹。

典型的一个.vscodeignore文件看起来像这样:

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

迁移现有扩展

将现有的扩展迁移到使用 esbuild 或 webpack 很简单,类似于上面的入门指南。一个采用 webpack 的实际示例是通过这个拉取请求实现 VS Code 的 References 视图。

在那里你可以看到:

  • 添加esbuild回复。webpackwebpack命令行工具,和ts-loader开发依赖项输入:.
  • 更新npm脚本以使用上述所示的打包器
  • 更新任务配置任务.json文件。
  • 添加和调整esbuild.jswebpack.config.js生成文件。
  • 更新.vscodeignore排除节点模块和中间输出文件。
  • 享受一个安装和加载更快的扩展!

故障排除

最小化

捆绑在生产模式还执行代码最小化。最小化通过删除空白和注释,并将变量和函数名称更改为一些丑陋但简短的内容来压缩源代码。源代码使用Function.prototype.name工作方式不同,因此您可能需要禁用压缩。

webpack 关键依赖

运行webpack时,你可能会遇到类似于关键依赖:依赖请求是一个表达式的警告。这些警告必须引起重视,很可能你的包无法正常工作。该消息意味着webpack无法静态地确定如何打包某些依赖项。这通常是由于动态要求声明,例如需要(someDynamicVariable)输入:.

要解决警告,您应该:

  • 尝试将依赖项静态化,以便可以将其打包。
  • 通过排除该依赖项外部 配置。同时确保这些JavaScript文件没有被排除在打包的扩展之外,使用一个 negated glob pattern.vscodeignore例如!node_modules/我的特殊模块输入:.

下一步

  • 扩展市场 - 了解更多关于 VS Code 公共扩展市场的信息。
  • 测试扩展 - 为您的扩展项目添加测试以确保高质量。
  • 持续集成 - 了解如何在 Azure Pipelines 上运行扩展 CI 构建。