Upgrade to Pro — share decks privately, control downloads, hide ads and more …

はてなCMSでFigmaを取り込むシステムに使われている技術

Sponsored · Your Podcast. Everywhere. Effortlessly. Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
Avatar for NanimonoDemonai NanimonoDemonai
November 29, 2025
94

 はてなCMSでFigmaを取り込むシステムに使われている技術

Kyoto.js 24

Avatar for NanimonoDemonai

NanimonoDemonai

November 29, 2025
Tweet

More Decks by NanimonoDemonai

Transcript

  1. ౰࣌ͷઌߦࣄྫௐࠪ • FigmaΛHTMLʹ͢ΔͨΊͷɺϧʔϧϕʔεͷΦʔϓϯιʔε͕͋Δ • Coding AgentͰFigma৯ΘͤΕ͹ɺHTMLͱCSSΛॻ͍ͯ͘ΕΔ • Gemini 2.5 Proʹ৯ΘͤΕ͹ɺHTMLͱCSSΛԠ౴ͯ͘͠ΕΔ

    • ௐࠪͷ੒Ռͱͯ͠ϓϩϯϓτҰൃͰม׵͢ΔPOC΋࡞ͬͯɺօͷධՁ΋্ʑ 9 ઌߦࣄྫΛ͋ͨͬͯΈΔͱ… ͔͠͠ɺAIʹ͓೚ͤͰ͸͏·͍͔͘ͳ͔ͬͨ
  2. Agentic Work fl owΛࢧ͑Δٕज़ 13 Agent Framework Agent Runtime Agent

    Harness • LangChain.js :͞·͟·ͳAIαʔϏεΛ౷Ұͨ͠ΠϯλʔϑΣʔεͰѻ͑Δ • αʔϏεΛந৅Խ͢ΔͨΊͷϨΠϠʔ https://blog.langchain.com/agent-frameworks-runtimes-and-harnesses-oh-my/ • LangGraph.js: ΤʔδΣϯτͷ಺෦ঢ়ଶΛ؅ཧ͢Δ • ReactͰ͍͏ͱ͜ΖͷReduxͳͲͷεςʔτ؅ཧϥΠϒϥϦͷงғؾ • Deep Agents: جຊతͳΤʔδΣϯτΛ࡞ΔͨΊͷϑϨʔϜϫʔΫ
  3. Figma࿈ܞ͸࠷ऴతʹͲ͏࡞ΒΕ͍ͯΔΜ͚ͩͬʁ • LangGraph.jsΛ༻͍ͨAgentic Work fl ow • LangChain.jsͰݺͼग़͍ͯ͠ΔAIαʔϏε ͸Vertex AI

    (Gemini 2.5 pro) • ΞʔΩςΫνϟ͸Re fl ectionͱݺ͹ΕΔ΋ ͷͰɺAIʹࣗ਎ͷग़ྗΛ൑ఆͤ͞ɺظ଴͢ Δग़ྗΛಘΒΕΔ·Ͱग़ྗΛॻ͖௚ͤ͞Δ ࢓૊Έ 14 ·Ί͖ͪ͠ ਪ࿦ʹ͸͕͔͔࣌ؒΔ͔Βɺ"QQͷ֎Ͱಈ͔͍ͯ͠·͢ "NB[PO424ͰΩϡʔΠϯά͍ͯ͠Δ
  4. Server-Sent Eventsͷ࣮૷ 21 async function * readPolling(readKey: string) { const

    encoder = new TextEncoder(); while (true) { const code = await getCodeForReadKey(readKey); if (code.type = = = 'pending') { yield encoder.encode('event: pending\ndata: pending\n\n'); await sleep(1000); continue; } if (code.type = = = 'expired') { yield encoder.encode('event: expired\ndata: expired\n\n'); return; } if (code.type = = = 'denied') { yield encoder.encode('event: denied\ndata: denied\n\n'); return; } if (code.type = = = 'success') { yield encoder.encode(`event: success\ndata: ${code.code}\n\n`); return; } return; } } • ͜Μͳײ͡ͷδΣωϨʔλ ؔ਺Λ༰қ͢Δ
  5. Server-Sent Events 22 export function GET(request: NextRequest) { const searchParams

    = request.nextUrl.searchParams; const readKey = searchParams.get('readKey'); if (!readKey) { return new Response('bad request', { status: 400 }); } const iterator = readPolling(readKey); const stream = iteratorToStream(iterator); request.signal.onabort = async () = > { await clearReadKey(readKey); }; return new Response(stream, { headers: { 'Content-Type': 'text/event - stream', 'Cache-Control': 'no - cache, no - transform', 'Connection': 'keep - alive', 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS', 'Access-Control-Allow-Headers': 'Content-Type, Authorization', }, }); } function iteratorToStream(iterator: AsyncGenerator<Uint8Array>) { return new ReadableStream({ async pull(controller) { const { value, done } = await iterator.next(); if (done) { controller.close(); } else { controller.enqueue(value); } }, }); } • Next.jsͳΒ͹ɺ RouteϋϯυϥʹδΣω Ϩʔλؔ਺Λ ReadableStreamʹม׵͠ ͨ΋ͷΛ౉ͯ͠΍Ε͹׬੒
  6. Figma to ͸ͯͳCMSʹ͓͚ΔServer-Sent Eventsͷ۩ମతͳར༻γʔϯ • ೝূϑϩʔͰͷϙʔϦϯά • FigmaϓϥάΠϯ͔ΒͷOIDCೝূετϦʔϜʹ͓͍ͯɺreadKeyʹอଘ͞Εͨೝ ূίʔυͷঢ়ଶΛϙʔϦϯά͢Δͷʹར༻ •

    ม׵݁ՌͷετϦʔϛϯά͸΍͍ͬͯͳ͍΋ͷͷ… • ͔͠͠ɺServer-Sent Events͸AI͕ੜ੒ͨ͠ίʔυยΛϢʔβʔʹܧଓతʹૹ৴ ͠ϦΞϧλΠϜʹ൓ө͢Δ͜ͱʹΑ͘࢖ΘΕΔٕज़ 23 Next.jsͰ؆୯ʹServer-Sent EventsΛ࡞Δํ๏͕ݟ͔ͭͬͨͷͰɺ ࠓޙ׆༻͍͖͍ͯͨ͠