Skip to content

MS_ESProj

nishi_74322014 edited this page Aug 21, 2026 · 1 revision

.esproj(JavaScript・TypeScriptプロジェクトシステム)

概要

  • Visual Studio 2022 から本格導入された、モダンな SPA 開発を C# の世界(MSBuild)と
    スマートに融合させるための新しいプロジェクト形式
  • 従来のように「.csproj の中に無理やり JavaScript のファイルを詰め込む」のではなく、
    フロントエンドを独立して扱うために作られた。

補足(何が「新しい」のか): 一連の SPA テンプレートの歴史
ASP.NET Core SPAテンプレート
JavaScript Services)の到達点
.esproj である、と位置付けると分かりやすい。

【第 1 世代(2017)】 JavaScript Services
   1 つの .csproj に ClientApp フォルダを同居させる
   .NET が webpack を起動し、Node.js を子プロセスで抱える
     → 【.NET がフロントの面倒を見る】
     → 廃止された ★

【第 2 世代(2020 頃)】 手作業での分離
   フロントを別フォルダ/別リポジトリにする
   それぞれ別に起動、別にビルド
     → 正しいが【IDE の支援がない】(VS の恩恵が薄い)

【第 3 世代(VS2022)】 .esproj
   フロントを【独立したプロジェクト】として扱う
   ただし【ソリューションには載る】
     → 分離しつつ、IDE の統合(F5 で両方起動)は保つ ★

「分離するが、統合された体験は諦めない」——
これが .esproj の設計思想である。

詳細

...VSCode 使えば良いのでは?...

補足(原文のこの一言への回答): 「VS Code 使えば良いのでは?」
という率直な疑問は、実務的にはかなり的を射ている
公平に整理しておく。

観点 VS + .esproj VS Code(2 つ開く / 1 つで両方)
C# のデバッグ 強力(VS の本領) 可能(C# Dev Kit)。VS には及ばない
フロントの編集体験 普通 快適(拡張が豊富、動作が軽い)
起動(F5) 1 ボタンで両方 launch.json の compound で同等にできる
CI との一貫性 MSBuild に乗る npm scripts で明示的に書く
チームの分業 フロント担当も VS が要る フロント担当は VS Code だけでよい
ライセンス VS のライセンスが要る 無償
動作の軽さ 重い 軽い
【.esproj が向く場面】
   ・C# 開発者が【フロントも自分で書く】小~中規模チーム
   ・すでに VS ライセンスがあり、CI も MSBuild 中心
   ・「F5 一発」の体験を重視する

【VS Code(分離)が向く場面】
   ・フロント専任がいる(その人に VS を買う理由がない)★
   ・フロントを別リポジトリ・別デプロイにする
   ・Mac / Linux の開発者がいる
   ・フロントのビルドを CI で独立させたい

原文の疑問が妥当なのは、「.esproj でなければできないこと」が
ほとんどない
ためである。
.esproj が提供するのは利便性であって、機能ではない

ただし、「CI/CD を一本化できる」点は実質的な利点である
(後述の「どんな人に向いている?」)。

CLIの利用

VS は VSC と同様に、生の npm、npx、または yarn、pnpm などの CLI ツールを
バックグラウンドで直接呼び出す。

補足(この点が最も重要): .esproj は独自のビルド機構を持たない——
これが Web Essentials の失敗(= IDE 依存のコンパイラ)から
学んだ点である。

【Web Essentials(2010~2015)】
   VS の拡張機能が【自前で】LESS/Sass/TS をコンパイルしていた
     → VS がないとビルドできない ✗

【.esproj(2022~)】
   VS は【npm run build を呼ぶだけ】★
     → package.json さえあれば、VS がなくてもビルドできる
     → CI でも、VS Code でも、コマンドラインでも同じ結果

つまり、.esproj を入れても
「VS がないとビルドできない」状態にはならない

これは採用判断において重要な性質である。

# .esproj のプロジェクトも、これで普通にビルドできる
cd myapp.client
npm ci
npm run build

解決した3つの課題

.esproj の導入により、Visual Studio での Web 開発は以下のように劇的に変化

  • ビルド

    • ...が重い:C# をビルドするたびに npm run build が走り、時間がかかる。
    • ...の分離:デバッグ時は Vite 等の高速な HMR(Hot Module Replacement)を使い、
      C# 側は API のコンパイルだけに専念。
  • PJ 依存関係

    • ...がごちゃ混ぜ:NuGet パッケージと npm パッケージの管理が 1 つの場所で混ざる。
    • ...の完全分離:バックエンドは .csproj(NuGet)、
      フロントエンドは .esproj(npm)と完全に分かれる。
  • デバッグの

    • ...開始が面倒:API と SPA を両方立ち上げるために、
      手動でターミナルを 2 つ開く必要があった。
    • ...マルチスタートアップ:VS の「開始」ボタン 1 つで、
      API の起動と SPA の開発サーバー(Vite 等)の起動、ブラウザ起動まで自動化。

補足(3 つの課題の背景): それぞれ、旧テンプレートで実際に
起きていた問題
である。

① ビルドが重い

【旧(1 プロジェクト)】
   dotnet build
     └ MSBuild のターゲットで npm run build が起動
          └ webpack が全部バンドル(数十秒)
     → C# を 1 行直すだけでも、フロントが丸ごと再ビルドされる ★

【新(.esproj)】
   Debug 構成では ShouldRunBuildScript = false
     → npm run build を【走らせない】
     → 代わりに Vite の dev server が HMR で差分更新

② 依存関係のごちゃ混ぜ

【旧】 1 つのフォルダに
         MyApp.csproj(NuGet の参照)
         package.json(npm の依存)
         node_modules/(数万ファイル)★

   ・node_modules が .csproj のファイル列挙に引っかかる
     → VS が遅くなる、ビルド対象に紛れ込む
   ・.gitignore の管理が煩雑
   ・「このプロジェクトの依存は何か」が一目で分からない

③ デバッグ開始が面倒

【旧(手動分離した場合)】
   ターミナル1: dotnet run
   ターミナル2: npm run dev
   ブラウザ:    手で開く
     → 毎回この手順。新メンバーへの説明も要る

【新】 F5 一発

なお、②の「完全分離」は現在の設計として正しいが、
node_modules の重さは消えていない点に注意する。

・node_modules は依然として巨大(数百 MB、数万ファイル)
・ウイルス対策ソフトの除外設定を推奨
   → [ウイルススキャン] 参照
・CI では npm ci(キャッシュ利用)で時間を抑える
・pnpm を使うと【ディスク使用量が劇的に減る】(ハードリンク方式)★

ファイルの中身(仕組み)

.esproj ファイルの実体は、C# の .csproj などと同じ XML 形式(MSBuild 形式)のファイルで、
主に「JavaScript ツールチェーンと MSBuild を結びつける設定」だけが書かれる。

<Project Sdk="Microsoft.VisualStudio.JavaScript.Sdk/1.0.0-alpha.x.x">
  <PropertyGroup>
    <StartupCommand>npm run dev</StartupCommand>
    <JavaScriptTestRoot>src\</JavaScriptTestRoot>
    <JavaScriptTestFramework>Jest</JavaScriptTestFramework>
    <SpawnServerScript >true</SpawnServerScript>
    <BuildOutputFolder>$(MSBuildProjectDirectory)\dist</BuildOutputFolder>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)' == 'Debug'">
    <ShouldRunBuildScript>false</ShouldRunBuildScript>
  </PropertyGroup>
  <ItemGroup>
    <Folder Include="src\assets\" />
  </ItemGroup>
</Project>
  • 重要な MSBuild プロパティ
    • ShouldRunNpmInstall: true(デフォルト)にしておくと、
      VS でソリューションを開いた時やビルド時に、自動で npm install を実行
    • ShouldRunBuildScript: 製品リリース用(Publish)ビルドの際、
      自動で npm run build を走らせ、成果物を指定のフォルダに出力

補足(各プロパティの意味と、実務での注意):

プロパティ 意味
Sdk JavaScript プロジェクト SDK.csprojMicrosoft.NET.Sdk に相当
StartupCommand F5 で実行されるコマンドnpm run dev 等)
JavaScriptTestRoot テストの探索対象フォルダ
JavaScriptTestFramework テスト エクスプローラーとの統合(Jest / Vitest / Mocha)
SpawnServerScript 開発サーバーを別プロセスで起動するか
BuildOutputFolder ビルド成果物の出力先dist
ShouldRunNpmInstall ソリューションを開いた際に npm install を自動実行
ShouldRunBuildScript ビルド時に npm run build を実行するか ★

ShouldRunNpmInstall には注意点がある

【問題】
   ・自動で npm install が走る=【package-lock.json が更新され得る】
      → 意図しない依存の版上がり
      → チーム内で lock ファイルの差分が出る ★
   ・オフライン環境で開くと失敗する
   ・開くたびに時間がかかる(キャッシュがあれば速いが)

【対策】
   ・CI では【npm ci】を使う(lock を厳密に守る。install ではない)
   ・気になるなら ShouldRunNpmInstall を false にし、
     手動 or CI で明示的に実行する

Condition="'$(Configuration)' == 'Debug'" の意味:

Debug 構成のときだけ ShouldRunBuildScript = false
  → デバッグ時は本番ビルドを走らせない(Vite の dev server を使う)
  → Release / Publish のときは true のまま= npm run build が走る

 → 【この 1 行が「ビルドが重い」問題の解】である ★

1.0.0-alpha.x.x というバージョン:
原文が記録している通り、
この SDK は長らく alpha 版として提供されていた
現在もバージョンを明示的にピン留めするのが安全である
(VS の更新で SDK の挙動が変わることがある)。

ASP.NETとの「プロキシ連携」

  • .esproj テンプレート(例:React with ASP.NET Core)を選ぶと、
    フロントエンドとバックエンドがどうやって通信するかの仕掛け(プロキシ設定)が
    自動で構築される。

    • SPA 側(Vite 等)のポート: localhost:5173
    • API 側(C#)のポート: localhost:7200
  • 開発中、SPA 側から /api/weather のようにリクエストを送ると、
    Vite 側の開発用プロキシ(vite.config.ts に自動記述される設定)が、
    裏側で自動的に C# 側の localhost:7200/api/weather へリクエストを転送し
    CORS エラーに悩まされることがなくなる。

補足(自動生成される設定の中身): Visual Studio CodeによるSPA開発
で「対策 B(プロキシ)が優れている」と述べた構成を、
VS が自動で作ってくれる——というのがこの節の内容である。

// vite.config.ts(テンプレートが生成するものの要点)
export default defineConfig({
    server: {
        proxy: {
            '^/api': {
                target: 'https://localhost:7200',
                secure: false,          // 開発用の自己署名証明書を許容
            }
        },
        port: 5173,
    }
});
【リクエストの流れ(開発時)】
   ブラウザ → localhost:5173/api/weather
                 │ Vite の dev server が受ける
                 │ /api で始まるので【転送】
                 ▼
             localhost:7200/api/weather(ASP.NET Core)

   → ブラウザから見ると【同一オリジン】
   → CORS が発生しない ★
   → Cookie 認証もそのまま効く

本番ではプロキシは存在しない点に注意する。

【本番の構成(例)】
   ① SPA を ASP.NET Core の wwwroot に配置し、同一ドメインで配信
        → MapFallbackToFile("index.html")([Spa Services] 参照)
   ② SPA を CDN / Static Web Apps に、API を別ドメインに
        → 【CORS の設定が必要になる】
   ③ リバース プロキシ(nginx / Azure Front Door)で
      同一ドメインに束ねる ★ 推奨

開発時に CORS が起きない構成にしていると、
本番で初めて CORS に当たる
——という事故が起こり得る。
本番と同じ構成をステージング環境で検証する必要がある。

証明書についての補足:

・ASP.NET Core は開発用の自己署名証明書を使う
   dotnet dev-certs https --trust
・Vite 側は secure: false で検証をスキップする
   → 【開発時のみ】。本番の設定に持ち込まないこと

どんな人に向いている?

  • Visual Studio 1 つで開発を完結させたい:
    「C# のデバッグは VS、フロントエンドは VS Code」と画面を行き来するのが面倒で、
    1 つの IDE、1 つの「デバッグ開始(F5)」ボタンで全てを制御したい場合に
    最高のパフォーマンスを発揮
  • CI/CD(ビルドパイプライン)を一本化したい:MSBuild の仕組みに乗っかっているため、
    Azure Pipelines や GitHub Actions で「ソリューション全体のビルド」を実行するだけで、
    フロントエンドの npm install & build も処理できる。

補足(CI/CD の一本化について、公平に): 2 番目の利点は実質的だが、
一本化が常に良いとは限らないので、両面を書いておく。

# 一本化した場合(GitHub Actions)
- run: dotnet publish -c Release
#   → .csproj のビルド + .esproj 経由で npm ci && npm run build
#   → 【1 コマンドで済む】★
# 分離した場合
- run: npm ci --prefix ./client
- run: npm run build --prefix ./client
- run: dotnet publish -c Release
#   → 記述は増えるが、【何が起きているかが見える】
一本化(.esproj) 分離
記述量 少ない 多い
失敗箇所の特定 MSBuild のログに埋もれる 明確
キャッシュ npm キャッシュを効かせにくい actions/setup-node のキャッシュが効く
並列化 しにくい フロントとバックを並列ビルドできる
部分デプロイ しにくい フロントだけ再デプロイ、が可能
必要な環境 .NET SDK のみ(Node は SDK が呼ぶ) .NET SDK + Node.js
【規模による使い分け】
   小~中規模、フロントとバックを常に同時にデプロイする
     → 【一本化で良い】

   大規模、フロントとバックのリリース サイクルが違う
     → 【分離する】
     → フロントは CDN、バックは App Service、と配置先も違う

**判断の軸は「フロントとバックを常に同時にデプロイするか」**である。
同時なら一本化、別々なら分離——と考えると迷いにくい。

参考

...

Microsoft Learn


Tags: 移行, .NET開発, .NET Core, ASP.NET, ASP.NET Web API, ASP.NET SPA, JavaScript

NetDevInfraWiki

マイクロソフト系技術情報 Wiki
Open 棟梁 Wiki

(未着手)

開発基盤部会 Wiki

移行管理: DONETODO

Clone this wiki locally