이 출시되었습니다! 11월의 새로운 기능 및 수정 사항을 읽어보세요.

확장 프로그램 번들링

Visual Studio Code 확장 프로그램을 번들링하는 첫 번째 이유는 모든 플랫폼의 VS Code 사용자가 확장 프로그램을 사용할 수 있도록 하는 것입니다. 번들링된 확장 프로그램만 github.devvscode.dev와 같은 VS Code for Web 환경에서 사용할 수 있습니다. VS Code가 브라우저에서 실행될 때 확장 프로그램에 대해 하나의 파일만 로드할 수 있으므로 확장 프로그램 코드는 하나의 웹 친화적인 JavaScript 파일로 번들링되어야 합니다. 이는 Notebook Output Renderers에도 적용되며, VS Code는 렌더러 확장 프로그램에 대해서도 하나의 파일만 로드합니다.

또한 확장 프로그램은 크기와 복잡성이 빠르게 증가할 수 있습니다. 여러 소스 파일로 작성되고 npm의 모듈에 의존할 수 있습니다. 분해 및 재사용은 개발 모범 사례이지만 확장 프로그램 설치 및 실행 시 비용이 발생합니다. 100개의 작은 파일을 로드하는 것은 하나의 큰 파일을 로드하는 것보다 훨씬 느립니다. 따라서 번들링을 권장합니다. 번들링은 여러 개의 작은 소스 파일을 하나의 파일로 결합하는 과정입니다.

JavaScript의 경우 다양한 번들러를 사용할 수 있습니다. 인기 있는 번들러로는 rollup.js, Parcel, esbuildwebpack이 있습니다.

esbuild 사용

esbuild는 구성이 간단하고 빠른 JavaScript 번들러입니다. esbuild를 설치하려면 터미널을 열고 다음을 입력합니다.

npm i --save-dev esbuild

esbuild 실행

명령줄에서 esbuild를 실행할 수 있지만 반복을 줄이고 문제 보고를 활성화하려면 빌드 스크립트인 esbuild.js를 사용하는 것이 좋습니다.

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);
});

빌드 스크립트는 다음을 수행합니다.

  • esbuild로 빌드 컨텍스트를 생성합니다. 컨텍스트는 다음과 같이 구성됩니다.
    • src/extension.ts의 코드를 dist/extension.js라는 단일 파일로 번들링합니다.
    • --production 플래그가 전달된 경우 코드를 최소화합니다.
    • --production 플래그가 전달되지 않은 경우 소스 맵을 생성합니다.
    • VS Code 런타임에서 제공하는 'vscode' 모듈을 번들에서 제외합니다.
  • 번들러가 완료되지 못하게 한 오류를 보고하기 위해 esbuildProblemMatcherPlugin 플러그인을 사용합니다. 이 플러그인은 esbuild 문제 해결사가 감지할 수 있는 형식으로 오류를 내보냅니다. 이 문제 해결사도 확장 프로그램으로 설치해야 합니다.
  • --watch 플래그가 전달된 경우 소스 파일의 변경 사항을 감시하고 변경 사항이 감지될 때마다 번들을 다시 빌드합니다.

esbuild는 TypeScript 파일과 직접 작동할 수 있습니다. 그러나 esbuild는 타입 검사를 수행하지 않고 모든 타입 선언을 제거하기만 합니다. 구문 오류만 보고되며 esbuild가 실패할 수 있습니다.

이러한 이유로 TypeScript 컴파일러(tsc)를 별도로 실행하여 타입을 확인하지만 코드를 내보내지는 않습니다(--noEmit 플래그).

package.jsonscripts 섹션은 다음과 같이 됩니다.

"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은 지정된 접두사와 일치하는 스크립트를 병렬로 실행하는 노드 모듈입니다. 저희의 경우 watch:esbuildwatch:tsc 스크립트를 실행합니다. npm-run-allpackage.jsondevDependencies 섹션에 추가해야 합니다.

compilewatch 스크립트는 개발용이며 번들 파일을 소스 맵과 함께 생성합니다. package 스크립트는 확장 프로그램을 게시하기 전에 실행되는 VS Code 패키징 및 게시 도구인 vsce에서 사용하는 vscode:prepublish 스크립트에서 사용됩니다. esbuild 스크립트에 --production 플래그를 전달하면 코드가 압축되고 작은 번들이 생성되지만 디버깅이 어려워지므로 개발 중에는 다른 플래그가 사용됩니다. 위의 스크립트를 실행하려면 터미널을 열고 npm run watch를 입력하거나 명령 팔레트(⇧⌘P (Windows, Linux Ctrl+Shift+P))에서 **작업: 작업 실행**을 선택합니다.

.vscode/tasks.json을 다음과 같이 구성하면 각 watch 작업에 대해 별도의 터미널이 제공됩니다.

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

이 watch 작업은 문제 보고를 위해 connor4312.esbuild-problem-matchers 확장 프로그램(connor4312.esbuild-problem-matchers)에 의존하므로 작업이 문제 보기에서 문제를 보고하려면 이 확장 프로그램을 설치해야 합니다. 이 확장 프로그램은 실행이 완료되려면 설치해야 합니다.

이를 잊지 않도록 작업 영역에 .vscode/extensions.json 파일을 추가합니다.

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

마지막으로 컴파일된 파일이 게시된 확장 프로그램에 포함되도록 .vscodeignore 파일을 업데이트해야 합니다. 자세한 내용은 게시 섹션을 확인하세요.

계속 읽으려면 테스트 섹션으로 이동합니다.

webpack 사용

Webpack은 npm에서 사용할 수 있는 개발 도구입니다. webpack 및 해당 명령줄 인터페이스를 설치하려면 터미널을 열고 다음을 입력합니다.

npm i --save-dev webpack webpack-cli

이렇게 하면 webpack이 설치되고 확장 프로그램의 package.json 파일이 업데이트되어 webpack이 devDependencies에 포함됩니다.

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'
          }
        ]
      }
    ]
  }
};
module.exports = config;

파일은 webpack-extension 샘플의 일부로 사용 가능합니다. Webpack 구성 파일은 일반 JavaScript 모듈이며 구성 개체를 내보내야 합니다.

위 샘플에서는 다음이 정의됩니다.

  • target은 확장 프로그램이 실행될 컨텍스트를 나타냅니다. webworker를 사용하는 것이 좋습니다. 이렇게 하면 확장 프로그램이 VS Code for web 및 VS Code 데스크톱 버전 모두에서 작동합니다.
  • webpack이 사용해야 하는 진입점입니다. 이는 package.jsonmain 속성과 유사하지만, webpack에 "출력" 진입점이 아닌 "소스" 진입점(일반적으로 src/extension.ts)을 제공합니다. webpack 번들러는 TypeScript를 이해하므로 별도의 TypeScript 컴파일 단계는 중복입니다.
  • output 구성은 webpack이 생성된 번들 파일을 배치할 위치를 webpack에 지시합니다. 관례적으로 이는 dist 폴더입니다. 이 샘플에서는 webpack이 dist/extension.js 파일을 생성합니다.
  • resolvemodule/rules 구성은 TypeScript 및 JavaScript 입력 파일을 지원하기 위한 것입니다.
  • externals 구성은 제외를 선언하는 데 사용됩니다. 예를 들어 번들에 포함되지 않아야 하는 파일 및 모듈입니다. vscode 모듈은 디스크에 존재하지 않고 필요할 때 VS Code에서 즉석으로 생성되므로 번들링해서는 안 됩니다. 확장 프로그램에서 사용하는 노드 모듈에 따라 더 많은 제외가 필요할 수 있습니다.

마지막으로 컴파일된 파일이 게시된 확장 프로그램에 포함되도록 .vscodeignore 파일을 업데이트해야 합니다. 자세한 내용은 게시 섹션을 확인하세요.

webpack 실행

webpack.config.js 파일이 생성되면 webpack을 호출할 수 있습니다. 명령줄에서 webpack을 실행할 수 있지만 반복을 줄이려면 npm 스크립트를 사용하는 것이 좋습니다.

이 항목들을 package.jsonscripts 섹션에 병합합니다.

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

compilewatch 스크립트는 개발용이며 번들 파일을 생성합니다. vscode:prepublish는 VS Code 패키징 및 게시 도구인 vsce에서 사용되며 확장 프로그램 게시 전에 실행됩니다. 차이점은 모드이며, 이는 최적화 수준을 제어합니다. production을 사용하면 가장 작은 번들이 생성되지만 시간이 더 오래 걸리므로 development가 사용됩니다. 위의 스크립트를 실행하려면 터미널을 열고 npm run compile을 입력하거나 명령 팔레트(⇧⌘P (Windows, Linux Ctrl+Shift+P))에서 **작업: 작업 실행**을 선택합니다.

확장 프로그램 실행

확장 프로그램을 실행하려면 package.jsonmain 속성이 번들을 가리켜야 합니다. 위의 구성에서는 "./dist/extension"입니다. 이 변경 후 확장 프로그램을 실행하고 테스트할 수 있습니다.

테스트

확장 프로그램 작성자는 확장 프로그램 소스 코드에 대한 단위 테스트를 작성하는 경우가 많습니다. 올바른 아키텍처 계층을 사용하면 확장 프로그램 소스 코드가 테스트에 의존하지 않으므로 webpack 및 esbuild로 생성된 번들에는 테스트 코드가 포함되지 않아야 합니다. 단위 테스트를 실행하려면 간단한 컴파일만 있으면 됩니다.

이 항목들을 package.jsonscripts 섹션에 병합합니다.

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

compile-tests 스크립트는 TypeScript 컴파일러를 사용하여 확장 프로그램을 out 폴더로 컴파일합니다. 이 중간 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 파일로 번들링된 모든 항목은 제외할 수 있습니다. 일반적으로 out 폴더(아직 삭제하지 않은 경우)와 가장 중요한 node_modules 폴더입니다.

일반적인 .vscodeignore 파일은 다음과 같습니다.

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

기존 확장 프로그램 마이그레이션

기존 확장 프로그램을 esbuild 또는 webpack을 사용하도록 마이그레이션하는 것은 쉽고 위의 시작 안내와 유사합니다. webpack을 채택한 실제 샘플은 VS Code의 참조 보기이며 다음 풀 요청을 통해 확인할 수 있습니다.

여기서 다음을 볼 수 있습니다.

  • esbuild 또는 webpack, webpack-cli, ts-loaderdevDependencies로 추가합니다.
  • 위에서 보여준 대로 번들러를 사용하도록 npm 스크립트를 업데이트합니다.
  • 작업 구성 tasks.json 파일을 업데이트합니다.
  • esbuild.js 또는 webpack.config.js 빌드 파일을 추가하고 조정합니다.
  • node_modules 및 중간 출력 파일을 제외하도록 .vscodeignore를 업데이트합니다.
  • 설치 및 로딩이 훨씬 빠른 확장 프로그램을 즐기세요!

문제 해결

최소화

production 모드에서 번들링하면 코드 최소화도 수행됩니다. 최소화는 공백과 주석을 제거하고 변수 및 함수 이름을 보기 흉하지만 짧은 이름으로 변경하여 소스 코드를 압축합니다. Function.prototype.name을 사용하는 소스 코드는 다르게 작동하므로 최소화를 비활성화해야 할 수 있습니다.

webpack 중요 종속성

webpack을 실행할 때 **중요 종속성: 종속성 요청이 표현식입니다**와 같은 경고가 발생할 수 있습니다. 이러한 경고는 심각하게 받아들여야 하며 번들이 작동하지 않을 가능성이 높습니다. 이 메시지는 webpack이 일부 종속성을 번들링하는 방법을 정적으로 결정할 수 없다는 것을 의미합니다. 이는 일반적으로 동적 require 문(예: require(someDynamicVariable))으로 인해 발생합니다.

경고를 해결하려면 다음 중 하나를 수행해야 합니다.

  • 종속성을 정적으로 만들어 번들링할 수 있도록 합니다.
  • externals 구성을 통해 해당 종속성을 제외합니다. 또한 해당 JavaScript 파일이 패키지된 확장 프로그램에서 제외되지 않도록 .vscodeignore에서 부정적인 glob 패턴을 사용하여 제외해야 합니다. 예를 들어 !node_modules/mySpecialModule과 같습니다.

다음 단계

  • 확장 마켓플레이스 - VS Code의 공개 확장 마켓플레이스에 대해 자세히 알아보세요.
  • 확장 프로그램 테스트 - 고품질을 보장하기 위해 확장 프로그램 프로젝트에 테스트를 추가하세요.
  • 지속적 통합 - Azure Pipelines에서 확장 프로그램 CI 빌드를 실행하는 방법을 알아보세요.
© . This site is unofficial and not affiliated with Microsoft.