DEV Community

Margai Wangara(he/him)
Margai Wangara(he/him)

Posted on

How To Load Static CSS and JS Files in Next.js

Recently I was working on a project that required conversion from a static HTML/CSS/JS theme to a Next.js application. I had done some hardcore React before so making a switch to Next.js wasn't that hard, it was pretty simple, to be honest, and I also wanted to benefit from the API routes availability and SEO advantages of using Next.js due to its server-side rendering capabilities. One of the issues I didn't take into consideration was the server-side rendering effect on normal js files execution. This ended up taking my entire week as I tried to figure out a way to integrate js files without painting my Chrome console red.

For me, this was a pretty straightforward situation, all I had to do was to import the css and js files into index.html file, but wait, Next.js doesn't have an index.html file. This was my first issue. Fortunately, after a little bit of research in the Next.js documentation, I figured it out(kind of). So, to import js and css files, it's pretty easy. In the pages directory, create a _document.js file and add the code below.

import Document, { Html, Head, Main, NextScript } from 'next/document'

class MyDocument extends Document {
  static async getInitialProps(ctx) {
    const initialProps = await Document.getInitialProps(ctx)
    return { ...initialProps }
  }

  render() {
    return (
      <Html>
        <Head>
            <link rel="stylesheet" href="styles.css"/>
        </Head>
        <body>
          <Main />
          <NextScript />
          <script src="main.js"></script>
        </body>
      </Html>
    )
  }
}

export default MyDocument

Enter fullscreen mode Exit fullscreen mode

Note: To call the css and js as above, the files need to be available in the public folder on the root of the project.

The above code works as expected under normal circumstances. CSS files are rendered and work as expected, however, when using JS, since some properties such as window are only available on the client-side, it throws errors. I had this problem, particularly when trying to use owl.min.js and wow.min.js files for slideshows because they utilize window. The most common error I faced was the one below:

Warning: Extra attributes from the server: style in nav (at DefaultNavbar.tsx:38)
Enter fullscreen mode Exit fullscreen mode

After a bit of research, I got a variety of solutions, which were really awesome and helpful, like checking if window exists inside the lifecycle method componentDidMount and then load the library, while this was helpful, I didn't know how I could load the static js files. So, after struggling for almost a week, I finally managed to load the js files without any errors as follows:

In the code above, while loading a js file, add the async={true} property which loads the script file when ready.

import Document, { Html, Head, Main, NextScript } from 'next/document'

class MyDocument extends Document {
  static async getInitialProps(ctx) {
    const initialProps = await Document.getInitialProps(ctx)
    return { ...initialProps }
  }

  render() {
    return (
      <Html>
        <Head>
            <link rel="stylesheet" href="styles.css"/>
        </Head>
        <body>
          <Main />
          <NextScript />
          <script src="main.js" async={true}></script>
        </body>
      </Html>
    )
  }
}

export default MyDocument

Enter fullscreen mode Exit fullscreen mode

To learn more about Next.js _document.js, you can check out the documentation here

Discussion (0)