Vue.js Performance Tips / #v_kansai 11

Vue.js Performance Tips / #v_kansai 11

v-kansai Vue.js/Nuxt Meetup #11 (京都Devかふぇ共催)でVue.jsのパフォーマンスに関する発表を行いました。

https://vuekansai.connpass.com/event/144194/

# 参考にした記事
- 超速! Webページ速度改善ガイド(WEB+DB PRESS plus)
- https://www.amazon.co.jp/dp/477419400X
- Web Fundamentals | Google Developers
- https://developers.google.com/web/fundamentals
- Vue.js App Performance Optimization – A Tutorial Series
- https://madewithvuejs.com/blog/vue-js-app-performance-optimization-a-tutorial-series-via-itnext
- How to Drastically Reduce Estimated Input Latency and Time to Interactive of SSR Vue.js Applications
- https://markus.oberlehner.net/blog/how-to-drastically-reduce-estimated-input-latency-and-time-to-interactive-of-ssr-vue-applications/
- Progressive Hydration #react_fukuoka - Speaker Deck
- https://speakerdeck.com/pirosikick/progressive-hydration-number-react-fukuoka

5cf7e9533a457726cd51232e06c1da9a?s=128

Masashi Hirano

October 09, 2019
Tweet

Transcript

  1. Vue.js Performance Tips v-kansai Vue.js/Nuxt.js meetup #11 Masashi Hirano /

    @shisama
  2. ฏ໺ ণ࢜ / Masashi Hirano αΠϘ΢ζגࣜձࣾ ɹɹϑϩϯτΤϯυΤΩεύʔτνʔϜ @shisama_ @shisama Node.js

    Core Collaborator ؔ੢NodeֶԂOrganizer
  3. Agenda • Webϖʔδͷ଎౓ʹ͍ͭͯ • ύϑΥʔϚϯεͷܭଌ • ϖʔδϩʔυͷ଎౓վળ • ϥϯλΠϜͷ଎౓վળ

  4. Webϖʔδͷ଎౓ʹΑΔӨڹ • αΠτͷىಈ͕࣌ؒ3ඵҎ্
 ɹ὎53%ͷϢʔβ͕அ೦ͯ͠͠·͏ • ىಈ͕࣌ؒ1ඵ஗͘ͳΔ
 ɹ὎ίϯόʔδϣϯ཰͕ 7% ‑Down

  5. Webϖʔδ͕දࣔ͞ΕΔ·Ͱ Loading Scripting Rendering Painting

  6. Webϖʔδ͕දࣔ͞ΕΔ·Ͱ Loading Scripting Rendering Painting Runtime

  7. ύϑΥʔϚϯεࢦඪʹͳΔRAILϞσϧ https://developers.google.com/web/fundamentals/performance/rail 100ms 10ms 50ms 1000ms Ϣʔβʔೖྗ εΫϩʔϧ
 Ξχϝʔγϣϯ ΞΠυϧதͷॲཧ

    ϖʔδϩʔυ
  8. https://developers.google.com/web/fundamentals/performance/rail 100ms 10ms 50ms 1000ms Ϣʔβʔೖྗ εΫϩʔϧ
 Ξχϝʔγϣϯ ΞΠυϧதͷॲཧ ϖʔδϩʔυ

    3VOUJNF ύϑΥʔϚϯεࢦඪʹͳΔRAILϞσϧ
  9. Webϖʔδͷ଎౓ • ϖʔδϩʔυͷ଎౓ • Loadingͷ࣌ؒΛ͍͔ʹ୹͘Ͱ͖Δ͔ • ϥϯλΠϜͷ଎౓ • දࣔ·Ͱͷ଎౓Λ͍͔ʹ୹͘Ͱ͖Δ͔ •

    ϢʔβʔΠϯλϥΫγϣϯʹ͍͔ʹ଎͘Ԡ͑Δ͔
  10. ύϑΥʔϚϯεΛܭଌ͢Δ

  11. ύϑΥʔϚϯεͷվળʹ͸ܭଌ͕ॏཁ • Measure, Don’t Guess (ਪଌ͢ΔͳɺܭଌͤΑ) • ݱঢ়ΛՄࢹԽͯ͠ϘτϧωοΫΛݟ͚ͭΔ • Chrome

    DevToolsɺLighthouseɺWebPageTestͳͲศརͳ πʔϧ͕͋Δ • User Timing APIͳͲͰݸผͷॲཧΛܭଌ
  12. User Timing API // ܭଌ։࢝ͷϚʔΫ performance.mark(“A"); heavyTask(); // ܭଌऴྃͷϚʔΫ performance.mark(“B");

    // “heavy task”ͱ͍͏໊લͰ”A”ͱ”B”ͷؒͷ࣌ؒΛܭଌ performance.measure("heavy task", "A", "B");
  13. User Timing API

  14. Vue.config.performance • ίϯϙʔωϯτ͝ͱͷॲཧ࣌ؒΛܭଌ • தͰUser Timing API͕࢖ΘΕ͍ͯΔ const isDev =

    process.env.NODE_ENV !== “production"; Vue.config.performance = isDev; // trueͰܭଌ͞ΕΔ new Vue({ router, store, render: h => h(App) }).$mount("#app");
  15. Vue.config.performance

  16. ϖʔδϩʔυͷ଎౓վળ

  17. ϖʔδϩʔυͷ଎౓վળ • JavaScriptͷ෼ׂɾ஗ԆಡΈࠐΈ • ը૾ͷ஗ԆಡΈࠐΈ • ը૾ͷ࠷దԽ • ServiceWorkerʹΑΔΩϟογϡ •

    …etc
  18. ϖʔδϩʔυͷ଎౓վળ • JavaScriptͷ෼ׂɾ஗ԆಡΈࠐΈ • ը૾ͷ஗ԆಡΈࠐΈ • ը૾ͷ࠷దԽ • ServiceWorkerʹΑΔΩϟογϡ •

    …etc
  19. JavaScriptͷ෼ׂɾ஗ԆಡΈࠐΈ import Home from ‘./Home.vue’ import About from ‘./About.vue’ const

    router = new VueRouter({ routes: [ { path: '/', component: Home }, { path: ‘/about', component: About }, ] }) ੩తͳimport
  20. JavaScriptͷ෼ׂɾ஗ԆಡΈࠐΈ "QQWVF )PNFWVF "CPVUWVF FOUSZKT 7VF WVF SPVUFS SPVUFSKT BQJKT

    BYJPT BQQKT ϒϥ΢βͰ࣮ߦ͞ΕΔίʔυ
  21. JavaScriptͷ෼ׂɾ஗ԆಡΈࠐΈ const router = new VueRouter({ routes: [ {path: '/',component:

    () => import('./Home.vue')}, {path: '/about',component: () => import('./About.vue')}, ] }) ಈతͳimportʹ͢Δ͜ͱͰ ෼ׂ͢Δ͜ͱ͕Ͱ͖Δ
  22. JavaScriptͷ෼ׂɾ஗ԆಡΈࠐΈ "QQWVF )PNFWVF "CPVUWVF FOUSZKT 7VF WVF SPVUFS SPVUFSKT BQJKT

    BYJPT BQQKT IPNFKT BCPVUKT
  23. JavaScriptͷ෼ׂɾ஗ԆಡΈࠐΈ "QQWVF )PNFWVF "CPVUWVF FOUSZKT 7VF WVF SPVUFS SPVUFSKT BQJKT

    BYJPT BQQKT IPNFKT BCPVUKT ࠷ॳ͸app.js͚ͩಡΈࠐΈɺ࣮ߦ࣌ʹ ෼ׂͨ͠ίʔυΛϩʔυ͢Δ
  24. ը૾ͷ஗ԆಡΈࠐΈ

  25. ϖʔδશମͷ͏ͪɺ࠷ॳʹදࣔ ͞ΕΔͷ͸͚ͩ͜͜

  26. ஗ԆಡΈࠐΈՄೳ

  27. εΫϦʔϯʹ ͍ࣸͬͯΔൣғ (viewport) ը૾ͷ஗ԆಡΈࠐΈ

  28. ը૾ͷཁૉ͕viewport ʹೖΔͱը૾Λϩʔυ ը૾ͷ஗ԆಡΈࠐΈ

  29. v-lazy-image https://github.com/alexjoverm/v-lazy-image

  30. v-lazy-image import Vue from "vue"; import { VLazyImagePlugin } from

    "v-lazy-image"; import App from "./src/App"; Vue.use(VLazyImagePlugin); new Vue({ el: "#app", render: h => h(App) }); Vue.useʹ౉͢͜ͱͰͲͷίϯϙʔω ϯτͰ΋࢖͑ΔΑ͏ʹͳΔ
  31. v-lazy-image <template> <div> <v-lazy-image src=“https://path/to/image.jpeg” alt="sample" ></v-lazy-image> </div> </template> <style

    scoped> .v-lazy-image { width: 100%; } </style> ίϯϙʔωϯτ಺Ͱ v-lazy-imageΛ࢖͏
  32. ϥϯλΠϜͷ଎౓վળ

  33. ϥϯλΠϜͷ଎౓վળ • FCP΍TTI·Ͱͷ࣌ؒΛ୹͘͢Δ • UIϒϩοΫ͢Δॏ͍ॲཧΛආ͚Δ • ϒϥ΢βͷΞΠυϧ࣌ؒΛ࠷େݶ׆༻͢Δ • Web WorkerΛ༻͍ͨϝΠϯεϨουͷॲཧͷ࡟ݮ

    • …etc
  34. ϥϯλΠϜͷ଎౓վળ • FCP΍TTI·Ͱͷ࣌ؒΛ୹͘͢Δ • UIϒϩοΫ͢Δॏ͍ॲཧΛආ͚Δ • ϒϥ΢βͷΞΠυϧ࣌ؒΛ࠷େݶ׆༻͢Δ • Web WorkerΛ༻͍ͨϝΠϯεϨουͷॲཧͷ࡟ݮ

    • …etc
  35. https://developers.google.com/web/fundamentals/performance/rail

  36. https://developers.google.com/web/fundamentals/performance/rail Կ͔͕දࣔ͞Εͨͱ͖ Կ͔ίϯςϯπ͕දࣔ͞Εͨͱ͖ ҙຯͷ͋Δද͕ࣔ͞Εͨͱ͖ ૢ࡞Մೳͱͳͬͨͱ͖

  37. Loading HTMLɾCSS JavaScript '$1 55* Client Side Rendering

  38. Loading JavaScript '$1 55* Server Side Rendering HTMLɾCSS

  39. Loading JavaScript '$1 55* Server Side Rendering αʔόʔαΠυͰϨϯμϦϯάͨ݁͠ՌΛฦ͍ͯ͠Δ HTMLɾCSS

  40. • VueͷίʔυΛNode.jsͰ࣮ߦ͠αʔόʔαΠυͰHTMLΛ૊ ΈཱͯΔ • ΫϥΠΞϯτ༻ͷJSϑΝΠϧ΋഑৴͢Δ • Nuxt.js͸σϑΥϧτͰSSR Server Side Rendering

  41. https://ssr.vuejs.org/guide/hydration.html

  42. • αʔόʔαΠυͰ૊ΈཱͯͨDOMΛ࠶ར༻͢Δ • ੩తͳHTMLʹΫϥΠΞϯταΠυͷVueΛΞλον • ΫϥΠΞϯταΠυͰσʔλมߋʹରԠͰ͖ΔಈతDOM ʹม׵ Client Side Hydration

  43. Loading JavaScript '$1 55* HTMLɾCSS Hydration )ZESBUJPO͍ͯ͠Δؒ͸ ૢ࡞Ͱ͖ͳ͍

  44. Loading JavaScript '$1 55* HTMLɾCSS Hydration ஈ֊తʹ)ZESBUJPO͢Δ

  45. Progressive Hydration • ඞཁͳ෼Λஈ֊తʹHydration͢Δ • Hydrationͷ࣌ؒΛ୹͘͢Δ͜ͱͰTTI·Ͱͷ࣌ؒΛ୹͘͢Δ • Google I/O 2019Ͱ΋঺հ͞Ε͍ͯΔ


    https://youtu.be/k-A2VfuUROg
  46. Progressive Hydration ·ͩHydration ͞Ε͍ͯͳ͍

  47. viewportʹೖ͖ͬͯͨͱ͖ʹ hydrationͯ͠ૢ࡞Մೳʹ͢Δ Progressive Hydration

  48. https://github.com/maoberlehner/vue-lazy-hydration

  49. vue-lazy-hydration <template> <div> <LazyHydrate when-visible> <SomeComponent/> </LazyHydrate> </div> </template> <script>

    import LazyHydrate from 'vue-lazy- hydration'; export default { components: { LazyHydrate, SomeComponent: () => import('./SomeComponent.vue'), }, // ... }; </script>
  50. <LazyHydrate when-idle> <ImageSlider/> </LazyHydrate> <LazyHydrate ssr-only> <ArticleContent :content="article.content"/> </LazyHydrate> <LazyHydrate

    when-visible> <AdSlider/> </LazyHydrate> <LazyHydrate :on-interaction="['focus', 'hover']"> <CommentForm :article-id="article.id"/> </LazyHydrate> ϒϥ΢β͕ΞΠυϧঢ়ଶʹͳͬ ͨͱ͖ʹhydration
  51. <LazyHydrate when-idle> <ImageSlider/> </LazyHydrate> <LazyHydrate ssr-only> <ArticleContent :content="article.content"/> </LazyHydrate> <LazyHydrate

    when-visible> <AdSlider/> </LazyHydrate> <LazyHydrate :on-interaction="['focus', 'hover']"> <CommentForm :article-id="article.id"/> </LazyHydrate> SSRͰͷΈॲཧ͢Δ
  52. <LazyHydrate when-idle> <ImageSlider/> </LazyHydrate> <LazyHydrate ssr-only> <ArticleContent :content="article.content"/> </LazyHydrate> <LazyHydrate

    when-visible> <AdSlider/> </LazyHydrate> <LazyHydrate :on-interaction="['focus', 'hover']"> <CommentForm :article-id="article.id"/> </LazyHydrate> viewportʹೖ͖ͬͯͨΒhydration
  53. <LazyHydrate when-idle> <ImageSlider/> </LazyHydrate> <LazyHydrate ssr-only> <ArticleContent :content="article.content"/> </LazyHydrate> <LazyHydrate

    when-visible> <AdSlider/> </LazyHydrate> <LazyHydrate :on-interaction="['focus', 'hover']"> <CommentForm :article-id="article.id"/> </LazyHydrate> ίϯϙʔωϯτʹରͯ͠ ૢ࡞ͨ͠ͱ͖hydration e.g. focusɺhover
  54. when-idle https://github.com/maoberlehner/vue-lazy-hydration/blob/master/src/LazyHydrate.js

  55. requestIdleCallback • ϒϥ΢β͕ΞΠυϧঢ়ଶͷͱ͖ʹίʔϧόοΫؔ਺Λ࣮ߦ͢ Δ • ϝΠϯεϨουઐ༗ʹΑΔϨϯμϦϯά΍Ϣʔβʔૢ࡞ͷ๦ ֐Λճආ͢Δ

  56. requestIdleCallback // 1ඵܦͬͯίʔϧόοΫ͕࣮ߦ͞Εͳ͚Ε͹λΠϜΞ΢τ const requestId = requestIdleCallback(() => { //

    ΞΠυϧঢ়ଶʹͳΕ͹࣮ߦ heavyTask(); }, {timeout: 1000}); // Ωϟϯηϧ͢Δ͜ͱ΋Մೳ cancelIdleCallback(requestId);
  57. when-visible https://github.com/maoberlehner/vue-lazy-hydration/blob/master/src/LazyHydrate.js

  58. IntersectionObserver • λʔήοτཁૉ͕viewportͱަࠩ͢Δͱ͖(ը໘಺ʹೖͬͯ ͖ͨͱ͖)ʹίʔϧόοΫؔ਺Λ࣮ߦ͢Δ • ࢖༻ྫɿը૾஗ԆಡΈࠐΈɺແݶεΫϩʔϧ etc

  59. IntersectionObserver const observer = new IntersectionObserver(entries => { const entry

    = entries[0]; if (entry.intersectionRatio > 0) { enterTask(); // ཁૉ͕ը໘಺ʹೖͬͨͱ͖ } else { exitTask(); // ཁૉ͕ը໘಺ʹग़ͨͱ͖ } }); observer.observe(document.querySelector("#target"));
  60. https://github.com/vuejs/vue-next

  61. https://github.com/vuejs/vue-next 4JHOJpDBOUMZGBTUFS ʹޤ͏͝ظ଴

  62. ·ͱΊ • ύϑΥʔϚϯεܭଌΛ͢Δ΂͠ • ଎౓վળʹ͸ϖʔδϩʔυͱϥϯλΠϜ͕͋Δ • ଎౓վળͷͨΊͷVue༻ͷOSSϥΠϒϥϦ͕͋Δ

  63. ࢀߟ • ௒଎! Webϖʔδ଎౓վળΨΠυ(WEB+DB PRESS plus) • Web Fundamentals |

    Google Developers • Vue.js App Performance Optimization – A Tutorial Series • How to Drastically Reduce Estimated Input Latency and Time to Interactive of SSR Vue.js Applications • Progressive Hydration #react_fukuoka - Speaker Deck
  64. એ఻ 10/25(Fri) 11/30(Sat), 12/1(Sun)

  65. Thanks. @shisama_ @shisama