Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Next.js 9.0.2] Shallow rendering issue: App cannot be invoked without 'new' #8175

Closed
rzschoch opened this issue Jul 30, 2019 · 19 comments
Closed

Comments

@rzschoch
Copy link

rzschoch commented Jul 30, 2019

Bug report

Describe the bug

After updating our app from Next.js 7.0.2 to 9.0.2 enzyme’s shallow rendering (same issue with enzyme’s mount) for the custom <App> (_app.is) not working anymore. The local development server is serving the app perfectly fine, though.

For experimental purposes we also tried running our tests with Next.js 8.1.0 and the rendering caused no problems.

To Reproduce

Clone the issue repository:
https://github.com/rzschoch/next-9-issues/tree/shallow-issue

  1. Run npm install
  2. Run npm run test
  3. See error: TypeError: Class constructor App cannot be invoked without 'new'

Expected behavior

The test in /src/pagesSpecs/_app.spec.js should be rendered without issues and compared against the existing snapshot (from Next.js 7.0.2).

Screenshots

image

System information

  • OS: MacOS 10.14.5 / Windows 10.0.17763 Build 17763
  • Version of Next.js: 9.0.2
@huv1k
Copy link
Contributor

huv1k commented Jul 30, 2019

Hey @rzschoch, could you test it with the latest canary? There should be a fix for it.

@rzschoch
Copy link
Author

Hi @huv1k 9.0.3-canary.5 does not fix it, unfortunately.

@rzschoch
Copy link
Author

rzschoch commented Jul 31, 2019

That’s @huv1k solution for now (thank you):
“We updated our build to use modern javascript with esmodules in this PR (#7014). There is a problem that node doesn't support it yet so you need to use for your tests current node. You can achieve this with this .babelrc:“

{
  "presets": ["next/babel"],
  "plugins": ["inline-react-svg"],
  "env": {
    "test": {
      "presets": [
        ["next/babel", { "preset-env": { "targets": { "node": "current" } } }]
      ],
      "plugins": ["dynamic-import-node"]
    }
  }
}

@huv1k
Copy link
Contributor

huv1k commented Jul 31, 2019

Now it should work just with canary @rzschoch #8181

@huv1k huv1k closed this as completed Jul 31, 2019
@rzschoch
Copy link
Author

rzschoch commented Jul 31, 2019

It is now working fine with the latest canary (9.0.3-canary.6 in my case) and a .babelrc like so:

{
  "presets": ["next/babel"],
  "plugins": ["inline-react-svg"]
}

@heeju
Copy link

heeju commented Aug 1, 2019

Same issue in 9.0.3
not happen in 9.0.2

@ricardo-cantu
Copy link

I have the same problem with 9.0.3 on a HOC of the custom _app.ts. I get the same error at super(props) in constructor of HOC.

compiled line:

_this = Object(_babel_runtime_corejs2_helpers_esm_possibleConstructorReturn__WEBPACK_IMPORTED_MODULE_16__["default"])(this, Object(_babel_runtime_corejs2_helpers_esm_getPrototypeOf__WEBPACK_IMPORTED_MODULE_17__["default"])(WithI18next).call(this, props));

source:

const withI18next = (WrappedApp: typeof App) => {
  const WrappedComponentWithSSR = withSSR()(WrappedApp)
  ...
  class WithI18next extends App<WithI18nextProps> {
    public static displayName = `WithI18next(${WrappedApp.name || 'App'})`
    ...
    public constructor(props: WithI18nextProps) {
      super(props)
      ...
    }

@alexmarmon
Copy link

The latest canary didn't work for me, but the following did:

{
  "plugins": [],
  "presets": [
    [
      "next/babel",
      {
        "preset-env": { "targets": { "node": "current" } }
      }
    ]
  ]
}

@chrisguidry
Copy link

Just a data point, I was able to resolve this issue with unit testing a custom _app.js by giving my App subclass a no-op constructor:

  // This no-op constructor helps with an error:
  // TypeError: Class constructor App cannot be invoked without 'new'
  constructor(props) {
    super(props);
  }

@PaxLyj
Copy link

PaxLyj commented Aug 22, 2019

Still same problem in next@9.0.4, my _app.js and _document.js files are exactly same as this example project about styled-component.
here is my .babelrc -

{
  "presets": [
    "@babel/preset-env",
    "@babel/preset-react",
    "@babel/preset-flow",
    [
      "next/babel",
      {
        "preset-env": { "targets": { "node": "current" } }
      }
    ]
  ],
  "plugins": [
    [
      "@babel/plugin-proposal-decorators",
      { "legacy": true }
    ],
    [
      "styled-components",
      { "ssr": true, "displayName": true, "preprocess": false }
    ],
    [
      "babel-plugin-root-import",
      {
        "rootPathPrefix": "~",
        "rootPathSuffix": "./src/app"
      }
    ]
  ]
}

It workes when removing both _app.js and _document.js.

@PaxLyj
Copy link

PaxLyj commented Aug 23, 2019

Never mind, removing "@babel/preset-env" from "presets" solve this issue.

@matigda
Copy link

matigda commented Aug 30, 2019

I have the same issue. This is mine next.config.js:

/* eslint no-param-reassign: 0 */
const appConfig = require("./config");
const path = require("path");
const webpack = require("webpack");

module.exports = {
  publicRuntimeConfig: {
    restRootEndpointUrl: appConfig.REST_ROOT_ENDPOINT_URL,
    adminAuthenticationUrl: appConfig.ADMIN_AUTHENTICATION_URL,
  },

  distDir: "../build/app",
  webpack: (config, { buildId, dev, isServer, defaultLoaders }) => {
    // Fixes npm packages that depend on `fs` module
    config.node = {
      fs: "empty"
    };

    config.resolve.alias["../../storefront-ui/config"] = path.resolve(
      __dirname,
      "storefront-ui/config.js"
    );

    config.resolve.alias["storefront-ui"] = `@r00dy/storefront-ui/`;

    config.module.rules.push({
      test: /\.(graphql|gql)$/,
      exclude: /node_modules/,
      loader: "graphql-tag/loader"
    });

    config.module.rules.push({
      test: /\.svg$/,
      use: [
        {
          loader: "@svgr/webpack",
          options: {
            svgoConfig: {
              plugins: {
                removeViewBox: false
              }
            },
            titleProp: true
          }
        }
      ]
    });

    // Variables required by storefront-ui to be defined globally. The following line makes them visible in bundle.
    config.plugins.push(
      new webpack.DefinePlugin({
        __DEV__: dev,
        __BROWSER__: !isServer
      })
    );

    return config;
  }
};

and this is babel.rc:

{
  "presets": ["next", "@babel/preset-react", "@emotion/babel-preset-css-prop"],
  "plugins": [
    ["@babel/plugin-proposal-decorators", { "legacy": true }],
    ["@babel/plugin-proposal-class-properties", { "loose": true }]
  ]
}

I tried with calling: constructor(props) { super(props); } but it didn't work. And it started after upgrading to 9.0.5.

@Comette
Copy link

Comette commented Sep 6, 2019

I'm also facing the same issue after updating from 7 to 9.0.5.
Here is my .babelrc:

{
    "presets": [
      "@babel/preset-env",
      "@babel/preset-react",
      ["next/babel", { "preset-env": { "targets": { "node": "current" } } }]
    ],
    "plugins": ["@babel/plugin-proposal-class-properties", "inline-react-svg"],
    "env": {
      "development" : {
        "compact": false
      }
    }
}

Also my next.config.js:

const withSass = require('@zeit/next-sass')
const eslintFormatter = require('react-dev-utils/eslintFormatter')
const alias = require('./config/alias')
const StyleLintPlugin = require('stylelint-webpack-plugin')
const FilterPlugin = require('./config/filter.plugin')
const withOffline = require('next-offline')
const withSize = require('next-size')
const nextBuildId = require('next-build-id')

module.exports = withOffline(withSize(withSass({
  useFileSystemPublicRoutes: false,
  cssModules: true,

  cssLoaderOptions: {
    localIdentName: '[local]_-[hash:base64:5]'
  },

  sassLoaderOptions: {
    includePaths: ['static/style']
  },

  publicRuntimeConfig: {
    API_URL: JSON.stringify(process.env.API_URL),
    PUBLIC_URL: JSON.stringify(process.env.PUBLIC_URL)
  },

  generateBuildId: () => nextBuildId({ dir: __dirname }),

  webpack(configuration) {
    const config = configuration

    config.node = {
      fs: 'empty'
    }

    config.resolve = {
      alias: { ...(config.resolve.alias || {}), ...alias },
      extensions: ['.web.js', '.mjs', '.js', '.json', '.web.jsx', '.jsx']
    }

    config.plugins.push(
      // Silence mini-css-extract-plugin generating lots of warnings for CSS ordering.
      // We use CSS modules that should not care for the order of CSS imports, so we
      // should be safe to ignore these.
      new FilterPlugin({ filter: /chunk styles \[mini-css-extract-plugin]\nConflicting order between:/ }),
    )

    config.module.rules.push(
      {
        test: /\.(js|jsx|mjs)$/,
        enforce: 'pre',
        use: [
          {
            options: {
              formatter: eslintFormatter,
              eslintPath: require.resolve('eslint')
            },
            loader: require.resolve('eslint-loader')
          }
        ],
        include: alias['app-root']
      },
      {
        test: /\.(ttf|eot|woff|woff2|otf|txt|jpg|png|svg|ico)$/,
        use: [
          {
            loader: 'url-loader',
            options: {
              limit: 10000,
              name: '[path][name].[hash].[ext]',
              publicPath: '/_next'
            }
          }
        ]
      }
    )

    config.plugins.push(
      new StyleLintPlugin({
        context: alias['app-root'],
        files: '**/*.scss',
        emitErrors: true
      })
    )

    return config
  }
})))

@dannypk
Copy link

dannypk commented Sep 18, 2019

Never mind, removing "@babel/preset-env" from "presets" solve this issue.

after i removed the preset-env in presets, all i had in .babelrc was

   "presets": [
    "next/babel"
  ] 

and it didn't work

After that i changed to

"presets": [
    [
      "next/babel",
      {
        "preset-env": { "targets": { "node": "current" } }
      }
    ]
  ]

and it works 👍

@troyblank
Copy link

Never mind, removing "@babel/preset-env" from "presets" solve this issue.

This also worked for me, I replaced

["@babel/preset-env", { "targets": "> 0.5% in US" } ]

with

["next/babel", { "preset-env": { "targets": "> 0.5% in US" } }]

@mwildehahn
Copy link

I'm running into this:

TypeError: Class constructor cannot be invoked without 'new'

with the following tsconfig.json:

{
  "compilerOptions": {
    "declaration": false,
    "target": "es6",
    "lib": [
      "dom",
      "dom.iterable",
      "esnext"
    ],
    "allowJs": true,
    "skipLibCheck": true,
    "strict": false,
    "forceConsistentCasingInFileNames": true,
    "noEmit": true,
    "esModuleInterop": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "jsx": "preserve"
  },
  "exclude": [
    "node_modules"
  ],
  "include": [
    "next-env.d.ts",
    "**/*.ts",
    "**/*.tsx"
  ]
}

Any ideas?

@gaurav5430
Copy link

In my case, I had a custom webpack config which was using babel loader like this:

      {
        // for all files except for node_modules, but including @scoped within node_modules
        test: /\.(js|tsx)$/,
        exclude: /node_modules(?!\/@scoped\/)/,
        use: {
          loader: 'babel-loader',
        },
      },

and the babel.config.js was like this:

module.exports = {
presets: [
 'next/babel',
  ],
  plugins: [
    [
      'react-css-modules', {
        generateScopedName: '[name]__[local]',
        webpackHotModuleReloading: true,
        handleMissingStyleName: 'warn',
      },
    ],
    'dynamic-import-node',
    [
      '@babel/plugin-proposal-decorators', {
        legacy: true,
      },
    ],
  ],
};

This was giving me an error 'App cannot be invoked without new'

The error was resolved by either of these:

  1. remove the custom webpack config which uses babel-loader. (not an option as we need it to include some files from inside node _modules for babel transpilation)
  2. by changing babel.config.js :
presets: [
[
'@babel/preset-env',
],
'next/babel',
]

Did not choose this option as nextjs docs specifically suggest not to add the presets which are already included in 'next/babel'
https://nextjs.org/docs/advanced-features/customizing-babel-config

  1. by changing babel.config.js:
 presets: [
    [
      'next/babel',
      {
        'preset-env': { targets: { node: 'current' } },
      },
    ],
  ],

This was the option we went ahead with, although it is still not clear why this solves the issue.

@mikestopcontinues
Copy link

mikestopcontinues commented Mar 31, 2020

What's the working solution for lerna, nextjs, and babel these days?

I'm trying to avoid pre-transpiling my libraries before import, and I've hit a brick wall with every solution here. Here's what I can't get working:

  • next-transpile-modules.
  • resetting the preset-env settings.
  • updating the next-babel-loader include and exclude rules to pass/fail respectively.

@balazsorban44
Copy link
Member

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.

@vercel vercel locked as resolved and limited conversation to collaborators Jan 30, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests