Image

nuxtjs

Performance

3 min read
Last update: November 28, 2021

Bundle size

nuxt.config.js
export default {
  build: {
      analyze: true,
      // or
      analyze: {
         analyzerMode: 'static'
      }
  }
}
yarn nuxt build --analyze

Go to localhost:8888

Misc

By pi0

Source: github.com/nuxt/nuxt.js/issues/7698

I second @voltane idea to leverage lazy-hydration, reducing JS execution time and Chunk splitting is mainly wepack's task so nothing much to do (hopefully would be improved by WP5)

One important tip worth mentioning is that nuxt plugins are usually main reason of blocking render/hydration since nuxt awaits on them before start rendering on client-side and also their dependencies will be added to main (or vendors) chunk which both are necessary to bootstrap too.

(NOTE: All examples below are for .client plugins)

Example 1: Defer plugins with a background task

Bad practice:

export default async function(ctx, inject) {
   await ...
}

Doing task in parallel to render:

async function task(ctx) {}

export default function(ctx, inject) {
   task(ctx).catch(console.error)
}

Using onNuxtReady to defer task after app is mounted:

async function task(ctx) {}

export default function(ctx, inject) {
   window.onNuxtReady(() => task(ctx).catch(console.error))
}

Example 2: Lazy importing dependencies

Bad practice:

import bigDep from 'big-dep'

export default function (ctx, inject) {}

Create a chunk to reduce execution time (and also preload in parallel) but still blocks render:

export default async function (ctx, inject) {
   const bigDep = await import('big-dep' /* webpackChunkName: 'big-dep' */)
}

Do logic in background:

async function task(ctx) {
   const bigDep = await import('big-dep' /* webpackChunkName: 'big-dep' */)
}

export default function (ctx, inject) {
  task(ctx).catch(console.error)
}

Example 3: Lazy import by usage:

Bad practice: (usage: this.$util.foo())

import getbigDep from 'big-dep'

export default function (ctx, inject) {
  inject('util', {
     async foo() {
          // some logic depending on bigDep
     }
  })
}

Lazy import by usage: (same usage)

const getbigDep = () => import('big-dep' /* webpackChunkName: 'big-dep' */)

const createUtils = ctx => ({
   async foo() {
      const bigDep = await getbigDep()
      // some logic depending on bigDep
  }
})

export default function (ctx, inject) {
  inject('util', createUtils(ctx))
}

Lazy import entire utils if utils themselfe are big: (Usage this.$utils().then(utils => ...))

// plugins/foo.utils.js
// we can either directly import or utilize lazy import too

export default (ctx) {
  return { ... }
}
// plugins/foo.client.js
export default (ctx, inject) {
  inject(utils => import('./foo.utils').then(createUtils => createUtils(ctx))
}