Next.js: Can't Build Next v9 With Non-React Components

Created on 4 Sep 2019  ·  19Comments  ·  Source: vercel/next.js

Bug report

Describe the bug

After upgrading from v8.9 to v9, Next will refuse to build my project because of the presence of non-react components. There doesn't seem to be a setting I can add in next's config to get around this, forcing me to completely destructure my pages. Isn't there a way to disabled automatic static optimization?
Spectrum question here.

Error:

> Build error occurred
Error: automatic static optimization failed: found pages without a React Component as default export in

proceeded by the list of all the files that aren't react components (AKA the style and test files).

To Reproduce

I have setup a file structure as such:

/pages
└── /MyPage
    └── index.js // Standard React exported page
    └── styles.js // EmotionJS styling for this specific page
    └── MyPage.test.js // Jest test file

Simply run next build or yarn build

Expected behavior

To build normally, like in Next v8.

Most helpful comment

Any reason this is allowed in development mode?

All 19 comments

This is not a bug and expected behavior. In Next.js 8 it would actually build and expose MyPage.test.js and styles.js as pages, which slow down builds and are accessible publicly.

The main constraint of Next.js is that pages are pages.

Hello @timneutkens ; so there's no workaround to this? ie: Next not exposing these files?

@zxiest this has been discussed many times in different GitHub issues. You shouldn't put components into pages as it:

  • Slows down builds, as every file is a page
  • Exposes the files publicly
  • Affects code splitting in a negative way

Most recent discussion is here https://github.com/zeit/next.js/issues/4315#issuecomment-526832636

Thanks for the link. We shall restructure accordingly.

Rethinking this, would it not be possible to add an ignorePattern (different name of course) by which Next can ignore *.test.js or *.style.js ?

This should not harm build speeds, not expose the files publicly (obviously this needs to be supported), and not harm code splitting.

It's very annoying having to separate the files in many directories and looking for them every time you need to do an edit. I am a big fan of convention over configuration coming from the Rails world but have noticed it's much more efficient to keep component assets in the same directory.

This has been discussed many times before as said and that still introduces security issues etc.

You can keep pages only to expose routes though and then keep a separate directory with a structure that you want.

Thank you for taking the time to respond =)

This is what we have ended up doing. We're following this structure outside the /pages directory and using /pages for the aforementioned purpose only.

But what to do with relay generated files placed under __generated__ subfolder? Having that we use queries at pages level?

And yes relay-compiler allow to use one folder for this files, but we have hundreds of such. Not easy to import, find etc. So using __generated__ subfolder is the main and possibly only option for us. Ive read links above and don't understand how ignored!!! files can somehow affect anything?

For now I excluded __generated__ files using webpack config option

    webpack: (config /* : any */) => {
      const originalEntry = config.entry;
      config.entry = async () => {
        const entries = await originalEntry();

        const keys = Object.keys(entries);
        keys.forEach(key => {
          if (key.includes('/__generated__/')) {
            delete entries[key];
          }
        });

        return entries;
      };

      return config;
    },
  })

So can be used as a solution

Just an idea for disappointed folks, that came previously from create-react-app (like me). And would like to have a directory per page:

Put your pages code inside src/pages

<root>/
  src/
    pages/
      welcome/
        index.js,
        Welcome.messages.js
        styles.js

And reference pages/welcome -> src/pages/welcome

// <root>/pages/welcome.js
export { default } from './src/pages/welcome'

IMHO, you also get more control, and its easier to reason about what will be available in prod, since the pages/ directory stays really lean and simple.

Any reason this is allowed in development mode?

This does not make sense to be allowed in the development environment since it applies to the production environment.

image

One solution I found at the moment was to leave my views in my src directory and to export only the default export of each component export { default } from '../src/views/About'. as I like to separate the styles, types and tests files in each module a was the best solution at the moment.

@istarkov's hack stopped working

@TrySound it likely has a slash too many /__generated__/ should be __generated__/.

@timneutkens This is how the key look like pages/__generated__/AppQuery.graphql. Your suggestion does not solve the problem.

Really went down the rabbit hole with this one. Got my page written, tests written and passing, and everything built fine in dev (next dev). Everything appeared to be working, but it was only when it came to build (next export) that I ran into issues.

I first tried to add a custom Webpack config. After adding IgnorePlugin I ran into issues with Webpack 4, so I had to opt into Webpack 5. I finally got Webpack to successfully ignore Jest tests (e.g. /pages/foo/index.spec.tsx)and Storybook stories (e.g. /pages/foo/index.stories.tsx), then finally ran up against this issue (Error: Build optimization failed: found page without a React Component as default export in...).

This has almost caused me to bail out on using Next.js for now. It's obvious that many folks would like to co-locate files next to pages for better developer experience. It's similar to the greatly improved developer experience of co-locating CSS files alongside their React components, instead of in some far-away directory (or back in the old days, one massive mysterious file).

From reading other threads and this one, it seems that Next.js maintainers may be open to adding some sort of ignore or include/exclude to next.config.js, which would be great, and I hope to see that someday.

Other than this issue, everything else in Next.js has worked out pretty nicely, and it's really lovely. Thank you!

@hiukky That solution seems somewhat reasonable, I'll give it a try. Thanks!

Next.js routing system and folder structure is terrible.

The story repeats itself numerous time over years and there seem to be no learnings from past mistakes (PHP, ASP.NET, WebForms etc).

I do understand what "opinionated" means but simply put, the opinion of creating a 1:1 bond between folderstructure and routing does not have any sensible foundation. Thats a perfect example, where "convention over configuration" does not work.

  • Naming files like [[...slug]].js or [id]/[category].js
  • Not being able to follow a "features" based folder structure where highly cohesive components and assets are grouped under same folder, only via hacks with mirrored/proxy "pages" folder
  • Broken navigation in IDEs due to funny file names
  • Refactoring constraints - where filename is based on the url params. Imagine multiple people working on same file.

Stop grouping files by extension eg:
/assets/css/home.css
/assets/img/promoImage.jpeg
/lib/carousel/carousel.js
/pages/home/index.js

Instead group them by coupling/relevance/cohesiveness:
/pages/home/home.js
/pages/home/home.css
/pages/home/components/carousel.js
/pages/home/......

And if its something reusable, great create a folder at top or extract it into its own NPM package where you'd have strict unit test coverage, linting rules, storybook or other showcasing UI, API referecence and patronized check-ins.

Deleting the /home directory i remove the feature in 1 click, no dependencies are broken. Navigation in IDE is simple. Routing is decoupled.

If the framework relies on walking through the directories based on "naming convention"only well then this sucks, offer a way to configure/map/mark/decorate/whatever so this relationship is not tightly coupled and forced onto the user.

Sorry for long winded answer but in pains me a lot...

Was this page helpful?
0 / 5 - 0 ratings

Related issues

havefive picture havefive  ·  3Comments

irrigator picture irrigator  ·  3Comments

timneutkens picture timneutkens  ·  3Comments

lixiaoyan picture lixiaoyan  ·  3Comments

kenji4569 picture kenji4569  ·  3Comments