<vue.js>scrapboxの複数ページを検索できるpwa


追記

公式の方で対応されました
Scrapbox最新情報2019/12 (daiiz)

この記事のpwaはもう使われることはないと思いますが、しばらく残しておきます。

元の記事

scrapboxのページをまとめて検索したいと思ったことはありませんか?
私以外の需要も多そうだなと思い、scrapboxの複数ページを検索するpwaを作りました。
scrapまとめて検索

やりたいこと

現在、Scrapboxには複数のprojectを横断して検索する機能がありません。(project横断検索 -Scrapboxへの要望

各プロジェクトだけの検索はシンプルで良いものの、やっぱり同時検索もしたい。そう思って探した時、ちょうどよいツールがなかったので作りました。

ちなみに、その際見つけたのはChromeの拡張ツールで、Google検索の結果の横に常に表示してくれるものです。こちらもとっても便利です!Scrapbox同時検索

できること・できないこと

OK

指定した複数のプロジェクトの同時検索
検索対象プロジェクトのオンオフ切り替え
前回検索したプロジェクトの記憶
pwaとしてアプリのように使用可能

NG

プライベートリポジトリは検索不可
Scrapboxの構文パースは行いません

具体的な利用方法

上のgifも参照ください。

  1. 「+」ボタンを押して、検索したい対象のプロジェクト名を登録
  2. 検索ボックスに検索ワードを入力
  3. プロジェクトごとに最大30件ずつ取得。スクロールが面倒なら不要なプロジェクト名をタップすれば非表示にできます。
  4. 登録したプロジェクトはページを閉じても消えません。

※プロジェクト名が間違っている・プライベートプロジェクトであるなどの理由でアクセスできない場合はアラートが表示されます。その際は「-」ボタンから一度プロジェクトを削除して必要であれば正しい名前で再登録してください。下記は「MISSTYPO」という存在しないプロジェクト名を誤って登録したため、エラーが表示されている例です。

技術面の話

概要

とってもシンプルです。
サイトはfirebaseでHosting。ScrapboxのapiはCloud Functionsで中継しています。
Scrapboxの検索APIにご興味がある方はこちらを参照ください。(非公式です)
Scrapbox API -yuisekiより

環境

ubuntu
vue.js
firebase
Cloud Functions(外部APIと通信するため、FlameもしくはBlazeプラン)

開発の流れ

まずはCloud Functionsで中継する関数をつくりました。(一部省略)


const functions = require('firebase-functions');
const axios = require('axios');

exports.helloWorld = functions.https.onRequest((request, response) => {

    return axios.get(`https://scrapbox.io/api/pages/${request.query.pages}/search/query`, {
        params: {
            skip: 0,
            sort: "updated",
            limit: 30,
            q: request.query.searchword
        },
    })
    .then(res => {
        console.log(res.data);
        return response.status(200).json({
            message: res.data
        })
    })
});

この関数をfirebaseと紐付けて、サイトを作っていきます。今回はvue.jsを利用しました。紐付けたアプリのfirebase.jsonにrewritesを追加すると/helloにアクセスした際に上記のCloud functionsが呼び出されます。


"rewrites": [{
  "source": "/hello",
  "function": "helloWorld"
}]

検索ボックスから受け付けた入力を上記の関数に投げ、返ってきたデータは以下のようなオブジェクトに保存。このオブジェクトをlocalStrageに保存しておくことで次回起動時に再度プロジェクト登録からはじめる手間を省きます。

それぞれ、Scrapboxプロジェクトの名前、検索有効無効のboolean、データの中身です。

this.targetPages.push({
  targetPageName: "",
  active: true,
  items: {}
})

ちなみに、localStrageは1つのキーに対して1つのデータしか保存できないため、上記のようなオブジェクトを直接保存することはできません。そのため、JSON.stringify()で一旦文字列に変換してから保存しています。データをlocalStrageから取得する際はJSON.parse()で戻しています。

あとは取得したデータの見た目を整えて表示するだけです。(プロジェクトの追加や削除の実装は省略します...)表示非表示の実装は以下。

  <div class="pageWrapper" v-for="targetPage in targetPages" :key="targetPage.targetPageName">
    <div v-if="targetPage.active">
      <Project :projectitem="targetPage.items" />
    </div>
  </div>

pwa化は後から@vue/cli-plugin-pwaを利用して行いました。

その他

面白いScrapboxのプロジェクトを探したいという方へのリンクまとめです。

Scrapboxのプロジェクトがまとめられているページ

上記ページで紹介されている「おもしろそうな他人のScrapboxをみつける方法」

参考になるユニークなプロジェクト

公式PRページ

以上です。
ざっくりとしか実装を解説していないのですが、githubでそのうち公開&補足していく予定です。