VS Codeのエージェントモードを拡張するには、を試してください!

コンテナー内で Node.js をデバッグする

Node.js プロジェクトに Docker ファイルを追加すると、コンテナー内でそのアプリケーションをデバッグできるようにタスクと起動構成が追加されます。ただし、Node.js を取り巻くエコシステムが大きいため、これらのタスクではすべてのアプリケーション フレームワークまたはライブラリに対応できず、一部のアプリケーションでは追加の構成が必要になります。

コンテナーのエントリ ポイントを構成する

Container Tools 拡張機能は、package.json のプロパティを介して、コンテナーのエントリ ポイント、つまりコンテナー内でデバッグ モードでアプリケーションを起動するためのコマンド ラインを推論します。拡張機能は、まず scripts オブジェクトで start スクリプトを探します。見つかった場合、そしてそれが node または nodejs コマンドで始まる場合、それを使用してデバッグ モードでアプリケーションを起動するためのコマンド ラインを構築します。見つからない場合、または認識された node コマンドでない場合、package.jsonmain プロパティが使用されます。どちらも見つからないか認識されない場合、コンテナーを起動するために使用される docker-run タスクの dockerRun.command プロパティを明示的に設定する必要があります。

一部の Node.js アプリケーション フレームワークには、アプリケーションを管理するための CLI が含まれており、start スクリプトでアプリケーションを起動するために使用され、基礎となる node コマンドを隠蔽します。これらの場合、Container Tools 拡張機能は開始コマンドを推論できないため、開始コマンドを明示的に構成する必要があります。

例: Nest.js アプリケーションのエントリ ポイントを構成する

{
  "tasks": [
    {
      "type": "docker-run",
      "label": "docker-run: debug",
      "dependsOn": ["docker-build"],
      "dockerRun": {
        "command": "nest start --debug 0.0.0.0:9229"
      },
      "node": {
        "enableDebugging": true
      }
    }
  ]
}

例: Meteor アプリケーションのエントリ ポイントを構成する

{
  "tasks": [
    {
      "type": "docker-run",
      "label": "docker-run: debug",
      "dependsOn": ["docker-build"],
      "dockerRun": {
        "command": "node --inspect=0.0.0.0:9229 main.js"
      },
      "node": {
        "enableDebugging": true
      }
    }
  ]
}

ブラウザーをアプリケーションのエントリ ページに自動的に起動する

Container Tools 拡張機能は、デバッガーでアプリケーションが起動した後、ブラウザーをアプリケーションのエントリ ポイントに自動的に起動できます。この機能はデフォルトで有効になっており、launch.json のデバッグ構成の dockerServerReadyAction オブジェクトを介して構成されます。

この機能は、アプリケーションのいくつかの側面によって異なります。

  • アプリケーションは、デバッグ コンソールにログを出力する必要があります。
  • アプリケーションは、「サーバー準備完了」メッセージをログに記録する必要があります。
  • アプリケーションは、ブラウザーで表示可能なページを提供する必要があります。

デフォルト設定は Express.js ベースのアプリケーションでは機能するかもしれませんが、他の Node.js フレームワークでは、これらの側面の1つ以上を明示的に構成する必要がある場合があります。

アプリケーションのログがデバッグ コンソールに書き込まれるようにする

この機能は、アプリケーションがログをアタッチされたデバッガーのデバッグ コンソールに書き込むことに依存します。ただし、すべてのロギング フレームワークがデバッグ コンソールに書き込むわけではありません。コンソールベースのロガーを使用するように構成されている場合でも (一部の「コンソール」ロガーは実際にはコンソールをバイパスして stdout に直接書き込みます)。

解決策はロギング フレームワークによって異なりますが、通常は実際にコンソールに書き込むロガーを作成/追加する必要があります。

例: Express アプリケーションがデバッグ コンソールに書き込むように構成する

デフォルトでは、Express.jsdebug ロギング モジュールを使用します。これはコンソールをバイパスできます。これは、ログ関数をコンソールの debug() メソッドに明示的にバインドすることで解決できます。

var app = require('../app');
var debug = require('debug')('my-express-app:server');
var http = require('http');

// Force logging to the debug console.
debug.log = console.debug.bind(console);

また、debug ロガーは、docker-run タスクで設定できる DEBUG 環境変数によって有効になった場合にのみログを書き込むことに注意してください。(この環境変数は、Docker ファイルがアプリケーションに追加されると、デフォルトで * に設定されます。)

{
  "tasks": [
    {
      "type": "docker-run",
      "label": "docker-run: debug",
      "dependsOn": ["docker-build"],
      "dockerRun": {
        "env": {
          "DEBUG": "*"
        }
      },
      "node": {
        "enableDebugging": true
      }
    }
  ]
}

アプリケーションが「準備完了」になるタイミングを構成する

拡張機能は、Express.js がデフォルトで行うように、アプリケーションがデバッグ コンソールに Listening on port <number> の形式のメッセージを書き込むと、HTTP 接続を受信する「準備ができた」と判断します。アプリケーションが異なるメッセージをログに記録する場合は、デバッグ起動構成の dockerServerReadyAction オブジェクトの pattern プロパティを、そのメッセージに一致する JavaScript 正規表現に設定する必要があります。正規表現には、アプリケーションがリッスンしているポートに対応するキャプチャ グループを含める必要があります。

たとえば、アプリケーションが次のメッセージをログに記録するとします。

function onListening() {
  var addr = server.address();
  var bind = typeof addr === 'string' ? 'pipe ' + addr : 'port ' + addr.port;
  debug('Application has started on ' + bind);
}

デバッグ起動構成 (launch.json 内) の対応する pattern は次のとおりです。

{
  "configurations": [
    {
      "name": "Containers: Node.js Launch",
      "type": "docker",
      "request": "launch",
      "preLaunchTask": "docker-run: debug",
      "platform": "node",
      "dockerServerReadyAction": {
        "pattern": "Application has started on port (\\d+)"
      }
    }
  ]
}

ポート番号の (\\d+) キャプチャ グループと、\d 文字クラスのバックスラッシュの JSON エスケープ文字としての \ の使用に注意してください。

アプリケーションのエントリ ページを構成する

デフォルトでは、Container Tools 拡張機能はブラウザーの「メイン」ページを開きます (アプリケーションによってどのように決定されるかによります)。ブラウザーを特定のページに開く必要がある場合は、デバッグ起動構成の dockerServerReadyAction オブジェクトの uriFormat プロパティを Node.js 形式の文字列に設定する必要があります。これには、ポートを置換する場所を示す1つの文字列トークンが含まれます。

メイン ページの代わりに about.html ページを開くためのデバッグ起動構成 (launch.json 内) の対応する uriFormat は次のとおりです。

{
  "configurations": [
    {
      "name": "Containers: Node.js Launch",
      "type": "docker",
      "request": "launch",
      "preLaunchTask": "docker-run: debug",
      "platform": "node",
      "dockerServerReadyAction": {
        "uriFormat": "https://:%s/about.html"
      }
    }
  ]
}

コンテナーのソース ファイルをローカル ワークスペースにマップする

デフォルトでは、Container Tools 拡張機能は、実行中のコンテナー内のアプリケーションのソース ファイルが /usr/src/app フォルダーにあると仮定し、デバッガーはこれらのファイルをオープンされたワークスペースのルートにマッピングして、コンテナーから Visual Studio Code にブレークポイントを変換します。

アプリケーションのソース ファイルが別の場所にある場合 (たとえば、Node.js フレームワークが異なると異なる規則があるため)、コンテナー内または開かれたワークスペース内のどちらかに関わらず、デバッグ起動構成の node オブジェクトの localRoot プロパティと remoteRoot プロパティのいずれかまたは両方を、それぞれワークスペースとコンテナー内のルート ソースの場所に設定する必要があります。

たとえば、アプリケーションが代わりに /usr/my-custom-location に存在する場合、対応する remoteRoot プロパティは次のようになります。

{
  "configurations": [
    {
      "name": "Containers: Node.js Launch",
      "type": "docker",
      "request": "launch",
      "preLaunchTask": "docker-run: debug",
      "platform": "node",
      "node": {
        "remoteRoot": "/usr/my-custom-location"
      }
    }
  ]
}

トラブルシューティング

node_modules がないためにコンテナー イメージのビルドまたは起動に失敗する

Dockerfile は、多くの場合、イメージのビルド時間、イメージ サイズ、またはその両方を最適化するように配置されています。ただし、すべての Node.js アプリケーション フレームワークがすべての一般的な Node.js Dockerfile 最適化をサポートしているわけではありません。特に、一部のフレームワークでは、node_modules フォルダーがアプリケーションのルート フォルダーの直下のサブフォルダーである必要がありますが、Container Tools 拡張機能は、node_modules フォルダーが親または祖先レベルに存在する Dockerfile をスキャフォールドします (これは通常、Node.js で許可されています)。

解決策は、Dockerfile からその最適化を削除することです。

FROM node:lts-alpine
ENV NODE_ENV=production
WORKDIR /usr/src/app
COPY ["package.json", "package-lock.json*", "npm-shrinkwrap.json*", "./"]
# Remove the `&& mv node_modules ../` from the RUN command:
# RUN npm install --production --silent && mv node_modules ../
RUN npm install --production --silent
COPY . .
EXPOSE 3000
RUN chown -R node /usr/src/app
USER node
CMD ["npm", "start"]