Chrome拡張機能 AmazingSearcher メモ 2021/03/10 ~
概要
↑のスクラップが長くなってメモが探しづらくなるのを防ぐため閉じたので、その続き。
Chrome拡張機能「AmazingSearcher」を作成中に得られた知見を記事にするためのまとめ。
Vue3でのv-modelについて
prop
: value
-> modelValue
event
: input
-> update:modelValue
のように2から3へ変更されている。もっと早くに気づけばよかった。
進捗報告 2021/03/14
オプションページのだいたいの表示が完成。
↓購読するリストの管理
↓自分で追加したレシピの管理
↓購読するリストのレシピや自分で追加したレシピのトグル
ソートとかURLをリンク化したり、URLの表示文字数の制限は後でやる。
拡張機能で画像が急に読み込まれなくなった
拡張機能のオプションページでは普通に表示されるが、web_accessible_resources
の設定を要する部分が表示されなくなった。web_accessible_resources
リストの各要素に設定するmatches
を["<all_urls>"]
にすれば治った。もともとは[]
じゃないと動かなかったけど変わったっぽい。ちゃんとした資料が見つけられなくて残念。
"web_accessible_resources": [{
"resources": ["imgs/*"],
- "matches": []
+ "matches": ["<all_urls>"]
}]
SVGはやっぱり画像ではなくコンポーネントとして読み込むことにした。
非同期のデータをVue3で表示
getRecipes()
をawait→setup()
にasyncつける→子コンポーネントにして、親コンポーネントからSuspense
を使って読み込む
...
<script>
import { getRecipes } from "@/composables/getOfficialInfo.js";
export default {
async setup() {
const hoge= await getRecipes();
return { hoge};
},
};
</script>
<template>
<div>
<Suspense>
<template #default>
<MyRecipes />
</template>
<template #fallback> Loading... </template>
</Suspense>
</div>
</template>
<script>
import MyRecipes from "@/components/MyRecipes.vue";
export default {
components: {
MyRecipes,
},
};
</script>
参考
chrome.storage.local.setに配列を保存&取り出し
chrome.storage.local.set({ key: array });
で配列を保存しても、chrome.storage.local.get(key、(hoge)=>{fuga});
するときには配列ではなくObjectとして取り出されてしまう。
保存する値はJSON化できる必要があるので、JSON.stringify(array)
やJSON.parse(data)
を使う必要がある。
最初Vueでの値の受け渡しが悪いのかと思ってめちゃくちゃ時間食ったので一安心。卒研のこともあるので早く完成させたい。
進捗報告 2021/04/17
- Recipe lists タブのテーブルで、リストごとにオンオフする機能の実装はしないことにした。これはオフにするのであれば、そのリストを削除し、また必要になったときに再登録をすれば良いと思ったから
- Recipe lists タブのテーブルで、リストごとにそのリストの登録を削除する機能を追加
- Recipe lists でレシピリスト登録時に、リストの中にあるレシピをchromeのstorageに登録する関数を追加。登録前にチェックも入れる
テーブルの表示幅は固定のほうが良さそう。
進捗報告 2021/04/19
- テーブルと入力欄を分けて表示
-
table-fixed
を適用- widthを指定
- name列とURL列に
truncate
を適用
進捗報告2021/04/26
- URL欄の文字列に色をつけて、リンク化
- Recipe listsで登録されたレシピリストのURLからレシピをchrome.storage.local.setで登録
- サンプルではなく、登録されているレシピを表示
当初思っていたものに近くなってきた!
TailwindCSSのボタン参考
進捗報告2021/05/04
引き続きオプションページ周り。
- URLからレシピを読み込む機能を削除
- それに伴いタブを一新
- Recipe lists, Custom recipes, Toggle Recipes を削除
- 既存のレシピをテーブル表示
- 入力欄の作成(入力機能は未実装)
- レシピの削除機能の実装
- レシピのリセット機能の実装
- リセットボタンは一番下にした
- リセットボタンを押すとデフォルトのレシピのみ登録されている状態になる
最初からいろいろやろうとするんじゃなくて、まずは最低限必要なところだけ完成させるべきだったなぁ。
進捗報告2021/05/07
- レシピ追加機能の実装
- リセット、レシピ追加、レシピ削除時に動作完了メッセージを表示
- レシピ追加前にチェック機能
- チェック機能の実装
- 無効な入力であればエラーとしてメッセージを表示
進捗報告2021/05/09
- (前回か前々回の下記忘れ)デフォルトデータの保存はjsonではなくcsvファイルに変更
- URLから読み込むのではなく実際に登録しているデータを検索結果に表示
- 別リポジトリに保存していたjsonに意味がなくなったのでそのレポジトリをアーカイブした
これで必要最低限の機能は揃った。あとはブラッシュアップ。その前に卒研の進捗
データをCSVファイルとしてダウンロードする
流れは以下
- 先頭行の文字列を変数に代入
- データから
,
と\n
で区切った文字列を変数に結合 -
Blob
の作成 window.URL.createObjectURL
- aタグを作り
href
にリンク、download
にファイル名を設定 - クリック発火
- ObjectURLの削除
コード
function hoge(){
let csvStr = '"target","lang","keyword","kind","url"\n';
csvStr += recipes.value
.map((recipe) => {
return (
'"' +
recipe.target +
'","' +
recipe.lang +
'","' +
recipe.keyword +
'","' +
recipe.kind +
'","' +
recipe.url +
'"'
);
})
.join("\n");
const blob = new Blob([csvStr], { type: "text/csv" });
const dlURL = window.URL.createObjectURL(blob);
const aTagDl = document.createElement("a");
aTagDl.href = dlURL;
aTagDl.download = "amazing-searcher-recipes.csv";
aTagDl.click();
window.URL.revokeObjectURL(dlURL);
}
参考
進捗報告2021/05/17
- 検索結果
- 期間絞り込みリンクを表示
- 言語絞り込みリンクを表示
- オプションページ
- 登録レシピのインポート機能を実装
- 登録レシピのエクスポート機能を実装
- 検索で表示する絞り込み期間について以下を実装
- 一覧を期間が短い順に表示
- 登録
- リセット
- インポート
- エクスポート
レシピや絞り込み期間のように絞り込み言語も実装し、オプションページは表示区切るかタブ表示に変えたい
進捗報告2021/05/20
- 設定を
Term
,Lang
,Recipe
の3つのタブで切り替え表示 - Selectに表示される選択肢の表示をわかりやすくした
-
v-for
に使う:key
の値が未定義の配列があったので修正 -
v-for
で表示する配列とchrome.storageへの登録のタイミングを変更 -
Lang
とRecipe
では追加データが先頭になるように、配列への要素追加を変更 -
Lang
設定の実装- 言語の選択肢は順番をわかりやすくするために全部英語表記にした
- 設定は手間ではないので、csv形式のインポートとエクスポート機能は無し
- 登録データを検索結果に表示
- 検索結果に表示する文字列は、パラメータではなく言語名英語表記にした
- 絞り込まないデフォルトのパラメータ
all
を追加
あとは公開のためのファイル設定!
createAppの段階でデータを渡したい
第2引数に指定してあげれば良い
createApp(App, {nowURL: "hoge", paramTbm: "fuga"}).mount('#amzSchRoot');
JavaScript String.replace
hoge.replace(fuga, "")
の第1引数は正規表現・ただの文字列のどちらでも良い
Vue formの検証を使いたい
form + イベント修飾子を使う
<form @submit.prevent="onSubmit">
<!-- なにかinputタグ書く -->
<button type="submit">Add</button>
</form>
VueのNumberをpropsで渡したい
Javascriptの式であると伝えなければ文字列だと思われてしまうので、動的にv-bind
として渡す。
<blog-post :likes="42"></blog-post>
拡張機能インストール時にデータが空
Resetボタンを押したときと同じデータを、拡張機能インストール時にも登録するように書かないと普通にだめ。忘れていた。
「拡張機能インストール時」のイベントは、 chrome.runtime.onInstalled.addListener
をバックグラウンドで動かす。
今までは開発時にしかbackground
を登録していなかったため、webpack.dev.js
とwebpack.dev.js
でコピーの設定は別々に行っていた。この設定を共通化し、webpack.common.js
に移す。
また、エントリーも追加する。
plugins: [
new CopyPlugin([
{
from: 'src/manifest.json',
transform: (content) => {
return JSON.stringify(
Object.assign({}, JSON.parse(content.toString()), {
"background": {"service_worker": "background.js"},
}), null, ' ');
},
},
{
context: 'public',
from: 'imgs/*',
}
]),
new ExtensionReloader(),
]
plugins: [
new CopyPlugin([{
from: 'src/manifest.json',
},
{
context: 'public',
from: 'imgs/*',
}
]),
new ZipPlugin({
filename: path.basename(__dirname) + ".zip",
pathPrefix: path.basename(__dirname)
}),
]
また、独自のプラグインExtensionReloader
のバックグラウンドの部分についても変更。
let background_reload = './background_reload.js';
if (entry.background) {
if (Array.isArray(entry.background)) {
entry.background.push(background_reload);
} else {
entry.background = [entry.background, background_reload];
}
}
webpackで特定のエントリだけ共通化したくない
background
だけは1つのスクリプトだけで簡潔させたいので、chunk.jsとか読み込まなくてもいいように共通化したくない。
webpack.js.org/split-chunks-plugin.md at master · webpack/webpack.js.org に書いてあるとおり、chunks
を関数にすれば良い。
optimization: {
splitChunks: {
name: 'chunk',
chunks(chunk) {
return chunk.name !== 'background';
},
}
},
進捗報告2021/05/30
Chrome Web Store の審査に出した。世界はまだまだ日曜日なので、審査結果が分かるまでだいぶ時間が掛かりそう。
公開!
↓インストール先
↓紹介記事
スクラップに残したメモは紹介とは別の記事に書く。
技術編書いた。これでこのスクラップをCloseする