Next.js: Shared App from module `cannot be invoked without 'new'`

Created on 14 Aug 2019  路  9Comments  路  Source: vercel/next.js

Bug report

Describe the bug

We have several apps who's _app.js exports a common structure from a shared module that is a dependency of each app. This has worked well for use with previous versions of next, but is failing under v9.

To Reproduce

git clone https://github.com/kinetifex/next-9-app-bug.git
cd ./next-9-app-bug
npm i
npm run build

This will fail with:

# TypeError: Class constructor App cannot be invoked without 'new'

Expected behavior

The app should build fine.

To see this working correctly with [email protected], in the same example project:

git checkout works-with-8
npm i
npm run build

System information

  • OS: macOS
    ~- Browser (if applies) [e.g. chrome, safari]~
  • Version of Next.js: 9.0.3

Additional context

I see other issues reporting App cannot be invoked without 'new', but under a different context to what we are experiencing.

Most helpful comment

A custom App component must be compiled different for the server and client.

On the server, you need to emit ES6 Class syntax! Then the client needs to be transformed with the identical preset as your application code.

This entails making your custom .babelrc for the shared app retain ES6 Class syntax:

{
  "presets": [
    [
      "next/babel",
      {
        "preset-env": {
          "modules": "commonjs",
          "exclude": ["transform-classes"]
        }
      }
    ]
  ]
}

You'll also need to mark shared-helpers as non-external and include them in your babel compilation, similar to next-transpile-modules.

All 9 comments

@thundermiracle hmm I'm not really understanding that explanation. Seems like that would imply _any_ modules that I import in _app.js would require some extra webpack config to get picked up, which is not the case.

For example, if I instead import a component from a shared module, that works fine:

import React from 'react';
import App, { Container } from 'next/app';
+ import { MyComponent } from 'shared-helpers'

class MyApp extends App {
  render() {
    const { Component, pageProps } = this.props;

    return (
      <Container>
+        <MyComponent />
        <Component {...pageProps} />
      </Container>
    )
  }
}

export default MyApp;

It is only an issue for App classes and looks like also Document from your issue.
Did you get your's fixed then? Do you have an example of the webpack config?

A custom App component must be compiled different for the server and client.

On the server, you need to emit ES6 Class syntax! Then the client needs to be transformed with the identical preset as your application code.

This entails making your custom .babelrc for the shared app retain ES6 Class syntax:

{
  "presets": [
    [
      "next/babel",
      {
        "preset-env": {
          "modules": "commonjs",
          "exclude": ["transform-classes"]
        }
      }
    ]
  ]
}

You'll also need to mark shared-helpers as non-external and include them in your babel compilation, similar to next-transpile-modules.

鈽濓笍 by the way, once it's marked non-external you can stop compiling to the commonjs modules since it'll be bundled by webpack.

@Timer Thanks, adding "exclude": ["transform-classes"] to the shared moduled fixed this without needing to update webpack externals. Though I'm curious why only ES6 class syntax is required by the next server? What has changed that does not allow the previous approach?

I'm curious of what has changed makes the approach different too.

My guess is that this is related to the TypeScript migration, but I'm not 100% positive about that.

It's related to our publishing process, we now publish default pages as "modern" code that is later compiled down to the version needed. This reduced bundle sizes for _app etc by quite a bit.

馃挴

Was fortunate to have @timer give me the heads up yesterday.

I, for one, welcome an IE11-free browser support matrix 馃槄

Was this page helpful?
0 / 5 - 0 ratings

Related issues

timneutkens picture timneutkens  路  3Comments

kenji4569 picture kenji4569  路  3Comments

sospedra picture sospedra  路  3Comments

swrdfish picture swrdfish  路  3Comments

flybayer picture flybayer  路  3Comments