Closed27

Chrome拡張機能 AmazingSearcher メモ 2021/03/10 ~

概要

https://zenn.dev/eetann/scraps/4231d06e84c869
↑のスクラップが長くなってメモが探しづらくなるのを防ぐため閉じたので、その続き。

Chrome拡張機能「AmazingSearcher」を作成中に得られた知見を記事にするためのまとめ。

進捗報告 2021/03/14

オプションページのだいたいの表示が完成。

↓購読するリストの管理
Recipe lists

↓自分で追加したレシピの管理
Custom Recipes

↓購読するリストのレシピや自分で追加したレシピのトグル
Toggle Recipes

ソートとかURLをリンク化したり、URLの表示文字数の制限は後でやる。

拡張機能で画像が急に読み込まれなくなった

拡張機能のオプションページでは普通に表示されるが、web_accessible_resourcesの設定を要する部分が表示されなくなった。web_accessible_resourcesリストの各要素に設定するmatches["<all_urls>"]にすれば治った。もともとは[]じゃないと動かなかったけど変わったっぽい。ちゃんとした資料が見つけられなくて残念。

    "web_accessible_resources": [{
        "resources": ["imgs/*"],
-        "matches": []
+        "matches": ["<all_urls>"]
        }]

https://stackoverflow.com/questions/66602828/web-accessible-resources-images-in-content-scripts-not-working-in-chrome-89-0

SVGはやっぱり画像ではなくコンポーネントとして読み込むことにした。

非同期のデータをVue3で表示

getRecipes()をawait→setup()にasyncつける→子コンポーネントにして、親コンポーネントからSuspenseを使って読み込む

子コンポーネント@/components/MyRecipes.vue
...
<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>

参考

https://v3.vuejs.org/guide/migration/suspense.html

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を適用

Recipe lists
Custom recipes
Toggle recipes

進捗報告2021/04/26

  • URL欄の文字列に色をつけて、リンク化
  • Recipe listsで登録されたレシピリストのURLからレシピをchrome.storage.local.setで登録
  • サンプルではなく、登録されているレシピを表示
    進捗
    当初思っていたものに近くなってきた!

進捗報告2021/05/04

引き続きオプションページ周り。

  • URLからレシピを読み込む機能を削除
  • それに伴いタブを一新
    • Recipe lists, Custom recipes, Toggle Recipes を削除
    • 既存のレシピをテーブル表示
    • 入力欄の作成(入力機能は未実装)
    • レシピの削除機能の実装
    • レシピのリセット機能の実装
      • リセットボタンは一番下にした
      • リセットボタンを押すとデフォルトのレシピのみ登録されている状態になる
        進捗報告

最初からいろいろやろうとするんじゃなくて、まずは最低限必要なところだけ完成させるべきだったなぁ。

進捗報告2021/05/07

  • レシピ追加機能の実装
  • リセット、レシピ追加、レシピ削除時に動作完了メッセージを表示
  • レシピ追加前にチェック機能
    • チェック機能の実装
    • 無効な入力であればエラーとしてメッセージを表示
      進捗報告

進捗報告2021/05/09

  • (前回か前々回の下記忘れ)デフォルトデータの保存はjsonではなくcsvファイルに変更
  • URLから読み込むのではなく実際に登録しているデータを検索結果に表示
  • 別リポジトリに保存していたjsonに意味がなくなったのでそのレポジトリをアーカイブした

これで必要最低限の機能は揃った。あとはブラッシュアップ。その前に卒研の進捗

データをCSVファイルとしてダウンロードする

流れは以下

  1. 先頭行の文字列を変数に代入
  2. データから,\nで区切った文字列を変数に結合
  3. Blobの作成
  4. window.URL.createObjectURL
  5. aタグを作りhrefにリンク、downloadにファイル名を設定
  6. クリック発火
  7. 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

  • 検索結果
    • 期間絞り込みリンクを表示
    • 言語絞り込みリンクを表示
  • オプションページ
    • 登録レシピのインポート機能を実装
    • 登録レシピのエクスポート機能を実装
    • 検索で表示する絞り込み期間について以下を実装
      • 一覧を期間が短い順に表示
      • 登録
      • リセット
      • インポート
      • エクスポート
        進捗報告1
        進捗報告2

レシピや絞り込み期間のように絞り込み言語も実装し、オプションページは表示区切るかタブ表示に変えたい

進捗報告2021/05/20

  • 設定をTerm, Lang, Recipeの3つのタブで切り替え表示
  • Selectに表示される選択肢の表示をわかりやすくした
  • v-forに使う:keyの値が未定義の配列があったので修正
  • v-forで表示する配列とchrome.storageへの登録のタイミングを変更
  • LangRecipeでは追加データが先頭になるように、配列への要素追加を変更
  • Lang設定の実装
    • 言語の選択肢は順番をわかりやすくするために全部英語表記にした
    • 設定は手間ではないので、csv形式のインポートとエクスポート機能は無し
    • 登録データを検索結果に表示
    • 検索結果に表示する文字列は、パラメータではなく言語名英語表記にした
    • 絞り込まないデフォルトのパラメータallを追加

進捗報告1
進捗報告2
進捗報告3

あとは公開のためのファイル設定!

createAppの段階でデータを渡したい

第2引数に指定してあげれば良い

main.js
createApp(App, {nowURL: "hoge", paramTbm: "fuga"}).mount('#amzSchRoot');

参考:propsData | Vue.js

Vue formの検証を使いたい

form + イベント修飾子を使う

<form @submit.prevent="onSubmit">
  <!-- なにかinputタグ書く -->
  <button type="submit">Add</button>
</form>

参考:イベントハンドリング | Vue.js

拡張機能インストール時にデータが空

Resetボタンを押したときと同じデータを、拡張機能インストール時にも登録するように書かないと普通にだめ。忘れていた。
「拡張機能インストール時」のイベントは、 chrome.runtime.onInstalled.addListener をバックグラウンドで動かす。

今までは開発時にしかbackgroundを登録していなかったため、webpack.dev.jswebpack.dev.jsでコピーの設定は別々に行っていた。この設定を共通化し、webpack.common.jsに移す。
また、エントリーも追加する。

今までのwebpack.dev.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(),
]
今までのewbpack.prod.jsの一部
plugins: [
  new CopyPlugin([{
    from: 'src/manifest.json',
  },
  {
    context: 'public',
    from: 'imgs/*',
  }
  ]),
  new ZipPlugin({
    filename: path.basename(__dirname) + ".zip",
    pathPrefix: path.basename(__dirname)
  }),
]

また、独自のプラグインExtensionReloaderのバックグラウンドの部分についても変更。

変更後のextension-reloader.jsの一部
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 の審査に出した。世界はまだまだ日曜日なので、審査結果が分かるまでだいぶ時間が掛かりそう。

スクラップに残したメモは紹介とは別の記事に書く。

このスクラップは2ヶ月前にクローズされました
作成者以外のコメントは許可されていません