マイクロROM研究クローンの構築


背景


アットDeta , 我々は、個々の開発者は、クラウド内の独自のツールを作成する権限を与える必要があります信じている.また、これらのツールを構築するためのツールは、これまで以上に親しみやすいです.以下は、私自身のツールを構築する説明です.Yarc , これを証明し、自分自身のワークフロー内でかゆみを掻く.
Roam Research “ネットワーク思考のためのツール”として自分自身を記述するノートアプリです.Roamは、堅い階層構造からノートを解放することを目指しますwhat they call 'the file cabinet approach' ) Evernoteのようなツールで.Roamを使用して、簡単かつ深くネットワークノートの高度なハイパーリンク機能を使用することができます.たとえば、任意の指定された注記では、1つは、すべての他のノート(バックリンク)を参照してください注記(双方向リンク)へのリンク.
私は個人的にロームでの双方向リンクが好きだったが、私は、フードを開くと、機能を追加する機能を追加すると、私は私のノートの生のテキストにアクセスAPIの上にアクセスするような軽量重量が欲しかった.私はRoamの双方向リンクを自分で提供したツールの多くの他の置換を見ましたObsidian , Foam ); 私自身のクローンyarc(さらに別のroamクローン)と名付けました.
YARCでは、私はこのプロジェクトがRoamのチームが何をしたかにマッチするように離れていると宣言していません.模倣はお世辞の最も誠実な形です、そして、RoamはYARCがすべてある可能性があるよりはるかに高度な能力を提供します.

プロジェクトデザイン


私は必要なのは、アプリケーションの単純な、3つの重要な部分から構成された

  • コア機能:ノートを書くための標準、それらを一意にアドレッシング、それらを双方向にリンク

  • バックエンド:バックエンドは、メモとその内容を提供するために必要なだけでなく、プロセスの更新

  • フロントエンド:クライアント/UIを簡単に表示し、ノートを更新する
  • コア機能


    まず、ノート自体のために、私は使用することを決めたMarkdown それは標準的な構文のコードスニペット、ハイパーリンク、写真、などのテキスト文書をサポートするための汎用性の組み込み、組み込みです.多くのツールの向こう側のMarkdownの途方もないサポートがあります.私がyarcからメモを移行する必要があるならば、他のツールを使用している主要な対立であるべきではありません.
    私がエミュレートしたかったRoamの基本的な特徴は、指示によって引き起こされた双方向指向のメモへの能力でした[[]] . 例えば、注意Aがテキストを含むならば:bla bla [[Note B]] , それから、AがメモBにリンクするのを注意してください、そして、メモBはバックリンクのそのリストで注意しなければなりません.そのためには、二つのことが必要でした.
  • 各ノート固有のアドレスを名前に関連付けられている必要がありますて
  • 処理方法[[name]] そのアドレスへのリンクとしてのタグ
  • YARCを駆動する原理は、MarkdownとHTMLがボックスからHTTPリンクをサポートしていることを認識しています.その結果、各メモにユニークなHTTPアドレスを与えることができました.:base_url/notes/:note_name ) HTMLとしてマークダウンノートをレンダリングする前に[[note_name]] リンク伝統的なマークダウンリンクに変換することによって[note_name](:base_url/notes/:note_name) , バックエンドのすべてのバックリンクを追跡しながら.
    すべてをユニークに認識する[[]] マークダウンノートのリンクで、私は短いJavaScript関数を書いた[[]] リンク.私たちはノートを保存すると、我々は現在のノート内のすべてのユニークなリンクへのバックリンクとして、現在のメモを追加するには、バックエンドを教えてください.
    const getUniqueLinks = rawMD => {
      const uniqueLinks = [...new Set(rawMD.match(/\[\[(.*?)\]]/g))];
      return uniqueLinks;
    };
    
    さらに、現在のリンクの配列を使用して、[[]] 通常のマークダウンリンクへのリンク[]() ) MarkdownをHTMLに変換する前に.
    この機能は、私たちのユニークなMarkdown[[]] タグと標準的なマークダウンを吐き出します
    const linkSub = (rawMD, links, baseUrl) => {
      let newMD = rawMD;
      for (const each of links) {
          let replacement;
          const bareName = each.substring(2, each.length - 2);
          replacement = `[${bareName}](${baseUrl}notes/${encodeURI(bareName)})`;
          newMD = newMD.split(each).join(replacement);
      }
      return newMD;
    };
    
    これらの2つの関数は、YARCのコアを形成します:ノートの双方向リンクのセットを認識して、我々が通常のMarkdown(HTMLに変換されることができる)に使用する構文を変えます.他のすべてのデータベース、ルート、およびUI一緒に結ぶことです.

    バックエンド:DETA + fastapi + Jinja 2


    バックエンド用には、

  • Deta Compute + APIとデータベースをホストするには

  • FastAPI 重いリフトを行うWebフレームワークとして

  • Jinja2 クライアントに提供するメモテンプレートを生成するには
  • データベース( DETA BASE )
    私は永続的なデータを格納するdeta基地を使用します.データベース操作は note.py 生のノートデータを読み書きするファイルとハンドル.ノートの基本的なデータスキーマはキー(ノートの名前のurlsafeバージョンです)の下に格納され、次のフィールドがあります
        name: str
        content: str
        links: list = []
        backlinks: list = []
    
    ルーティングと主な機能
    私は、DetaAPIアプリケーションを実行して、ユニークなURLでそれをホストするために、DETAマイクロを使いました.アプリケーションのルートとビジネスロジックを使用して構築されてFastAPI そして main.py . FastAPIは'マイクロフレームワーク'として説明されていて、SANEのデフォルトと低学習曲線の彼らの哲学はYARCを構築する迅速なプロセスに貢献するのに大いに役立ちました.Pythonを知っているなら、FastAPIでWebアプリケーションを構築することはとても簡単なプロセスです.
    yarcのバックエンドには三つの主要なルートと機能があります.

  • GET / : ホームページを返す

  • GET /notes/{note_name} : 指定された名前を持つ注記を返します.オプションのクエリパラメータを受け取りますjson=true を返します.

  • PUT /{note_name} : 注記ペイロードを受信、指定された音符のデータベースエントリを更新し、他のすべてのノートを(バックリンクのフィールドを更新する必要がある)にリンクします.
  • この3番目のルートでは、正しいリンクとバックリンクのメモを辿っていますが、ここではこの操作を含みます.
    @app.put("/{note_name}")
    async def add_note(new_note: Note):
        old_note = get_note(new_note.name) 
        old_links = old_note.links if old_note else []
        removed_links = list_diff(old_links, new_note.links)
        added_links = list_diff(new_note.links, old_links)
    
        for each in removed_links:
            remove_backlink(each, new_note.name)
    
        db_update_note(new_note)
    
        for each in added_links:
            add_backlink_or_create(each, new_note.name)
    
        return {"message": "success"}
    
    テンプレート
    使ったメモを出すJinja2 HTMLのファイルをメモデータとフロントエンドのJavaScriptコードをテンプレートにハイパーアプリで書かれています.モジュールとしてインポートする代わりにフロントエンドJavaScriptをテンプレートに注入することによって、すべてのページロードで1つのAPI呼び出しを保存しました.
    使用するライブラリ
  • FastAPI (w/ Pydantic)
  • Jinja2
  • bleach
  • フロントエンド



    私が使用したWebアプリのクライアント側についてHyperapp . HyperAppは超軽量(1 KB、ビルドなしステップ!)機能的、宣言的な方法で対話型アプリケーションを構築するためのフレームワーク.コンポーネントは、状態管理、DOMの説明、副作用を組み合わせた反応(+ redux)を使用して経験を持って、私はハイパーアプリは明確にそれらの概念(ビュー、アクション、エフェクト、およびサブスクリプション)を改行すると言うだろう.他のフレームワークと同様に、彼らの概念に慣れるために少しの学習があります、しかし、一旦あなたが彼らの上でハンドルを得るならば、それは働く喜びです.FastAPIのように、それはその名前に住んでおり、構築することができますし、便利なアプリケーションを超迅速に出荷します.
    ノートとの対話のために note.js ), HyperAppのアプリケーションには、エンドユーザーとして2つの主要な'モード'があります.

  • このモードでは、ノートの生のマークダウンが表示され、ユーザーがノートを書くことができます

  • 表示モード:このモードでは、ユーザーがリンクを次のように、HTMLとしてのメモが表示されます
  • 編集モード
    編集モードは、ユーザーがHyperAppで編集アクションを送信する編集ボタンをクリックするとトリガーされます.このアクションは、使用したテキストエディターをアタッチします.CodeJar , 正しいDOM要素に対して、UpdateContentを別のアクションにバインドし、テキストエディタの現在の状態をHyperAppの状態ツリーに保存します.
    // Edit Action
    const Edit = state => {
      const newState = {
        ...state,
        view: "EDIT"
      };
      return [newState,
        [attachCodeJar, { state: newState, UpdateContent }]
      ];
    };
    
    // attachCodeJar Effect
    const attachCodeJar = (dispatch, options) => {
      requestAnimationFrame(() => {
        var container = document.getElementById("container");
        container.classList.add("markdown");
    
        const highlight = editor => {
            editor.textContent = editor.textContent;
            hljs.highlightBlock(editor);
        };
    
        jar = CodeJar(container, highlight);
        jar.updateCode(options.state.note.content);
        jar.onUpdate(code =>
          dispatch(options.UpdateContent(options.state, code))
        );
    
      });
    };
    
    // UpdateContent Action
    const UpdateContent = (state, newContent) => {
      return {
        ...state,
        note: {
          ...state.note,
          content: newContent
        }
      };
    };
    
    表示モード
    ビューモードでは、ハイパーアプリで保存アクションをディスパッチし、2つの効果をトリガするボタンをクリックしてトリガされます:AttachMarkdownとUpdateDatabase.

  • attachMarkdown DOM要素からテキストエディタを削除し、使用している状態で最新のメモマークダウンを変換することからHTML出力で置き換えますShowdown .

  • updateDatabase 最新のメモのマークダウン、リンクを送信し、バックエンドにバックリンクには、APIの呼び出しを介してデータベースに保存します.
  • フロントエンド用のライブラリ
  • Hyperapp
  • highlightjs
  • Showdown
  • CodeJar
  • 概要


    The full source code of the project is here そして、ホームページのようなアプリケーションの他のビット、検索、およびCLI以上のノートとの対話が含まれます.また、命令を提供しますdeployment on Deta YARCの独自のインスタンスを展開する場合.
    そこに素晴らしいツールの数が非常に迅速に、ほとんどのオーバーヘッドで、独自のクラウドツールを構築できるようになります.DETAでは、コードを実行するために大規模なインフラストラクチャを提供しようとします.私は個人的にFastAPI(サーバー用)とHyperApp(クライアントのための)は、軽量、個人的なアプリを構築するための本当に相補的なフレームワークであることがわかりましたどちらも素晴らしい、大騒ぎ、何かを得るためにライティングクイックルートを提供するオプションです.