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 full-size slide

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

    View full-size 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 full-size 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 full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size 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 full-size 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 full-size slide

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

    View full-size slide

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

    >
    )
    }

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  19. 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 full-size slide

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

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

    *OMJOF47(
    3FBDU$PNQPOFOU

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide



  25. 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 full-size slide

  26. 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 full-size slide

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

    View full-size slide

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

    View full-size slide

  29. AST Transformation
    https://astexplorer.net

    View full-size slide

  30. 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 full-size slide

  31. 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 full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide