Skip to content
This repository was archived by the owner on Jul 6, 2021. It is now read-only.
This repository was archived by the owner on Jul 6, 2021. It is now read-only.

Importing a css file in _app.js may cause Cannot read property 'default' of undefined #244

@kachkaev

Description

@kachkaev
next@6.1.1-canary.5
next-css@0.2.1-canary.1

I started seeing a pretty magic bug in production recently and am writing to share the results of my investigation. Here's what was showing up in the browser's console during some of the page loads:

TypeError: Cannot read property 'default' of undefined
    at http://localhost:3000/_next/static/bc4f7954-f656-4e9e-af24-a4404cecb3c7/pages/_app.js:1:4762
    at r (http://localhost:3000/_next/static/runtime/main-68ba217b0c0184534eba.js:9:96586)
    at e.value (http://localhost:3000/_next/static/runtime/main-68ba217b0c0184534eba.js:9:96973)
    at http://localhost:3000/_next/static/runtime/main-68ba217b0c0184534eba.js:1:1034
    at Array.forEach (<anonymous>)
    at Object.110 (http://localhost:3000/_next/static/runtime/main-68ba217b0c0184534eba.js:1:991)
    at l (http://localhost:3000/_next/static/runtime/webpack-7dba61e9b6510e660c00.js:1:520)
    at Object.105 (http://localhost:3000/_next/static/runtime/main-68ba217b0c0184534eba.js:1:156)
    at l (http://localhost:3000/_next/static/runtime/webpack-7dba61e9b6510e660c00.js:1:520)
    at Object.104 (http://localhost:3000/_next/static/runtime/main-68ba217b0c0184534eba.js:1:103)

This was followed by no JavaScript working on the client. However, if the exception was somehow avoided on the first page load, all subsequent Next.js pages were working well as long as they were loaded dynamically via <Link/>. The same exception never showed up in development.

After removing pretty much any bit from my app (😅) and testing various hypotheses, I was able to craft an MWE where the exception was reproduced pretty stably. All you need to do is to install next-css, create pages/_app.js and import a CSS file there:

import App, { Container } from "next/app";
import React from "react";

import "../styles/index.css"; // 😱

export default class MyApp extends App {
  render() {
    const { Component, pageProps } = this.props;
    return (
      <Container>
        <Component {...pageProps} />
      </Container>
    );
  }
}

Interestingly, the exception was only occurring in Chrome and not Firefox and could disappear when I varied the size and the complexity of a page. However, with pages/index.jsx being just export default () => <div>hello</div>; the exception appeared every time.

Here's how adding import "../styles/index.css"; to _app.jsx affects the HTML in production:

 <!DOCTYPE html>
 <html>
 
 <head>
   <meta charSet="utf-8" class="next-head" />
   <link rel="preload" href="/_next/static/HASH/pages/index.js" as="script" />
   <link rel="preload" href="/_next/static/HASH/pages/_app.js" as="script" />
   <link rel="preload" href="/_next/static/HASH/pages/_error.js" as="script" />
   <link rel="preload" href="/_next/static/runtime/webpack-HASH.js" as="script" />
   <link rel="preload" href="/_next/static/chunks/HASH.js" as="script" />
   <link rel="preload" href="/_next/static/runtime/main-HASH.js" as="script" />
+  <link rel="preload" href="/_next/static/chunks/HASH.js" as="script" />
+  <link rel="stylesheet" href="/_next/static/css/styles.HASH.chunk.css" />
 </head>
 
 <body>
   <div id="__next">
     <div>hello</div>
   </div>
   <div id="__next-error"></div>
   <script>
     __NEXT_DATA__ = { "props": { "pageProps": {} }, "page": "/", "pathname": "/", "query": {}, "buildId": "HASH" }
     module = {}
     __NEXT_LOADED_PAGES__ = []
 
     __NEXT_REGISTER_PAGE = function (route, fn) {
       __NEXT_LOADED_PAGES__.push({ route: route, fn: fn })
     }
   </script>
   <script async="" id="__NEXT_PAGE__/" src="/_next/static/HASH/pages/index.js"></script>
   <script async="" id="__NEXT_PAGE__/_app" src="/_next/static/HASH/pages/_app.js"></script>
   <script async="" id="__NEXT_PAGE__/_error" src="/_next/static/HASH/pages/_error.js"></script>
   <script src="/_next/static/runtime/webpack-HASH.js" async=""></script>
   <script src="/_next/static/chunks/HASH.js" async=""></script>
   <script src="/_next/static/runtime/main-HASH.js" async=""></script>
+  <script src="/_next/static/chunks/HASH.js" async=""></script>
 </body>
 
</html>

As you can see, importing a stylesheet in _app.js not just adds a link to a CSS file, but also produces a new JS chunk. This JS file does not contain anything really:

(window.webpackJsonp=window.webpackJsonp||[]).push([[6],{220:function(n,w,o){}}]);

/_next/static/HASH/pages/_app.js changes a bit too and my suspicion is that it is trying to import a module from the extra JS chunk before that one is loaded. This race condition does not happen on any page because the size of its server-rendered content may affect the order in which Chrome loads the JS files and bootstraps the client-side app.

Getting rid of the bug was pretty simple. I just moved the CSS import into the page HOC in my real app (pages/index.js in the MWE) and the exception never showed up again.

What can we do to save others from the same trap? It took me more than half a day to detect the bug and to investigate it 😅

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions