Next.js: Decorators don't work in with-typescript example.

Created on 1 Jul 2018  路  16Comments  路  Source: vercel/next.js

Examples bug report

Example name

with-typescript

Describe the bug

If I start using decorators, next.js throws an error to ask to add @babel/plugin-proposal-decorators.
And, it throws same error even after I add the plugin.

Syntax Error:
   6 | }
   7 |
>  8 | @myDecorator
     | ^
   9 | export default class IndexPage extends React.Component{
  10 |   render () {
  11 |     return <div>

Add @babel/plugin-proposal-decorators (https://git.io/vb4ST) to the 'plugins' section of your Babel config to enable transformation

To Reproduce

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

  1. Set "experimentalDecorators": true to tsconfig.json
  2. Add some any decorators to any page
import React from 'react'
import Link from 'next/link'

function myDecorator (constructor: any) {

}

@myDecorator
export default class IndexPage extends React.Component{
  render () {
    return <div>
      Hello World.{' '}
      <Link href="/about">
        <a>About</a>
      </Link>
    </div>
  }
}

Expected behavior

It should work with decorators.

Screenshots

If applicable, add screenshots to help explain your problem.

System information

  "dependencies": {
    "@zeit/next-typescript": "^1.1.0",
    "next": "^6.1.1",
    "react": "^16.4.1",
    "react-dom": "^16.4.1"
  },
  "devDependencies": {
    "@babel/plugin-proposal-decorators": "^7.0.0-beta.51",
    "@types/next": "^2.4.7",
    "@types/react": "^16.0.36"
  }

Most helpful comment

After adding @babel/plugin-proposal-decorators and @babel/plugin-proposal-class-properties, I still got the following error:

ColumnTypeUndefinedError: Column type for User#id is not defined and cannot be guessed. Make sure you have turned on an "emitDecoratorMetadata": true option in tsconfig.json. Also make sure you have imported "reflect-metadata" on top of the main entry file in your application (before any entity imported).If you are using JavaScript instead of TypeScript you must explicitly provide a column type.

Solved by installing and using babel-plugin-transform-typescript-metadata:

npm install --dev --save babel-plugin-transform-typescript-metadata

.babelrc

{
  "presets": ["next/babel"],
  "plugins": [
    "babel-plugin-transform-typescript-metadata",
    ["@babel/plugin-proposal-decorators", { "legacy": true }],
    ["@babel/plugin-proposal-class-properties", { "loose" : true }]
  ]
}

.tsconfig

...
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
...

All 16 comments

It seems to work if I add those two plugins below.

    "babel-plugin-transform-class-properties": "^6.24.1",
    "babel-plugin-transform-decorators-legacy": "^1.3.5"
{
  "presets": [
    "next/babel"
  ],
  "plugins": [
    "transform-decorators-legacy",
    "transform-class-properties"
  ]
}

But, I assume those two plugins will be deprecated in babel v7. Therefore, we need to use @babel/plugin-proposal-decorators eventually.

This plugin is specifically for Babel 6.x. If you're using Babel 7, this plugin is not for you. Babel 7's @babel/plugin-proposal-decorators officially supports the same logic that this plugin has, but integrates better with Babel 7's other plugins. You can enable this with
https://github.com/loganfsmyth/babel-plugin-transform-decorators-legacy#babel--7x

But, It starts breaking again after I tried like the below.

{
  "plugins": [
    ["@babel/plugin-proposal-decorators", { "legacy": true }],
    ["@babel/plugin-proposal-class-properties", { "loose" : true }]
  ]
}

Then throws this error:

ModuleBuildError: Module build failed: Error: [BABEL] /PROJECT_ROOT/pages/index.tsx: You gave us a visitor for the node type PrivateName but it's not a validtype (While processing: "/PROJECT_ROOT/node_modules/@babel/plugin-proposal-class-properties/lib/index.js")

Fortunately, it works again after I install thew newest version of babel(v7.0.0-beta.51).

@timneutkens Is it okay to upgrade the version of @babel/core so I could update .babelrc of with-mobx example too?

I assume it is inevitable to use @babel/plugin-proposal-decorators for now.

Is it okay to upgrade the version of @babel/core

This is a breaking change.

Okay. Then, I'll stick with my temporary solution until it is upgraded. 馃憤

I still get an error when trying to import a typescript module with a decorator @Rokt33r, any ideas on how to make this work? thanks!

ModuleParseError: Module parse failed: Unexpected character '@' (10:2)
You may need an appropriate loader to handle this file type.
|
| export class PlaylistsStore {
>   @observable playlists: List<Playlist> = List([]);

I'm on next 7.0.0-canary.0

I had similar problem as here:
https://github.com/kriasoft/react-starter-kit/issues/1522

The solution was to check what babel version is used by next, and use the same version in @babel/plugin-proposal-decorators

@lkostrowski 's solution is also valid. If you don't want to see deprecated warnings, please install specific version of @babel/core, which fits the version of @babel/plugin-proposal-decorators, again to override the one with next.js.

as far as I'm aware this is fixed with Next 7.x.

@timneutkens

I cloned the latest with-typescript repo & added those 2 settings to .babelrc, but I'm still getting those errors.

next_config_js_ _next_js

https://github.com/webberwang/next.js/commit/ed1a37ff865ed101e9fefb91ee9dafa04e69c9d7

@webberwang The problem is that neither @babel/plugin-proposal-decorators nor @babel/plugin-proposal-class-properties support the function parameter decorator.

This

@injectable()
class Ninja implements Warrior {
    @inject(TYPES.Weapon) private _katana: Weapon;
    @inject(TYPES.ThrowableWeapon) private _shuriken: ThrowableWeapon;
    public fight() { return this._katana.hit(); }
    public sneak() { return this._shuriken.throw(); }
}

instead of

@injectable()
class Ninja implements Warrior {

    private _katana: Weapon;
    private _shuriken: ThrowableWeapon;

    public constructor(
        @inject(TYPES.Weapon) katana: Weapon,
        @inject(TYPES.ThrowableWeapon) shuriken: ThrowableWeapon
    ) {
        this._katana = katana;
        this._shuriken = shuriken;
    }

    public fight() { return this._katana.hit(); }
    public sneak() { return this._shuriken.throw(); }
}

will work well.

There is a babel plugin for the parameter decorator: https://github.com/WarnerHooh/babel-plugin-parameter-decorator. I've applied it to use the parameter decorator on nextjs but failed to remove all error messages :(

I add a comment because maybe it will save some time for others. The current condition is still as @myeongjae-kim wrote in August 2019. I am currently working on a Next.js web application, that uses "module": "esnext". Interestingly, when I run tests using mocha and chai, I need to modify on the fly the "module" mode to "commonjs" with a command like this one:

cross-env TS_NODE_COMPILER_OPTIONS='{ \"module\": \"commonjs\" }' mocha -r ts-node/register tests/**/*.test.ts

And in this case, parameter decorators work fine. But they don't work when starting the web app using yarn next with the different module mode. Removing constructors work fine, but in my opinion it also make classes a bit harder to test and more verbose, since now I cannot simply instantiate a class to test it and need to add property setters to otherwise full private properties. Pity.

After adding @babel/plugin-proposal-decorators and @babel/plugin-proposal-class-properties, I still got the following error:

ColumnTypeUndefinedError: Column type for User#id is not defined and cannot be guessed. Make sure you have turned on an "emitDecoratorMetadata": true option in tsconfig.json. Also make sure you have imported "reflect-metadata" on top of the main entry file in your application (before any entity imported).If you are using JavaScript instead of TypeScript you must explicitly provide a column type.

Solved by installing and using babel-plugin-transform-typescript-metadata:

npm install --dev --save babel-plugin-transform-typescript-metadata

.babelrc

{
  "presets": ["next/babel"],
  "plugins": [
    "babel-plugin-transform-typescript-metadata",
    ["@babel/plugin-proposal-decorators", { "legacy": true }],
    ["@babel/plugin-proposal-class-properties", { "loose" : true }]
  ]
}

.tsconfig

...
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
...

Thanks @denniske That worked for me like a charm

Despite having the same config as yours @denniske, I'm still having issues:
I use type-graphql, when using Arg decorator, I get:

Module parse failed: Unexpected character '@' (55:17)
File was processed with these loaders:
 * ./node_modules/next/dist/build/webpack/loaders/next-babel-loader.js
You may need an additional loader to handle the result of these loaders.
|
|
>   async register(@Arg("data")
|   {
|     email,

Any ideas?

Despite having the same config as yours @denniske, I'm still having issues:
I use type-graphql, when using Arg decorator, I get:

Module parse failed: Unexpected character '@' (55:17)
File was processed with these loaders:
 * ./node_modules/next/dist/build/webpack/loaders/next-babel-loader.js
You may need an additional loader to handle the result of these loaders.
|
|
>   async register(@Arg("data")
|   {
|     email,

Any ideas?

Having the same issue. Have you found any solution yet?

Edit: Fixed it

Had to add additional plugin for parameter decorators. 馃憠馃徎 LINK

Here is my:

// .babelrc
{
  "presets": ["next/babel"],
  "plugins": [
    "babel-plugin-transform-typescript-metadata",
    ["@babel/plugin-proposal-decorators", { "legacy": true }],
    ["@babel/plugin-proposal-class-properties", { "loose": true }],
    "babel-plugin-parameter-decorator"
  ]
}
// tsconfig.json
{
  "compilerOptions": {
    "target": "ES2017",
    "module": "esnext",
    "lib": ["ES2017", "dom", "dom.iterable", "esnext"],
    "sourceMap": true,
    "outDir": "./dist",
    "moduleResolution": "node",
    "removeComments": true,
    "noImplicitAny": true,
    "strictNullChecks": true,
    "strictFunctionTypes": true,
    "noImplicitThis": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noImplicitReturns": true,
    "noFallthroughCasesInSwitch": true,
    "allowSyntheticDefaultImports": true,
    "esModuleInterop": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "resolveJsonModule": true,
    "baseUrl": ".",
    "allowJs": true,
    "skipLibCheck": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "noEmit": true,
    "isolatedModules": true,
    "jsx": "preserve"
  },
  "exclude": ["node_modules"],
  "include": ["./**/*.tsx", "./**/*.ts"]
}
Was this page helpful?
0 / 5 - 0 ratings

Related issues

timneutkens picture timneutkens  路  3Comments

wagerfield picture wagerfield  路  3Comments

swrdfish picture swrdfish  路  3Comments

ghost picture ghost  路  3Comments

rauchg picture rauchg  路  3Comments