Qiitaで記事を新規作成するときに自動でテンプレートを適用する拡張機能の開発

# はじめに
## ひとこと
アクセスしていただきありがとうございます。
最近Qiitaの記事を書くことが多くなってきたため、記事を新規作成するときに自動でテンプレートを適用する拡張機能を開発してみました。

## 目的
+ Qiitaで「記事を新規作成」するときに自動でテンプレートを適用する拡張機能を開発する

## 検証済みの環境
+ OS: Windows11 Home x64
+ CPU: 13th Gen Intel(R) Core(TM) i7-13700H
+ メモリ: 16.0GB
+ GPU: Intel(R) Iris(R) Xe Graphics
+ 対象のサービス: Qiita（2024/11/26現在のバージョン）
+ ブラウザ: Google Chrome
    + バージョン: 131.0.6778.86（Official Build） （64 ビット）
    + （拡張機能） manifest v3

## ご注意
+ この記事の情報は **2024/11/26現在** のものです
+ この記事は **Geminiが生成したコンテンツを含み** ます
+ この記事では、例えば「manifest.jsonとは何か」などの前提となる仕組みについては解説していません。後日、この記事に加筆するか、別の記事で解説する予定です
+ この拡張機能を開発し公開すること、またその拡張機能について記事を執筆することについてはQiitaサポートに問い合わせを行い、「ご連絡いただいた内容でしたら、開発・公開ともに問題ございません。」との返信をいただいております。問い合わせに対応していただいたこと、そして許可いただいたことに、この場を借りて感謝申し上げます
+ この拡張機能は力技によって成り立っているので、ウェブページの構造が変わった、などで使えなくなる可能性があります

# 1.Chrome 拡張機能について
Chrome 拡張機能とは、Chrome ブラウザの機能を拡張し、より快適なウェブ体験を提供するための小さなプログラムのことです。

https://developer.chrome.com/docs/extensions?hl=ja

# 2.拡張機能を開発
## 1.拡張機能を保存するディレクトリとファイルを作成
以下のようなディレクトリとファイルを作成します。
なお、ディレクトリの名前は任意の名前でも問題ないです。
```
AutomaticTemplateApplierOnQiita(任意の名前でも可)
|-- content.js
|-- manifest.json
```

## 2.manifest.jsonを編集
以下の内容をコピーし、manifest.jsonを開いて貼り付けてください。
なお、"name"と"description"の値は任意のテキストでも問題ないです。
```json: manifest.json
{
    "manifest_version": 3,
    "name": "Automatic Template Applier On Qiita",
    "version": "1.0.0",
    "description": "Qiitaで記事を新規作成するときに自動でテンプレートを適用します。",
    "content_scripts": [
        {
            "matches": [
                "https://qiita.com/*"
            ],
            "include_globs": [
                "https://qiita.com/drafts/new"
            ],
            "js": [
                "content.js"
            ]
        }
    ]
}
```

## 3.content.jsを編集
以下の内容をコピーし、content.jsを開いて貼り付けてください。
そしてtemplateTextの値を任意の文字列で書き換えてください。
```js: content.js
const templateText = `
（任意の内容）
`

function applyTemplate() {
    const targetClassName = 'cm-content'
    const targetElement = document.getElementsByClassName(targetClassName)[0]
    if (targetElement) {
        targetElement.textContent = templateText
    }
}

setTimeout(applyTemplate, 2000)
```

## 4.拡張機能を読み込む
以下の公式のドキュメントが参考になります。

https://developer.chrome.com/docs/extensions/get-started/tutorial/hello-world?hl=ja#load-unpacked

# 3.拡張機能の仕組み
## URL
Qiitaで「記事を新規作成」すると`https://qiita.com/drafts/new`という固定のURLに遷移します。
その後、タイトルや本文などに何かしらの変更があると、`https://qiita.com/drafts/xxx/edit`という固有のURLに変わります。
そのため、拡張機能を実行するURLの条件は`https://qiita.com/drafts/new`となります。

## テキストの代入
Qiitaのエディタは「文章修正提案機能」などがあることから、単純な`textarea`要素などではないと思っていましたが、想像以上に複雑な構造でした。
検証の結果、エディタのテキストは以下の画像の要素とその子要素で管理されていました。
そして、この要素の`textContent`に値を代入すると、キーボードから入力したときと同じようになると判明しました。

![スクリーンショット (77).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2969427/d0d5fff1-9b9f-bc15-bc9e-b0da92dbb003.png)

この要素につけられた`cm-content`クラスがドキュメント全体で1つしかないことも判明しました。
そのため`getElementsByClassName(targetClassName)[0]`として、この要素を取得しています。

## 遅延処理
Chrome 拡張機能を実行するタイミングは以下で指定できます（以下の例では、必要な部分以外を省略しています）。
```json: manifest.json
{
    "content_scripts": [
        {
            "run_at": ""
        }
    ]
}
```

https://developer.chrome.com/docs/extensions/reference/manifest/content-scripts?hl=ja#world-timings

`"run_at"`には3つの値を指定できます。
その中で、最も遅いタイミングで実行できるのがデフォルトの値の`"document_idle"`です。
これを指定すると、DOMとリソースの読み込みが完了したら実行されるようになります。
しかし、その時には **スクリプトが実行中か、まだ実行されていない** 可能性があります。
検証の結果、先ほどの`cm-content`クラスがつけられた要素も、静的なコンテンツではなく、スクリプトによって生成されていることが分かりました。
そのため、筆者の[検証済みの環境](#検証済みの環境)では、`setTimeout()`で`2000ms`待機することによって確実に実行できるようにしました。

# おわりに
最後までお読みいただきありがとうございます。
筆者は遅延処理で特につまずきましたので、どなたかの参考になれば幸いです。