vercel / next.js

The React Framework
https://nextjs.org
MIT License
125.95k stars 26.87k forks source link

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

Closed michaeljonathanblack closed 5 years ago

michaeljonathanblack commented 5 years ago

Bug report

Describe the bug

Updating from Next 8 to Next 9.1.x results in the following production build runtime errors:

This can be fixed by adding preset-env configuration to the babel.config.js file (shared below), however my understanding is that this should not be required (and therefore may have unintended side effects).

presets: [['next/babel', { 'preset-env': { targets: { node: true } } }]],

To Reproduce

Steps to reproduce the behavior, please provide code snippets or a repository:

  1. Clone the repository located at: https://github.com/mherodev/next-demo
  2. npm i
  3. Replace the currently working presets: [['next/babel', { 'preset-env': { targets: { node: true } } }]], line of code inside babel.config.js with presets: ['next/babel'],
  4. npm run build
  5. npm start
  6. Visit localhost:3003
  7. See the internal server error provided below:
206476943-MAC2:next-demo 206476943$ npm run build

> next-demo@1.0.0 build /Users/206476943/git/next-demo
> run-s build:clean build:server build:next build:copy

> next-demo@1.0.0 build:clean /Users/206476943/git/next-demo
> rm -rf ./build ./src/.next && npm run clean:babel-loader

> next-demo@1.0.0 clean:babel-loader /Users/206476943/git/next-demo
> rm -rf node_modules/.cache/babel-loader

> next-demo@1.0.0 build:server /Users/206476943/git/next-demo
> NODE_ENV=production npx babel src --out-dir build

Successfully compiled 30 files with Babel.

> next-demo@1.0.0 build:next /Users/206476943/git/next-demo
> NODE_ENV=production npx next build src

Creating an optimized production build ..[2:11:27 PM] Compiling client
[2:11:27 PM] Compiling server
Creating an optimized production build ...[2:11:31 PM] Compiled server in 4s
Creating an optimized production build ..[2:11:35 PM] Compiled client in 7s
Creating an optimized production build  

Compiled successfully.

Warning: You have opted-out of Automatic Static Optimization due to `getInitialProps` in `pages/_app`.
Read more: https://err.sh/next.js/opt-out-auto-static-optimization

Automatically optimizing pages  

Page            Size     Files  Packages
┌   /_app       302 kB       0        23
├   /_document
├   /_error     182 B        0         6
├ σ /AboutPage  968 B       14         6
└ σ /HomePage   1.02 kB     16         6

σ  (Server)       page will be server rendered (i.e. getInitialProps)
⚡  (Static File)  page was prerendered as static HTML

Creating an optimized production build ...
> next-demo@1.0.0 build:copy /Users/206476943/git/next-demo
> cp -r src/.next/ build/.next/ && cp -r src/static build/

206476943-MAC2:next-demo 206476943$ npm start

> next-demo@1.0.0 start /Users/206476943/git/next-demo
> NODE_ENV=production node build/server.js

TypeError: Class constructor App cannot be invoked without 'new'
    at new MyApp (/Users/206476943/git/next-demo/build/.next/server/static/4oNbjBtSOiwSJYUowORKH/pages/_app.js:805:120)
    at c (/Users/206476943/git/next-demo/node_modules/react-dom/cjs/react-dom-server.node.production.min.js:33:323)
    at Sa (/Users/206476943/git/next-demo/node_modules/react-dom/cjs/react-dom-server.node.production.min.js:36:1)
    at a.render (/Users/206476943/git/next-demo/node_modules/react-dom/cjs/react-dom-server.node.production.min.js:41:467)
    at a.read (/Users/206476943/git/next-demo/node_modules/react-dom/cjs/react-dom-server.node.production.min.js:41:58)
    at renderToString (/Users/206476943/git/next-demo/node_modules/react-dom/cjs/react-dom-server.node.production.min.js:53:83)
    at render (/Users/206476943/git/next-demo/node_modules/next/dist/next-server/server/render.js:81:16)
    at renderPage (/Users/206476943/git/next-demo/node_modules/next/dist/next-server/server/render.js:283:20)
    at Function.getInitialProps (/Users/206476943/git/next-demo/build/.next/server/static/4oNbjBtSOiwSJYUowORKH/pages/_document.js:162:18)
    at Object.loadGetInitialProps (/Users/206476943/git/next-demo/node_modules/next/dist/next-server/lib/utils.js:50:35)
TypeError: Class constructor Document cannot be invoked without 'new'
    at new RootDocument (/Users/206476943/git/next-demo/build/.next/server/static/4oNbjBtSOiwSJYUowORKH/pages/_document.js:173:256)
    at c (/Users/206476943/git/next-demo/node_modules/react-dom/cjs/react-dom-server.node.production.min.js:33:323)
    at Sa (/Users/206476943/git/next-demo/node_modules/react-dom/cjs/react-dom-server.node.production.min.js:36:1)
    at a.render (/Users/206476943/git/next-demo/node_modules/react-dom/cjs/react-dom-server.node.production.min.js:41:467)
    at a.read (/Users/206476943/git/next-demo/node_modules/react-dom/cjs/react-dom-server.node.production.min.js:41:58)
    at Object.renderToStaticMarkup (/Users/206476943/git/next-demo/node_modules/react-dom/cjs/react-dom-server.node.production.min.js:53:181)
    at renderDocument (/Users/206476943/git/next-demo/node_modules/next/dist/next-server/server/render.js:90:18)
    at Object.renderToHTML (/Users/206476943/git/next-demo/node_modules/next/dist/next-server/server/render.js:319:16)
    at process._tickCallback (internal/process/next_tick.js:68:7)

Expected behavior

It shouldn't error, the site should load.

System information

Additional context

This error didn't occur in Next 8.

scott-thrillist commented 5 years ago

Happens to me too. Would just like to add that any browsers targets in addition to node triggers this issue for me again. We can't seem to spit out code that is IE11 compatible.

lfades commented 5 years ago

@mherodev Your demo is updating the default webpack config and breaking the build step here. Next.js already includes babel-loader (a custom version) and including it again is going to create a lot of unexpected issues.

To fix your issues remove the babel loader from next.config.js. Try to avoid custom webpack config unless you really need it and none of the next plugins and configs can help you out.

You're also using the same babel config for both the custom server and next app, that's not a good idea because next/babel is not intended to be used by custom servers.

scott-thrillist commented 5 years ago

@lfades I did what you recommended, even went so far as to remove my next.config.js but I'm still seeing the error message as described above when I add browsers: ['> 1%'] in the targets object. The code appears to be compiled correctly without any arrow functions and the page loads for about 4 seconds, but then it turns white and displays the Uncaught TypeError: Class constructor App cannot be invoked without 'new' error.

Any idea why? Feel like I'm so close on getting IE11 to work.

michaeljonathanblack commented 5 years ago

@lfades Thanks so much for the investigation and feedback!

I imagine the custom loader was a work-around for a transpilation issue we had in the past, either around our build or tests, but I'll experiment with removing it and see if I can get it running without issue.

As for the server transpilation using the same next/babel config, our goal was to be able to write the same code on our server that we write on the client. Are you aware of any side effects we might encounter by using this mirrored config?

Given how many users are adopting a custom server and transpiling their server code, perhaps a feature request for a next-server/babel would make sense? Since they're essentially coupled, barring any client-only transpilation that should be done for backward compatibility (perhaps introducing de-optimizations?)

lfades commented 5 years ago

@mherodev We recommend the usage of serverless and API routes over a custom server, in your case for example a custom server is not needed at all. Transpiling the server code is okay, but you should use the recommended babel way of doing it for Node.js and not the preset used by Next.js.

@scott-thrillist I don't have many details about your project so I can't say much. Next.js supports IE11 by default, if that's not the case please open up an issue with a reproduction 🙏

michaeljonathanblack commented 5 years ago

@lfades Huh, I can't remove that babel-loader override from our next config. If I try to run the app without it, our inline svg loader inline-react-svg doesn't work correctly, i.e.

https://github.com/mherodev/next-demo/blob/master/src/components/Header/Header.js#L5-L6

Module parse failed: Unexpected token (1:0)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders

I'm not sure if this is a bug with babel-plugin-inline-react-svg or next, but it's a blocker for correctly transpiling our project.

scott-thrillist commented 5 years ago

If anyone else gets here via Google the package that fixed my issue was:

import 'react-app-polyfill/ie11';

In polyfills.js

michaeljonathanblack commented 4 years ago

@scott-thrillist Could you share your polyfills.js file and how it's hooked into the next/babel config? We've had (currently have?) issues with ie11 as well and I'd love to give this fix a shot.

scott-thrillist commented 4 years ago

My polyfills.js is small:

/* eslint no-extend-native: 0 */

// IE11 support
import 'react-app-polyfill/ie11';

// Load polyfill for Intersection Observer
import 'intersection-observer';

The env portion of my babel config looks like this:

env: {
  development: {
    presets: [['next/babel', { 'preset-env': { targets: { browsers: '>1% in US' } } }]],
    compact: false
  },
  production: {
    presets: [['next/babel', { 'preset-env': { targets: { browsers: '>1% in US' } } }]]
  },
  test: {
    presets: [
      ['next/babel', { 'preset-env': { modules: 'commonjs', targets: { node: 'current' } } }]
    ],
    plugins: ['require-context-hook', 'dynamic-import-node']
  }
}
scott-thrillist commented 4 years ago

@mherodev also, I had to remove ignore: [/node_modules/] in our babel config to make sure things are funneling through babel.

michaeljonathanblack commented 4 years ago

Does next ignore node_modules by default? We don't have that in our config either.

jemliF commented 4 years ago

Hi, I have the same issue when migrating from next v8.1.0 to 9.2, here is my configuration files: next.config.js:

const withSass = require('@zeit/next-sass');
/*const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');*/
const { resolve } = require('path');

let baseUrl = process.env.BASE_URL;
baseUrl = baseUrl && baseUrl.length && '/' !== baseUrl ? baseUrl : '';

module.exports = withSass({
  transpileModules: ['file-type'],
  /*webpack(config, options) {
    config.module.rules.push({
      test: /\.tsx?$/,
      use: [
        {
          loader: 'babel-loader',
          options: {
            configFile: resolve('babel.config.js'),
          },
        },
        {
          loader: 'ts-loader',
          options: {
            // disable type checker - we will use it in fork plugin
            transpileOnly: true,
          },
        },
      ],
    });
    config.module.rules.push({
      test: /node_modules\/file-type/,
      use: [
        {
          loader: 'babel-loader',
          options: {
            configFile: resolve('babel.config.js'),
            exclude: /node_modules\/(?!(file-type))/,
            include: /node_modules\/file-type/,
            sourceType: 'unambiguous',
          },
        },
      ],
    });

    config.resolve.extensions.push('.ts');
    config.resolve.extensions.push('.tsx');
    config.resolve.extensions.push('.jsx');

    return config;
  },*/
  pageExtensions: ['jsx', 'tsx'],
  cssModules: true,
  cssLoaderOptions: {
    importLoaders: 1,
    localIdentName: '[local]___[hash:base64:5]',
  },
  sassLoaderOptions: {
    includePaths: [resolve('src/scss')],
  },
  webpackDevMiddleware: config => {
    if (process.env.ENABLE_WATCH_POLL) {
      const watchOptions = {
        poll: true,
        aggregateTimeout: 500,
        ignored: [
          '.git/**',
          'src/.next/**',
          '**/__tests__/**',
          '.scannerwork/**',
          'cypress/**',
          'doc/**',
          'node_modules/**',
          'src/static/**',
        ],
      };
      return { ...config, watch: true, watchOptions };
    }
    return config;
  },

  publicRuntimeConfig: {
    env: process.env.APP_ENV,
    nodeEnv: process.env.NODE_ENV,
    apiProxy: process.env.API_PROXY,
    subscriptionKey: process.env.OCP_APIM_SUBSCRIPTION_KEY,
    apiEndpoint: process.env.API_ENDPOINT,
    serverPort: process.env.SERVER_PORT,
    gmapApiendpoint: process.env.GMAP_API_KEY,
    gigyaApiKey: process.env.GIGYA_API_KEY,
    gigyaDatacenter: process.env.GIGYA_DATACENTER,
    templateReimbursementLink: process.env.TEMPLATE_REIMBURSEMENT_LINK,
    reimbursementStatusLink: process.env.REIMBURSEMENT_STATUS_LINK,
    gtmId: process.env.GTM_ID,
    captchaSiteKey: process.env.CAPTCHA_SITE_KEY,
    baseUrl,
    redisPort: process.env.REDIS_PORT,
    redisHost: process.env.REDIS_HOST,
    redisPassword: process.env.REDIS_PASSWORD,
  },
});

.babelrc.js:

const env = require('./src/lib/env-config.js');

module.exports = require('./babel.config.js');

babel.config.js:


const env = require('./src/lib/env-config.js');

module.exports = {
  env: {
    development: {
      extends: './config/.babelrc.default.js',
    },
    production: {
      extends: './config/.babelrc.default.js',
    },
    test: {
      extends: './config/.babelrc.test.js',
      plugins: ['require-context-hook'],
    },
    storybook: {
      extends: './config/.babelrc.test.js',
    },
  },
  plugins: [
    ['transform-define', env],
    ['styled-components', { ssr: true }],
    ['@babel/plugin-proposal-class-properties'],
    ['@babel/plugin-proposal-optional-chaining'],
  ],
  presets: [
    '@babel/env',
    [
      'next/babel',
      {
        'preset-env': { targets: { node: 'current' } },
      },
    ],
  ],
};

.babelrc.default.js:

module.exports = {
  presets:  [
    [
      "next/babel",
      {
        "preset-env": { "targets": { "node": "current" } }
      }
    ]
  ],
  plugins: [
    '@babel/plugin-transform-runtime',
    '@babel/plugin-proposal-export-default-from',
    [
      'module-resolver',
      {
        root: ['./src'],
        alias: {
          src: './src',
          config: './src/config',
        },
      },
    ],
  ],
};
balazsorban44 commented 2 years ago

This issue has been automatically locked due to no recent activity. If you are running into a similar issue, please create a new issue with the steps to reproduce. Thank you.