LoginSignup
0
0

Chrome拡張を自作してGitHubのリリースとして公開する備忘録

Posted at

Chrome拡張機能を作成&開発

プロジェクト作成

npx create chrome-extからのプロジェクト作成を行いました。
create chrome-extというコマンドは辿っていくと以下のリポジトリにたどり着きます。

  • 著名なフロントエンドフレームワーク(React、Vue、Svelte、他多数)&Viteのビルドを想定したプロジェクトが作成できる(バニラも選択可)
  • デフォルトの状態でコンテンツスクリプト、ポップアップ、バックグラウンド、サイドパネル等の機能が有効化されたテンプレートとなっている(Vueのテンプレートでのみ確認)

今回はdemo-chrome-extという名前でVue.jsを使用したChrome拡張を作成していきます

CLIからプロジェクト作成

$ npx create chrome-ext demo-chrome-ext
√ Framework: » vue
√ Language: » vue-ts

Scaffolding project in C:\workspace_browser_ext\demo-chrome-ext...

Done. Now run:

  cd demo-chrome-ext
  npm install
  npm run dev

   Suggest you next step:
    1. cd demo-chrome-ext
    2. Run npm install
    3. Open chrome://extensions/ in your browser
    4. Check the box for Developer mode in the top right.
    5. Click the Load unpacked extension button.
    6. Select the build/ directory that was created.

以下のような形で使用するフレームワークとJavaScript or TypeScriptの選択が行えました。
今回はvuevue-tsと選択。

image.png

image.png


プロジェクト作成時のコンソール出力の内容に従い作成したプロジェクトのディレクトリに移動&npmで管理するパッケージをインストール

$ cd demo-chrome-ext
$ npm install

ひとまずViteの開発サーバーを起動するnpmスクリプトが実行できることを確認

$ npm run dev

> demo-chrome-ext@0.0.0 dev
> vite


  VITE v4.5.3  ready in 711 ms

  ➜  Local:   http://localhost:5173/
  ➜  Network: use --host to expose
  ➜  press h to show help
The emitted file "img/logo-34.png" overwrites a previously emitted file of the same name.
The emitted file "img/logo-48.png" overwrites a previously emitted file of the same name.
The emitted file "img/logo-128.png" overwrites a previously emitted file of the same name.
The emitted file "img/logo-16.png" overwrites a previously emitted file of the same name.

パッケージ最新化

npmで管理しているパッケージは全体的にやや古い状態だったので以下のコマンドで最新のものを入れ直しました。
6件見つかった脆弱性に関するアラートが消えました。

dependencies側を更新
$ npm install vue@latest

up to date, audited 479 packages in 1s

43 packages are looking for funding
  run `npm fund` for details

6 high severity vulnerabilities

To address issues that do not require attention, run:
  npm audit fix

To address all issues (including breaking changes), run:
  npm audit fix --force

Run `npm audit` for details.
devDependencies側を更新
$ npm install -D @crxjs/vite-plugin@^2.0.0-beta.23 @types/chrome@latest @vitejs/plugin-vue@latest gulp@latest gulp-zip@latest prettier typescript vite@latest vue-tsc@latest

added 25 packages, removed 256 packages, changed 71 packages, and audited 248 packages in 19s

39 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities

package.jsonのアップデート前後の差分は以下の通りとなりました。

package.json
{
  "name": "demo-chrome-ext",
  "displayName": "demo-chrome-ext",
  "version": "0.0.0",
  "author": "**",
  "description": "",
  "type": "module",
  "license": "MIT",
  "keywords": [
    "chrome-extension",
    "vue",
    "vite",
    "create-chrome-ext"
  ],
  "engines": {
    "node": ">=14.18.0"
  },
  "scripts": {
    "dev": "vite",
    "build": "vue-tsc --noEmit && vite build",
    "preview": "vite preview",
    "fmt": "prettier --write '**/*.{vue,ts,json,css,scss,md}'",
    "zip": "npm run build && node src/zip.js"
  },
  "dependencies": {
-    "vue": "^3.3.4"
+    "vue": "^3.4.27"
  },
  "devDependencies": {
-    "@crxjs/vite-plugin": "^2.0.0-beta.19",
-    "@types/chrome": "^0.0.246",
-    "@vitejs/plugin-vue": "^4.4.0",
-    "gulp": "^4.0.2",
+    "@crxjs/vite-plugin": "^2.0.0-beta.23",
+    "@types/chrome": "^0.0.268",
+    "@vitejs/plugin-vue": "^5.0.5",
+    "gulp": "^5.0.0",
    "gulp-zip": "^6.0.0",
-    "prettier": "^3.0.3",
-    "typescript": "^5.2.2",
-    "vite": "^4.4.11",
-    "vue-tsc": "^1.8.18"
+    "prettier": "^3.3.1",
+    "typescript": "^5.4.5",
+    "vite": "^5.2.13",
+    "vue-tsc": "^2.0.21"
  }
}

Chromeに開発中のChrome拡張をインストール

  1. Viteの開発サーバーを起動しておく
  2. Chromeでchrome://extensionsにアクセス
  3. パッケージ化されていない拡張機能を読み込むボタンをクリック
  4. ダイアログで開発中のChrome拡張のbuildディレクトリを指定

image.png

image.png

image.png

開発中のChrome拡張の動作確認

create chrome-extコマンドで作成したVue&TypeScriptのテンプレートではChrome拡張の各機能間で共有可能なカウントアップが行えるような拡張機能となっていました。


POPUP PAGEというポップアップが表示できることを確認

image.png


インストールしたChrome拡張のService Workerをクリックして表示されたdevtoolでカウントアップ時のコンソール出力を確認

image.png

image.png


Chrome拡張のボタンを右クリック > オプションからオプションページが表示できることを確認

image.png


Chrome拡張のボタンを右クリック > サイドパネルを開くからサイドパネルが表示できることを確認

image.png


新規タブ追加時のページがデフォルトの状態から上書きされていることを確認

image.png

ボイラープレートから不要な機能を取り除く

create chrome-extコマンドで作成したVue&TypeScriptのボイラープレートに不要な機能がある場合の除外手順をまとめてみました

新規タブ追加時の画面が不要な場合

手順

不要なファイルを削除

$ rm -fr newtab.html src/newtab

src/manifest.tsを編集

src/manifest.ts
import { defineManifest } from '@crxjs/vite-plugin'
import packageData from '../package.json'

//@ts-ignore
const isDev = process.env.NODE_ENV == 'development'

export default defineManifest({
  name: `${packageData.displayName || packageData.name}${isDev ? ` ➡️ Dev` : ''}`,
  description: packageData.description,
  version: packageData.version,
  manifest_version: 3,
  icons: {
    16: 'img/logo-16.png',
    32: 'img/logo-34.png',
    48: 'img/logo-48.png',
    128: 'img/logo-128.png',
  },
  action: {
    default_popup: 'popup.html',
    default_icon: 'img/logo-48.png',
  },
  options_page: 'options.html',
  devtools_page: 'devtools.html',
  background: {
    service_worker: 'src/background/index.ts',
    type: 'module',
  },
  content_scripts: [
    {
      matches: ['http://*/*', 'https://*/*'],
      js: ['src/contentScript/index.ts'],
    },
  ],
  side_panel: {
    default_path: 'sidepanel.html',
  },
  web_accessible_resources: [
    {
      resources: ['img/logo-16.png', 'img/logo-34.png', 'img/logo-48.png', 'img/logo-128.png'],
      matches: [],
    },
  ],
  permissions: ['sidePanel', 'storage'],
-  chrome_url_overrides: {
-    newtab: 'newtab.html',
-  },
})

(Git管理している場合)VSCodeで見た差分

image.png

ポップアップが不要な場合

手順

不要なファイルを削除

$ rm -fr popup.html src/popup

src/manifest.tsを編集

src/manifest.ts
import { defineManifest } from '@crxjs/vite-plugin'
import packageData from '../package.json'

//@ts-ignore
const isDev = process.env.NODE_ENV == 'development'

export default defineManifest({
  name: `${packageData.displayName || packageData.name}${isDev ? ` ➡️ Dev` : ''}`,
  description: packageData.description,
  version: packageData.version,
  manifest_version: 3,
  icons: {
    16: 'img/logo-16.png',
    32: 'img/logo-34.png',
    48: 'img/logo-48.png',
    128: 'img/logo-128.png',
  },
-  action: {
-    default_popup: 'popup.html',
-    default_icon: 'img/logo-48.png',
-  },
  options_page: 'options.html',
  devtools_page: 'devtools.html',
  background: {
    service_worker: 'src/background/index.ts',
    type: 'module',
  },
  content_scripts: [
    {
      matches: ['http://*/*', 'https://*/*'],
      js: ['src/contentScript/index.ts'],
    },
  ],
  side_panel: {
    default_path: 'sidepanel.html',
  },
  web_accessible_resources: [
    {
      resources: ['img/logo-16.png', 'img/logo-34.png', 'img/logo-48.png', 'img/logo-128.png'],
      matches: [],
    },
  ],
  permissions: ['sidePanel', 'storage'],
  chrome_url_overrides: {
    newtab: 'newtab.html',
  },
})

(Git管理している場合)VSCodeで見た差分

image.png

オプション画面が不要な場合

手順

不要なファイルを削除

$ rm -fr options.html src/options

src/manifest.tsを編集

src/manifest.ts
import { defineManifest } from '@crxjs/vite-plugin'
import packageData from '../package.json'

//@ts-ignore
const isDev = process.env.NODE_ENV == 'development'

export default defineManifest({
  name: `${packageData.displayName || packageData.name}${isDev ? ` ➡️ Dev` : ''}`,
  description: packageData.description,
  version: packageData.version,
  manifest_version: 3,
  icons: {
    16: 'img/logo-16.png',
    32: 'img/logo-34.png',
    48: 'img/logo-48.png',
    128: 'img/logo-128.png',
  },
  action: {
    default_popup: 'popup.html',
    default_icon: 'img/logo-48.png',
  },
-  options_page: 'options.html',
  devtools_page: 'devtools.html',
  background: {
    service_worker: 'src/background/index.ts',
    type: 'module',
  },
  content_scripts: [
    {
      matches: ['http://*/*', 'https://*/*'],
      js: ['src/contentScript/index.ts'],
    },
  ],
  side_panel: {
    default_path: 'sidepanel.html',
  },
  web_accessible_resources: [
    {
      resources: ['img/logo-16.png', 'img/logo-34.png', 'img/logo-48.png', 'img/logo-128.png'],
      matches: [],
    },
  ],
  permissions: ['sidePanel', 'storage'],
  chrome_url_overrides: {
    newtab: 'newtab.html',
  },
})

(Git管理している場合)VSCodeで見た差分

image.png

サイドパネルが不要な場合

手順

不要なファイルを削除

$ rm -fr sidepanel.html src/sidePanel

src/manifest.tsを編集

src/manifest.ts
import { defineManifest } from '@crxjs/vite-plugin'
import packageData from '../package.json'

//@ts-ignore
const isDev = process.env.NODE_ENV == 'development'

export default defineManifest({
  name: `${packageData.displayName || packageData.name}${isDev ? ` ➡️ Dev` : ''}`,
  description: packageData.description,
  version: packageData.version,
  manifest_version: 3,
  icons: {
    16: 'img/logo-16.png',
    32: 'img/logo-34.png',
    48: 'img/logo-48.png',
    128: 'img/logo-128.png',
  },
  action: {
    default_popup: 'popup.html',
    default_icon: 'img/logo-48.png',
  },
  options_page: 'options.html',
  devtools_page: 'devtools.html',
  background: {
    service_worker: 'src/background/index.ts',
    type: 'module',
  },
  content_scripts: [
    {
      matches: ['http://*/*', 'https://*/*'],
      js: ['src/contentScript/index.ts'],
    },
  ],
-  side_panel: {
-    default_path: 'sidepanel.html',
-  },
  web_accessible_resources: [
    {
      resources: ['img/logo-16.png', 'img/logo-34.png', 'img/logo-48.png', 'img/logo-128.png'],
      matches: [],
    },
  ],
-  permissions: ['sidePanel', 'storage'],
+  permissions: ['storage'],
  chrome_url_overrides: {
    newtab: 'newtab.html',
  },
})

(Git管理している場合)VSCodeで見た差分

image.png

タグ作成をトリガーとしたGitHub Actionsのワークフローを作成

目的達成に至るまでの備忘録
  1. vite buildの成果物のアップロード先としてGitHubのリリースを作成しAssetsにアップロードするワークフローを作る必要がある
  2. actions/create-releaseアクションでGitHubのリリースを作成しactions/upload-release-assetアクションでリリースのAssetsにファイルをアップロードできそう
  3. softprops/action-gh-releaseアクションについて調べ、リリースの作成とAssetsへのアップロードについて1つのアクションで実行できることを確認

作成したワークフローは以下のようになりました。

.github/workflows/create-release.yml
name: Create Release

on:
  push:
    tags:
      - "*"

permissions:
  contents: write

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: "20"

      - name: Build
        run: |
          npm install
          npm run build
          mv build demo-chrome-ext
          zip -r demo-chrome-ext-${{ github.ref_name }}.zip demo-chrome-ext

      - name: Release
        uses: softprops/action-gh-release@v2
        with:
          files: demo-chrome-ext-${{ github.ref_name }}.zip
          generate_release_notes: true
  • softprops/action-gh-releaseアクションのREADMEにも書いてありますがワークフローを実行するのにcontents: writeの権限が必要です
  • generate_release_notes: trueオプションを指定することでリリースノートについて自動生成しています
  • ${{ github.ref_name }}はタグ作成をトリガーとしているため0.0.1のようなバージョンが入ります

リリースノート自動生成用のカテゴリ設定

以下のようなrelease.ymlを作成

.github/release.yml
changelog:
  categories:
    - title: 🐛 Bug Fixes
      labels:
        - bug
    - title: 📚 Documentation
      labels:
        - documentation
    - title: 🚫 Duplicates
      labels:
        - duplicate
    - title: 🚀 Enhancements
      labels:
        - enhancement
    - title: 👶 Good First Issues
      labels:
        - good first issue
    - title: 🙋 Help Wanted
      labels:
        - help wanted
    - title: 🚷 Invalid
      labels:
        - invalid
    - title: ❓ Questions
      labels:
        - question
    - title: ⛔ Won't Fix
      labels:
        - wontfix
    - title: Others
      labels:
        - "*"
  • GitHubリポジトリにデフォルトで設定されている9つのラベルに対応するrelease.ymlを作成しました(大枠はAIに出力してもらった)
    • 意味を理解してないラベルがある...
    • 必ずしもデフォルトのまま使い続ける必要はないはず。不要なものは削除しても良いかも
  • デフォルト以外のラベルのPRは全てOthersというカテゴリに含まれるような設定としています

ワークフローの動作確認

ローカルでタグを作成してリモートにプッシュ(最新のmainブランチにいる状態で以下実施

$ git tag 0.0.1
$ git push origin 0.0.1
Total 0 (delta 0), reused 0 (delta 0), pack-reused 0
To https://github.com/imo-tikuwa/demo-chrome-ext.git
 * [new tag]         0.0.1 -> 0.0.1

タグ作成をトリガーとしたワークフローが走ったことを確認

image.png


ワークフローの実行によって生成されたリリース内にリリースノートが生えてることを確認

image.png

  • リリースノートの自動生成について.github/release.ymlで設定したカテゴリごとにPRがまとめられていることを確認
  • vite buildによって出来上がったChrome拡張機能のコード一式を固めたzipファイルをAssets欄にアップロードできていることを確認

備考

  • 今回は手動によるタグ作成をワークフローのトリガーとしていますが、ストアへの公開を目標とした正式なChrome拡張を開発する場合はセマンテックバージョニングのルールに基づいたバージョン管理を行える必要があると思います
  • 記事の中で書いたVue&TypeScriptのテンプレートではpackage.jsonのversionに記載した値をChrome拡張のバージョンとして設定するようになっているため、前段としてpackage.jsonのバージョンを書き換えるようなワークフローを組めると良いかなと思いました

今回の記事の中で実際に作成したデモのChrome拡張は以下のリポジトリで公開しています

参考サイト

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0