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

前回: 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 は CLI の実行時引数などから生成したオブジェクト
  • resolveConfigResolvedConfig 型の値を返す
    • inlineConfig の configFilefalse でなければ loadConfigFromFile で読む (明示的に "使いません!!" としない限りロードする)
    • 次の順番でロードを試みる
      1. configFile でファイル指定がある場合はそれをロード
      2. vite.config.js
      3. vite.config.mjs
      4. vite.config.ts
      5. vite.config.cjs
    • ESM の場合 (package.json の type が module、または設定ファイルが .mjs.ts )は bundleConfigFile
      • esbuildでビルド
      • Pluginとして externalize-depsreplace-import-meta を適用している
      • そういうプラグインパッケージがあるわけじゃなく、ただ名前つけてるだけぽい
        • externalize-deps → 外部パッケージをマーク
        • replace-import-metaimport.meta.url, __dirname, __filename を実体に置き換え
  const httpsOptions = await resolveHttpsConfig(
    config.server.https,
    config.cacheDir
  )
  • vite/packages/vite/src/node/http.ts # resolveHttpsConfig
  • https接続用の ca,cert,key,pfx ファイルをロード
const middlewares = connect() as Connect.Server
const httpServer = middlewareMode
  ? null
  : await resolveHttpServer(serverConfig, middlewares, httpsOptions)
const ws = createWebSocketServer(httpServer, config, httpsOptions)
  • connect でサーバのMiddlewareを作成
  • server設定で middlewareMode が設定されていなければ resolveHttpServer
    • https://ja.vitejs.dev/config/#server-middlewaremode
      • index.html の配布を誰が責務を持つかの話
      • ドキュメント上では ssr or html が設定に渡せるようだが、実際は true false もいける
    • https/proxyの設定に応じて、 http or https or http2 モジュールで createServer (connectで作られたMiddlewareを渡す)
  • createWebSocketServer : HMR用のWebSocketサーバーの準備。基本的に↑で使っているサーバーをそのまま使う
    • Midlewareモードだったりserver.htr.server の設定などによってはサーバーを作る
    • 先に作ったサーバーを利用する場合は、upgrade 要求で WebSocket コネクションを確立する

createPluginContainer

  const container = await createPluginContainer(config, moduleGraph, watcher)
// 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 {
  ...
}

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

  • parse : acornでコードをparse
  • resolve : ID(ファイルのURLやパス)を解決
  • addWatchFile : chokiderの監視対象にファイルを乗せる

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

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

  • buildStart : すべてのプラグインを対象に buildStart を呼ぶ
  • resolveId : ID(ファイルのURLやパス)を解決
  • load : すべてのプラグインを対象に id を引数に load を呼ぶ
  • transform : すべてのプラグインを対象に id を引数に transform を呼ぶ
  • close : すべてのプラグインを対象に buildEndcloseBundle を呼ぶ

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

const closeHttpServer = createServerCloseFn(httpServer)

ViteDevServer の生成

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


感想

  • createServer だけでもやってることめっちゃ多かった
  • vite.config 書くときに「tsでも書けて便利〜〜」とか思ってたけど、裏で普通にesbuildしててそりゃそうだよなってなった
  • RollUp用の PluginContainer で複雑なことをやってんだなってのはわかった

次回

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

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

前回: Viteのコードを読む - リポジトリ直下のファイル群 - memo_md

コアのファイルをよむ

  • packages/vite を見ていく
  • とりあえずディレクトリ構造を眺めてみる

ディレクトリ構造

.
├── bin
├── dist
│   ├── client
│   └── node
│       └── chunks
├── scripts
├── src
│   ├── client
│   └── node
│       ├── __tests__
│       │   ├── packages
│       │   │   ├── name
│       │   │   └── noname
│       │   └── plugins
│       ├── optimizer
│       ├── plugins
│       ├── server
│       │   ├── __tests__
│       │   │   └── fixtures
│       │   │       ├── lerna
│       │   │       │   └── nested
│       │   │       ├── none
│       │   │       │   └── nested
│       │   │       ├── pnpm
│       │   │       │   └── nested
│       │   │       └── yarn
│       │   │           └── nested
│       │   └── middlewares
│       └── ssr
│           └── __tests__
└── types
  • 実はそんなにディレクトリはないっぽい
  • 普段はCLI経由で叩くことが多いので、CLIからどういった流れでコアのコードが実行されているのかを追ってみる

CLI経由でのコマンド実行の流れ

  1. bin/vite.js
  2. dist/node/cli
  3. コマンドに応じた振り分け

bin/vite.js

  • source-map-supportのインストール (StackTraceから追えるようにぽい)
  • --profile オプションに応じた挙動の切り替え
    • APIドキュメントとかには記述がない
    • new inspector.Session() を呼び出しているのでデバッグ用?
  • require('../dist/node/cli') … 実行本体
    • 実際には packages/vite/src/node/cli.ts

dist/node/cli (packages/vite/src/node/cli.ts)

コマンドに応じた振り分け

[root]

  • vite起動本体。ViteDevServerが立ち上がる(実体は https://nodejs.org/api/http.html
  • packages/vite/src/node/server/index.ts # createServer
  • CLIオプションを inlineConfig として渡す

build

  • 本番用build
  • packages/vite/src/node/build.ts # build

optimize

  • packages/vite/src/node/optimizer.ts # optimizeDeps
  • https://vitejs.dev/guide/dep-pre-bundling.html
  • 通称 dependency pre-bundling の実行
  • 一部依存を事前解決しておくことで、vite serve 時のパフォーマンス向上に繋がるぽい

preview


  • 依存しているライブラリ (cac とか picocolors とか) は自分でも使えそう
  • CLI経由の場合オプションはそれほどない。まだ読めるって感じする
  • コア(root)の中に入るとそれなりに大きい。そこからが本番って感じ

次 → 振り分けている各コマンドの詳細を見ていく

Viteのコードを読む - リポジトリ直下のファイル群

前回: Viteのコードを読む - ディレクトリ構造とテスト実行 - memo_md


リポジトリ直下のファイル群をみてみる

チェックアウトしたリポジトリの直下にあるファイル群。 主に設定ファイルとかそういう系を眺めてみる。

一覧

  • package.json
  • LICENSE
  • CODE_OF_CONDUCT.md
  • CONTRIBUTING.md
  • jest.config.ts
  • netlify.toml
  • pnpm-lock.yaml
  • pnpm-workspace.yaml
  • README.md

LICENCEとかそういうのは省略。必要そうなのを見ていく。

package.json

  • node ≥ 12.2.0
  • scripts
    • preinstallnpx only-allow pnpm
      • https://github.com/pnpm/only-allow
      • 利用可能なパッケージマネージャを強制するツールらしい。こんなのあったのか..
      • 試しに yarn install とかすると Use "pnpm install" for installation in this project. とエラーにしてくれる
    • formatlint はよくある感じ。eslintやprettierを実行してる。
    • 他は jest実行系, vitepressによるドキュメント生成系、viteやpluginのビルド系、などがある
  • lint-staged
    • https://github.com/okonet/lint-staged
    • gitでstageされたファイルを対象にlint,prettierを実行
    • prettierは全ファイル。eslintはtsファイルのみ対象に実行している
  • simple-git-hooks

pnpm-workspace.yaml / pnpm-lock.yaml

以下をmonorepos対象にしてる

  • packages/*
  • packages/playground/**

jest.config.ts

  • ts-jest利用
    • 意外とテスト実行時に型チェックしてるんだなという感想
  • VITE_TEST_BUILD 指定時は実行対象を playground 配下に絞ってる
    • npm script の test-build test-serve の呼び分けで使う
    • 開発サーバモードでテストするか、ビルドモードでテストするかの違い
    • CONTRIBUTING.md にそのあたりの説明がある
  • globalSetup: './scripts/jestGlobalSetup.cjs'
    • playwright-chromium で browser を起動
    • packages/temp に playground のファイルをコピーしてる?
  • globalTeardown: './scripts/jestGlobalTeardown.cjs'
    • global.__BROWSER_SERVER__ にサーバーがあれば閉じる
    • packages/temp を消して後片付け
  • testEnvironment: './scripts/jestEnv.cjs'
    • 独自のEnvironmentを実装して適用
    • setup
      • wsEndpoint を参照して、ブラウザで接続
      • global.page に新しく開いたブラウザのページを保持
    • teerdown
      • ブラウザを閉じてる
  • setupFilesAfterEnv: ['./scripts/jestPerTestSetup.ts']
    • 各 Playground のテストディレクトリにある serve.js があれば実行する
      • ビルドやサーバ起動を行ってる
      • requireしてみて serve or preServe があれば実行という感じ
    • isBuildTest (VITE_TEST_BUILD で決まる)の値に応じて page から繋ぐ接続先のURLを切り替えてる
      • isBuildTest がtruthyならビルドされる
      • Viteのサーバではなく、ビルド結果を使って http パッケージによる配信を行う

CODE_OF_CONDUCT.md

健全なOSS運営についてのポリシーが書いてある。

大事。

CONTRIBUTING.md

  • リポジトリのセットアップ方法
    • pnpm 周りの導入あたりがわかる
  • テスト実行周り
    • playwright使ってますよ〜という話
    • 開発サーバモードとビルドモードの違い
    • テストの書き方
  • デバッグログの出力方法
  • PRのガイドライン
  • Dependencies周りの注意点
    • 小さく保つためRollupでバンドルするのが前提で、基本的にdevDependenciesになる
    • requireは使えないので dynamic import を使う必要がある
    • 依存関係が大きく、機能のわりにサイズが大きいものは使わない
    • 結構厳しい感じ。自力で作れるものは作りましょうって感じかもしれん
  • 型付けを完璧に維持してますという話
  • オプション追加、ホントに必要かよく考えろよという話
    • 価値があるのか、他に方法(別オプションやプラグインでの解決)が無いのか、など
  • 翻訳や Vite Land (https://chat.vitejs.dev) の話

感想

  • JestのEnvironment独自で作ってるのはナルホドって感じだった
  • 依存関係気軽に足せないのは大変そう
  • lint-staged とか普通に知らんかった..、便利そうなので使っていきたい

次→Viteのコアコードを少しずつ読んでく

Viteのコードを読む - ディレクトリ構造とテスト実行

(全然ブログ書いてなかった...)

Viteのコードを読んでみようという試み

Viteが盛り上がっていて個人的にも使っているので中身を少しでも把握したい。

大変だろうけど、バージョンが上がりまくって機能追加されてからだと中身追うのも無理になりそうなので、今のうちに見れるだけ見てみるという試み。心が折れたらやめるかもしれない。

読む対象

  • v2.8.3
  • hash: e2349569cf96e506e0d5fff1d043727a77fdad70

ファイル一覧を眺める

とりあえず何も考えずに tree コマンドで列挙してみた

見てみる(クリックで展開)

.
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── docs
│   ├── blog
│   │   └── announcing-vite2.md
│   ├── config
│   │   └── index.md
│   ├── guide
│   │   ├── api-hmr.md
│   │   ├── api-javascript.md
│   │   ├── api-plugin.md
│   │   ├── assets.md
│   │   ├── backend-integration.md
│   │   ├── build.md
│   │   ├── comparisons.md
│   │   ├── dep-pre-bundling.md
│   │   ├── env-and-mode.md
│   │   ├── features.md
│   │   ├── index.md
│   │   ├── migration.md
│   │   ├── ssr.md
│   │   ├── static-deploy.md
│   │   ├── using-plugins.md
│   │   └── why.md
│   ├── images
│   │   ├── bundler.png
│   │   ├── esm.png
│   │   ├── graph.png
│   │   ├── vercel-configuration.png
│   │   └── vite-plugin-inspect.png
│   ├── index.md
│   ├── plugins
│   │   └── index.md
│   └── public
│       ├── _headers
│       ├── cypress.svg
│       ├── divriots.png
│       ├── logo.svg
│       ├── mux.svg
│       ├── plaid.svg
│       ├── stackblitz.svg
│       ├── tailwind-labs.svg
│       ├── vite.mp3
│       ├── voice.svg
│       └── vuejobs.png
├── jest.config.ts
├── netlify.toml
├── package.json
├── packages
│   ├── create-vite
│   │   ├── CHANGELOG.md
│   │   ├── LICENSE
│   │   ├── README.md
│   │   ├── __tests__
│   │   │   └── cli.spec.ts
│   │   ├── index.js
│   │   ├── package.json
│   │   ├── template-lit
│   │   │   ├── _gitignore
│   │   │   ├── index.html
│   │   │   ├── package.json
│   │   │   ├── src
│   │   │   │   ├── favicon.svg
│   │   │   │   └── my-element.js
│   │   │   └── vite.config.js
│   │   ├── template-lit-ts
│   │   │   ├── _gitignore
│   │   │   ├── index.html
│   │   │   ├── package.json
│   │   │   ├── src
│   │   │   │   ├── favicon.svg
│   │   │   │   ├── my-element.ts
│   │   │   │   └── vite-env.d.ts
│   │   │   ├── tsconfig.json
│   │   │   ├── tsconfig.node.json
│   │   │   └── vite.config.ts
│   │   ├── template-preact
│   │   │   ├── _gitignore
│   │   │   ├── index.html
│   │   │   ├── package.json
│   │   │   ├── src
│   │   │   │   ├── app.jsx
│   │   │   │   ├── favicon.svg
│   │   │   │   ├── index.css
│   │   │   │   ├── logo.jsx
│   │   │   │   └── main.jsx
│   │   │   └── vite.config.js
│   │   ├── template-preact-ts
│   │   │   ├── _gitignore
│   │   │   ├── index.html
│   │   │   ├── package.json
│   │   │   ├── src
│   │   │   │   ├── app.tsx
│   │   │   │   ├── favicon.svg
│   │   │   │   ├── index.css
│   │   │   │   ├── logo.tsx
│   │   │   │   ├── main.tsx
│   │   │   │   ├── preact.d.ts
│   │   │   │   └── vite-env.d.ts
│   │   │   ├── tsconfig.json
│   │   │   ├── tsconfig.node.json
│   │   │   └── vite.config.ts
│   │   ├── template-react
│   │   │   ├── _gitignore
│   │   │   ├── index.html
│   │   │   ├── package.json
│   │   │   ├── src
│   │   │   │   ├── App.css
│   │   │   │   ├── App.jsx
│   │   │   │   ├── favicon.svg
│   │   │   │   ├── index.css
│   │   │   │   ├── logo.svg
│   │   │   │   └── main.jsx
│   │   │   └── vite.config.js
│   │   ├── template-react-ts
│   │   │   ├── _gitignore
│   │   │   ├── index.html
│   │   │   ├── package.json
│   │   │   ├── src
│   │   │   │   ├── App.css
│   │   │   │   ├── App.tsx
│   │   │   │   ├── favicon.svg
│   │   │   │   ├── index.css
│   │   │   │   ├── logo.svg
│   │   │   │   ├── main.tsx
│   │   │   │   └── vite-env.d.ts
│   │   │   ├── tsconfig.json
│   │   │   ├── tsconfig.node.json
│   │   │   └── vite.config.ts
│   │   ├── template-svelte
│   │   │   ├── README.md
│   │   │   ├── _gitignore
│   │   │   ├── index.html
│   │   │   ├── jsconfig.json
│   │   │   ├── package.json
│   │   │   ├── public
│   │   │   │   └── favicon.ico
│   │   │   ├── src
│   │   │   │   ├── App.svelte
│   │   │   │   ├── assets
│   │   │   │   │   └── svelte.png
│   │   │   │   ├── lib
│   │   │   │   │   └── Counter.svelte
│   │   │   │   ├── main.js
│   │   │   │   └── vite-env.d.ts
│   │   │   └── vite.config.js
│   │   ├── template-svelte-ts
│   │   │   ├── README.md
│   │   │   ├── _gitignore
│   │   │   ├── index.html
│   │   │   ├── package.json
│   │   │   ├── public
│   │   │   │   └── favicon.ico
│   │   │   ├── src
│   │   │   │   ├── App.svelte
│   │   │   │   ├── assets
│   │   │   │   │   └── svelte.png
│   │   │   │   ├── lib
│   │   │   │   │   └── Counter.svelte
│   │   │   │   ├── main.ts
│   │   │   │   └── vite-env.d.ts
│   │   │   ├── svelte.config.js
│   │   │   ├── tsconfig.json
│   │   │   ├── tsconfig.node.json
│   │   │   └── vite.config.ts
│   │   ├── template-vanilla
│   │   │   ├── _gitignore
│   │   │   ├── favicon.svg
│   │   │   ├── index.html
│   │   │   ├── main.js
│   │   │   ├── package.json
│   │   │   └── style.css
│   │   ├── template-vanilla-ts
│   │   │   ├── _gitignore
│   │   │   ├── favicon.svg
│   │   │   ├── index.html
│   │   │   ├── package.json
│   │   │   ├── src
│   │   │   │   ├── main.ts
│   │   │   │   ├── style.css
│   │   │   │   └── vite-env.d.ts
│   │   │   └── tsconfig.json
│   │   ├── template-vue
│   │   │   ├── README.md
│   │   │   ├── _gitignore
│   │   │   ├── index.html
│   │   │   ├── package.json
│   │   │   ├── public
│   │   │   │   └── favicon.ico
│   │   │   ├── src
│   │   │   │   ├── App.vue
│   │   │   │   ├── assets
│   │   │   │   │   └── logo.png
│   │   │   │   ├── components
│   │   │   │   │   └── HelloWorld.vue
│   │   │   │   └── main.js
│   │   │   └── vite.config.js
│   │   └── template-vue-ts
│   │       ├── README.md
│   │       ├── _gitignore
│   │       ├── index.html
│   │       ├── package.json
│   │       ├── public
│   │       │   └── favicon.ico
│   │       ├── src
│   │       │   ├── App.vue
│   │       │   ├── assets
│   │       │   │   └── logo.png
│   │       │   ├── components
│   │       │   │   └── HelloWorld.vue
│   │       │   ├── env.d.ts
│   │       │   └── main.ts
│   │       ├── tsconfig.json
│   │       ├── tsconfig.node.json
│   │       └── vite.config.ts
│   ├── playground
│   │   ├── alias
│   │   │   ├── __tests__
│   │   │   │   └── alias.spec.ts
│   │   │   ├── customResolver.js
│   │   │   ├── dir
│   │   │   │   ├── from-script-src.js
│   │   │   │   ├── module
│   │   │   │   │   ├── index.js
│   │   │   │   │   └── package.json
│   │   │   │   ├── test.css
│   │   │   │   └── test.js
│   │   │   ├── index.html
│   │   │   ├── package.json
│   │   │   ├── test.js
│   │   │   └── vite.config.js
│   │   ├── assets
│   │   │   ├── __tests__
│   │   │   │   └── assets.spec.ts
│   │   │   ├── css
│   │   │   │   ├── css-url.css
│   │   │   │   ├── fonts.css
│   │   │   │   ├── icons.css
│   │   │   │   ├── import.css
│   │   │   │   └── nested
│   │   │   │       └── at-imported-css-url.css
│   │   │   ├── fonts
│   │   │   │   ├── Inter-Italic.woff
│   │   │   │   └── Inter-Italic.woff2
│   │   │   ├── foo.js
│   │   │   ├── index.html
│   │   │   ├── nested
│   │   │   │   ├── asset.png
│   │   │   │   ├── fragment-bg.svg
│   │   │   │   ├── fragment.svg
│   │   │   │   ├── icon.png
│   │   │   │   └── �\203\206�\202��\203\210-測試-white\ space.png
│   │   │   ├── package.json
│   │   │   ├── static
│   │   │   │   ├── icon.png
│   │   │   │   ├── import-expression.js
│   │   │   │   ├── raw.css
│   │   │   │   └── raw.js
│   │   │   ├── vite.config.js
│   │   │   └── �\203\206�\202��\203\210-測試-white\ space.js
│   │   ├── backend-integration
│   │   │   ├── __tests__
│   │   │   │   └── backend-integration.spec.ts
│   │   │   ├── frontend
│   │   │   │   ├── entrypoints
│   │   │   │   │   ├── global.css
│   │   │   │   │   ├── index.html
│   │   │   │   │   └── main.ts
│   │   │   │   ├── images
│   │   │   │   │   └── logo.png
│   │   │   │   └── styles
│   │   │   │       ├── background.css
│   │   │   │       └── tailwind.css
│   │   │   ├── package.json
│   │   │   ├── postcss.config.js
│   │   │   ├── references.css
│   │   │   ├── tailwind.config.js
│   │   │   └── vite.config.js
│   │   ├── cli
│   │   │   ├── __tests__
│   │   │   │   ├── cli.spec.ts
│   │   │   │   └── serve.js
│   │   │   ├── index.html
│   │   │   ├── index.js
│   │   │   ├── package.json
│   │   │   └── vite.config.js
│   │   ├── cli-module
│   │   │   ├── __tests__
│   │   │   │   ├── cli-module.spec.ts
│   │   │   │   └── serve.js
│   │   │   ├── index.html
│   │   │   ├── index.js
│   │   │   ├── package.json
│   │   │   └── vite.config.js
│   │   ├── css
│   │   │   ├── __tests__
│   │   │   │   └── css.spec.ts
│   │   │   ├── async-treeshaken.css
│   │   │   ├── async-treeshaken.js
│   │   │   ├── async.css
│   │   │   ├── async.js
│   │   │   ├── composed.module.css
│   │   │   ├── composed.module.less
│   │   │   ├── composed.module.scss
│   │   │   ├── composes-path-resolving.module.css
│   │   │   ├── css-dep
│   │   │   │   ├── index.css
│   │   │   │   ├── index.js
│   │   │   │   ├── index.scss
│   │   │   │   ├── index.styl
│   │   │   │   └── package.json
│   │   │   ├── dep.css
│   │   │   ├── glob-dep
│   │   │   │   ├── bar.css
│   │   │   │   └── foo.css
│   │   │   ├── glob-dep.css
│   │   │   ├── imported-at-import.css
│   │   │   ├── imported.css
│   │   │   ├── index.html
│   │   │   ├── inlined.css
│   │   │   ├── less.less
│   │   │   ├── linked-at-import.css
│   │   │   ├── linked.css
│   │   │   ├── main.js
│   │   │   ├── minify.css
│   │   │   ├── mod.module.css
│   │   │   ├── mod.module.scss
│   │   │   ├── nested
│   │   │   │   ├── _index.scss
│   │   │   │   ├── _partial.scss
│   │   │   │   ├── icon.png
│   │   │   │   ├── nested.less
│   │   │   │   └── nested.styl
│   │   │   ├── ok.png
│   │   │   ├── options
│   │   │   │   ├── absolute-import.styl
│   │   │   │   └── relative-import.styl
│   │   │   ├── package.json
│   │   │   ├── pkg-dep
│   │   │   │   ├── _index.scss
│   │   │   │   ├── index.js
│   │   │   │   └── package.json
│   │   │   ├── postcss-caching
│   │   │   │   ├── blue-app
│   │   │   │   │   ├── imported.css
│   │   │   │   │   ├── index.html
│   │   │   │   │   ├── main.js
│   │   │   │   │   ├── package.json
│   │   │   │   │   └── postcss.config.js
│   │   │   │   ├── css.spec.ts
│   │   │   │   └── green-app
│   │   │   │       ├── imported.css
│   │   │   │       ├── index.html
│   │   │   │       ├── main.js
│   │   │   │       ├── package.json
│   │   │   │       └── postcss.config.js
│   │   │   ├── postcss.config.js
│   │   │   ├── sass.scss
│   │   │   ├── stylus.styl
│   │   │   └── vite.config.js
│   │   ├── css-codesplit
│   │   │   ├── __tests__
│   │   │   │   └── css-codesplit.spec.ts
│   │   │   ├── index.html
│   │   │   ├── main.css
│   │   │   ├── main.js
│   │   │   ├── other.js
│   │   │   ├── package.json
│   │   │   ├── style.css
│   │   │   └── vite.config.js
│   │   ├── css-codesplit-cjs
│   │   │   ├── __tests__
│   │   │   │   └── css-codesplit.spec.ts
│   │   │   ├── index.html
│   │   │   ├── main.css
│   │   │   ├── main.js
│   │   │   ├── other.js
│   │   │   ├── package.json
│   │   │   ├── style.css
│   │   │   └── vite.config.js
│   │   ├── data-uri
│   │   │   ├── __tests__
│   │   │   │   └── data-uri.spec.ts
│   │   │   ├── index.html
│   │   │   └── package.json
│   │   ├── define
│   │   │   ├── __tests__
│   │   │   │   └── define.spec.ts
│   │   │   ├── index.html
│   │   │   ├── package.json
│   │   │   └── vite.config.js
│   │   ├── dynamic-import
│   │   │   ├── __tests__
│   │   │   │   └── dynamic-import.spec.ts
│   │   │   ├── css
│   │   │   │   └── index.css
│   │   │   ├── index.html
│   │   │   ├── mxd.js
│   │   │   ├── mxd.json
│   │   │   ├── nested
│   │   │   │   ├── index.js
│   │   │   │   └── shared.js
│   │   │   ├── package.json
│   │   │   ├── qux.js
│   │   │   ├── views
│   │   │   │   ├── bar.js
│   │   │   │   ├── baz.js
│   │   │   │   └── foo.js
│   │   │   └── vite.config.js
│   │   ├── env
│   │   │   ├── __tests__
│   │   │   │   └── env.spec.ts
│   │   │   ├── index.html
│   │   │   ├── package.json
│   │   │   └── vite.config.js
│   │   ├── extensions
│   │   │   ├── __tests__
│   │   │   │   └── extensions.spec.ts
│   │   │   ├── index.html
│   │   │   ├── package.json
│   │   │   └── vite.config.js
│   │   ├── file-delete-restore
│   │   │   ├── App.jsx
│   │   │   ├── Child.jsx
│   │   │   ├── __tests__
│   │   │   │   └── file-delete-restore.spec.ts
│   │   │   ├── index.html
│   │   │   ├── package.json
│   │   │   └── vite.config.js
│   │   ├── fs-serve
│   │   │   ├── __tests__
│   │   │   │   └── fs-serve.spec.ts
│   │   │   ├── entry.js
│   │   │   ├── nested
│   │   │   │   └── foo.js
│   │   │   ├── package.json
│   │   │   ├── root
│   │   │   │   ├── src
│   │   │   │   │   ├── index.html
│   │   │   │   │   └── safe.txt
│   │   │   │   ├── unsafe.txt
│   │   │   │   └── vite.config.js
│   │   │   ├── safe.json
│   │   │   └── unsafe.json
│   │   ├── glob-import
│   │   │   ├── __tests__
│   │   │   │   └── glob-import.spec.ts
│   │   │   ├── dir
│   │   │   │   ├── baz.json
│   │   │   │   ├── foo.js
│   │   │   │   ├── index.js
│   │   │   │   ├── nested
│   │   │   │   │   └── bar.js
│   │   │   │   └── node_modules
│   │   │   │       └── hoge.js
│   │   │   ├── index.html
│   │   │   └── package.json
│   │   ├── hmr
│   │   │   ├── __tests__
│   │   │   │   └── hmr.spec.ts
│   │   │   ├── customFile.js
│   │   │   ├── global.css
│   │   │   ├── hmr.js
│   │   │   ├── hmrDep.js
│   │   │   ├── hmrNestedDep.js
│   │   │   ├── index.html
│   │   │   ├── package.json
│   │   │   ├── unicode-path
│   │   │   │   └── 中�\226\207-�\201��\201��\202\223�\201\224-�\225\234�\200-�\237\214\225�\237\214\226�\237\214\227
│   │   │   │       └── index.html
│   │   │   └── vite.config.js
│   │   ├── html
│   │   │   ├── __tests__
│   │   │   │   └── html.spec.ts
│   │   │   ├── common.css
│   │   │   ├── emptyAttr.html
│   │   │   ├── foo.html
│   │   │   ├── index.html
│   │   │   ├── inline
│   │   │   │   ├── common.js
│   │   │   │   ├── dep1.js
│   │   │   │   ├── dep2.js
│   │   │   │   ├── dep3.js
│   │   │   │   ├── module-graph.dot
│   │   │   │   ├── shared-1.html
│   │   │   │   ├── shared-2.html
│   │   │   │   ├── shared.js
│   │   │   │   ├── unique.html
│   │   │   │   └── unique.js
│   │   │   ├── invalid.html
│   │   │   ├── link.html
│   │   │   ├── main.css
│   │   │   ├── main.js
│   │   │   ├── nested
│   │   │   │   ├── index.html
│   │   │   │   ├── nested.css
│   │   │   │   └── nested.js
│   │   │   ├── noBody.html
│   │   │   ├── noHead.html
│   │   │   ├── package.json
│   │   │   ├── scriptAsync.html
│   │   │   ├── scriptMixed.html
│   │   │   ├── shared.js
│   │   │   ├── unicode-path
│   │   │   │   └── 中�\226\207-�\201��\201��\202\223�\201\224-�\225\234�\200-�\237\214\225�\237\214\226�\237\214\227
│   │   │   │       └── index.html
│   │   │   ├── vite.config.js
│   │   │   └── zeroJS.html
│   │   ├── json
│   │   │   ├── __tests__
│   │   │   │   └── json.spec.ts
│   │   │   ├── index.html
│   │   │   ├── package.json
│   │   │   ├── public
│   │   │   │   └── public.json
│   │   │   └── test.json
│   │   ├── legacy
│   │   │   ├── __tests__
│   │   │   │   ├── legacy.spec.ts
│   │   │   │   └── ssr
│   │   │   │       ├── legacy-ssr.spec.ts
│   │   │   │       └── serve.js
│   │   │   ├── async.js
│   │   │   ├── entry-server.js
│   │   │   ├── immutable-chunk.js
│   │   │   ├── index.html
│   │   │   ├── main.js
│   │   │   ├── package.json
│   │   │   ├── style.css
│   │   │   ├── vite.config-custom-filename.js
│   │   │   └── vite.config.js
│   │   ├── lib
│   │   │   ├── __tests__
│   │   │   │   ├── lib.spec.ts
│   │   │   │   └── serve.js
│   │   │   ├── index.dist.html
│   │   │   ├── index.html
│   │   │   ├── package.json
│   │   │   ├── src
│   │   │   │   ├── main.js
│   │   │   │   ├── main2.js
│   │   │   │   └── message.js
│   │   │   ├── vite.config.js
│   │   │   └── vite.dyimport.config.js
│   │   ├── multiple-entrypoints
│   │   │   ├── __tests__
│   │   │   │   └── multiple-entrypoints.spec.ts
│   │   │   ├── deps.json
│   │   │   ├── dynamic-a.js
│   │   │   ├── dynamic-b.js
│   │   │   ├── entrypoints
│   │   │   │   ├── a0.js
│   │   │   │   ├── a1.js
│   │   │   │   ├── a10.js
│   │   │   │   ├── a11.js
│   │   │   │   ├── a12.js
│   │   │   │   ├── a13.js
│   │   │   │   ├── a14.js
│   │   │   │   ├── a15.js
│   │   │   │   ├── a16.js
│   │   │   │   ├── a17.js
│   │   │   │   ├── a18.js
│   │   │   │   ├── a19.js
│   │   │   │   ├── a2.js
│   │   │   │   ├── a20.js
│   │   │   │   ├── a21.js
│   │   │   │   ├── a22.js
│   │   │   │   ├── a23.js
│   │   │   │   ├── a24.js
│   │   │   │   ├── a3.js
│   │   │   │   ├── a4.js
│   │   │   │   ├── a5.js
│   │   │   │   ├── a6.js
│   │   │   │   ├── a7.js
│   │   │   │   ├── a8.js
│   │   │   │   └── a9.js
│   │   │   ├── index.html
│   │   │   ├── index.js
│   │   │   ├── package.json
│   │   │   ├── reference.js
│   │   │   ├── reference.scss
│   │   │   └── vite.config.js
│   │   ├── nested-deps
│   │   │   ├── __tests__
│   │   │   │   └── nested-deps.spec.ts
│   │   │   ├── index.html
│   │   │   ├── package.json
│   │   │   ├── test-package-a
│   │   │   │   ├── index.js
│   │   │   │   └── package.json
│   │   │   ├── test-package-b
│   │   │   │   ├── index.js
│   │   │   │   ├── node_modules
│   │   │   │   │   └── test-package-a
│   │   │   │   │       ├── index.js
│   │   │   │   │       └── package.json
│   │   │   │   └── package.json
│   │   │   ├── test-package-c
│   │   │   │   ├── index-es.js
│   │   │   │   ├── index.js
│   │   │   │   ├── package.json
│   │   │   │   └── side.js
│   │   │   ├── test-package-d
│   │   │   │   ├── index.js
│   │   │   │   ├── package.json
│   │   │   │   └── test-package-d-nested
│   │   │   │       ├── index.js
│   │   │   │       └── package.json
│   │   │   ├── test-package-e
│   │   │   │   ├── index.js
│   │   │   │   ├── package.json
│   │   │   │   ├── test-package-e-excluded
│   │   │   │   │   ├── index.js
│   │   │   │   │   └── package.json
│   │   │   │   └── test-package-e-included
│   │   │   │       ├── index.js
│   │   │   │       └── package.json
│   │   │   └── vite.config.js
│   │   ├── optimize-deps
│   │   │   ├── __tests__
│   │   │   │   └── optimize-deps.spec.ts
│   │   │   ├── cjs-dynamic.js
│   │   │   ├── cjs.js
│   │   │   ├── dedupe.js
│   │   │   ├── dep-cjs-compiled-from-cjs
│   │   │   │   ├── index.js
│   │   │   │   └── package.json
│   │   │   ├── dep-cjs-compiled-from-esm
│   │   │   │   ├── index.js
│   │   │   │   └── package.json
│   │   │   ├── dep-esbuild-plugin-transform
│   │   │   │   ├── index.js
│   │   │   │   └── package.json
│   │   │   ├── dep-linked
│   │   │   │   ├── index.js
│   │   │   │   └── package.json
│   │   │   ├── dep-linked-include
│   │   │   │   ├── Test.vue
│   │   │   │   ├── foo.js
│   │   │   │   ├── index.mjs
│   │   │   │   ├── package.json
│   │   │   │   └── test.css
│   │   │   ├── glob
│   │   │   │   └── foo.js
│   │   │   ├── index.html
│   │   │   ├── nested-exclude
│   │   │   │   ├── index.js
│   │   │   │   ├── nested-include
│   │   │   │   │   ├── index.js
│   │   │   │   │   └── package.json
│   │   │   │   └── package.json
│   │   │   ├── package.json
│   │   │   └── vite.config.js
│   │   ├── optimize-missing-deps
│   │   │   ├── __test__
│   │   │   │   ├── optimize-missing-deps.spec.ts
│   │   │   │   └── serve.js
│   │   │   ├── index.html
│   │   │   ├── main.js
│   │   │   ├── missing-dep
│   │   │   │   ├── index.js
│   │   │   │   └── package.json
│   │   │   ├── multi-entry-dep
│   │   │   │   ├── index.browser.js
│   │   │   │   ├── index.js
│   │   │   │   └── package.json
│   │   │   ├── package.json
│   │   │   └── server.js
│   │   ├── package.json
│   │   ├── preload
│   │   │   ├── __tests__
│   │   │   │   └── preload.spec.ts
│   │   │   ├── index.html
│   │   │   ├── package.json
│   │   │   ├── router.js
│   │   │   ├── src
│   │   │   │   ├── App.vue
│   │   │   │   └── components
│   │   │   │       ├── About.vue
│   │   │   │       ├── Hello.vue
│   │   │   │       └── Home.vue
│   │   │   └── vite.config.js
│   │   ├── preserve-symlinks
│   │   │   ├── __tests__
│   │   │   │   └── preserve-symlinks.spec.ts
│   │   │   ├── index.html
│   │   │   ├── moduleA
│   │   │   │   ├── linked.js -> ./src/index.js
│   │   │   │   ├── package.json
│   │   │   │   └── src
│   │   │   │       ├── data.js
│   │   │   │       └── index.js
│   │   │   ├── package.json
│   │   │   └── src
│   │   │       └── main.js
│   │   ├── react
│   │   │   ├── App.jsx
│   │   │   ├── __tests__
│   │   │   │   └── react.spec.ts
│   │   │   ├── components
│   │   │   │   └── Dummy.jsx
│   │   │   ├── index.html
│   │   │   ├── package.json
│   │   │   └── vite.config.ts
│   │   ├── react-emotion
│   │   │   ├── App.jsx
│   │   │   ├── __tests__
│   │   │   │   └── react.spec.ts
│   │   │   ├── index.html
│   │   │   ├── package.json
│   │   │   └── vite.config.ts
│   │   ├── resolve
│   │   │   ├── __tests__
│   │   │   │   └── resolve.spec.ts
│   │   │   ├── browser-field
│   │   │   │   ├── multiple.dot.path.js
│   │   │   │   ├── no-ext-index
│   │   │   │   │   └── index.js
│   │   │   │   ├── no-ext.js
│   │   │   │   ├── not-browser.js
│   │   │   │   ├── out
│   │   │   │   │   ├── cjs.node.js
│   │   │   │   │   └── esm.browser.js
│   │   │   │   ├── package.json
│   │   │   │   └── relative.js
│   │   │   ├── config-dep.js
│   │   │   ├── custom-condition
│   │   │   │   ├── index.custom.js
│   │   │   │   ├── index.js
│   │   │   │   └── package.json
│   │   │   ├── custom-ext.es
│   │   │   ├── custom-main-field
│   │   │   │   ├── index.custom.js
│   │   │   │   ├── index.js
│   │   │   │   └── package.json
│   │   │   ├── dir
│   │   │   │   └── index.js
│   │   │   ├── dir-with-ext
│   │   │   │   └── index.js
│   │   │   ├── dir-with-ext.js
│   │   │   │   └── empty
│   │   │   ├── dir.js
│   │   │   ├── exact-extension
│   │   │   │   ├── file.js
│   │   │   │   └── file.js.js
│   │   │   ├── exports-env
│   │   │   │   ├── browser.js
│   │   │   │   ├── browser.mjs
│   │   │   │   ├── browser.prod.mjs
│   │   │   │   ├── fallback.umd.js
│   │   │   │   └── package.json
│   │   │   ├── exports-path
│   │   │   │   ├── cjs.js
│   │   │   │   ├── deep.js
│   │   │   │   ├── dir
│   │   │   │   │   └── dir.js
│   │   │   │   ├── main.js
│   │   │   │   └── package.json
│   │   │   ├── index.html
│   │   │   ├── inline-package
│   │   │   │   ├── inline.js
│   │   │   │   └── package.json
│   │   │   ├── package.json
│   │   │   ├── ts-extension
│   │   │   │   ├── hello.ts
│   │   │   │   └── index.ts
│   │   │   ├── utf8-bom
│   │   │   │   └── main.js
│   │   │   ├── util
│   │   │   │   ├── bar.util.js
│   │   │   │   └── index.js
│   │   │   └── vite.config.js
│   │   ├── resolve-config
│   │   │   ├── __tests__
│   │   │   │   ├── resolve-config.spec.ts
│   │   │   │   └── serve.js
│   │   │   ├── package.json
│   │   │   └── root
│   │   │       ├── index.js
│   │   │       └── vite.config.js
│   │   ├── resolve-linked
│   │   │   ├── dep.js
│   │   │   ├── package.json
│   │   │   └── src
│   │   │       └── index.js
│   │   ├── shims.d.ts
│   │   ├── ssr-deps
│   │   │   ├── __tests__
│   │   │   │   ├── serve.js
│   │   │   │   └── ssr-deps.spec.ts
│   │   │   ├── define-properties-exports
│   │   │   │   ├── index.js
│   │   │   │   └── package.json
│   │   │   ├── define-property-exports
│   │   │   │   ├── index.js
│   │   │   │   └── package.json
│   │   │   ├── forwarded-export
│   │   │   │   ├── index.js
│   │   │   │   └── package.json
│   │   │   ├── index.html
│   │   │   ├── message
│   │   │   ├── object-assigned-exports
│   │   │   │   ├── index.js
│   │   │   │   └── package.json
│   │   │   ├── only-object-assigned-exports
│   │   │   │   ├── index.js
│   │   │   │   └── package.json
│   │   │   ├── package.json
│   │   │   ├── primitive-export
│   │   │   │   ├── index.js
│   │   │   │   └── package.json
│   │   │   ├── read-file-content
│   │   │   │   ├── index.js
│   │   │   │   └── package.json
│   │   │   ├── require-absolute
│   │   │   │   ├── foo.js
│   │   │   │   ├── index.js
│   │   │   │   └── package.json
│   │   │   ├── server.js
│   │   │   ├── src
│   │   │   │   └── app.js
│   │   │   └── ts-transpiled-exports
│   │   │       ├── index.js
│   │   │       └── package.json
│   │   ├── ssr-html
│   │   │   ├── __tests__
│   │   │   │   ├── serve.js
│   │   │   │   └── ssr-html.spec.ts
│   │   │   ├── index.html
│   │   │   ├── package.json
│   │   │   ├── server.js
│   │   │   └── src
│   │   │       └── app.js
│   │   ├── ssr-pug
│   │   │   ├── __tests__
│   │   │   │   ├── serve.js
│   │   │   │   └── ssr-pug.spec.ts
│   │   │   ├── index.pug
│   │   │   ├── package.json
│   │   │   ├── server.js
│   │   │   └── src
│   │   │       └── app.js
│   │   ├── ssr-react
│   │   │   ├── __tests__
│   │   │   │   ├── serve.js
│   │   │   │   └── ssr-react.spec.ts
│   │   │   ├── index.html
│   │   │   ├── package.json
│   │   │   ├── prerender.js
│   │   │   ├── server.js
│   │   │   ├── src
│   │   │   │   ├── App.jsx
│   │   │   │   ├── add.js
│   │   │   │   ├── circular-dep-init
│   │   │   │   │   ├── README.md
│   │   │   │   │   ├── circular-dep-init.js
│   │   │   │   │   ├── module-a.js
│   │   │   │   │   └── module-b.js
│   │   │   │   ├── entry-client.jsx
│   │   │   │   ├── entry-server.jsx
│   │   │   │   ├── forked-deadlock
│   │   │   │   │   ├── README.md
│   │   │   │   │   ├── common-module.js
│   │   │   │   │   ├── deadlock-fuse-module.js
│   │   │   │   │   ├── fuse-stuck-bridge-module.js
│   │   │   │   │   ├── middle-module.js
│   │   │   │   │   └── stuck-module.js
│   │   │   │   ├── multiply.js
│   │   │   │   └── pages
│   │   │   │       ├── About.jsx
│   │   │   │       ├── Env.jsx
│   │   │   │       └── Home.jsx
│   │   │   └── vite.config.js
│   │   ├── ssr-vue
│   │   │   ├── __tests__
│   │   │   │   ├── serve.js
│   │   │   │   └── ssr-vue.spec.ts
│   │   │   ├── dep-import-type
│   │   │   │   ├── deep
│   │   │   │   │   └── index.d.ts
│   │   │   │   └── package.json
│   │   │   ├── example-external-component
│   │   │   │   ├── ExampleExternalComponent.vue
│   │   │   │   ├── index.js
│   │   │   │   └── package.json
│   │   │   ├── index.html
│   │   │   ├── package.json
│   │   │   ├── prerender.js
│   │   │   ├── server.js
│   │   │   ├── src
│   │   │   │   ├── App.vue
│   │   │   │   ├── assets
│   │   │   │   │   ├── button.css
│   │   │   │   │   ├── fonts
│   │   │   │   │   │   ├── Inter-Italic.woff
│   │   │   │   │   │   └── Inter-Italic.woff2
│   │   │   │   │   └── logo.png
│   │   │   │   ├── components
│   │   │   │   │   ├── Foo.jsx
│   │   │   │   │   ├── ImportType.vue
│   │   │   │   │   ├── button.js
│   │   │   │   │   └── foo.css
│   │   │   │   ├── entry-client.js
│   │   │   │   ├── entry-server.js
│   │   │   │   ├── main.js
│   │   │   │   ├── pages
│   │   │   │   │   ├── About.vue
│   │   │   │   │   ├── External.vue
│   │   │   │   │   ├── Home.vue
│   │   │   │   │   └── Store.vue
│   │   │   │   └── router.js
│   │   │   ├── vite.config.js
│   │   │   └── vite.config.noexternal.js
│   │   ├── ssr-webworker
│   │   │   ├── __tests__
│   │   │   │   ├── serve.js
│   │   │   │   └── ssr-webworker.spec.ts
│   │   │   ├── package.json
│   │   │   ├── src
│   │   │   │   └── entry-worker.jsx
│   │   │   ├── vite.config.js
│   │   │   └── worker.js
│   │   ├── tailwind
│   │   │   ├── __test__
│   │   │   │   └── tailwind.spec.ts
│   │   │   ├── index.css
│   │   │   ├── index.html
│   │   │   ├── package.json
│   │   │   ├── postcss.config.js
│   │   │   ├── public
│   │   │   │   └── favicon.ico
│   │   │   ├── src
│   │   │   │   ├── App.vue
│   │   │   │   ├── assets
│   │   │   │   │   └── logo.png
│   │   │   │   ├── components
│   │   │   │   │   └── HelloWorld.vue
│   │   │   │   ├── main.js
│   │   │   │   ├── router.ts
│   │   │   │   └── views
│   │   │   │       └── Page.vue
│   │   │   ├── tailwind.config.js
│   │   │   └── vite.config.ts
│   │   ├── testUtils.ts
│   │   ├── tsconfig-json
│   │   │   ├── __tests__
│   │   │   │   └── tsconfig-json.spec.ts
│   │   │   ├── index.html
│   │   │   ├── nested
│   │   │   │   ├── main.ts
│   │   │   │   ├── not-used-type.ts
│   │   │   │   └── tsconfig.json
│   │   │   ├── nested-with-extends
│   │   │   │   ├── main.ts
│   │   │   │   ├── not-used-type.ts
│   │   │   │   └── tsconfig.json
│   │   │   ├── package.json
│   │   │   ├── src
│   │   │   │   ├── main.ts
│   │   │   │   └── not-used-type.ts
│   │   │   └── tsconfig.json
│   │   ├── tsconfig-json-load-error
│   │   │   ├── __tests__
│   │   │   │   └── tsconfig-json-load-error.spec.ts
│   │   │   ├── has-error
│   │   │   │   ├── main.ts
│   │   │   │   └── tsconfig.json
│   │   │   ├── index.html
│   │   │   ├── package.json
│   │   │   ├── src
│   │   │   │   └── main.ts
│   │   │   └── tsconfig.json
│   │   ├── tsconfig.json
│   │   ├── vue
│   │   │   ├── Assets.vue
│   │   │   ├── AsyncComponent.vue
│   │   │   ├── CssModules.vue
│   │   │   ├── CustomBlock.vue
│   │   │   ├── CustomBlockPlugin.ts
│   │   │   ├── CustomElement.ce.vue
│   │   │   ├── Hmr.vue
│   │   │   ├── Main.vue
│   │   │   ├── Node.vue
│   │   │   ├── PreProcessors.vue
│   │   │   ├── ReactivityTransform.vue
│   │   │   ├── ScanDep.vue
│   │   │   ├── Slotted.vue
│   │   │   ├── Syntax.vue
│   │   │   ├── __tests__
│   │   │   │   └── vue.spec.ts
│   │   │   ├── assets
│   │   │   │   ├── asset.png
│   │   │   │   └── fragment.svg
│   │   │   ├── index.html
│   │   │   ├── package.json
│   │   │   ├── public
│   │   │   │   └── icon.png
│   │   │   ├── setup-import-template
│   │   │   │   ├── SetupImportTemplate.vue
│   │   │   │   └── template.html
│   │   │   ├── src-import
│   │   │   │   ├── SrcImport.vue
│   │   │   │   ├── script.ts
│   │   │   │   ├── srcImportStyle.vue
│   │   │   │   ├── srcImportStyle2.vue
│   │   │   │   ├── style.css
│   │   │   │   ├── style2.css
│   │   │   │   └── template.html
│   │   │   └── vite.config.ts
│   │   ├── vue-jsx
│   │   │   ├── Comp.tsx
│   │   │   ├── Comps.jsx
│   │   │   ├── OtherExt.tesx
│   │   │   ├── Script.vue
│   │   │   ├── SrcImport.jsx
│   │   │   ├── SrcImport.vue
│   │   │   ├── __tests__
│   │   │   │   └── vue-jsx.spec.ts
│   │   │   ├── index.html
│   │   │   ├── main.jsx
│   │   │   ├── package.json
│   │   │   └── vite.config.js
│   │   ├── vue-lib
│   │   │   ├── __tests__
│   │   │   │   ├── serve.js
│   │   │   │   └── vue-lib.spec.ts
│   │   │   ├── index.html
│   │   │   ├── package.json
│   │   │   ├── src-consumer
│   │   │   │   └── index.ts
│   │   │   ├── src-lib
│   │   │   │   ├── CompA.vue
│   │   │   │   ├── CompB.vue
│   │   │   │   └── index.ts
│   │   │   ├── vite.config.consumer.ts
│   │   │   └── vite.config.lib.ts
│   │   ├── wasm
│   │   │   ├── __tests__
│   │   │   │   └── wasm.spec.ts
│   │   │   ├── heavy.wasm
│   │   │   ├── heavy.wasm.map
│   │   │   ├── index.html
│   │   │   ├── light.wasm
│   │   │   └── package.json
│   │   └── worker
│   │       ├── __tests__
│   │       │   └── worker.spec.ts
│   │       ├── index.html
│   │       ├── my-shared-worker.ts
│   │       ├── my-worker.ts
│   │       ├── newUrl
│   │       │   ├── module.js
│   │       │   ├── url-shared-worker.js
│   │       │   └── url-worker.js
│   │       ├── package.json
│   │       ├── possible-ts-output-worker.mjs
│   │       ├── test-plugin.tsx
│   │       ├── vite.config.ts
│   │       └── workerImport.js
│   ├── plugin-legacy
│   │   ├── CHANGELOG.md
│   │   ├── README.md
│   │   ├── index.d.ts
│   │   ├── index.js
│   │   └── package.json
│   ├── plugin-react
│   │   ├── CHANGELOG.md
│   │   ├── LICENSE
│   │   ├── README.md
│   │   ├── api-extractor.json
│   │   ├── package.json
│   │   ├── src
│   │   │   ├── babel.d.ts
│   │   │   ├── fast-refresh.ts
│   │   │   ├── index.ts
│   │   │   └── jsx-runtime
│   │   │       ├── babel-import-to-require.ts
│   │   │       ├── babel-restore-jsx.spec.ts
│   │   │       ├── babel-restore-jsx.ts
│   │   │       └── restore-jsx.ts
│   │   └── tsconfig.json
│   ├── plugin-vue
│   │   ├── CHANGELOG.md
│   │   ├── LICENSE
│   │   ├── README.md
│   │   ├── api-extractor.json
│   │   ├── package.json
│   │   ├── src
│   │   │   ├── compiler.ts
│   │   │   ├── handleHotUpdate.ts
│   │   │   ├── helper.ts
│   │   │   ├── index.ts
│   │   │   ├── main.ts
│   │   │   ├── script.ts
│   │   │   ├── style.ts
│   │   │   ├── template.ts
│   │   │   └── utils
│   │   │       ├── descriptorCache.ts
│   │   │       ├── error.ts
│   │   │       └── query.ts
│   │   └── tsconfig.json
│   ├── plugin-vue-jsx
│   │   ├── CHANGELOG.md
│   │   ├── LICENSE
│   │   ├── README.md
│   │   ├── index.d.ts
│   │   ├── index.js
│   │   └── package.json
│   └── vite
│       ├── CHANGELOG.md
│       ├── LICENSE.md
│       ├── README.md
│       ├── api-extractor.json
│       ├── bin
│       │   ├── openChrome.applescript
│       │   └── vite.js
│       ├── client.d.ts
│       ├── package.json
│       ├── rollup.config.js
│       ├── scripts
│       │   └── patchTypes.ts
│       ├── src
│       │   ├── client
│       │   │   ├── client.ts
│       │   │   ├── env.ts
│       │   │   ├── overlay.ts
│       │   │   └── tsconfig.json
│       │   └── node
│       │       ├── __tests__
│       │       │   ├── asset.spec.ts
│       │       │   ├── build.spec.ts
│       │       │   ├── config.spec.ts
│       │       │   ├── dev.spec.ts
│       │       │   ├── packages
│       │       │   │   ├── name
│       │       │   │   │   └── package.json
│       │       │   │   └── noname
│       │       │   │       └── package.json
│       │       │   ├── plugins
│       │       │   │   ├── css.spec.ts
│       │       │   │   └── import.spec.ts
│       │       │   ├── scan.spec.ts
│       │       │   └── utils.spec.ts
│       │       ├── build.ts
│       │       ├── certificate.ts
│       │       ├── cli.ts
│       │       ├── config.ts
│       │       ├── constants.ts
│       │       ├── http.ts
│       │       ├── importGlob.ts
│       │       ├── index.ts
│       │       ├── logger.ts
│       │       ├── optimizer
│       │       │   ├── esbuildDepPlugin.ts
│       │       │   ├── index.ts
│       │       │   ├── registerMissing.ts
│       │       │   └── scan.ts
│       │       ├── packages.ts
│       │       ├── plugin.ts
│       │       ├── plugins
│       │       │   ├── asset.ts
│       │       │   ├── assetImportMetaUrl.ts
│       │       │   ├── clientInjections.ts
│       │       │   ├── css.ts
│       │       │   ├── dataUri.ts
│       │       │   ├── define.ts
│       │       │   ├── esbuild.ts
│       │       │   ├── html.ts
│       │       │   ├── importAnalysis.ts
│       │       │   ├── importAnalysisBuild.ts
│       │       │   ├── index.ts
│       │       │   ├── json.ts
│       │       │   ├── loadFallback.ts
│       │       │   ├── manifest.ts
│       │       │   ├── modulePreloadPolyfill.ts
│       │       │   ├── preAlias.ts
│       │       │   ├── reporter.ts
│       │       │   ├── resolve.ts
│       │       │   ├── ssrRequireHook.ts
│       │       │   ├── terser.ts
│       │       │   ├── wasm.ts
│       │       │   ├── worker.ts
│       │       │   └── workerImportMetaUrl.ts
│       │       ├── preview.ts
│       │       ├── server
│       │       │   ├── __tests__
│       │       │   │   ├── fixtures
│       │       │   │   │   ├── lerna
│       │       │   │   │   │   ├── lerna.json
│       │       │   │   │   │   └── nested
│       │       │   │   │   │       └── package.json
│       │       │   │   │   ├── none
│       │       │   │   │   │   └── nested
│       │       │   │   │   │       └── package.json
│       │       │   │   │   ├── pnpm
│       │       │   │   │   │   ├── nested
│       │       │   │   │   │   │   └── package.json
│       │       │   │   │   │   ├── package.json
│       │       │   │   │   │   └── pnpm-workspace.yaml
│       │       │   │   │   └── yarn
│       │       │   │   │       ├── nested
│       │       │   │   │       │   └── package.json
│       │       │   │   │       └── package.json
│       │       │   │   ├── pluginContainer.spec.ts
│       │       │   │   └── search-root.spec.ts
│       │       │   ├── 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
│       │       ├── ssr
│       │       │   ├── __tests__
│       │       │   │   └── ssrTransform.spec.ts
│       │       │   ├── ssrExternal.ts
│       │       │   ├── ssrManifestPlugin.ts
│       │       │   ├── ssrModuleLoader.ts
│       │       │   ├── ssrStacktrace.ts
│       │       │   └── ssrTransform.ts
│       │       ├── tsconfig.json
│       │       └── utils.ts
│       ├── tsconfig.base.json
│       └── types
│           ├── alias.d.ts
│           ├── anymatch.d.ts
│           ├── chokidar.d.ts
│           ├── commonjs.d.ts
│           ├── connect.d.ts
│           ├── customEvent.d.ts
│           ├── dynamicImportVars.d.ts
│           ├── hmrPayload.d.ts
│           ├── http-proxy.d.ts
│           ├── importMeta.d.ts
│           ├── package.json
│           ├── shims.d.ts
│           ├── terser.d.ts
│           └── ws.d.ts
├── pnpm-lock.yaml
├── pnpm-workspace.yaml
├── scripts
│   ├── jestEnv.cjs
│   ├── jestGlobalSetup.cjs
│   ├── jestGlobalTeardown.cjs
│   ├── jestPerTestSetup.ts
│   ├── patchEsbuildDist.ts
│   ├── patchFileDeps.ts
│   ├── publishCI.ts
│   ├── release.ts
│   ├── releaseUtils.ts
│   ├── tsconfig.json
│   └── verifyCommit.ts
└── tree.txt

298 directories, 969 files

  • 298 directories, 969 files
  • packages/playground 配下が大きい
    • 215 directories, 628 files を占める
    • 様々な環境でViteを利用するミニマムセットで、全てテストを含んでいる
    • playgroundgrepしてみると、 CONTRIBUTING.md がヒットし、テストに関する記述などが出てくる
    • jestの設定に含まれており、 playwright-chromium 経由で Playwright を起動してブラウザ上でテストが実行される
  • packages/vite がvite本体ぽい
    • 27 directories, 114 files
    • コア部分は意外と小さい

ディレクトリだけ一覧して眺める

ファイル一覧だと Playground 配下が巨大すぎてアレなので、ディレクトリだけで一覧してみる。

  • tree -d
  • playground node_modules は除去

という感じで出力してみた。

.
├── docs
│   ├── blog
│   ├── config
│   ├── guide
│   ├── images
│   ├── plugins
│   └── public
├── packages
│   ├── create-vite
│   │   ├── __tests__
│   │   ├── template-lit
│   │   │   └── src
│   │   ├── template-lit-ts
│   │   │   └── src
│   │   ├── template-preact
│   │   │   └── src
│   │   ├── template-preact-ts
│   │   │   └── src
│   │   ├── template-react
│   │   │   └── src
│   │   ├── template-react-ts
│   │   │   └── src
│   │   ├── template-svelte
│   │   │   ├── public
│   │   │   └── src
│   │   │       ├── assets
│   │   │       └── lib
│   │   ├── template-svelte-ts
│   │   │   ├── public
│   │   │   └── src
│   │   │       ├── assets
│   │   │       └── lib
│   │   ├── template-vanilla
│   │   ├── template-vanilla-ts
│   │   │   └── src
│   │   ├── template-vue
│   │   │   ├── public
│   │   │   └── src
│   │   │       ├── assets
│   │   │       └── components
│   │   └── template-vue-ts
│   │       ├── public
│   │       └── src
│   │           ├── assets
│   │           └── components
│   ├── playground
│   │   └── (※省略)
│   ├── plugin-legacy
│   ├── plugin-react
│   │   ├── dist
│   │   └── src
│   │       └── jsx-runtime
│   ├── plugin-vue
│   │   ├── dist
│   │   └── src
│   │       └── utils
│   ├── plugin-vue-jsx
│   └── vite
│       ├── bin
│       ├── dist
│       │   ├── client
│       │   └── node
│       │       └── chunks
│       ├── scripts
│       ├── src
│       │   ├── client
│       │   └── node
│       │       ├── __tests__
│       │       │   ├── packages
│       │       │   │   ├── name
│       │       │   │   └── noname
│       │       │   └── plugins
│       │       ├── optimizer
│       │       ├── plugins
│       │       ├── server
│       │       │   ├── __tests__
│       │       │   │   └── fixtures
│       │       │   │       ├── lerna
│       │       │   │       │   └── nested
│       │       │   │       ├── none
│       │       │   │       │   └── nested
│       │       │   │       ├── pnpm
│       │       │   │       │   └── nested
│       │       │   │       └── yarn
│       │       │   │           └── nested
│       │       │   └── middlewares
│       │       └── ssr
│       │           └── __tests__
│       └── types
└── scripts
  • そこまで階層が深いわけでもなく、わりとシンプルなディレクトリ構造な印象
  • create-vite vite の2つがコアって感じ

テストを動かしてみる

pnpm i
pnpm test
  • 普通に大量に落ちる。なんでや!
  • Target page, context or browser has been closed
  • https://github.com/vitejs/vite/issues/4543 1回ビルドしないとダメぽい
  • pnpm build 実行 → まだ落ちる

Since Jest will attempt to run tests in parallel, if your machine has many cores this may cause flaky test failures with multiple Playwright instances running at the same time. You can force the tests to run in series with pnpm run test-serve -- --runInBand.

  • らしいので、 pnpm run test-serve -- --runInBand を試したところパスした

とりあえずディレクトリを眺めてテストを通すところまでやった。

最初に全ファイル出力したときは「おおぅ...」となったが、playground系のコードを省いたらわりとなんとかなる気がしてきた。

次→ルートにある各種ファイルを見てみる

サイボウズのフロントエンドエキスパートチームに入った

今月からサイボウズに入社し、フロントエンドエキスパートチームのメンバーになった。

有休消化期間&GWでたっぷり眠る生活を続けていたので社会復帰できるか心配だったが、なんとかなってる。

blog.cybozu.io

よくある感じで数ヶ月は試用期間扱いで、それが終わってからブログに書こうかなと思っていた。ただ、試用期間中所属を隠すとなると、チームの活動内容のひとつに「発信」があるにも関わらず数ヶ月間なにも発信しない気かお前という話になってしまうし、そもそもそんな気持ちで仕事するの良くないよなという考えに至り、書いちゃうことにした。

なぜ

チームの存在は以前から知っていて、特にYouTubeでやってるフロントエンドマンスリーはよく観ていた。

最初は「ほ〜ん、すごい人たちがおるもんやな〜」ぐらいに思ってたのだが、フロントエンドを探究・研鑽しつつレガシーを改善するというテーマにも立ち向かっているのを知り、個人的にも本を出したくらいにはフロントエンドの脱レガシーには思い入れはあったので、なんとなく通ずるものは感じていた。

同時に自分自身は「このままだと良くないなぁ」という漠然とした不安みたいなものがあり、今思えばコンフォートゾーンってものへの危機感だったのかもしれない。

ぼんやりと「一緒に仕事できたら何か少しは役に立てる部分があるかもしれない」「つよいチームなので自分も成長できそう」「とはいえ自分で通用するのかな」とかを考えていたころ、偶然にも元同僚の身内に社員の方がいることを教えてもらい、その方に繋いでもらってカジュアル面談を受けることができた。本当に超絶感謝しています。

カジュアル面談にチームのほぼ全員が現れたのにはビビったが、採用に対してチームで真摯に向き合ってる証拠だと思えたし、実際に話せたことで想像していた以上に魅力に感じた。

そのあとは採用に応募し、なんやかんやあって今にいたる。

なお個人的に5年以上地域RubyコミュニティであるToyama.rbを運営しており、Rubyコミュニティ主催者がRuby書かなくてええんかという話だが、冷静に考えると自分はここ1年ぐらいのもくもく会ではRustとJSしかやってないし、そもそも内容を縛っているコミュニティではない。RubyRailsも今でも好きだから問題ない。問題ない!!!

入ってみてどうか

社風

まずサイボウズという会社の風土にいい意味で驚くことが多い。自由度が高く、現場の裁量がとても大きい。これだけの規模の会社でこれを実現できているのは衝撃を受ける。ここまで辿り着くまでいったいどれだけの血と汗と涙が流れたのだろう..。

ただ、自由であることは同時に各々が考えと責任を持って行動する必要があるため、ぼんやりと決められた仕事をするのを期待していると死ぬことになりそう。

チーム

フロントエンドエキスパートチームについては、予想通り「すごい人たちの集まりやでぇ..!!」となってる。各々が何かしらで特出した領域を持っている印象。そしてみんな良い人。

チームの活動範囲は広く、組織横断的なチームなので関わるプロダクトも多い。そして社風もそうだが、チーム特性上さらに自由度が高く、何らかの目的意識を見つけて自主的に動いていく必要がある。

今のところはまだ特に何も色を出せてない焦りを早くも感じるが、自分は地に足をつけて泥臭い改善作業を時間かけて倒すみたいなところが力を出せる部分だと理解しているので、焦るよりも少し長いスパンで考えて成果に繋げることができたらいいなぁと思う。ひとまずは今までやってきたことを信じて頑張っていきたい。

今後

この機会なので今までやれてなかったことも取り組みたい。OSS活動と英語かなと思う。特に英語は信じられないぐらい貧弱なのでやばい。社内制度使ってレアジョブを始めることにしたので、ちゃんとやるぞ。

ちなみに

すぐにサイボウズに応募しようと決めたわけではなく、数ヶ月間で多くの企業のカジュアル面談を受けた。ご対応頂いた企業様・担当者様ありがとうございました。

あらためて、リモートワーク可能な会社がめっちゃ増えたんだなぁと実感した。

4年半前に転職活動をしたときは、富山からフルリモート可能な会社を探すのは非常に困難だった覚えがある。コロナによる影響だとは思うが、地方在住勢にとっては選択肢が増えるのは人生の幅が広がるのでとてもありがたい。4年半前に同じ転職が可能だったか?と言われると自信はない。

自分への戒めとして、地方に住んでいることを言い訳にすることがないように今後も頑張っていきたい。

おわり。

雑談用Shownoteの作成・共有サービスをつくった

チュートリアルじゃなくて、ちゃんと何か作って試しておかないとな〜という技術がたくさん自分の中で累積していたので、次のようなサービスを作って公開した。

shownotes.vercel.app

概要

雑談・1on1・リモート飲み会・勉強会などで、話したいネタを事前に作成・共有しておき、会話時には再生する形で1つずつネタを提示してくれる。

いまのところShownote自体の作成はGoogleログインを必要としているが、作ったShownoteの閲覧や雑談トピックの追加みたいなところはURLさえ知ってれば誰でもオッケーにしてる。

ログインしたらボタンを押せばShownoteの雛形が作れる。

f:id:mugi1:20210505225118p:plain

Shownote自体には自由に雑談テーマを追加できる。これはURLさえ知ってれば誰でもできるので、一緒に話したい人に事前共有しておける。

f:id:mugi1:20210505225358p:plain

実際に話すときは、追加順 or ランダム再生で、1個ずつトピックを表示してくれる。

f:id:mugi1:20210505225707p:plain

一応一定間隔でPollingしてるので、同じ画面を見ている人では表示が同期されるようになってる。5秒ほど開けてるので、同時に見ると少しラグとかズレがあるのは勘弁してほしい。websocketとか使えば良かったのだが、あんまりそのへんで頑張りたくなかったので雑にApolloClientでPollingとした。

f:id:mugi1:20210505230611g:plain
Pollingでなんとか同期している図

話してる時間をそれっぽく計測しているので、最後に一番盛り上がったトークテーマがどれだったかとかが表示される。

f:id:mugi1:20210505230454p:plain

なお一応公開しているが、使う人がいるかはわからなかったので現状以下の制約がある。

  • PostgreSQLがHerokuのフリープランなので10000レコードでサービスが死ぬ
  • アプリ自体がVercelにデプロイしてるので、DB接続で若干ラグがある

もし使う人がいるようであれば追々解消させる予定だが、誰もいなければ何もしない。

使った技術要素とそれらへの所感

次のようなものを使ってる

3画面しかないのに完全にオーバーキル構成である。 実現機能を考えればどう考えてもFirestoreとか使った方が10000000%良いのは最初からわかっていたが、これは仕事ではないので、そんなことより自分が勉強目的に使ってみたいモチベーションで使いたいものを全部入れた。問題はない。

Next.js

かなり昔のバージョンでチュートリアル的なことはやったことがあったが、改めてちゃんと何かを作ったのは始めてかもしれない。

普段Vueに慣れ親しんでいた身としては、ReactというだけでTS親和性が高くてとても良かった。また、next/image での画像最適化など、痒いところに手が届く感もあり、Vercelを使ったのでデプロイの簡単さも抜群だった。

一応部分的にSSRも採用したが、これは実際にプロダクション導入する場合は慎重に検討すべきところだな〜と改めて感じた。 Next.js側自体の推奨としても、認証が必要なページでのSSRとかはいらないよね??みたいな話もあったりするし、どうしても複雑化するので、サービスとして何を重視するのかとちゃんと向き合うのが最初にすべきことかもしれない

とはいえ、トータルの開発体験としてはとても素晴らしいものだった。新規で何か作るなら積極的に採用するよなぁというのも頷ける。

Prisma

今回このサービスを作った発端のモチベーションは「Prisma使って何か作ってみたい!!!」だったので、強引にPrismaを採用した。簡単に説明すると、Node.jsで動くORMです。

最近まで仕事でRailsを使っていて、今もRailsは好きなのだが、何が好きかというとActiveRecordの操作感に尽きるな〜と思ってる。(色々細かいことやりだすと大変なんだけども)

PrismaでのDB操作はかなりそれに近い感覚があり、prisma.user.findFirst(...) のような形でデータを取得できる。そして何よりも、それらを全てTypeScriptで型安全に操作できるのがとても良い。

また、現在はPrismaにはMigrationの仕組みが備わっていて、全体の主軸となる *.prisma に書かれたスキーマ定義をもとに、変更時には差分をMigrationとして抽出することができる。今回のような趣味レベルで使った範囲では特に困ることもなく動作したし、Migrationファイルの内容もただのALTER文が書かれているだけなので、SQL読める人なら内容も簡単に理解できて、編集しようと思えば編集できる。

全体的にかなり使いやすい印象。今後大きく流行っても全然不思議じゃない。

Nexus

APIはGraphQLにしたが、バックエンドにはNexusを使ってみた。

GraphQLでAPIを構築する際には Schema First か Code First の選択肢があるが、Nexusは Code Firstのフレームワークに該当する。

Schema First と Code First のどちらを良しとするかはサービスの規模感やチームの方針によって変わるため一概には判断できないと思うが、個人的には Code First のほうが全体の記述量が減ることが多いので好み。

ただ、Nexusにしたのは好みだけが理由ではなく、Prismaとの相性が良いのもある。 nexus-plugin-prismaというNexus用のプラグインが存在しており、たとえば「Bookモデルの中身を返すクエリ」を作るときに、Prismaが生成しているモデル情報をもとにレスポンスを定義することができる。

これの何が嬉しいかというと、DBが変わるとそれに伴ってNexusが生成するGraphQLスキーマも変化するので、そこからGraphQL Code Generatorを通せばクライアント側での型不整合なども全部チェックできるようになる。

なお、DBモデルをそのままクエリとして露呈するとか危ないでしょって最初は思ったが、公開するフィールドは明示的に指定したもののみに限定されるため、意図せず公開されるみたいなことは無く、そのあたりも問題なかった。

DB⇄APIサーバー⇄クライアントの全てが型定義で一貫してチェックされるのはとても快適で、DB変更時にクライアント側の変更が漏れたりするようなケースは開発中に一度も無かった。

Redux (Redux Toolkit)

Reduxをちゃんと使ったのは5年くらい前で、とてもツラかったような記憶があったのだが、Hooks対応なども経てとても良くなったと聞いたので試してみた。

結果としてはかなり使いやすくなってた。Redux Toolkitがとても良かった。昔Reduxでストレスに感じてたのは、やりたいことに対して手数があまりにも多すぎる点だったが、そのあたりが綺麗さっぱり解消されてる感覚があった。

これだけ使いやすいなら、下手にオレオレ状態管理するよりかは、何も考えずにとりあえずRedux採用したほうがトータルのコストは下がりそう。

まとめ

チュートリアルだけ過去にやった技術も多かったが、実際に小さいアプリケーションを作ってみることで得られる知見はとても多かった。モノを作って学ぶのは大事だな〜と改めて感じた。

ちなみに、今回のサービスのアイデアとしては「Clubhouseでのアジェンダ共有ができるといいかな〜」というのがあったが、先にClubhouseが瀕死になってしまった。

とはいえ中途半端で終わるのは悲しいので気合いで作り切った。完走するのは大事。

サービスとしては公開しておくので興味があれば使ってみてください。 https://shownotes.vercel.app/

不具合とか機能要望とかあれば @mugi_uno まで。

おわり

退職

退職

正確にはまだ在籍中だが、約4年在籍していたMisoca(→今は合併して弥生株式会社)を2021年4月いっぱいで退職する。4/16が最終出社日だった。

いま思い返すと色々やったなぁという感じ。主にフロントエンドのモダン化に力を注いでいた。とはいえ、バックエンドも日常的に触ってたし、採用に関わらせてもらう機会もあった。貴重な経験を多く積めて、考え方的な部分では今後一生使えるものを学ぶことができたと思う。Misocaで働けて本当によかった。

大変お世話になりました。ありがとうございました。

なぜ

フロントエンドを仕事でやっていて、改めておもしろいな〜と感じるようになり、もっとフロントエンドに浸かれる環境で仕事をしたいと考えたのと同時に、研鑽できるよう、さらにチャレンジできるような環境に身を置きたくなった。また、今までやってきたことが、さらに大きい規模でも通用するのか試してみたい気持ちもある。

そういうわけで、5月からは某社のフロントエンドチームでどっぷりフロントエンドをやっていく予定です。

以前から遠目で見てすごいな〜って思っていた方々と一緒に働くことになるので、 自分がついていけるのか不安になってますが、これまでの経験をもとに頑張りたい。


そういうわけで例のリスト置いておきます。

https://www.amazon.jp/hz/wishlist/ls/29597IU52BIZ6?ref_=wl_share