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.
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'
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
I see other issues reporting App cannot be invoked without 'new', but under a different context to what we are experiencing.
Maybe this will help.
https://github.com/zeit/next.js/issues/8201#issuecomment-517491282
@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 馃槄
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
.babelrcfor the shared app retain ES6 Class syntax:You'll also need to mark
shared-helpersas non-external and include them in your babel compilation, similar tonext-transpile-modules.