Re: ブラウザの中でスタンド使いになってみた。
はじめに
今年もこの季節がやってきて年末だと改めて感じますが皆様いかがお過ごしでしょうか?
今回はクソアプリアドベントカレンダーに参加するにあたり昔作ったChrome拡張に急遽、季節感を出す拡張テーマ機能を追加し、よりキータイプを阻害するwアプリに仕上げました。
そもそもどんな拡張よ?という方はこちらの過去記事をどうぞ。
少しでもご興味ある方是非インストール&アンスト。(正直鬱陶しいです)
何を変更したのか
仕組みは単純で現在日が設定ファイルに記載された日付範囲なら対象のテーマファイルをimportする、というものです。
随時季節によってテーマを追加できるようにしてあります。
クリスマスなので雪のエフェクトが入ります。
エフェクトはsvgにアニメーションをつけて対応しています。
この辺はサラッと流します。
const tags = `
<svg id="svg-out-jojo" width="100%" height="100vh">
<radialGradient id="tama" cx="60%" cy="40%" r="80%">
<stop offset="0" style="stop-color:#fff"/>
<stop offset="0.5" style="stop-color:#eee"/>
</radialGradient>
<symbol id="jojo-symbol">
<circle cx="30%" cy="10%" r="10" fill="url(#tama)"/>
</symbol>
<use id="snow" href="#jojo-symbol"/>
</svg>
`;
$("body").prepend(tags);
$("#svg-out-jojo").css({
display: "block",
position: "fixed",
overflow: "visible",
"z-index": 1000000,
"pointer-events": "none",
});
$("#snow").css({
animation: "snow 4s linear forwards",
filter: "blur(3px)",
});
$.keyframe.define([
{
name: "snow",
from: { transform: "translateY(-20vh)" },
to: { transform: "translateY(120vh)" },
},
]);
const svgOutJojo = $("#svg-out-jojo");
const snow = $("#snow");
let count = 0;
const reproduction = () => {
let clone = snow.clone(true);
clone.on("animationend", function () {
clone.remove();
});
let iti = String(Math.random() * 200 - 100) + "%";
clone.attr("x", iti);
svgOutJojo.append(clone);
count++;
};
setInterval(function () {
reproduction();
}, 150);
今回の変更で対応したこと
manifest_versionをV2 -> V3に
V2は段階的に廃止予定とのことなのでこのタイミングでV3に変更。
V3に変更するにあたって、manifest.jsonのweb_accessible_resources
の書き方が若干変わっていたので変更。
- "web_accessible_resources": [
- "images/*"
- ],
+ "web_accessible_resources": [{
+ "resources": [
+ "images/*"
+ ],
+ "matches" : ["<all_urls>"]
+ }],
リソースはresources
キーとして指定、また対象のマッチするURLをmatches
として指定する必要がありました。
テーマ用の設定ファイルはmoduleモードで読み込み
import、export構文を使いたかったのでいつものようにファイル冒頭に
import config from "./config.js";
const resolveDate = async () => {
const today = new Date();
const match = config.seasons.find((season) => {
const from = new Date(season.from);
const to = new Date(season.to);
return today >= from && today <= to;
});
return match.file || false;
};
を記述したかったのですが、モジュールモードではないため以下のようなエラーが発生してしまいます。
いつもはバンドルツールありきなのでめんどくせー。
Uncaught SyntaxError: Cannot use import statement outside a module
なので動的インポートを使用します。
const resolveDate = async () => {
const config = await import("./config.js");
const today = new Date();
const match = config.seasons.find((season) => {
const from = new Date(season.from);
const to = new Date(season.to);
return today >= from && today <= to;
});
return match.file || false;
};
<details><summary>抜粋だとわかりずらいかと思うのでテーマ関連の全処理を書いておきます。</summary>
export const seasons = [
{
from: "2022-12-01",
to: "2022-12-25",
file: "christmas",
},
];
/**
* 現在日付から設定済みのテーマファイル名を取得する
* @returns
*/
const resolveDate = async () => {
const config = await import("./config.js");
const today = new Date();
const match = config.seasons.find((season) => {
const from = new Date(season.from);
const to = new Date(season.to);
return today >= from && today <= to;
});
return match.file || false;
};
/**
* 拡張テーマのrenderを実行
* @returns
*/
const matchMedhods = async () => {
const matchFile = await resolveDate();
if (matchFile) {
const method = await import(`./apps/${matchFile}.js`);
return method.render();
} else {
return false;
}
};
/**
* 拡張テーマ関数は必ずrenderという命名にすること
*/
export const render = () => {
const tags = `
<svg id="svg-out-jojo" width="100%" height="100vh">
<radialGradient id="tama" cx="60%" cy="40%" r="80%">
<stop offset="0" style="stop-color:#fff"/>
<stop offset="0.5" style="stop-color:#eee"/>
</radialGradient>
<symbol id="jojo-symbol">
<circle cx="30%" cy="10%" r="10" fill="url(#tama)"/>
</symbol>
<use id="snow" href="#jojo-symbol"/>
</svg>
`;
$("body").prepend(tags);
$("#svg-out-jojo").css({
display: "block",
position: "fixed",
overflow: "visible",
"z-index": 1000000,
"pointer-events": "none",
});
$("#snow").css({
animation: "snow 4s linear forwards",
filter: "blur(3px)",
});
$.keyframe.define([
{
name: "snow",
from: { transform: "translateY(-20vh)" },
to: { transform: "translateY(120vh)" },
},
]);
const svgOutJojo = $("#svg-out-jojo");
const snow = $("#snow");
let count = 0;
const reproduction = () => {
let clone = snow.clone(true);
clone.on("animationend", function () {
clone.remove();
});
let iti = String(Math.random() * 200 - 100) + "%";
clone.attr("x", iti);
svgOutJojo.append(clone);
count++;
};
setInterval(function () {
reproduction();
}, 150);
};
// 拡張テーマの読み込み
document.onready = async () => {
await matchMedhods();
};
...
</details>
manifest.jsonの変更
extensionMethods.jsのmatchMedhods
を外部ファイルから実行するためにcontent_scripts
とweb_accessible_resources.resources
にファイルを指定します。
{
"manifest_version": 3,
"name": "Jojo experience",
"version": "1.1.0",
"description": "スタンド使いになれるChrome Extensionです",
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": [
"jquery.min.js",
"soundEffect.mjs",
"caretposition.js",
+ "extensions/extensionMethods.js"
]
}
],
"web_accessible_resources": [{
"resources": [
"images/*",
+ "extensions/*"
],
"matches" : ["<all_urls>"]
}],
"permissions": [
"storage"
]
}
Github Actionsでstoreへ自動アップロード
手作業でアプリをアップロードするのも面倒なので、アップロード、app storeへの申請をGithub Actionsで行うよう設定しました。
name: Publish
# リリースを公開したタイミングで発火
# https://docs.github.com/ja/actions/using-workflows/events-that-trigger-workflows#release
on:
release:
types: [published]
jobs:
release-actions:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 16
- name: Archive
run: |
# アプリ公開の際にはzipでアップロードする必要があるので圧縮
zip -r extension.zip ./ -x "*.git*"
- name: Publish
run: |
yarn global add chrome-webstore-upload-cli
npx chrome-webstore-upload-cli@2 upload --source extension.zip --auto-publish
env:
EXTENSION_ID: ${{ secrets.EXTENSION_ID }}
CLIENT_ID: ${{ secrets.CLIENT_ID }}
CLIENT_SECRET: ${{ secrets.CLIENT_SECRET }}
REFRESH_TOKEN: ${{ secrets.REFRESH_TOKEN }}
以下のnpmパッケージでアプリUPと申請を自動化しています。
- アプリのID(EXTENSION_ID)
- GCPでclientIDを発行(CLIENT_ID)
- 同じくsercretを発行(CLIENT_SECRET)
- refresh token(REFRESH_TOKEN)
が別途必要になるので、Githubのsercretsに設定します。
sercretやclient idなどの発行手順はパッケージのREADMEに記載があります。
いざデプロイ
早速Githubのreleasesを公開してworkflowを回してみます。
あるぇー?
Googleアカウントの2要素認証を有効にしろ的なメッセージが。。
2要素認証を有効にして再度トライ。
今度は連絡先メールアドレスを追加しないとだめっぽいので追加して再度トライ。
またまたダメだったのでdevconsoleを確認、公開までにクリアしないことが多々あったため(プライバシーへの取り組みの入力など)、諸々対応してもう一度回す。
無事成功しました🎉🎉🎉
これでGoogleの審査が通れば晴れて公開となります。
最後に
何かしら邪魔が入った方が燃える、など特殊な性癖の方にはもってこいの拡張だと思うので気が向いたら追加してみてください。
Discussion