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. Generate React Component
    with TypeScript AST
    2021.11.18

    View Slide

  2. About me
    - Twitter/GitHub: @Quramy
    - ϦΫϧʔτͰWebϑϩϯτΤϯδχΞ΍ͬͯ·͢
    - ࠓ೥ͷ7݄ࠒ͔ΒελσΟαϓϦͷ࢓ࣄΛ͢ΔΑ͏
    ʹͳΓ·ͨ͠

    View Slide

  3. ݸਓతͳ 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Ͱѻ͏ͨΊͷϢʔςΟϦςΟ

    View Slide

  4. ݸਓతͳ 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ʹภ͍ͬͯΔ

    View Slide

  5. ࠓ೔࿩͢͜ͱ
    - ࠓ೔΋ࠓ೔ͱͯ TypeScript ͷ࿩
    - QuramyࢀըதͷελσΟαϓϦϓϩδΣΫτ:
    Next.js + TypeScript + GraphQL ͳ ΞϓϦέʔγϣϯ
    ※ Web෦෼ʹݶΔ. ผ్ωΠςΟϒApp΋͋Δ
    - ϓϩδΣΫτͰ࣮ࢪ͍ͯ͠Δ Figma -> React Component (TSX) ͷࣗ
    ಈੜ੒෦෼ʹ͍ͭͯ঺հ

    View Slide

  6. Agenda
    1. σβΠϯγεςϜͱ Iconography Token
    2. Iconography React Component ͷࣗಈੜ੒

    View Slide

  7. Agenda
    1. σβΠϯγεςϜͱ Iconography Token
    2. Iconography React Component ͷࣗಈੜ੒

    View Slide

  8. σβΠϯγεςϜ
    - ݱࡏࢀը͍ͯ͠ΔϓϩδΣΫτͷσβΠϯγεςϜͷಛ௃
    - Designer ͕ Figma Ͱ؅ཧ
    ※ Figma ʹରԠ͢Δ࣮૷ʹ͍ͭͯ͸ Web Devs / Native app Devs ͷ੹຿
    - ίϯϙʔωϯτࢤ޲
    - Atomic Design ϕʔε

    View Slide

  9. “Extended” Atomic Design
    https://bradfrost.com/blog/post/extending-atomic-design/

    View Slide

  10. Design Token ͱ͸
    - ͦΕࣗ਎͸UIཁૉʹͳΓ͑ͳ͍͕ɺͦΕͳͯ͘͠σβΠϯγεςϜΛ࣮
    ݱͰ͖ͳ͍ߏ੒෺ͷ͜ͱ
    - e.g. ৭ม਺΍λΠϙάϥϑΟͳͲ
    - Extended Atomic Design Ͱ͸ Atoms ΑΓ΋ͳ͓ԼҐͷଘࡏ
    - (༨ஊ) ߏจղੳͰ΋ʮ͜ΕҎ্෼ղෆՄೳͳจࣈྻʯͱ͍͏ҙຯͰ
    token ͱ͍͏ݴ༿͕Ͱͯ͘Δ

    View Slide

  11. Design Tokenͷҙٛ
    - Token ͸ϓϥοτϑΥʔϜʹґଘ͠ͳ͍ ϓϩμΫτσβΠϯͷࠜݩ
    - TokenΛϓϥοτϑΥʔϜݻ༗ͷݴޠ (React ΍ Kotlin) ʹ຋༁ɾม׵ͯ͠ར༻͢Δ͜ͱͰɺ
    Ұ؏ੑͷ͋ΔσβΠϯͱͳΔ
    - ࣗಈੜ੒ͱ૬ੑ͕ྑ͍
    UI Component for PC Web
    UI Component for Android
    Token Automatic Compilation

    View Slide

  12. Token Kinds
    Web ΞϓϦέʔγϣϯʹ͓͚Δ Design Token ࣮ݱखஈ(Ұྫ)
    छྨ ࣮૷ܗଶ
    $PMPS4IBEPX(VUUFS
    $44$VTUPN1SPQFSUJFT
    PS
    +BWB4DSJQUDPOTUBOU $44JO+4

    5ZQPHSBQIZ
    $44!GPOUGBDF
    MJOFIFJHIUGPOUTJ[FQSPQT
    *DPOPHSBQIZ 47(pMFPS*OMJOF47(PS8FC'POUTFUD

    View Slide

  13. Token Kinds
    Web ΞϓϦέʔγϣϯʹ͓͚Δ Design Token ࣮ݱखஈ(Ұྫ)
    छྨ ࣮૷ܗଶ
    $PMPS4IBEPX(VUUFS
    $44$VTUPN1SPQFSUJFT
    PS
    +BWB4DSJQUDPOTUBOU $44JO+4

    5ZQPHSBQIZ
    $44!GPOUGBDF
    MJOFIFJHIUGPOUTJ[FQSPQT
    *DPOPHSBQIZ 47(pMFPS*OMJOF47(PS8FC'POUTFUD

    View Slide

  14. Iconography Token
    - ৭ม਺΍ϑΥϯτάϦϑͱಉ༷ʹΞΠίϯΛߏ੒͢Δύε৘ใ΋
    Design Token
    - ϓϩδΣΫτͰ͸ɺWeb Ͱͷ Token࣮૷ܗଶͱͯ͠ Inline SVGΛબ୒
    - Atoms Component͔Β࢖͍΍͍͢Α͏ʹɺIconography Tokenࣗମ΋
    React Componentͱ࣮ͯ͠૷

    View Slide

  15. Iconography Token via React
    - ྫ: υϩοϓμ΢ϯϦετ
    - ҙຯΛ࣋ͭ࠷খUI୯Ґ͸ υϩοϓμ΢ϯ
    ▼ ෦෼ͷ SVG ୯ମʹҙຯ͸ແ͍
    Iconography Token
    Dropdown Component (Atoms)
    import { Down } from "../../tokens/Iconography/Common"
    export function Dropdown() {
    return (
    <>
    {/* தུ */}

    >
    )
    }

    View Slide

  16. Agenda
    1. σβΠϯγεςϜͱ Iconography Token
    2. Iconography React Component ͷࣗಈੜ੒

    View Slide

  17. PC Web Devs workflow
    ϓϩδΣΫτͰͷେ·͔ͳը໘։ൃϫʔΫϑϩʔ
    'JHNBͰ6*694QFD֬ೝ 3FBDU54Ͱ࣮૷ 4UPSZCPPLͰ֬ೝςετ

    View Slide

  18. View Slide

  19. ίΠπϥΛΰχϣΰχϣͯ͠
    3FBDU$PNQPOFOUʹͨ͠Ε

    View Slide

  20. 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 (

    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'
    />

    )
    }
    case 'Outlined': {
    return (

    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'
    />

    )
    }
    default:
    return assertNever(iconType)
    }
    }
    Iconography Token
    Component ͷத਎

    View Slide

  21. Why inline SVG?
    ଞํࣜͱൺֱ͢ΔͱɺInline SVG ͕ Icon Tokenͷ࣮૷ʹ࠷΋ద͍ͯ͠Δ
    ํ๏ QSPTDPOT
    JNH47(pMF
    'JHNB͔ΒҰׅͰ47(ϑΝΠϧΛFYQPSU͢Δ͚ͩ
    ৭Λมߋ͢Δͷ͕༰қͰ͸ͳ͍ %FTJHO5PLFOͱͯ͠க໋త

    8FC'POUT
    ७ਮʹ໘౗
    ςΩετͱͯ͠ղऍ͞ΕΔͨΊɺҙਤͤ͵࠷దԽ͕ͳ͞ΕΔ ಛʹXFCLJUܥ

    *OMJOF47(
    3FBDU$PNQPOFOU

    5SFF4IBLBCMF
    ͱ͸͍͑໰୊͕ແ͍Θ͚Ͱ͸ͳ͍˞ޙड़

    View Slide

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

    View Slide

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

    View Slide

  24. ʮ΋Ζ΋Ζʯ͕ॏཁ
    ͩͬͨΓ͢Δ

    View Slide

  25. id໰୊
    - Inline SVG ʹ͓͚ΔidଐੑͷऔΓѻ͍͸ཁ஫ҙ
    - ਺߲લͷʮͱ͸͍͑໰୊͕ແ͍Θ͚Ͱ͸ͳ͍ʯͷ෦෼

    View Slide



  26. fill-rule="evenodd"
    clip-rule="evenodd"
    d=“…”
    fill="#808D96"
    />


    fill-rule="evenodd"
    clip-rule="evenodd"
    d=“…”
    fill="#808D96"
    />

    fill-rule="evenodd"
    clip-rule="evenodd"
    d=“…”
    - ΫϦοϐϯάϚεΫ͕ id + URL ܗࣜͰࢀর͞ΕΔ
    - Inline SVG ͱͯ͠ల։͢Δ৔߹ɺdocument શମͰৗʹ
    ҰҙͰ͋Δ͜ͱΛ୲อ͢Δඞཁ͕͋Δ
    - ( ͷѻ͍͕໘౗ͳͷͱಉ͡)

    View Slide

  27. const id = useId()
    return (


    fill-rule="evenodd"
    clip-rule="evenodd"
    d=“…”
    fill="#808D96"
    />


    fill-rule="evenodd"
    clip-rule="evenodd"
    d=“…”
    fill="#808D96"
    />

    fill-rule="evenodd"
    clip-rule="evenodd"
    d=“…”
    - id஋ͷॏෳΛ๷͙ʹ͸ɺComponent ͷඳը࣌ʹಈతʹ
    ൃ൪͢Δඞཁ͕͋Δ
    ※ ಉ࣌ʹಉ͡ SVG ͕ෳ਺ඳը͞Εͨ৔߹΋ߟྀ͠ͳͯ͘͸ͳΒͳ͍ͨΊ
    - நग़ͨ͠SVG ʹ id ଐੑ/ࢀরؚ͕·Ε͍ͯΔ৔߹ɺ౰
    ֘ͷ id ଐੑΛJSXࣜʹஔ׵͢ΔରԠ͕ඞཁʹ

    View Slide

  28. Figma to TSX (ࣗಈ)
    - Figma͔ΒSVGίʔυΛίϐϖ
    - svgo Ͱѹॖ, svg2jsx Ͱ JSXԽ
    - ΤσΟλʹషΓ෇͚ͨޙɺ΋Ζ΋ΖΛ੔
    ͑ͯอଘ
    'JHNB"1*Ͱ47(&YUSBDU
    JEͷ݅Ҏ֎ʹ΋ࡉʑͨ͠มߋ͕৭ʑඞཁ
    QBUIཁૉͷpMMଐੑΛDVSSFOU$PMPSʹ
    DMBTT/BNFଐੑΛ௥Ճ
    WJFX#PYΛἧ͑Δ
    FUD

    View Slide

  29. AST Transformation
    ʮ΋Ζ΋ΖΛ੔͑ͯอଘʯΛݴ͍׵͑Δͱ:
    SVG ͷ໦ߏ଄Λ୳ࡧͭͭ͠ɺඞཁʹԠͨ͡ஔ׵ॲஔ
    - AST(Abstract Syntax Tree) Transformation ͦͷ΋ͷ
    - Babel ΍ swc ͕ߦ͍ͬͯΔ Transpile ॲཧ(.ts -> .js) ͱಉ͡ܥ౷ͷॲཧ

    View Slide

  30. AST Transformation
    https://astexplorer.net

    View Slide

  31. 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

    View Slide

  32. AST Transformation via TS
    - TS Compiler APIʹΑΔ AST ม׵ίʔυ
    - Try with Playground!
    export function transform(src: ts.Node) {
    const factory: ts.TransformerFactory = (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]
    }

    View Slide

  33. ͜͜·Ͱͷ·ͱΊ
    - Inline SVG Λඳը͢Δ React ComponentͰ Iconography TokenΛ࣮ݱ͠
    ͍ͯΔΑ
    - Iconography Token Component ͸ Figma API Λ࢖ͬͯࣗಈੜ੒͍ͯ͠
    ΔΑ
    - ͜·͝·ͨ͠ཁ͕݅৭ʑ͋Δ͚ͲɺAST ม׵Ͱؤு͍ͬͯΔΑ

    View Slide

  34. ΍ͬͯͯྑ͔ͬͨࣗಈੜ੒
    - Ұൠతʹίʔυੜ੒શൠʹݴ͑Δ͜ͱͰ͕͢
    - ७ਮʹ޻਺ͷ࡟ݮʹͭͳ͕Δ
    - Կेݸ΋React ComponentԽͨ͠ޙͰ΋मਖ਼͕༰қ
    - ϓϩδΣΫτΛ૸Βͤͳ͕ΒɺϝϯόʔͱʮIcon͸΍ͬͺΓ͜͏͍
    ͏Propsʹͨ͠ํ͕Α͍ʯͷΑ͏ͳٞ࿦Λͯ͠΋௧Έ͕গͳ͍

    View Slide

  35. Why AST?
    - ͜͜·Ͱͷ࿩ͰʮͦΕਖ਼نදݱͰे෼Ͱ͸ʯͱࢥͬͨਓ΋͍Δ͔΋͠Ε
    ͳ͍
    - ASTૢ࡞Λ஌͍ͬͯΔͱϑϩϯτΤϯυ։ൃͷ༷ʑͳγʔϯͰ༗༻
    - Project Specific ͳ ESLint rule ࡞੒, webpack custom loader (AoT
    Compilation), etc…

    View Slide

  36. Thank you !

    View Slide