Viteのコードを読む - createServer(ViteDevServer生成まで)

  • Vite

前回: Viteのコードを読む - CLI経由でのコア実行の流れ - memo_md

viteパッケージ内部 / サーバー起動部分をよむ

vite dev vite serve などで起動する packages/vite/src/node/server をよむ

ファイル一覧

.
├── __tests__
├── hmr.ts
├── index.ts
├── middlewares
│   ├── base.ts
│   ├── error.ts
│   ├── indexHtml.ts
│   ├── proxy.ts
│   ├── spaFallback.ts
│   ├── static.ts
│   ├── time.ts
│   └── transform.ts
├── moduleGraph.ts
├── openBrowser.ts
├── pluginContainer.ts
├── searchRoot.ts
├── send.ts
├── sourcemap.ts
├── transformRequest.ts
└── ws.ts

CLI からの起動は ↓

const { createServer } = await import('./server')
try {
  const server = await createServer({
    root,
    base: options.base,
    mode: options.mode,
    configFile: options.config,
    logLevel: options.logLevel,
    clearScreen: options.clearScreen,
    server: cleanOptions(options)
  })

  ...

vite/packages/vite/src/node/server/index.ts # createServer が該当

createServer

コンフィグの読み込みとサーバー生成

const config = await resolveConfig(inlineConfig, 'serve', 'development')

inlineConfig の configFilefalse でなければ loadConfigFromFile で読む (明示的に "使いません!!" としない限りロードする)

configFile でファイル指定がある場合はそれをロード

esbuildでビルド

externalize-deps → 外部パッケージをマーク

  const httpsOptions = await resolveHttpsConfig(
    config.server.https,
    config.cacheDir
  )
const middlewares = connect() as Connect.Server
const httpServer = middlewareMode
  ? null
  : await resolveHttpServer(serverConfig, middlewares, httpsOptions)
const ws = createWebSocketServer(httpServer, config, httpsOptions)

https://ja.vitejs.dev/config/#server-middlewaremode

index.html の配布を誰が責務を持つかの話

https/proxyの設定に応じて、 http or https or http2 モジュールで createServer (connectで作られたMiddlewareを渡す)

createWebSocketServer : HMR用のWebSocketサーバーの準備。基本的に↑で使っているサーバーをそのまま使う

createPluginContainer

  const container = await createPluginContainer(config, moduleGraph, watcher)

指定したファイル上でプラグインフックを実行できる Rollup プラグインコンテナ。 とある

https://ja.vitejs.dev/guide/api-plugin.html#%E5%85%B1%E9%80%9A%E3%81%AE%E3%83%95%E3%83%83%E3%82%AF

適宜 Rollup ビルドを行うためのコンテナ

// we should create a new context for each async hook pipeline so that the
// active plugin in that pipeline can be tracked in a concurrency-safe manner.
// using a class to make creating new contexts more efficient
class Context implements PluginContext {
  ...
}

次のようなものを持つ(特徴的ぽい一部だけ抜粋)

都度生成しているケースもあるし、TransformContext のように継承しているケースもある。

最終的に返される PluginContainer は次のメソッドを持つ

サーバー停止用ハンドラの生成

const closeHttpServer = createServerCloseFn(httpServer)

https://nodejs.org/api/http.html#event-connection

全ての接続に対して destroy で破棄

ViteDevServer の生成

ここまで作ってきた全てを一通り保持する ViteDevServer オブジェクトを作る 詳細は次回以降。

感想

実際プラグイン書いてみないと真髄はわからなさそう

次回

createServer 読み終わってないので、続きをよむ