Lazy loading modules in your Next.js app is a great way to optimize your application and improve performance. One module that we often need to load in specific parts of our app is the Moment library for handling date and time. In this article, we will explore how to lazy load the Moment library in Next.js and improve the performance of your app.

To begin, let’s install the Moment library by running the following command in your terminal:

npm install moment

This will include the Moment library in your project.

Now, let’s consider a scenario where we need to use the Moment library on two different routes in our app: /blog and /blog/[id]. In the /pages/blog/[id].js file, we import the Moment library as follows:

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>
   )
}

In this example, we are simply adding today’s date using the Moment library.

When we analyze the bundle size using the npm run analyze command, we can see that the Moment.js library is included in the blog post page bundle, as shown below:

Bundle Analysis

As you can see, the bundle size has increased significantly due to the inclusion of the Moment.js library. This means that every time we load a blog post, all this code will be transferred to the client, which is not ideal for performance.

To address this issue, we can separate the Moment code into a separate bundle. Instead of importing Moment at the component level, we can perform an async import inside the getInitialProps function and calculate the value to send to the component. It’s important to note that complex objects cannot be returned directly from the getInitialProps() function, so we calculate the date inside it.

Here’s how the updated /pages/blog/[id].js file looks like:

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

In this updated code, we use an async import of the Moment library and use the .default() function to reference the default export in the dynamic import.

Now, when we run npm run analyze again, we can see that the /blog/[id] bundle is significantly smaller, as the Moment library has been moved to its own bundle file and loaded separately by the browser:

Bundle Analysis

By lazy loading the Moment library in this way, we have improved the performance of our Next.js app by reducing the bundle size and optimizing the loading of modules. This technique can be applied to other modules in your app as well, allowing you to optimize the performance and deliver a faster user experience.