【CRSJS 】vite5でcontent_scriptsを書くとエラーになったので調べてみた

# CRSJSとは？
「CRSJS」はviteのプラグインで、クロームの拡張機能を作るときにいい感じに環境を整えてくれる！（らしい！）
こちらの記事が非常にわかりやすかったです。
https://zenn.dev/7oh/scraps/98d5cdcceb9bd8

# 環境(抜粋）

```json
{
    "typescript": "^5.2.2",
    "vite": "^5.0.8",
    "@crxjs/vite-plugin": "^2.0.0-beta.21",
(後略)

```


# content_scriptsを追記すると、build時にエラー

が、manifest.jsonにcontent_scriptsを書き、buildした時点でエラーとなったので原因を探りました。

# manifest.jsonの中身
※viteでは、vite.config.jsにmanifestの内容をtypescriptで書くことができます。

```vite.config.js

import { crx, defineManifest } from "@crxjs/vite-plugin";
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'

const manifest = defineManifest({
	manifest_version: 3,
	name: "web_memo",
	version: "1.0.0",
	content_scripts:[
		{
			matches: ['http://*/*', 'https://*/*', 'file:///*'],
			js:["src/content_scripts.js"],
		},
	],
	action: {
		default_popup: "src/popup/popup.html",
	},
});

// https://vitejs.dev/config/
export default defineConfig({
	plugins: [
		react(),crx({manifest})
	],
})


```

# エラーの内容

```js
[crx:web-accessible-resources] TypeError: OutputBundle["manifest.json"] is undefined.
    at parseJsonAsset (file:///Users/xxxxx/Desktop/hoge/node_modules/@crxjs/vite-plugin/dist/index.mjs:105:11)
    at Object.renderCrxManifest (file:///Users/xxxxx/Desktop/hoge/node_modules/@crxjs/vite-plugin/dist/index.mjs:1887:32)
    at Object.generateBundle (file:///Users/xxxxx/Desktop/hoge/node_modules/@crxjs/vite-plugin/dist/index.mjs:1670:60)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async Bundle.generate (file:///Users/xxxxx/Desktop/hoge/node_modules/vite/node_modules/rollup/dist/es/shared/node-entry.js:17006:9)
    at async file:///Users/xxxxx/Desktop/hoge/node_modules/vite/node_modules/rollup/dist/es/shared/node-entry.js:19552:27
    at async catchUnfinishedHookActions (file:///Users/xxxxx/Desktop/hoge/node_modules/vite/node_modules/rollup/dist/es/shared/node-entry.js:18983:16)
    at async build (file:///Users/xxxxx/Desktop/hoge/node_modules/vite/dist/node/chunks/dep-R0I0XnyH.js:66815:22)
    at async CAC.<anonymous> (file:///Users/xxxxx/Desktop/hoge/node_modules/vite/dist/node/cli.js:845:9)
[crx:manifest-post] Error in crx:web-accessible-resources.renderCrxManifest
✓ built in 458ms
error during build:
Error: Error in crx:web-accessible-resources.renderCrxManifest
    at Object.generateBundle (file:///Users/xxxxx/Desktop/hoge/node_modules/@crxjs/vite-plugin/dist/index.mjs:1683:19)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async Bundle.generate (file:///Users/xxxxx/Desktop/hoge/node_modules/vite/node_modules/rollup/dist/es/shared/node-entry.js:17006:9)
    at async file:///Users/xxxxx/Desktop/hoge/node_modules/vite/node_modules/rollup/dist/es/shared/node-entry.js:19552:27
    at async catchUnfinishedHookActions (file:///Users/xxxxx/Desktop/hoge/node_modules/vite/node_modules/rollup/dist/es/shared/node-entry.js:18983:16)
    at async build (file:///Users/xxxxx/Desktop/hoge/node_modules/vite/dist/node/chunks/dep-R0I0XnyH.js:66815:22)
    at async CAC.<anonymous> (file:///Users/xxxxx/Desktop/hoge/node_modules/vite/dist/node/cli.js:845:9)
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

```
xxxxのとこはユーザー名です。プロジェクト名はhogeです。

# 対処方法
ひとまずエラーのうち、「TypeError: OutputBundle["manifest.json"] is undefined.」でググると以下の記事がhitしました。
https://github.com/crxjs/chrome-extension-tools/issues/836
割と最近issueとして上がっています。

で、どうすればいいか？というと、
node_modules/@crxjs/vite-plugin/dist/index.mjs
上記のファイルの、
```jsx
const asset = bundle[key];
```
を、以下に書き換えます。
```jsx
const asset = bundle[key] || bundle[`.vite/${key}`];
```

するとbuildでのエラーは発生せず、無事完了しました！

# 原因
これだけだとさっぱり原因がわからないのできちんとissue、コードを読み込んでみました。

### ヒント1：issueにあるコメント

>Stumbled on this today with Vite 5: they introduced a .vite directory where the manifest.json file is stored. They have a section about that in the migration docs for v5: https://vitejs.dev/guide/migration#manifest-files-are-now-generated-in-vite-directory-by-default

vite5では、manifest.jsonが.vite directoryの中に保存されているように変わったっぽい。。
これによりこの事象が起きている。というコメントです。
なんでだろう？


### ヒント2: エラーメッセージを読みんさい
build中のエラーはメッセージでググると解決に至ることが多いので、つい慣れずに読むのを飛ばしてしまいました。
ちゃんと2行目にヒントがあります。

```js
at parseJsonAsset (file:///Users/xxxxx/Desktop/hoge/node_modules/@crxjs/vite-plugin/dist/index.mjs:105:11)

```
index.mjsの105行目あたり、parseJsonAssetでエラーが出ていると。
該当の関数です。

```js
function parseJsonAsset(bundle, key) {
  const asset = bundle[key]
  if (typeof asset === "undefined")
    throw new TypeError(`OutputBundle["${key}"] is undefined.`);
  if (asset.type !== "asset")
    throw new Error(`OutputBundle["${key}"] is not an OutputAsset.`);
  if (typeof asset.source !== "string")
    throw new TypeError(`OutputBundle["${key}"].source is not a string.`);
  return JSON.parse(asset.source);
}
```
で、気づいたのですが、
エラーの一行目。「throw new TypeError(`OutputBundle["${key}"] is undefined.`);」で投げられていますね。
つまり、  if (typeof asset === "undefined")　に入っていると言うことです。

### ヒント3
ではここでparseJsonAssetを使っているところを見てみます。
検索すると。。定義とは別にhitしたのは1箇所だけ。1箇所でだけ使われているのでした。
同じファイルの以下の部分です。

```js
if (contentScripts.size > 0) {
	const viteManifest = parseJsonAsset(
	bundle,
	"manifest.json"
);
(後略)
```
contentScriptsがあるときにこの関数が実行されるようです。
なんとなくゴールが近くなってきた気がしますね。


### 取り急ぎの結論
この関数はbudleの中のkeyを取得して動作してます。keyはヒント3のコードにあるように"manifest.json"ですね。
つまりconst assets = bundle["manifest.json"]ということになります。
が、bundleをconsole.logを仕込んでからbuildしてみると、確かに["manifest.json"]がありません。
代わりに、.vite/manifest.jsonはありました！

console.logで出したやつ
![hint3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/287983/c9260248-7e12-6b30-fe17-3112f92f4243.png)


ここの部分が、ヒント1で書いた「vite5でmanifest.jsonの位置が.vite配下に変わった」ことががエラーの原因になる、ということになります。
つまり

bundle["manifest.json"]
はないけど、
bundle[".vite/manifest.json"]
はあるので、「対処方法」に書いた内容で解消した、という状態でした。


## まとめ
エラーで検索するのも大事ですが、エラーを読んでいくのも大事だなと改めて実感しました。
プラグインとかライブラリの中まで読んで、理解できていくと楽しいですね！（ほんの一部だけですが！）