DEV Community

SHOTA
SHOTA

Posted on

Building a Japanese-First Read-Later PWA: From Pocket Shutdown to Launch

When Mozilla shut down Pocket in July 2025, I lost my favorite tool. Worse, none of the English alternatives (Instapaper, Readwise, Matter, Raindrop) had Japanese UI, and their article extraction was mediocre on Japanese pages.

So I built one. It's called Readbox — Japanese-first, English-too, read-later as a PWA. Here's what I learned shipping it.

The stack

  • Next.js 15 App Router + TypeScript strict (no any)
  • Supabase (Postgres + Auth + RLS)
  • Stripe (JPY + USD prices, locale-routed)
  • Tailwind CSS
  • Service Worker for PWA install + offline read

Three things that bit me

1. Article extraction on Vercel serverless

First attempt: Mozilla Readability + jsdom. Doesn't bundle on Vercel because of ESM compatibility issues and the 50MB serverless function size limit. I tried 6 approaches — Webpack externals, dynamic imports, edge runtime — none worked cleanly.

Ended up using Jina Reader, which returns clean Markdown/HTML from any URL. Trade-off: third-party dependency, rate limits at scale. But it works today, and it's free.

2. Storing article body on-device

I didn't want to host millions of articles' worth of HTML on Supabase (cost + privacy). Solution: extracted HTML lives in the browser's IndexedDB only (via Dexie); only metadata (URL, title, tags, read status) syncs to the server.

Trade-off: cross-device sync of body content doesn't work seamlessly. Acceptable for a "read it later" workflow where you usually read on the device you saved on.

3. i18n routing — the silent sitemap killer

For Japanese + English from one codebase: app/[locale]/ segment with /en prefix for English (default Japanese has no prefix, to preserve old URLs).

Middleware detects cookie / Accept-Language and redirects accordingly.

The gotcha (cost me a launch-day hour): middleware matcher excludes _next, api, image extensions — but if you forget .xml/.txt/.webmanifest, sitemap.xml and robots.txt get rewritten to /ja/sitemap.xml (which doesn't exist as a route → 404).

Fix:

export const config = {
  matcher: [
    '/((?!api|_next|.*\\.(?:xml|txt|webmanifest|svg|png|jpg|jpeg|gif|webp|ico)$).*)',
  ],
};
Enter fullscreen mode Exit fullscreen mode

If you do i18n routing with metadata routes (sitemap/robots/manifest), put this in your test plan.

Where Readbox is now

Live with paid plans (¥450/mo, $3/mo, free for 100 articles). Pocket CSV import handles both 5-col legacy and 6-col new formats, up to 5,000 articles per batch.

If you migrated from Pocket, I'd love to hear what your read-later workflow looks like and what made you pick whatever you picked.

<!--

Publish 手順(しょうた手動、2 コマンド)

  1. このファイル全体を C:/job/S-hub/dev-to/articles/readbox-en-launch.md にコピー
    (上の HTML コメントブロック <!-- ... --> を含めて全文コピーで OK、
    Dev.to の Markdown レンダリングは HTML コメントを無視するので
    公開記事には表示されない。気になる場合はコピー後に削除)

  2. publish.mjs を実行(DEVTO_API_KEY を env で渡す):

   cd C:/job/S-hub/dev-to
   DEVTO_API_KEY=<あなたの devto API key> node publish.mjs
Enter fullscreen mode Exit fullscreen mode

期待動作:

  • publish.mjs が articles/ 配下の .md を順次スキャン
  • 本記事 frontmatter の devto_id: null を見て draft 作成 → devto_id 書き込み
  • publish_date "2026-05-28" が today (5/28) と一致するので即 published 化
  • 公開後、コンソールに Published! + 公開 URL が出力
  1. 公開された Dev.to URL を秘書 (3zzd1isy) に共有 → SNS 拡散発注(X/Bluesky/Threads の 5/29 JP slot に URL 添付)

補足

  • canonical_url は null(Dev.to をオリジナル扱い、Zenn は日本語独自記事として 並立、SEO 重複扱いされない)
  • tags は Dev.to 上限 4 個(javascript, nextjs, webdev, indiehackers)
  • cover image (main_image) は任意。Dev.to は記事 URL から OG 画像を自動 pull するので未設定 OK。設定する場合は readbox の OG エンドポイント https://readbox.dev-tools-hub.xyz/en/opengraph-image を main_image に
  • description (150 字以内) は Dev.to feed カード / 検索結果に表示される短文。 約 143 文字で設定済

トラブル対応

  • API key 不正なら 401 で fail → key 確認
  • tags 5 個以上だと 422 → tags を 4 個に切り詰め (既に 4 個で OK)
  • title が既存記事と完全一致だと 422 → Dev.to の draft list 確認
  • ネットワークエラー → publish.mjs は内部で retry 3 回 + 30s backoff、 それでもダメなら手動再実行で同じ devto_id を上書き更新可能 -->

Top comments (0)