nuxt icon indicating copy to clipboard operation
nuxt copied to clipboard

Error when using parameter decorator in server middleware

Open izure1 opened this issue 2 years ago • 8 comments

Versions

  • nuxt: v2.15.8
  • node: v14.16.1

Reproduction

An error occurs when the parameter decorator is used in the server middleware.
I am using type-graphql module in the project, and below is the code that causes the error.

Additional Details
I'm not sure, but I think it's a problem related to jiti.

This is my jiti version.

└─┬ [email protected]
  ├─┬ @nuxt/[email protected]
  │ └── [email protected]
  └─┬ @nuxt/[email protected]
    └── [email protected] deduped

Steps to reproduce

import 'reflect-metadata'

import { Arg, Field, Int, Mutation, ObjectType, Query, Resolver } from 'type-graphql'
import { AutoIncrement, Column, DataType, IsInt, Length, Model, PrimaryKey, Table } from 'sequelize-typescript'

@Table
@ObjectType()
export class Department extends Model {
  @IsInt
  @Field(_type => Int)
  @PrimaryKey
  @AutoIncrement
  @Column(DataType.INTEGER)
  id: number

  @Length({ min: 1, max: 20 })
  @Field(_type => String)
  @Column(DataType.STRING)
  name: string
}

@Resolver(Department)
export class DepartmentResolver {
  @Mutation(_returns => Department)
  async add_department(
    @Arg('name', _type => String) name: string // <--- Here
  ): Promise<Department> {
    return await Department.create({ name })
  }
}

What is Expected?

It should work.

What is actually happening?

Displayed error.

Decorating class property failed.
Please ensure that proposal-class-properties is enabled and runs after the decorators transform.

izure1 avatar Aug 15 '21 10:08 izure1

I have the same issue, is there any news on this?

fatheaddrummer avatar Nov 15 '21 10:11 fatheaddrummer

Versions

Nuxt:2.15.8 Node: 14.15.1 Typescript:4.0.8

Reproduction

  1. Set up a local nuxt module @/modules/test.ts
  2. Write simple code with usage of class decorators (example below)
  3. Add the module to nuxt.config.js
  4. npm run dev

What is expected?

It should work.

What is actually happening?

The following error.

Error: Decorating class property failed. Please ensure that proposal-class-properties is enabled and runs after the decorators transform.

Here is the code to reproduce the issue in a simply local nuxt module using typescript

` import 'reflect-metadata' import { Module } from '@nuxt/types' import { Expose, plainToClass } from 'class-transformer'

class Category { @Expose() iAmWhitelisted: string }

const module: Module = function () { plainToClass(Category, { iAmWhitelisted: 'Foo', iAmNotWhitelisted: 'Foo', }) }

export default module

`

fatheaddrummer avatar Nov 15 '21 10:11 fatheaddrummer

@fatheaddrummer I was able to solve this problem by referring to the code in the jiti repo. but it's pretty old code, so I'm not sure if it will work.

This is my nuxt.config.js code

import jiti from 'jiti'
import { transformSync } from '@babel/core'

export default {

  ...

  createRequire: (jsFileName) => {
    return jiti(jsFileName, {
      // cache: false
      debug: false,
      legacy: true,
      transform (opts) {
        const _opts = {
          babelrc: false,
          configFile: false,
          compact: false,
          retainLines: typeof opts.retainLines === 'boolean' ? opts.retainLines : true,
          filename: '',
          cwd: '/',
          ...opts.babel,
          plugins: [
            [require('@babel/plugin-transform-modules-commonjs'), { allowTopLevelThis: true }],
            [require('babel-plugin-dynamic-import-node'), { noInterop: true }],
            [require('babel-plugin-transform-import-meta')],
            [require('@babel/plugin-syntax-class-properties')]
          ]
        }
      
        const parameterDecorator = require('babel-plugin-parameter-decorator')
        if (opts.ts) {
          _opts.plugins.push([require('@babel/plugin-transform-typescript'), { allowDeclareFields: true, onlyRemoveTypeImports: true }])
          // `unshift` because this plugin must come before `@babel/plugin-syntax-class-properties`
          _opts.plugins.unshift([require('@babel/plugin-proposal-decorators'), { legacy: true }])
          _opts.plugins.unshift(require('babel-plugin-transform-typescript-metadata'))
          _opts.plugins.push(parameterDecorator)
        }
        
        if (opts.legacy) {
          _opts.plugins.push(require('@babel/plugin-proposal-nullish-coalescing-operator'))
          _opts.plugins.push(require('@babel/plugin-proposal-optional-chaining'))
        }
        
        // `babel-plugin-parameter-decorator` plugin must come after `@babel/plugin-proposal-class-properties`
        const decoratorIndex = _opts.plugins.indexOf(parameterDecorator)
        if (decoratorIndex !== -1) {
          _opts.plugins.splice(decoratorIndex + 1, 0, [require('@babel/plugin-proposal-class-properties'), { loose: true }])
        }

        if (opts.babel && Array.isArray(opts.babel.plugins)) {
          _opts.plugins?.push(...opts.babel.plugins)
        }
      
        try {
          return {
            code: transformSync(opts.source, _opts)?.code || ''
          }
        } catch (err) {
          return {
            error: err,
            code: 'exports.__JITI_ERROR__ = ' + JSON.stringify({
              filename: opts.filename,
              line: err.loc?.line || 0,
              column: err.loc?.column || 0,
              code: err.code?.replace('BABEL_', '').replace('PARSE_ERROR', 'ParseError'),
              message: err.message?.replace('/: ', '').replace(/\(.+\)\s*$/, '')
            })
          }
        }
      }
    })
  }
}

and I needed additional module installation once more. npm i @babel/plugin-proposal-class-properties @babel/plugin-transform-typescript babel-plugin-parameter-decorator babel-plugin-transform-import-meta babel-plugin-transform-typescript-metadata --save-dev

If the problem is not solved, it may be a cache problem of jiti. Please disable the cache by giving the cache: false option.

Please forgive me for my poor English and I hope it was helpful.

izure1 avatar Nov 15 '21 13:11 izure1

Thanks for your contribution to Nuxt! This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. If you would like this issue to remain open:

  1. Verify that you can still reproduce the issue in the latest version of nuxt-edge
  2. Comment the steps to reproduce it

Issues that are labeled as pending will not be automatically marked as stale.

stale[bot] avatar Apr 17 '22 10:04 stale[bot]

I also have same problem. If anyone knows some workaround, I would like you to share it.

versions

  • nuxt : 2.15.8
  • node : 16.14.2
  • yarn : 1.22.15

what I did

  1. npx create-nuxt-app
  2. created the file ./api/index.ts and ./api/sample.ts
  3. add serverMiddleware: ['~~/api/'], to the nuxt.config.js
  4. yarn dev and access to http://localhost:3000/sample

errors shown

Decorating class property failed. Please ensure that proposal-class-properties is enabled and runs after the decorators transform.

files that were created

./api/index.ts

import express, { json, urlencoded } from 'express'
import { Sample } from './sample'

const app = express()
app.use(json())
app.use(urlencoded({ extended: true }))

app.get('/sample', (_request: express.Request, response: express.Response) => {
  console.log(new Sample())
  response.send({ message: 'OK' })
})

export default app

./api/sample.ts

const sampleDeco = (target: any, memberName: string) => {
  let currentValue: string = target[memberName]

  Object.defineProperty(target, memberName, {
    set: (newValue: string) => {
      currentValue = newValue
    },
    get: () => {
      return currentValue
    },
  })
}

export class Sample {
  @sampleDeco
  aaa?: string
}

shin4488 avatar Apr 26 '22 11:04 shin4488

I'm facing a similar issue using json2typescript in a server middleware. Seems likely it is related to jiti needing to use @babel/plugin-proposal-class-properties instead of @babel/plugin-syntax-class-properties.

https://github.com/unjs/jiti/issues/57

cshomo11 avatar Dec 02 '22 18:12 cshomo11

facing the similar issue with typeorm, anyone has workaround ?

JasonGaoG avatar Jan 16 '24 07:01 JasonGaoG

@JasonGaoG With my particular issue I ended up having to make new models that were just for the server middleware. Then I could drop json2typescript out of the files. It's not great since I have two sets of duplicate models in some spots but it worked.

cshomo11 avatar Jan 26 '24 17:01 cshomo11