Chrome拡張のバンドラ周りなんもわからんから解決したいスクラップ
そもそも
https://github.com/Jonghakseo/chrome-extension-boilerplate-react-vite のテンプレートをもとに作ってる
目的
chrome.scripting で特定のページで実行する関数orファイルを作るとき、その関数外に宣言されているものを import したりしていると存在していないとなっちゃうので、特定の関数orファイルに関連のものをまとめる(バンドル?)する必要がある。引数を渡したいから関数のほうがいいかな?
なんもわからん技術
この何もわからんやつを理解して目的を達成する方法を知る
- turbo: build のとき使ってそう、モノレポまわりこいつがやってそう
- esbuild:
page/
じゃない共有ディレクトリのビルドの設定が書かれてるんだけどどこから実行されてるの - vite:
page/
下のそれぞれ一つのファイルに吐き出されるやつビルドしてる - rollup: vite がラップしてるバンドラ?的な?
turbo
(おそらく)turborepo というものを使ってるみたい、 turbo には turborepo と turbopack(beta) がある
モノレポをやってるというのあってそう
使い方?
このページに書いて有りそう
vite
何度も公式ドキュメント読んでるしなんどもわからないと言っている。
これは /pages
以下のビルドで使われていて、 root の dist/
に置く単一のファイルにバンドルするために使われている。(例: background.js
popup.js
)
- 基本ライブラリモードを使っている
- 設定は各パッケージの
vite.config.mts
rollup
vite のバンドルの設定を細かくするときに rollupOptions
から触るやつ。
だいたいは vite がやってくれるからやりたいことが出てきたら覚えれば良さそう。
esbuild
これもビルドツールらしい
rollup と比較してるけど早いらしい
Major features:
- Extreme speed without needing a cache
- JavaScript, CSS, TypeScript, and JSX built-in
- A straightforward API for CLI, JS, and Go
- Bundles ESM and CommonJS modules
- Bundles CSS including CSS modules
- Tree shaking, minification, and source maps
- Local server, watch mode, and plugins
え、Go って golang ?
使い方
./node_modules/.bin/esbuild app.jsx --bundle --outfile=out.js
で node_modules にも依存しない自己完結した js ファイルが出力される。すごい。
// package.json に登録する場合
{
"scripts": {
"build": "esbuild app.jsx --bundle --outfile=out.js"
}
}
これを↓と書くこともできる。
// build.mjs
import * as esbuild from 'esbuild'
await esbuild.build({
entryPoints: ['app.jsx'],
bundle: true,
outfile: 'out.js',
})
これは package.json に script.build: "node build.mjs"
とでも登録すれば実行できるらしい。
今やりたいこと
- Chrome拡張の
chrome.scripting
にて関数orファイルを差し込むためのパッケージの実装をする - 実行時に指定したもの以外指定したページで呼び込まれないため、関数orファイルは外部依存せずバンドルされている必要がある。
- 関数は、他の vite でバンドルされているパッケージから実行時に呼ばれる
一旦こんなかんじで↓
- packages
- content-script
- package.json
- esbuild.mjs
- dist/
- src/
- shared/
- checks/
呼び出すがわからはこれで使うイメージ
// この @extension ってどこに書かれてる?
import { getImages } from '@extension/content-script/shared'
import { checkAlt } from '@extension/content-script/check/'
// content-script/package.json
{
"exports": {
"./shared": "./dist/shared/index.js",
"./checks": "./dist/checks/index.js"
}
}
とかければ良さそうなので、 src 下のファイルが dist/checks/index.js
にバンドルされてればいい?
import esbuild from 'esbuild';
/**
* @type { import('esbuild').BuildOptions }
*/
const buildOptions = {
entryPoints: ['./src/shared/index.js', './src/checks/index.ts'],
tsconfig: './tsconfig.json',
bundle: true,
target: 'es6',
outdir: './dist',
sourcemap: true,
};
await esbuild.build(buildOptions);
一旦これでできるか試してみます
出力されたファイルは即時関数になってて、外から import できなくなってる。
// dist/checks/index.ts
"use strict";
(() => {
// src/shared/getImages.ts
var getImages = () => {
console.log("getImages");
};
// src/checks/checkHoge.ts
var checkHoge = () => {
const h = "hoge huga";
console.log(h);
getImages();
};
})();
//# sourceMappingURL=index.js.map
-> build.mjs
にて、 buildOptios に format: 'esm'
で解決
// src/shared/getImages.ts
var getImages = () => {
console.log("getImages");
};
// src/checks/checkHoge.ts
var checkHoge = () => {
const h = "hoge huga";
console.log(h);
getImages();
};
export {
checkHoge
};
//# sourceMappingURL=index.js.map
package.json
の exports にパスを各方法はまだ vscode が対応していなくて、ビルドは通るがエラーが出る状態になっている。そのため変更する
モジュール '@extension/content-scripts/checks' またはそれに対応する型宣言が見つかりません。ts(2307)
import 側の tsconfig.json の paths に各方法を試したが解決できない
むむむ、
dist/checks/index.js
と dist/shared/index.js
にバンドルされるようにはなったが、 chrome.scripting
は関数かファイルのみで、ファイルは引数を渡せない。
関数にすると、こういうのは getImages がなくてエラーになっている。
// libs/shared/getImages.ts
var getImages = () => {
console.log("getImages");
};
// libs/checks/checkHoge.ts
var checkHoge = () => {
const h = "hoge huga";
console.log(h);
getImages();
};
export {
checkHoge
};
//# sourceMappingURL=index.js.map
(() => {
const h = "hoge huga";
console.log(h);
getImages();
})()
関数は無理そう。。。ファイルしかない
考え直してファイルでインポートする形にシテク。
作戦
- root/ にファイルを出力する。 この場合は
content-script/checks/checksHoge.js
? - 引数で渡したいものは storage にいれる。chrome.storage は使えそうだった。
できた!設定書く
- dist
- packages
- content-script
- ibs
- checks
- checkHoge.ts
こういった配置で、content-script に書いたファイルはファイルごとにバンドルされて dist 下に置かれるようにした。
// /packages/content-script/esbuid.mjd
import esbuild from 'esbuild';
/**
* @type { import('esbuild').BuildOptions }
*/
const buildOptions = {
entryPoints: ['./libs/**/*.ts'],
tsconfig: './tsconfig.json',
bundle: true,
target: 'es6',
outdir: './../../dist',
sourcemap: true,
};
await esbuild.build(buildOptions);
// /packages/content-script/tsconfig.json
{
"extends": "@extension/tsconfig/utils",
"compilerOptions": {
"baseUrl": ".",
"outDir": "./../../dist",
"types": ["chrome"]
},
"include": ["libs"]
}
これで拡張機能のページ内で以下のように呼び出せる。
await chrome.scripting
.executeScript({
target: { tabId: pageInfo.tabId },
files: ['/checks/checkHoge.js'],
})
.catch(err => {
console.error(err);
});
今の設定だとHRが効かないので見てみる!
Hot-reloading for JavaScript is not currently implemented by esbuild. It's possible to transparently implement hot-reloading for CSS because CSS is stateless, but JavaScript is stateful so you cannot transparently implement hot-reloading for JavaScript like you can for CSS.
え。。。。?