InkdropのノートをAstroサイトに簡単に同期する方法

InkdropのノートをAstroサイトに簡単に同期する方法

InkdropのノートをAstroサイトに簡単に同期する方法

live-exportというノートをProgrammaticallyに出力するツールを作りました

こんにちは、Inkdrop作者のTAKUYAです。

僕はMarkdownのシンタックス拡張を必要とするような機能要望にノーと言い続けてきました。なぜならInkdropは ‘Markdown’のノートアプリであり、その普及率の高さによる利用可能性を最大限に活かせるように作っているからです。例えば、Markdownは多くの静的サイトジェネレータで広く採用されています。Astro、Gatsby、Jekyll、Hugoなどなど。御存知の通り、既に多くの人がMarkdownでブログ記事を書いています(より厳密にはGitHub-flavored Markdown)。つまり、それは技術ノートだけでなく技術記事の投稿にも適しているのです。

Inkdropはプラットフォームとデバイスをまたいでシームレスな体験を提供します。それによりどこでもMarkdownを閲覧・執筆できます。しかしながら、その同期機能のためにファイルシステムとの親和性を犠牲にしました。それがInkdropからブログ記事を投稿する妨げになっていました — — これまでは。ここで、live-exportをご紹介します。これは、ローカルのファイルシステムにProgrammaticallyにノートをエクスポートできるツールです。以下、詳しく説明していきます。

柔軟にファイルシステムで作業するための方法

なぜlive-exportが必要なのでしょうか?Inkdropはノートをメニューからエクスポートする機能を既に持っています。しかし、メタデータに従ってファイル名のフォーマットやディレクトリ構造、どのノートを出力するか否かなどを自由に決められません。live-exportは柔軟なAPIを提供することでその問題を解決します。更に、名前の通り、これはInkdrop内で変更がある度に ‘continuously(継続的)’ に出力します。それは、結果をブラウザで確認しながら記事が書けるということです。このように:

Live export demo

なかなか便利ではないでしょうか。今回に向けて、デモも用意しました。こちらは、Astroで構築した僕のブログです:

What I use — Takuya Matsuyama
As an indie developer, I’ve been spending hours and hours at my desk every day. So, I’ve been continuously improving my…

ソースコードはこちらにあります:

GitHub — craftzdog/craftzdog-uses: A curated list of the tech I use, built with Astro and Tailwind…
A curated list of the tech I use, built with Astro and Tailwind CSS https://uses.craftz.dog/ Watch how I built this…

いい感じでしょう :) 英語ですがYouTubeにチュートリアルもあります:

データやデザイン、デプロイ先まで全てコントロール可能

どのように動作するのでしょうか。live-exportはInkdrop内部で動くプラグインではありません。ターミナル上で別個に動作し、ローカルInkdropサーバ経由でノートのデータにアクセスします。

こちらがノートブックからノートをインポートするコードの例です:

import { LiveExporter, toKebabCase } from '@inkdropapp/live-export'
const liveExport = new LiveExporter({  username: 'foo',  password: 'bar',  port: 19840})
const sub = await liveExport.start({  live: true,  bookId: '<YOUR_BOOK_ID>',  // Pre-process the specified note. It is useful to update the frontmatter information based on the note metadata  preProcessNote: ({ note, frontmatter, tags }) => {    frontmatter.title = note.title    // Convert note title to kebab case (eg. "kebab-case-note-title")    frontmatter.slug = toKebabCase(note.title)    frontmatter.tags = tags.map(t => t.name)  },  // Generate a path to export the specified note  pathForNote: ({ /* note, */ frontmatter }) => {    // export only if it's public    if (frontmatter.public) {      return `./<PATH_TO_EXPORT_NOTES>/${frontmatter.slug}.md`    } else return false  },  // Generate a URL for the specified note. It is necessary to link from the note to another note  urlForNote: ({ frontmatter }) => {    if (frontmatter.public) {      return `/<URL_TO_LINK_NOTES>/${frontmatter.slug}`    } else return false  },  // Generate a path and URL to export the specified image file  pathForFile: ({ mdastNode, /* note, file, */ extension, frontmatter }) => {    if (frontmatter.slug && mdastNode.alt) {      const fn = `${frontmatter.slug}_${toKebabCase(        mdastNode.alt      )}${extension}`      const res = {        filePath: `./<PATH_TO_EXPORT_IMAGES>/${fn}`,        url: `./<URL_TO_LINK_IMAGES>/${fn}`      }      // If the `alt` attribute of the image is 'thumbnail', use it as a hero image      if (mdastNode.alt === 'thumbnail') {        frontmatter.heroImage = res.filePath      }      return res    } else return false  },  // Post-process the specified note right before writing the note to a file. It is useful to tweak the Markdown data  postProcessNote: ({ md }) => {    // Remove the thumbnail image from the Markdown body    const md2 = md.replace(/\!\[thumbnail\]\(.*\)\n/, '')    return md2  }})

ご覧の通り、live-exportはツール非依存であり、基本的にどの静的サイトジェネレータとも動作します。データからディレクトリ構造、サイトのデザイン、どこにデプロイするかも自由自在です。仮にInkdropを使うのをやめてしまっても、ブログ記事はgitリポジトリの中に存在し続けます。ノー・ロックインです。

テンプレートからブログを作成する

使用方法について学んでいきましょう。先述の通り、live-exportはローカルのInkdropサーバ経由でデータにアクセスします。まずはそれを有効化します。ユーザデータディレクトリにある config.cson を編集します。

  • macOS: ~/Library/Application Support/inkdrop/config.cson
  • Windows: %APPDATA%\inkdrop\config.cson
  • Linux(deb/rpm): ~/.config/inkdrop/config.cson
  • Linux(Snap): ~/snap/inkdrop/current/.config/inkdrop/config.cson

Inkdropを終了し、以下の行を追記します:

"*":  core:    server:      enabled: true      port: 19840      bindAddress: "127.0.0.1"      auth:        username: "foo"        password: "bar"

そしてアプリを再起動します。以下のコマンドを実行すれば、サーバが正しく動いていることを確認できます:

curl http://foo:bar@localhost:19840/# => {"version":"5.5.1","ok":true}

これでlive-exportを使う準備が整いました!ブログをすぐに作れるようにテンプレートを用意しました:

GitHub — inkdropapp/inkdrop-blog-template: A template for creating simple blogs with Inkdrop
A template for creating simple blogs using live-export.

このテンプレートはAstroで組まれています。Astroは静的サイトジェネレータの一つで、スピードに特化しています:

Astro | Build faster websites
Trusted by over 30,000 developers and world-class teams Your content, your way. Astro works with your favorite content…

テンプレートをあなたのディレクトリにcloneします:

git clone git@github.com:inkdropapp/inkdrop-blog-template.git ./your-blogcd ./your-blog

次に依存モジュールをインストールします:

npm install# Or, yarn install

そして、以下のような.env ファイルをプロジェクトのルートに作成してください:

DEBUG='inkdrop:export:info,inkdrop:export:error'INKDROP_USERNAME='foo'INKDROP_PASSWORD='bar'INKDROP_PORT=19840INKDROP_BOOKID='<BOOKID>'

ここで、出力したいノートブックのIDが必要になります。このIDを簡単に取得するには、dev-toolsというプラグインをインストールします。Preferences → Plugins/Installの画面からインストールしてください。

Install dev-tools

インストールできたら、早速目的のノートブックを右クリックして「Copy Notebook ID」を選択してください:

Copy a notebook ID

.env ファイルに戻り、コピーしたノートブックIDを貼り付けます。

DEBUG='inkdrop:export:info,inkdrop:export:error'INKDROP_USERNAME='foo'INKDROP_PASSWORD='bar'INKDROP_PORT=19840INKDROP_BOOKID='book:r8KUw7SBx'

よし、ではAstroのdev serverを立てましょう。

npm run start

ブログがhttp://localhost:3000/ で走っているはずです:

Dev server

ではブログ用ノートブックに新規ノートを作成しましょう。

Example post

ここで、ノートがYAML frontmatterという —--ブロックで始まっている事に注目してください:

---public: true---

public: true をそこで指定することで、live-exportはそのノートがエクスポート対象であると認識します。ではlive-exportを別のターミナルで実行しましょう:

npm run live-import
> inkdrop-blog-template@0.0.1 live-import> node --experimental-vm-modules tools/import.mjs
(node:59628) ExperimentalWarning: The Fetch API is an experimental feature. This feature could change at any time(Use `node --trace-warnings ...` to show where the warning was created)  inkdrop:export:info Exporting note: note:_F3VsSEhJ Convert mp4 to webm +0ms  inkdrop:export:info Watching changes.. +6ms

するとノートがファイルにインポートされ、以下のように新しい記事が見えるようになったはずです:

記事をクリックします:

live-exportが走っている間は、ほぼリアルタイムにInkdrop側の変更がブログ側に反映され続けます。

添付画像にも対応しています。一つ画像ファイルをノートに追加してみましょう。

---public: true---
![rocket](inkdrop://file:3Z5LUBZk5)
```shffmpeg -i masthead-bg.mp4 -c:v libvpx-vp9 -crf 30 -b:v 0 -b:a 128k -c:a libopus masthead-bg.webm```

すると、画像ファイルは <PROJECT_ROOT>/public/posts/配下に出力され、ブログ側にも画像が現れたはずです。しかし記事一覧にはまだ出てきません。この画像を記事のサムネイルとして使用したいですね。その場合は、画像のalt部分を “thumbnail” に変更します:

![thumbnail](inkdrop://file:3Z5LUBZk5)

すると、記事一覧にも画像が現れました!

次にノートにタグを追加してみましょう。ブログはノートに付与されたタグを自動で検出してページを生成してくれます。

ノートにタグを追加すると、タグ一覧ページ http://localhost:3000/tags にそれが現れたはずです。

もしタグが見えない場合は、live-exportを再実行してみてください。これであなたのブログを執筆する準備ができました。もちろん、ナビゲーションバーのロゴやタイトル、配色など全てあなたの好きにカスタマイズ可能です。エンジョーイ!

以下はいくつか想定されるFAQです。

どこに私のブログをデプロイすれば良いですか?

Astroのドキュメンテーションに詳しいガイドが記載されています。

ローカルサーバのアクセスログはどうやったら見れますか?

Inkdropを --enable-logging フラグを付加して実行してください。詳しくはドキュメンテーションを参照ください。

ノートをInkdropにインポートして戻せますか?

いいえ。live-exportはあなたのプロジェクトに合わせてノートを変形させます。よってInkdropとの互換性が失われます。

Read more

ノート駆動AIコーディング術の提案

ノート駆動AIコーディング術の提案

どうもTAKUYAです。みなさんはAIエージェントを普段のコーディングで活用されていますか。ちょっと面白いワークフローを思いついたのでシェアします。それは、ノート駆動のエージェンティック・コーディング・ワークフローです。最近Claude Codeのプランモードを使っていたら、ターミナル内で生成されたプランを読むのが辛かったんです。それで、じゃあMarkdownノートアプリであるInkdropをプランの保存先バックエンドとして使えば解決するんじゃないかと思って、 試してみました。こちらがそのデモです(英語): こちらがClaude Codeの設定ファイル群です: GitHub - inkdropapp/note-driven-agentic-coding-workflow at devas.lifeComplete Claude Code configuration collection - agents, skills, hooks, commands, rules, MCPs. Battle-tested configs from an Anthropic hackathon w

By Takuya Matsuyama
2025年個人開発活動の振り返り

2025年個人開発活動の振り返り

どうもTAKUYAです。もう1月も半ばに差し掛かっているけど、2025年の自分の活動の振り返りをしたい。去年を一言で言うなら、本厄を満喫した年だった。 厄年とは、人生の節目にあたって、体調不良や災難が起こりやすいと経験的に言われる年齢のこと。数え年で42歳、確かにもう若さに任せた事は出来ないなと痛感した年だった。(ところであなたの国ではこのような年はありますか?) 夏に体調を崩して2~3ヶ月動けなくなった 暖かくなり花粉が飛び出した頃に、持病のアトピーが悪化しだして、まともに生活出来なくなってしまった。酷さで言うと、2019年に脱ステした時と同じぐらい。 脱ステに無事成功したから、この地獄は二度と味わうことはないだろうと高を括っていたが、まさか7年後にまた味わうとは思わなかった。当時の独身時代と違い、妻も子供もいる中で、周りに多大な迷惑をかける事となった。夏の子供との思い出が全く無い。悲しい。 現在はQoLもほとんど元の状態まで復活できた。写真を撮って症状の変化を記録したので、機会があればシェアしたい。食事療法など色々試したが、結局歩くのが一番自分に効いた。それ以来、一日一万歩

By Takuya Matsuyama
書いて、歩け!なぜノートアプリはシンプルで充分なのか

書いて、歩け!なぜノートアプリはシンプルで充分なのか

どうもTAKUYAです。今回はノートやメモから新しい発想を生むための考え方についてシェアします。 自分はシンプルさをウリにした開発者向けのMarkdownアプリInkdropを作っています。なので、どうしても「ノートアプリの作者」としてのポジショントークが含まれてしまいますが、逆に言えば、「ノートアプリを約10年間作り続けてきた人間が、どうやってアイデアを生み出しているのか」 という実際的な体験談として読んでもらえれば幸いです。 結論から言うと、僕は「アプリ上でノート同士を連携させる必要はない。繋げるのはあなたの脳だ」と考えています。本稿では、ノートアプリの機能に溺れずユニークなアイデアを考え出すために僕が実践している事をシェアします。 TL;DR * ノート整理に時間をかけるな。グループ化で充分だ * すごい人はアイデアが「降りてくる」のを待つ * プログラミング × 料理動画 という有機的な掛け合わせ * ノートは「忘れる」ために書く * 歩け! ノート整理に時間をかけるな。グループ化で充分だ 巷ではZettelkastenなどが流行っているようですね。これ

By Takuya Matsuyama
貫禄を捨てて愛嬌で生き延びろ!40代オッサンの生存戦略

貫禄を捨てて愛嬌で生き延びろ!40代オッサンの生存戦略

どうもTAKUYAです。 つい先週(11月19日)に誕生日を迎え、41歳になりました。40代と言うのは若い頃には想像もしなかった年代で、どう生きれば良いのかというイメージがあまり具体的に湧かない、曖昧な年齢ではないでしょうか?自分の父親を想像するも、日中はいつも仕事でいなかったのであまり参考になりません。 自分は個人開発で生計を立てていて20代、30代で積み上げて来たものが上手く実を結んだおかげで今の生活があります。育児にも、いわゆるサラリーマンよりかは柔軟に参加できていて、子供との時間も沢山取れています。ママ友も出来ました(迷惑かけっぱなしですが)。 本記事では、そんなライフスタイルを送る自分が40代で大事にしたいことについて書きたいと思います。タイトルにもある通り、結論から言うとそれは「愛嬌」だと思います。以下、中年男性の愛嬌の重要性について説明します。 TL;DR * 「貫禄が出てきたね」と言われたら注意 * 笑顔を作れ。オッサンがムスッとしてたら普通に怖い * 謙虚に振る舞え。実績を積むと周りが萎縮する * ギャップ萌えを活用しろ 「貫禄が出てきたね」と言わ

By Takuya Matsuyama