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

Generate React Component with TypeScript AST

Yosuke Kurami
November 18, 2021

Generate React Component with TypeScript AST

Yosuke Kurami

November 18, 2021
Tweet

More Decks by Yosuke Kurami

Other Decks in Programming

Transcript

  1. ݸਓతͳ OSS works - storycap reg-suit: StorybookΛ༻͍ͨVisual Regression Testing πʔϧ܈

    - tsuquyomi: TypeScript Language Server ͷ Vim client - ts-graphql-plugin: TypeScript Client ޲͚ͷGraphQL ։ൃ༷πʔϧ܈ - typed-css-modules: CSS Modules Λ TypeScriptͰѻ͏ͨΊͷϢʔςΟϦςΟ
  2. ݸਓతͳ OSS works - storycap reg-suit: StorybookΛ༻͍ͨVisual Regression Testing πʔϧ܈

    - tsuquyomi: TypeScript Language Server ͷ Vim client - ts-graphql-plugin: TypeScript Client ޲͚ͷGraphQL ։ൃ༷πʔϧ܈ - typed-css-modules: CSS Modules Λ TypeScriptͰѻ͏ͨΊͷϢʔςΟϦςΟ ஌ࣝɾڵຯ͕UTʹภ͍ͬͯΔ
  3. ࠓ೔࿩͢͜ͱ - ࠓ೔΋ࠓ೔ͱͯ TypeScript ͷ࿩ - QuramyࢀըதͷελσΟαϓϦϓϩδΣΫτ: Next.js + TypeScript

    + GraphQL ͳ ΞϓϦέʔγϣϯ ※ Web෦෼ʹݶΔ. ผ్ωΠςΟϒApp΋͋Δ - ϓϩδΣΫτͰ࣮ࢪ͍ͯ͠Δ Figma -> React Component (TSX) ͷࣗ ಈੜ੒෦෼ʹ͍ͭͯ঺հ
  4. σβΠϯγεςϜ - ݱࡏࢀը͍ͯ͠ΔϓϩδΣΫτͷσβΠϯγεςϜͷಛ௃ - Designer ͕ Figma Ͱ؅ཧ ※ Figma

    ʹରԠ͢Δ࣮૷ʹ͍ͭͯ͸ Web Devs / Native app Devs ͷ੹຿ - ίϯϙʔωϯτࢤ޲ - Atomic Design ϕʔε
  5. Design Token ͱ͸ - ͦΕࣗ਎͸UIཁૉʹͳΓ͑ͳ͍͕ɺͦΕͳͯ͘͠σβΠϯγεςϜΛ࣮ ݱͰ͖ͳ͍ߏ੒෺ͷ͜ͱ - e.g. ৭ม਺΍λΠϙάϥϑΟͳͲ -

    Extended Atomic Design Ͱ͸ Atoms ΑΓ΋ͳ͓ԼҐͷଘࡏ - (༨ஊ) ߏจղੳͰ΋ʮ͜ΕҎ্෼ղෆՄೳͳจࣈྻʯͱ͍͏ҙຯͰ token ͱ͍͏ݴ༿͕Ͱͯ͘Δ
  6. Design Tokenͷҙٛ - Token ͸ϓϥοτϑΥʔϜʹґଘ͠ͳ͍ ϓϩμΫτσβΠϯͷࠜݩ - TokenΛϓϥοτϑΥʔϜݻ༗ͷݴޠ (React ΍

    Kotlin) ʹ຋༁ɾม׵ͯ͠ར༻͢Δ͜ͱͰɺ Ұ؏ੑͷ͋ΔσβΠϯͱͳΔ - ࣗಈੜ੒ͱ૬ੑ͕ྑ͍ UI Component for PC Web UI Component for Android Token Automatic Compilation
  7. Token Kinds Web ΞϓϦέʔγϣϯʹ͓͚Δ Design Token ࣮ݱखஈ(Ұྫ) छྨ ࣮૷ܗଶ $PMPS4IBEPX(VUUFS

    $44$VTUPN1SPQFSUJFT PS +BWB4DSJQUDPOTUBOU $44JO+4 5ZQPHSBQIZ $44!GPOUGBDF  MJOFIFJHIUGPOUTJ[FQSPQT *DPOPHSBQIZ 47(pMFPS*OMJOF47(PS8FC'POUTFUD
  8. Token Kinds Web ΞϓϦέʔγϣϯʹ͓͚Δ Design Token ࣮ݱखஈ(Ұྫ) छྨ ࣮૷ܗଶ $PMPS4IBEPX(VUUFS

    $44$VTUPN1SPQFSUJFT PS +BWB4DSJQUDPOTUBOU $44JO+4 5ZQPHSBQIZ $44!GPOUGBDF  MJOFIFJHIUGPOUTJ[FQSPQT *DPOPHSBQIZ 47(pMFPS*OMJOF47(PS8FC'POUTFUD
  9. Iconography Token - ৭ม਺΍ϑΥϯτάϦϑͱಉ༷ʹΞΠίϯΛߏ੒͢Δύε৘ใ΋ Design Token - ϓϩδΣΫτͰ͸ɺWeb Ͱͷ Token࣮૷ܗଶͱͯ͠

    Inline SVGΛબ୒ - Atoms Component͔Β࢖͍΍͍͢Α͏ʹɺIconography Tokenࣗମ΋ React Componentͱ࣮ͯ͠૷
  10. Iconography Token via React - ྫ: υϩοϓμ΢ϯϦετ - ҙຯΛ࣋ͭ࠷খUI୯Ґ͸ υϩοϓμ΢ϯ

    ▼ ෦෼ͷ SVG ୯ମʹҙຯ͸ແ͍ Iconography Token Dropdown Component (Atoms) import { Down } from "../../tokens/Iconography/Common" export function Dropdown() { return ( <> {/* தུ */} <Down /> </> ) }
  11. import { css } from '@emotion/react' import { assertNever }

    from 'assert-never' import { gray } from '../../colors' import { IconSize } from '../../sizing' export type Props = { readonly iconType: 'Outlined' | 'Filled' readonly css?: JSX.IntrinsicAttributes['css'] readonly size: IconSize } export function Home(props: Props) { const { iconType, size } = props const cssObj = (props as any).className ?? css` fill: ${gray[500]}; ` switch (iconType) { case 'Filled': { return ( <svg xmlns='http://www.w3.org/2000/svg' width={size} height={size} viewBox='0,0,24,24' css={cssObj}> <path d='M14 19a1 1 0 0 1-1 1h-2a1 1 0 0 1-1-1v-3a2 2 0 0 1 4 0v3Zm9.578-8.797.01-.016-11-8.002-.128-.065-.108-.055a.985.985 0 0 0-.7 fillRule='evenodd' /> </svg> ) } case 'Outlined': { return ( <svg xmlns='http://www.w3.org/2000/svg' width={size} height={size} viewBox='0,0,24,24' css={cssObj}> <path d='M20 19.994h-5v-4a3 3 0 0 0-6 0v4H4V10.05l8-5.818 8 5.818v9.945Zm-9 0v-4a1 1 0 0 1 2 0v4h-2ZM23.578 10.2l.01-.015-11-8-.128-. fillRule='evenodd' /> </svg> ) } default: return assertNever(iconType) } } Iconography Token Component ͷத਎
  12. Why inline SVG? ଞํࣜͱൺֱ͢ΔͱɺInline SVG ͕ Icon Tokenͷ࣮૷ʹ࠷΋ద͍ͯ͠Δ ํ๏ QSPTDPOT

    JNH 47(pMF  'JHNB͔ΒҰׅͰ47(ϑΝΠϧΛFYQPSU͢Δ͚ͩ  ৭Λมߋ͢Δͷ͕༰қͰ͸ͳ͍ %FTJHO5PLFOͱͯ͠க໋త 8FC'POUT  ७ਮʹ໘౗  ςΩετͱͯ͠ղऍ͞ΕΔͨΊɺҙਤͤ͵࠷దԽ͕ͳ͞ΕΔ ಛʹXFCLJUܥ *OMJOF47( 3FBDU$PNQPOFOU  5SFF4IBLBCMF  ͱ͸͍͑໰୊͕ແ͍Θ͚Ͱ͸ͳ͍˞ޙड़
  13. Figma to TSX (खಈ) - Figma͔ΒSVGίʔυΛίϐϖ - svgo Ͱѹॖ, svg2jsx

    Ͱ JSXԽ - ΤσΟλʹషΓ෇͚ͨޙɺ΋Ζ΋ΖΛ੔ ͑ͯอଘ
  14. Figma to TSX (ࣗಈ?) - Figma͔ΒSVGίʔυΛίϐϖ - svgo Ͱѹॖ, svg2jsx

    Ͱ JSXԽ - ΤσΟλʹషΓ෇͚ͨޙɺ΋Ζ΋ΖΛ੔ ͑ͯอଘ 'JHNB"1*Ͱ47(&YUSBDU ΋Ζ΋Ζʜ
  15. <svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> <mask id="a" style="mask-type:

    alpha” maskUnits="userSpaceOnUse" x="1" y="1" width="22" height="22"> <path fill-rule="evenodd" clip-rule="evenodd" d=“…” fill="#808D96" /> </mask> <g mask="url(#a)"> <path fill-rule="evenodd" clip-rule="evenodd" d=“…” fill="#808D96" /> </g> <path fill-rule="evenodd" clip-rule="evenodd" d=“…” - ΫϦοϐϯάϚεΫ͕ id + URL ܗࣜͰࢀর͞ΕΔ - Inline SVG ͱͯ͠ల։͢Δ৔߹ɺdocument શମͰৗʹ ҰҙͰ͋Δ͜ͱΛ୲อ͢Δඞཁ͕͋Δ - ( <label htmlFor=“…”> ͷѻ͍͕໘౗ͳͷͱಉ͡)
  16. const id = useId() return ( <svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0

    0 24 24"> <mask id={id} style="mask-type: alpha” maskUnits="userSpaceOnUse" x="1" y="1" width="22" height="22"> <path fill-rule="evenodd" clip-rule="evenodd" d=“…” fill="#808D96" /> </mask> <g mask={`url(#${id})`}> <path fill-rule="evenodd" clip-rule="evenodd" d=“…” fill="#808D96" /> </g> <path fill-rule="evenodd" clip-rule="evenodd" d=“…” - id஋ͷॏෳΛ๷͙ʹ͸ɺComponent ͷඳը࣌ʹಈతʹ ൃ൪͢Δඞཁ͕͋Δ ※ ಉ࣌ʹಉ͡ SVG ͕ෳ਺ඳը͞Εͨ৔߹΋ߟྀ͠ͳͯ͘͸ͳΒͳ͍ͨΊ - நग़ͨ͠SVG ʹ id ଐੑ/ࢀরؚ͕·Ε͍ͯΔ৔߹ɺ౰ ֘ͷ id ଐੑΛJSXࣜʹஔ׵͢ΔରԠ͕ඞཁʹ
  17. Figma to TSX (ࣗಈ) - Figma͔ΒSVGίʔυΛίϐϖ - svgo Ͱѹॖ, svg2jsx

    Ͱ JSXԽ - ΤσΟλʹషΓ෇͚ͨޙɺ΋Ζ΋ΖΛ੔ ͑ͯอଘ 'JHNB"1*Ͱ47(&YUSBDU JEͷ݅Ҏ֎ʹ΋ࡉʑͨ͠มߋ͕৭ʑඞཁ  QBUIཁૉͷpMMଐੑΛDVSSFOU$PMPSʹ  DMBTT/BNFଐੑΛ௥Ճ  WJFX#PYΛἧ͑Δ  FUD
  18. AST Transformation via TS - XML ͱͯ͠ͷม׵Ͱ͋Ε͹ɺDOM APIͰे෼࣮ݱՄೳ (i.e. XSLT)

    - ઌͷ URL referenceͳͲɺJSXࣜͱͳΔͱͦ͏͸͍͔ͳ͍ - ࣮͸ TypeScript ୯ମͰͰ͖ͯ͠·͏ - parse( string -> ts.Node) : ts.craeteSourceFile - ASTม׵(ts.Node -> ts.Node): ts.transform - unparse(ts.Node -> string): ts.createPrinter().printFile
  19. AST Transformation via TS - TS Compiler APIʹΑΔ AST ม׵ίʔυ

    - Try with Playground! export function transform(src: ts.Node) { const factory: ts.TransformerFactory<ts.Node> = (ctx) => { const visitor = (node: ts.Node): ts.Node | undefined => { // ͜͜ʹ node ʹର͢ΔॲཧΛॻ͍͍ͯ͘ } return (node) => ts.visitEachChild(node, visitor, ctx) } const result = ts.transform(src, [factory]) return result.transformed[0] }
  20. ͜͜·Ͱͷ·ͱΊ - Inline SVG Λඳը͢Δ React ComponentͰ Iconography TokenΛ࣮ݱ͠ ͍ͯΔΑ

    - Iconography Token Component ͸ Figma API Λ࢖ͬͯࣗಈੜ੒͍ͯ͠ ΔΑ - ͜·͝·ͨ͠ཁ͕݅৭ʑ͋Δ͚ͲɺAST ม׵Ͱؤு͍ͬͯΔΑ