Lazy loading module in Next.js

How to lazily load modules in Next.js applications

Being able to analyze the bundled software visually is very useful because we can optimize the application very easily.

Suppose we need to load the Moment library in a blog post. run:

npm install moment

Include it in the project.

Now let us simulate the fact that we need to use it in two different routes:/blogwith/blog/[id].

We import itpages/blog/[id].js:

import moment from 'moment'

const Post = props => { return ( <div> <h1>{props.post.title}</h1> <p>Published on {moment().format(‘dddd D MMMM YYYY’)}</p> <p>{props.post.content}</p> </div> ) }

Let me take today’s date as an example.

As you can see, it will include Moment.js in the blog post page bundle.npm run analyze:

See that we now have a red entry/blog/[id], Is the route we added Moment.js!

It changed from ~1kB to 350kB, which is a large number. This is because the Moment.js library itself is 349kB.

Now, the customer bundle visualization shows us that larger bundles are the first page, which used to be very few. And 99% of its code is Moment.js.

Every time a blog post is loaded, we will transmit all this code to the client. This is not ideal.

One solution is to find a smaller library, because Moment.js is not known for its lightweight (especially out of the box, including all locales), but let's assume that for the sake of example, we have to use it .

Instead, what we can do is to separate all Moment codes into oneSeparate bundle.

how is it? Instead of importing Moment at the component level, an asynchronous import is performed internallygetInitialProps, And then we calculate the value to be sent to the component. Remember, we can’tgetInitialProps()The returned object, so we calculate the date in it:

import posts from '../../posts.json'

const Post = props => { return ( <div> <h1>{props.post.title}</h1> <p>Published on {props.date}</p> <p>{props.post.content}</p> </div> ) }

Post.getInitialProps = async ({ query }) => { const moment = (await import(‘moment’)).default() return { date: moment.format(‘dddd D MMMM YYYY’), post: posts[query.id] } }

export default Post

Saw that special call.default()Rearawait import? The default export needs to be referenced in the dynamic import (seehttps://v8.dev/features/dynamic-import)

Now if we runnpm run analyzeAgain, we can see:

our/blog/[id]The package is again small because Moment has moved to its own package file and loaded separately by the browser.

Download mine for freeNext.js manual


More tutorials next: