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

人気サービスをFlutter Webでリプレースするとどうなるのか

Koji Wakamiya
November 16, 2022

人気サービスをFlutter Webでリプレースするとどうなるのか

FlutterKaigi 2022 Day 1 17:45~18:15

Koji Wakamiya

November 16, 2022
Tweet

More Decks by Koji Wakamiya

Other Decks in Technology

Transcript

  1. ਓؾαʔϏεΛFlutter WebͰ

    ϦϓϨʔε͢Δͱ
    Ͳ͏ͳΔͷ͔
    FlutterKaigi 2022
    @koji-1009/2022-11-16
    1

    View Slide

  2. ࣗݾ঺հ
    • एٶߒ࢘/@koji-1009(GitHub)


    • ελσΟϓϥεגࣜձࣾ


    • ϞόΠϧΫϥΠΞϯτνʔϜ ςοΫϦʔυ


    • Google for Startups Accelerator Mentor
    2

    View Slide

  3. ࣗݾ঺հ
    • FlutterʹUIͷϚΠΫϩαʔϏε։ൃΛಋೖ͠ɺ

    ѹ౗తͳDXΛ࣮ݱ͠Α͏ʂ


    • FlutterKaigi 2021 day 2


    • Flutter Webͷ։ൃΛߦ͏ͨΊͷ஌ݟʢϦϙδτϦ෼ׂʣ
    3

    View Slide

  4. ελσΟϓϥεגࣜձࣾ
    • Mission


    • ֶ
    ぶ
    ت
    び
    Λ͢
    べ
    ͯͷਓ΁


    • Value


    • Dive to Learn - ֶशऀͷͨΊʹ΍Ζ͏


    • Fail Forward -
    ど
    Μ
    ど
    Μࣦഊ͠Α͏


    • Far Together - ҧ͍ʹ׮༰
    で
    ͋Ζ͏
    4

    View Slide

  5. ελσΟϓϥεגࣜձࣾ
    • 2010೥૑ۀͷEdTechاۀ


    • αʔϏε


    • toC޲͚: Studyplus


    • toB޲͚: Studyplus for School
    5

    View Slide

  6. ελσΟϓϥεͱFlutter
    • 2019೥9݄ϦϦʔεͷPortoʹͯFlutterΛ࠾༻


    • Portoͷػೳ͸2021೥͔ΒStudyplusʹ౷߹


    • 2021೥12݄͔ΒStudyplusʹ΋Add-to-appͰར༻


    • 2023೥ʹKotlin/Swift͔ΒFlutter΁શ໘తʹҠߦ༧ఆ
    6

    View Slide

  7. ໨࣍
    • Flutter Webͷ঺հ


    • Flutter Webͷ࠾༻ࣄྫ


    • Flutter Webͷಛ௃


    • ׆༻ͷͨΊͷ޻෉


    • Flutter WebΛ࠾༻͢ΔͱͲ͏ͳΔ͔
    7

    View Slide

  8. Flutter Web
    8

    View Slide

  9. Flutter Web
    • Flutter 2.0.0͔Βstable



    fl
    utter build webίϚϯυʹΑΓSPAΛੜ੒


    • Dart੡ͷύοέʔδͰ͋Ε͹ར༻Մೳ


    • શͯͷύοέʔδ͕࢖͑ΔΘ͚Ͱ͸ͳ͍


    • Windowؔ਺΍JSϥΠϒϥϦΛಡΈࠐΜͰར༻Ͱ͖Δ΋ͷ΋͋Δ
    9

    View Slide

  10. Flutter Web
    • Navigator 2ͱ૊Έ߹ΘͤΔ͜ͱʹΑΓϒϥ΢βͷಈ࡞ʹରԠ


    • CanvasKitͱHTMLͷ2ͭͷϨϯμϦϯάϞʔυ


    • Flutter 3.3Ͱ͸SEOʹ՝୊ΞϦ


    • SSR΍SSG͸2022೥࣌఺Ͱਖ਼ࣜαϙʔτ͞Εͣ


    • ಈతͳΞϓϦέʔγϣϯ޲͚
    10

    View Slide

  11. https://docs.
    fl
    utter.dev/development/platform-integration/web/faq#search-
    engine-optimization-seo
    In general, Flutter is geared towards dynamic application
    experiences. Flutter’s web support is no exception. Flutter web
    prioritizes performance,
    fi
    delity, and consistency. This means application
    output does not align with what search engines need to properly index.
    For web content that is static or document-like, we recommend
    using HTML—just like we do on
    fl
    utter.dev, dart.dev, and pub.dev.
    You should also consider separating your primary application experience
    —created in Flutter—from your landing page, marketing content, and
    help content—created using search-engine optimized HTML.
    11

    View Slide

  12. Flutter Webͷ࠾༻ࣄྫ

    View Slide

  13. ࠾༻ࣄྫ
    • WebΞϓϦέʔγϣϯͷ։ൃʹFlutterΛ࠾༻


    • Ұ෦ͷސ٬޲͚ΞϓϦέʔγϣϯ͸ϦϦʔεࡁΈ


    • Ұൠ޲͚ͷΞϓϦέʔγϣϯΛ։ൃத


    • ϞόΠϧΫϥΠΞϯτνʔϜ͕։ൃΛओಋ


    • ςοΫϦʔυ + AndroidΤϯδχΞ 2໊ + iOSΤϯδχΞ 2໊
    13

    View Slide

  14. Flutter Web࠾༻ͷϞνϕʔγϣϯ
    • ϛογϣϯ΍Ϗδωε໨తͱ։ൃ্ͷ੍໿ͷဃ཭


    • ϓϥοτϑΥʔϜ͝ͱͷ։ൃ͸ຊ࣭తͳ໨తͰ͸ͳ͍


    • ΑΓૣ͘ɺΑΓ޿͍؀ڥʹ޲͚ͨαʔϏεల։


    • ΞΫηγϏϦςΟ


    • ݹ͍୺຤΍OSͰ΋ར༻Ͱ͖ΔαʔϏε΁
    14

    View Slide

  15. Flutter Webͷ࠾༻໨త
    • MobileͷΑ͏ʹWebΞϓϦέʔγϣϯ͕࡞ΕΔ


    • MobileΤϯδχΞ͕WebΞϓϦέʔγϣϯΛ։ൃͰ͖Δ
    15

    View Slide

  16. MobileͷΑ͏ͳWebΞϓϦέʔγϣϯ
    • WebΞϓϦέʔγϣϯʹMobileతͳίϯϙʔωϯτΛ࣋ͪࠐΊΔ


    • ListView΍ButtonɺSpinnerɺը໘ભҠͳͲ


    • LongTap΍Hoverঢ়ଶͳͲʹରԠ


    • Ϛ΢εɺࢦɺλονϖϯʹରԠ


    • Dark Theme΋ඪ४αϙʔτ
    16

    View Slide

  17. ෳ਺ϓϥοτϑΥʔϜʹରԠͰ͖ΔΤϯδχΞ
    • ΤϯδχΞͷ࠾༻͕ඇৗʹ೉͍͠


    • MobileΞϓϦέʔγϣϯ։ൃ͕Ͱ͖ΔΤϯδχΞ͸رগ


    • طଘϝϯόʔͷطଘεΩϧͷԆ௕ઢ্ͰWebʹରԠ͍ͨ͠


    • υϝΠϯ஌ࣝ΋े෼ͳͨΊɺ׆༂Ͱ͖Δૉ஍͸े෼ʹ͋Δ


    • (௕ظతʹ͸ҭ੒΍࠾༻Λ͢Δ΂͖)
    17

    View Slide

  18. Flutter Web΁ͷ఍߅ײ
    • Flutter Web΁औΓ૊Ή͜ͱࣗମ͸఍߅ײͳ͠


    • ։ൃ͢ΔͨΊͷ஌ݟ͕଍Γͳ͍ͨΊෆ҆


    • DartͷίʔυΛϨϏϡʔ͢Δ஌ݟ΍ࣗ৴


    • WebʹରԠ͢ΔͨΊͷϥΠϒϥϦ΍ઃܭ
    18

    View Slide

  19. Flutter WebΛޮՌతʹ׆༻͢Δ޻෉
    • FlutterΛར༻ͯ͠։ൃ͢ΔνʔϜʹม͑Δ


    • MobileͱWebͷ։ൃϦϙδτϦΛ෼͚Δ


    • MobileͱWebͷମݧΛ౷Ұ͢Δ
    19

    View Slide

  20. FlutterΛར༻ͯ͠։ൃ͢ΔνʔϜʹม͑Δ
    • طଘͷAndroid/iOSΞϓϦέʔγϣϯ։ൃΛ࠷খݶʹ͢Δ


    • ։ൃλεΫΛػೳ୯ҐͰ෼ׂ͢Δ


    • 2 approve͕mergeͷ৚݅ʹͳΔΑ͏มߋ͢Δ
    20

    View Slide

  21. ։ൃϦϙδτϦͷ෼ׂ
    • MobileͱWebʹ߹ΘͤΔͨΊʹɺ։ൃΛ෼͚Δ


    • Navigation routes͕Web͸MobileͱҟͳΔ


    • ը໘ͷॎԣൺͷύλʔϯ͕MobileΑΓଟ͍


    • MobileͱWebͷϦϙδτϦ͕ಉҰͩͱɺDeployʹࠔΔ


    • Web͸”ଈ࣌”ʹ”ແ৹ࠪ”ͰDeployͰ͖Δ
    21

    View Slide

  22. UIΛڞ༗͢ΔͨΊͷϦϙδτϦ෼ׂ
    • Flutter͸ɺUI(Widget)ϨϕϧͰΞϓϦέʔγϣϯΛ෼ׂͰ͖Δ


    • 2021೥౓ͷൃද͸ɺUIϨϕϧͷϦϙδτϦ෼ׂΛఏҊ


    • WebͱMobileͰڞ༗͍ͨ͠UIΛϦϙδτϦԽ


    • 1ͭͷػೳվળΛɺෳ਺ͷΞϓϦέʔγϣϯʹ൓өͤ͞Δ࢓૊Έ

    View Slide

  23. UIΛڞ༗͢ΔͨΊͷϦϙδτϦ෼ׂ
    'MVUUFS8FCΞϓϦ "

    'MVUUFS.PCJMFΞϓϦ
    'MVUUFS8FCΞϓϦ #

    6*
    .PEVMF
    6*
    .PEVMF
    6*
    .PEVMF
    -PHJD
    .PEVMF
    -PHJD
    .PEVMF
    -PHJD
    .PEVMF
    6*
    .PEVMF
    6*
    .PEVMF
    -PHJD
    .PEVMF
    6*
    .PEVMF

    View Slide

  24. MobileͱWebͷମݧΛ౷Ұ
    • Phone/Tablet/Desktopͷҧ͍ΛBreakpointͰ੔ཧ


    • ը໘ͷԣ෯ͷҧ͍ΛϨΠΞ΢τͱMarginͰௐ੔


    • ϨΠΞ΢τΛܾఆ͢Δେ࿮͕ɺදࣔWidgetͷݟ͑ํΛ֬ఆ


    • Widgetͷ֎෦͔ΒPaddingΛௐ੔Մೳʹ͢Δ


    • ListViewΛPaddingͰׅΔॲཧΛͳ͘͢
    24

    View Slide

  25. Paddingͷௐ੔
    class HogeWidget extends StatelessWidget {
    const HogeWidget({super.key});
    @override
    Widget build(BuildContext context) {
    return const Padding(
    padding: EdgeInsets.symmetric(
    horizontal: 16,
    ),
    child: InnerWidget()
    );
    }
    }

    View Slide

  26. Paddingͷௐ੔
    class HogeWidget extends StatelessWidget {
    const HogeWidget({super.key});
    @override
    Widget build(BuildContext context) {
    final margin = calculateMargin(context);
    return Padding(
    padding: EdgeInsets.symmetric(
    horizontal: margin,
    ),
    child: const InnerWidget()
    );
    }
    double calculateMargin(BuildContext context) {
    if (MediaQuery.of(context).size.width < 600) {
    return 16;
    } else {
    return 32;
    }
    }
    }
    ը໘෯ʹΑΔmarginରԠ

    View Slide

  27. Paddingͷௐ੔
    class HogeWidget extends StatelessWidget {
    const HogeWidget({super.key});
    @override
    Widget build(BuildContext context) {
    final margin = calculateMargin(context);
    return InnerWidget(
    margin: margin,
    );
    }
    double calculateMargin(BuildContext context) {
    if (MediaQuery.of(context).size.width < 600) {
    return 16;
    } else {
    return 32;
    }
    }
    }
    Widgetͷ಺෦Padding

    View Slide

  28. View Slide

  29. Paddingͷௐ੔
    class InnerWidget extends StatelessWidget {
    const InnerWidget({
    super.key,
    required this.margin,
    });
    final double margin;
    @override
    Widget build(BuildContext context) {
    return ListView.builder(
    padding: EdgeInsets.symmetric(
    horizontal: margin,
    ),
    itemBuilder: (context, index) => ListTile(
    title: Text(‘$index’),
    ),
    );
    }
    }
    ֎෦͔Βͷࢦఆ

    View Slide

  30. Paddingͷௐ੔
    class InnerWidget extends StatelessWidget {
    const InnerWidget({
    super.key,
    required this.margin,
    });
    final double margin;
    @override
    Widget build(BuildContext context) {
    return ListView.builder(
    itemBuilder: (context, index) => ListTile(
    contentPadding: EdgeInsets.symmetric(
    horizontal: margin,
    ),
    title: Text(‘$index’),
    ),
    );
    }
    }
    λονྖҬͷௐ੔

    View Slide

  31. View Slide

  32. Flutter WebΛ

    ࠾༻͢ΔͱͲ͏ͳΔͷ͔
    32

    View Slide

  33. Flutter Webͷҹ৅
    • FontͷରԠΛؚΊɺݸผʹղফ͢Δ΂͖՝୊͕ଟ͍


    • MobileͰಈ͍͍ͯͯ΋ɺWebͰಈ͘ͱ͸ݶΒͳ͍


    • ϚϧνεϨουͷར༻ʹݸผͷ࣮૷͕ඞཁ


    • ը໘ͷଟ༷ͳαΠζɺಈతͳαΠζมߋ΁ͷରԠ


    • MobileͱWebͰPadding͕ҟͳΔWidget
    33

    View Slide

  34. Flutter Webͷҹ৅
    • ύϑΥʔϚϯε͸े෼ʹ࣮༻త


    • ֤छϥΠϒϥϦαϙʔτ͸ॏཁͳ΋ͷΛ֬ೝ͢Ε͹OK


    • Firebase͸௥͍͍͖ͭͯͨ


    • Pure DartͰ͸ͳ͍ϥΠϒϥϦ͸ݸผʹ൑அඞਢ
    34

    View Slide

  35. ૯࿦
    • Ϧιʔεͷগͳ͍νʔϜͰ͸બ୒ࢶʹͳΓ͏Δ


    • ϞόΠϧΤϯδχΞ͕ଟ͍νʔϜͳΒݕ౼ͯ͠΋Α͍


    • Ϧιʔε͕५୔Ͱ͋Ε͹ɺ͋͑ͯબ୒ͤͣͱ΋Α͍


    • PWAΛؚΊͨϞόΠϧϑΝʔετͳ։ൃʹϚον͢Δ


    • ϓϥοτϑΥʔϜΛލ͍ͩ࠷େެ໿਺తͳ։ൃʹϚον
    35

    View Slide

  36. ૯࿦
    • αʔϏε։ൃʹूதͰ͖ΔνʔϜʹͳΔ


    • όάमਖ਼΍ػೳվળ͕͠΍͍͢


    • ػೳ։ൃͷػೳͷ͋Γํʹूத͠΍͍͢


    • FlutterΛ࠷େݶʹ׆༻͠΍͘͢ͳΔ


    • Mobile޲͚ͷ։ൃΛͦͷ··Webʹల։Մೳ
    36

    View Slide

  37. Thanks!
    37

    View Slide