1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

あらゆるWebページに、コミュニケーションレイヤーを。Chrome拡張『NoteLink』を作った

1
Posted at

はじめまして。Webエンジニアを15年以上やっています。

普段はシステム開発の現場で、設計やプログラミングをしたり、プロジェクト全体の進行を見たりしています。

最近はAIの進化が本当に速く、エンジニアとして「この先、自分たちの仕事はどう変わっていくんだろう」と考えることも増えました。

少し落ち着かない気持ちもありますが、それ以上に面白い時代になったと感じています。

特に個人開発では、AIのおかげでアイデアを形にするまでの時間がぐっと短くなりました。

以前なら時間や工数を考えて後回しにしていたことも、「とりあえず作ってみよう」と思えるようになったのは大きな変化です。

そんな環境を楽しみながら、最近はいくつかの個人開発に取り組んでいます。

今回は、そのひとつであるChrome拡張機能「NoteLink」を紹介します。

Webは進化した。でも「ここ」を伝えるのは、まだ面倒くさい。

Webはここまで進化したのに、ページの「ここ」を伝えるのは、まだ面倒くさい。

URLを共有することは簡単です。

でも、URLの先にある特定の文章やボタン、画像について誰かと話そうとすると、途端に手間が増えます。

「このページの真ん中あたりにある、青いボタンの少し下の……」

伝える側も大変ですが、受け取る側もちょっとした謎解きです。

結局、スクリーンショットを撮って、赤枠をつけて、チャットに貼り付ける。

もちろん、それでも十分に仕事は進みます。

ただ、エンジニアとしては、こういう小さな手間がどうにも気になります。

だったら、Webページそのものにコミュニケーション機能を追加すればいい。

そんな発想から、Chrome拡張機能「NoteLink」を開発しました。

NoteLinkとは?

NoteLink は、Webページ上の好きな場所にピンを立て、コメントやメモをチームで共有できるChrome拡張機能です。

既存のWebサイトに手を加える必要はありません。

Chrome拡張をインストールすることで、普段見ているWebページに、もうひとつのコミュニケーションレイヤーを重ねることができます。

言葉で場所を説明するのではなく、伝えたい場所を、そのまま指し示す。

やりたかったことは、実はそれだけです。

ただ、それを使いやすい形にするとなると、なかなか奥が深いものでした。

Webページ上にピンとコメントを表示している画面
demo_pin.gif
demo_comments.gif

主な機能

機能 内容
ピンの配置 Webページの任意の場所を指定してノートを作成
コメント・返信 指定した場所を起点にコミュニケーション
チーム共有 メンバーを招待してノートを共有
メンション・通知 特定のメンバーに確認を依頼
URL・ドメイン単位の管理 ページ単位、サイト単位でノートを整理
検索・アーカイブ 過去のやり取りを検索・整理
ダッシュボード 複数のノートをまとめて管理

基本的な考え方はシンプルです。

「どのページの、どの場所について、誰と、何を話しているのか」を分かりやすくすること。

機能を増やすこと自体が目的にならないよう、この考え方を大切にしています。

なぜChrome拡張にしたのか?

最初に考えたのは、どうすれば普段のWeb閲覧を邪魔せずに、この仕組みを実現できるかということでした。

Webサイト側に専用のプログラムを組み込む方法も考えられますが、それでは利用できるサイトが限られてしまいます。

WordPressでも、業務システムでも、ニュースサイトでも。

ユーザーが普段見ているWebページに、そのまま機能を追加したい。

そこで選んだのがChrome拡張です。

Chrome拡張であれば、Webサイト自体を改修することなく、ブラウザ側から独自のUIや機能を追加できます。

もちろん、Webページごとに構造や動作が異なるため、何でも簡単にできるわけではありません。

むしろ、そこが面白いところでもあります。

技術構成について

ここからは、少し技術的な話をします。

NoteLinkは、Chrome拡張機能とバックエンドAPIを組み合わせた、比較的シンプルな構成です。

技術スタック

分類 採用技術
Chrome拡張 Manifest V3
フロントエンド TypeScript / Vanilla HTML・CSS
UI分離 Shadow DOM
ビルド esbuild
バックエンド PHP(独自REST API)
データベース MySQL 8.0
認証 Google OAuth 2.0 / JWT
データ暗号化 AES-256-GCM
通知 Chrome Alarms / Notifications API

フロントエンドはTypeScriptを中心に実装し、ReactなどのUIフレームワークは使っていません。

バックエンドも、Laravelなどのフレームワークを使用せず、PHPで必要なAPIを実装しています。

個人開発では、技術的な新しさだけでなく、無理なく開発・運用を続けられることも大切だと考えています。

AIの支援によって実装スピードは上がりましたが、どの技術を採用し、どこまで作り込むかという判断は、やはり開発者側に残ります。

作れるものが増えた分、何を作るか、何を作らないかを考える時間も大切になった気がします。

全体の仕組み

Webページ上に表示するピンやノートのUIはContent Scriptが担当します。

データの保存・取得はPHP APIを経由し、通知の確認はBackground Service Workerが担当する形です。

実装で考えたこと

今回は初回の記事なので、コードの詳細を網羅するのではなく、実装時に考えたことをいくつか紹介します。

AIのおかげで実装の試行錯誤は以前より速くなりましたが、実際のWebページで使ってみると、細かな課題は次々に見つかります。

コードを書く時間が短くなっても、使い勝手を考える時間はなくならない。むしろ、そこに時間を使えるようになったのは良い変化だと感じています。

1. Webページ上の要素にピンを紐づける

NoteLinkでは、ピンの位置を固定座標で保存するのではなく、対象となるHTML要素のCSSセレクターを保存しています。

表示時には document.querySelector() で要素を取得し、getBoundingClientRect() で現在の表示位置を計算します。

const targetEl = document.querySelector(selector);

if (targetEl) {
  const rect = targetEl.getBoundingClientRect();

  pin.style.left = `${rect.left}px`;
  pin.style.top = `${rect.top}px`;
}

※実際の処理を説明用に簡略化しています。

ここまでは比較的シンプルな実装です。

ただ、実際のWebページではスクロールやリサイズ、動的なDOMの変更などが発生します。

そのため、NoteLinkでは次のような処理を組み合わせています。

  • スクロールやリサイズ時にピンの位置を更新する
  • 同じ要素に複数のピンがある場合は、表示位置を少しずらす
  • 対象要素が非表示になった場合はピンも非表示にする
  • 対象要素が見つからない場合は、無理に別の場所へ表示しない

また、HTML構造が大きく変わると、保存したセレクターが一致しなくなることもあります。

そのため、現時点ではすべてのWebページで位置を完全に保証できるわけではありません。

基本的な仕組みはシンプルでも、さまざまなWebページで破綻しにくくするには、細かな対応が必要でした。

demo_pin.gif

2. Webサイト側のCSSと干渉させない

Chrome拡張で少し厄介なのが、CSSの衝突です。

Webサイトによって、ボタンやフォント、余白などのスタイルはまったく異なります。

そこに拡張機能のUIを追加すると、サイト側のCSSによって表示が崩れることがあります。

逆に、拡張機能側のCSSが元のサイトへ影響するのも避けたいところです。

そこでNoteLinkでは、Shadow DOMを利用してUIを分離しています。

const container = document.createElement('div');
container.id = 'notelink-extension-root';

document.body.appendChild(container);

const shadowRoot = container.attachShadow({
  mode: 'open'
});

※説明用に簡略化したコードです。

サイドバー、ピン、ポップアップなどは、基本的にShadow DOM内で描画しています。

これにより、Webサイト側と拡張機能側のスタイルが干渉しにくくなります。

ただし、Shadow DOMだけですべての問題が解決するわけではありません。

継承されるスタイルなども考慮して、内部では必要なCSSリセットを行っています。

また、Webページの要素とノートを結ぶSVGの矢印については、表示上の都合から親ドキュメント側に配置しています。

UIを分離しつつ、必要な部分では元のページと連携する。

このあたりは、Chrome拡張ならではの設計だと感じました。

3. 動的に変化するWebページへの対応

最近のWebサイトでは、ReactやVue、Next.jsなどを使ったSPAも一般的です。

こうしたページでは、URLを開いた直後にすべてのHTML要素が存在するとは限りません。

例えば、通知から特定のノートを開こうとしても、対象となるボタンがまだ描画されていないことがあります。

そこで、NoteLinkでは MutationObserver を利用しています。

対象要素がすぐに見つからない場合はDOMの変化を監視し、要素が表示されたタイミングでピンやノートを表示します。

対象が現れない場合に備えて、監視にはタイムアウトも設けています。

実装自体は特別なものではありませんが、こうした対応を組み合わせることで、動的なWebページでも使いやすくなるようにしています。

4. データの暗号化と検索のバランス

もうひとつ考えたのが、ノートに保存される情報の扱いです。

NoteLinkはチームで利用することを想定しているため、業務に関するコメントや修正指示などが含まれる可能性があります。

そこで、ノート本文やコメント本文は、バックエンド側でAES-256-GCMによって暗号化してからMySQLに保存しています。

ただ、暗号化すると別の問題が出てきます。

暗号化した本文は、MySQLの LIKE や FULLTEXT でそのまま検索できません。

そこで現在は、APIから取得したノートを認証済みユーザー向けに復号し、拡張機能側のメモリ上で検索する方式にしています。

これなら、検索キーワードの入力に合わせて結果をすぐに絞り込めます。

一方で、ノート数が大幅に増えた場合は、取得件数やメモリ使用量が課題になります。

セキュリティと使いやすさをどう両立させるか。

個人開発でも、こうした設計上のトレードオフは避けて通れません。

なお、Webページの本文全体やフォームの入力値を収集してサーバーに送る設計にはしていません。

ノート作成に必要なURL、ページタイトル、対象要素のセレクター、ユーザーが入力したノート内容などを扱っています。

5. Manifest V3での通知処理

NoteLinkでは、メンションなどの通知機能も実装しています。

Chrome拡張のManifest V3では、Background Service Workerが常に起動しているわけではありません。

そのため、常駐を前提とした setInterval() による監視には向いていません。

そこで chrome.alarms を利用し、一定間隔で未読通知を確認する方式にしています。

現在は1分間隔でAPIを確認し、未読があれば拡張機能のアイコンバッジやデスクトップ通知に反映しています。

WebSocketなどによる完全なリアルタイム通知ではありませんが、NoteLinkの用途を考えると、まずはこの構成で運用しています。

メンション通知や拡張機能の通知バッジが分かる画面
demo_notification.gif

どんな場面で使えるのか?

開発当初は、Webサイトの制作やレビュー業務を強く意識していました。

ただ、考えていくうちに、それ以外にも使い道がありそうだと感じています。

Webサイトの制作・レビュー

デザイナー、エンジニア、ディレクター間での修正依頼やフィードバック。

スクリーンショットを何枚も撮る代わりに、対象箇所に直接コメントを残せます。

業務システムの操作確認

管理画面や業務システムの特定の入力項目、ボタン、表示内容について、チーム内で確認できます。

「どの画面の、どの項目の話なのか」が伝わりやすくなります。

情報収集・調査

Web上で見つけた情報について、気になった箇所にメモを残したり、チームで意見を交換したり。

単にURLをブックマークするだけでなく、ページ内の特定箇所を起点に情報を共有できます。

学習・ナレッジ共有

技術ドキュメントや解説記事を読みながら、補足情報や疑問点を残す使い方も考えられます。

Webページそのものが、ちょっとした共有ノートになるイメージです。

もちろん、すべての用途に最適なツールだとは思っていません。

ただ、Webページ上で「ここについて話したい」という場面は、想像以上に多いのではないかと感じています。

AI時代の個人開発について、少しだけ

今回のNoteLinkを作りながら、改めて感じたことがあります。

AIによって、個人開発のハードルは確実に下がっているということです。

これまでは、アイデアが浮かんでも、調査して、設計して、実装して、テストして……と考えるうちに、なかなか着手できないこともありました。

今はAIを活用することで、最初の一歩を踏み出すまでの時間がかなり短くなっています。

もちろん、AIが書いたコードが常に正しいわけではありませんし、設計やセキュリティ、運用まで任せきりにはできません。

ただ、試せるアイデアの数が増えたのは間違いありません。

エンジニアとして長く仕事をしていると、AIの進化に少し焦りを感じる瞬間もあります。

でも、それ以上に、自分の経験とAIを組み合わせることで、以前より自由にものづくりができるようになったと感じています。

思いついたものを、自分の手で動くサービスにできる。

今は、その楽しさを改めて実感しています。

ひとまず、公開しました。

NoteLinkは、2026年9月にChrome拡張機能として公開しました。

スクリーンショット 2026-10-14 11.46.41.png
スクリーンショット 2026-10-14 11.48.00.png

個人開発なので、企画から設計、開発、公開まで、試行錯誤の連続でした。

AIのおかげで開発のスピードは上がりましたが、作っている途中で新しいアイデアが浮かんだり、当初は想定していなかった課題が見つかったり。

気づけば、最初に考えていたものよりも少し大きなサービスになっていました。

とはいえ、公開したら完成というわけでもありません。

むしろ、ここからが本番だと思っています。

実際に使っていただいた方の意見を取り入れながら、少しずつ育てていきたいです。

おわりに

Webページを見ていて、気になったところにコメントを残す。

それを誰かと共有して、必要ならそのまま会話する。

文章にすると、ごく普通のことのように思えます。

でも、普段のWeb閲覧の中でそれを自然に実現しようとすると、意外と考えることがたくさんありました。

CSSセレクターによる位置管理、Shadow DOMによるUIの分離、動的なDOMへの対応、データの暗号化。

どれも特別に新しい技術というわけではありませんが、目的に合わせて組み合わせていく過程は、なかなか面白いものでした。

そして、AIによってその試行錯誤を以前より速く回せるようになったことも、今回の開発では大きな変化でした。

Webページを「見る場所」から、「コミュニケーションが生まれる場所」へ。

少し大げさに聞こえるかもしれませんが、目指しているのはそんな世界です。

興味を持っていただけたら、ぜひ一度触ってみてください。

また、Chrome拡張の開発経験がある方や、似たような課題を感じている方がいれば、コメントで意見をいただけるとうれしいです。

今後は、Chrome拡張の実装や設計で工夫した部分についても、もう少し詳しく紹介していこうと思います。

1
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
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?