TypeStrong / ts-loader

TypeScript loader for webpack
https://johnnyreilly.com/ts-loader-goes-webpack-5
MIT License
3.44k stars 429 forks source link

ts-loader fails on stage 3 decorators: Unexpected character '@' #1631

Open jeroenknoef opened 9 months ago

jeroenknoef commented 9 months ago

Expected Behaviour

Since TS 5 we can create stage 3 decorators. Using webpack and ts-loader they should be compiled without issue.

Actual Behaviour

The build fails with Unexpected character '@'

Module parse failed: Unexpected character '@' (21:0)
File was processed with these loaders:
 * ../../node_modules/ts-loader/index.js
You may need an additional loader to handle the result of these loaders.

Steps to Reproduce the Problem

https://stackblitz.com/edit/webpack-terser-ztxsth?file=src%2Findex.ts,tsconfig.json,package.json

Location of a Minimal Repository that Demonstrates the Issue.

Please see the link above

Workaround

I posted this issue on Stack Overflow and received a workaround where useDefineForClassFields must be set to false. However, this enables legacy behaviour. It would be nice if this issue could be resolved so the workaround is no longer needed. If there's another solution to the issue, I would also be happy to hear it.

IanRichter commented 5 months ago

I had the same issue and it looks like I managed to solve it. Looks like you're doing the same thing I did so hopefully this helps you too.

Problem:

Your tsconfig.json specifies target: "ESNext", which causes ts-loader to basically just emit your code with decorators intact. Webpack then picks up your code and doesn't know how to handle the decorators, hence the error. So it doesn't seem to be ts-loader that's the problem here.

Solution:

Change target to something like ES2022, which doesn't support decorators natively. This way Typescript transpiles the decorators away. The specific target shouldn't really matter so long as it's old enough to not support decorators natively.

Before:

// tsconfig.json
{
    "compilerOptions": {
        "target": "ESNext"
    }
}

After:

// tsconfig.json
{
    "compilerOptions": {
        "target": "ES2022"
    }
}