Git Product home page Git Product logo

Comments (3)

addyosmani avatar addyosmani commented on April 29, 2024

Optimization: Reduce bloated dependencies to keep JS payloads smaller.

Step 1: Measure

We start out by testing npm run dev. We know Vue doesn't apply all production optimizations at this point. We're looking at a 2.3MB payload overall:

image

Of this, 1.7MB of the payload is JavaScript:

image

Let's try running the production build to see how this changes.

Thanks to Vue's usage of the Webpack performance budget feature, we're able to highlight [big] files:

image

Lots of large PNGs/images but also a very large 2.16MB JavaScript vendor file. The rest of our application JavaScript is pretty small.

We can use Lighthouse to analyze how we're doing on performance:

image

We have large network payloads:

image

A lot of the initial JS bootup costs are low because we aren't doing a whole lot when the app first starts. Most of the UI that gets executed is on the next route:

image

And we can see that Parse/Compile of JS takes a few hundred milliseconds:

image

But enormous payloads are still the biggest problem.

Let's try analyzing this bundle in some more depth. Following https://code.luasoftware.com/tutorials/vuejs/vuejs-webpack-analyze-bundle-size/, we know we can run npm run build --report to run Webpack Bundle Analyzer.

It gives us an output that looks like this:

image

with the drawer

image

That unicode (SO.js) module seems troublesome! The parsed cost is 1.64MB of code, which we know will take a few seconds to parse and gzipped that code is still ~93KB.

image

Where do we use this module?

  • Having a hard time finding it. I looked in the source. No unicode or so.js
  • Looked in package.json and lockfile. Seems it might be tied to a babel transform for regex/unicode
  • Digging through npm, I see that this unicode module is relied upon by https://www.npmjs.com/package/slug (which we use for slugifying URLs). Let's try to replace it with something much slimmer.

We go to our editor, and because we're using the import-cost plugin in VSCode, we can see that yes, slug does indeed take up a bunch of extra bytes and has a heavy weight:

image

BundlePhobia is a nice tool for finding out the consumption weight of different npm modules. We use it to test the slug module as follows:

image

and can then try out alternatives. I find one called Limax which is 42KB gzipped: https://bundlephobia.com/[email protected] and another called https://bundlephobia.com/[email protected] which is 4.2KB gzipped. Let's try that one.

Step 2: Optimize

Looks pretty okay in editor and bundlephobia. Let's use the slugify module.

image

image

When we make this change to our app, we can see that Vue's webpack build report changes:

image

We have now saved 1.72MB on the size of the bundle and it's down to 444KB.

This audit now passes the enormous payloads check in Lighthouse:

image

and here's some bumps in performance metrics:

image

Success 🎉

from oodle-demo.

addyosmani avatar addyosmani commented on April 29, 2024

Optimization: Remove unused/unnecessary dependencies to reduce JS payload size

Originally, we made changes to our app because we were experimenting with using Material Design - cards, toolbars, nav. Later, once we decided to go more custom, we kept these imports in and they were bloating our bundle.

We can also see that the Vue MDC adapter is taking up a chunk of our bundle:

image

Looking back after the last optimization, we were at 444KB for the size of the bundle.

image

Lighthouse audits for main thread consumption and JS bootup time:

image

Dropping the MDC Web JavaScript only, we're able to trim the bundles down much more heavily.

image

We can still use the CSS styles (which we import) as needed.

We shaved off 327KB off our bundle.

Everything seems to work as expected:

image

Lighthouse wise, this takes us from this:

to this:

image

Our network payloads and JS bootup time are down

image

image

from oodle-demo.

addyosmani avatar addyosmani commented on April 29, 2024

Optimization - code-splitting

Note: this may not be entirely practical for now, so documenting the change but not including in PR just yet.

Originally, we're looking at a 12-13KB app.js size:

This is before we even considered doing anything with code-splitting etc.

image

Let's look at the old code before we add code-splitting:

import DoodleHome from '@/components/DoodleHome'
import DoodleBrowse from '@/components/DoodleBrowse'
import DoodleFullscreen from '@/components/DoodleFullscreen'
import DoodleOffline from '@/components/DoodleOffline'

and after:

const DoodleHome = () => import('@/components/DoodleHome')
const DoodleBrowse = () => import('@/components/DoodleBrowse')
const DoodleFullscreen = () => import('@/components/DoodleFullscreen')
const DoodleOffline = () => import('@/components/DoodleOffline')

and if we want to name these chunks:

const DoodleHome = () => import(/* webpackChunkName: "doodle-home" */ '@/components/DoodleHome')
const DoodleBrowse = () => import(/* webpackChunkName: "doodle-browse" */'@/components/DoodleBrowse')
const DoodleFullscreen = () => import(/* webpackChunkName: "doodle-fullscreen" */'@/components/DoodleFullscreen')
const DoodleOffline = () => import(/* webpackChunkName: "doodle-offline" */'@/components/DoodleOffline')

Post-build, we're looking at some pretty small sized bundles now for each route:
image

With named chunks, it looks like this:

image

However...

I now notice a short lag before the doodles browser view loads. As the previous app chunks were small enough (12KB) we might want to suggest we tried code-splitting but it wasn't needed in the end, or, try to inflate the size of a route artificially so that the benefit is more pronounced.

from oodle-demo.

Related Issues (19)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.