evanw / esbuild

An extremely fast bundler for the web
https://esbuild.github.io/
MIT License
38.11k stars 1.15k forks source link

Feature request: Decorators support #104

Closed fannheyward closed 5 months ago

fannheyward commented 4 years ago

error: Decorators are not supported yet

Any plan to support decorators?

Akimyou commented 4 years ago

https://github.com/vuejs/vue-cli/tree/dev/packages/@vue/babel-preset-app#readme

Hope can support Decorators, then we can try it in vue project.

evanw commented 4 years ago

The decorator spec unfortunately still seems like it's a long way off, both based on low activity and based on how many things it looks like they still have to figure out. The proposal has drifted pretty far from what the entire rest of the JavaScript ecosystem has been doing for many years. It also appears to be incompatible with a lot of the JavaScript ecosystem (e.g. no CommonJS support). So I'm not planning on supporting decorators based on the spec, at least not any time soon.

Separate from that, decorators in TypeScript have been around for a while behind the experimentalDecorators flag, and have found a lot of adoption in the web development community. I think esbuild would be useful to many more people if it had support for TypeScript-style decorators. So I'm planning to implement those at some point.

wxs77577 commented 4 years ago

nest.js is a great web framework but it's extremely slow during compilation. There are over 20 modules in my project. :(

evanw commented 4 years ago

An initial implementation of TypeScript decorators has been released in version 0.4.10. You can read more about this in the release notes. Please let me know if you encounter any issues.

guoyunhe commented 2 years ago

I have a JS project, not TS. When compiling decorators, it throws errors:

[vite:esbuild] Transform failed with 1 error:
/Users/guoyunhe/src/pages/aaa/components/bbb/index.jsx:13:0: error: Unexpected "@"
file: /Users/guoyunhe/src/pages/aaa/components/bbb/index.jsx:13:0

Unexpected "@"
12 |  
   |   ^
13 |  @connect(({ aaa, bbb }) => ({
   |  ^
14 |    aaa,
evanw commented 2 years ago

Decorators are not a JS feature, so esbuild doesn't support them in JS. Nothing in the JS specification mentions decorators: https://262.ecma-international.org/12.0/. But they are a TS feature, so esbuild supports them in TS. You can tell esbuild to compile your JS as TS if you like: --loader:.jsx=tsx.

guoyunhe commented 2 years ago

Decorators are not a JS feature, so esbuild doesn't support them in JS. Nothing in the JS specification mentions decorators: https://262.ecma-international.org/12.0/. But they are a TS feature, so esbuild supports them in TS. You can tell esbuild to compile your JS as TS if you like: --loader:.jsx=tsx.

Thanks. I am now moving my project to TS and it works very well.

UndiedGamer commented 2 years ago

Looks like decorators but without the metadata has moved to stage 3 and i am sure typescript will implement this in a while, what are your plans for javascript decorators support, @evanw

evanw commented 2 years ago

My plans are to implement it after it has shipped in a browser, in node, or in TypeScript. This is the same thing that I do for all other syntax features.

rluvaton commented 1 year ago

TypeScript implemented this on 5.0 beta

https://devblogs.microsoft.com/typescript/announcing-typescript-5-0-beta/#decorators

evanw commented 1 year ago

I looked into this in more detail and it seems like TypeScript is only doing a partial implementation. Work on the specification is ongoing and the API is likely going to change, at which point TypeScript will also have to change their implementation too: https://github.com/tc39/proposal-decorators/issues/494. So implementing this in esbuild still seems premature (although it's closer than before!).

jakebailey commented 1 year ago

I believe everything's been resolved as of today:

Meesayen commented 1 year ago

Hi @evanw, could this ticket be re-opened now that https://github.com/tc39/proposal-decorators/issues/494 has been closed and necessary changes been merged into the spec?

evanw commented 1 year ago

It looks like the specification is still actively being iterated on. For example: https://github.com/tc39/proposal-decorators/issues/499. I can reopen this issue if you want, but I still don't think it's the right time for esbuild to implement this yet as the specification is still evolving.

Amareis commented 1 year ago

https://github.com/tc39/proposal-decorators/issues/499 is fully merged and there is no any real issues now to implement decorators.

wycats commented 1 year ago

At the moment, the fact that esbuild doesn't even parse @decorator accessor field results in Vite reporting an error when it attempts to scan files containing that syntax for dependencies.

This makes it impossible to work around the current limitation in esbuild by using Vite plugins, since Vite assumes that it esbuild will be able to parse the syntax of JS files.

And while there have been some minor changes in semantics, the syntax of decorators has remained forwards compatible since decorators were approved for Stage 3.

Is there any chance that you would be willing to implement Stage 3 syntax in advance of implementing the full compilation?

evanw commented 1 year ago

Yes, I'm planning to do this. That's one of the main reasons why I did the work behind #3019. Previously esbuild considered all decorators in TypeScript files to be experimental decorators regardless of TypeScript's experimentalDecorators setting. This was blocking esbuild's implementation of JavaScript decorators, but that has been unblocked now that esbuild has started requiring experimentalDecorators: true to use experimental decorators in version 0.18.0+.

evanw commented 1 year ago

Version 0.18.5 of esbuild now supports parsing and printing JavaScript decorators, and parsing and transforming auto-accessors. Please try out these features and let me know if you encounter any problems.

Ciantic commented 1 year ago

Did something change with 0.18.5? Decorators started to appear in transpiled code at the moment like this:

var MonitoringApp = class {
  @(observable)
  isVisiblePerson = false;
  @(observable)
  personDetectorConnected = false;
...

And causes syntax errors.

jakebailey commented 1 year ago

Do you have a tsconfig with experimentalDecorators set? Otherwise, you're using the new "standard" decorators which AFAIK esbuild has not yet implemented downleveling for (and therefore stays in the output).

Ciantic commented 1 year ago

@jakebailey thank you!

I had to add

  1. tsconfig.json with experimentalDecorators (previously it was fine without it)
  2. in esbuild config a new line tsconfig: "tsconfig.json",

I was using Deno to call esbuild, it worked fine a month ago but 0.18.5 indeed disabled the default setting.

jakebailey commented 1 year ago

Note that you can also provide tsconfigRaw rather than creating an all new tsconfig, though I'm not quite sure what TS setup you'd have without a tsconfig at all. I guess if you're trying to bundle Deno code but that's a few too many technologies for me to reason about in my head 😄

ianzone commented 1 year ago

any chance to support emitDecoratorMetadata? it's very desired https://github.com/nestjs/nest-cli/issues/731#issuecomment-1041573532

evanw commented 1 year ago

The link you pasted already has the answer:

The emitDecoratorMetadata TypeScript configuration option is not supported. This feature passes a JavaScript representation of the corresponding TypeScript type to the attached decorator function. Since esbuild does not replicate TypeScript's type system, it does not have enough information to implement this feature.

MachineMakesNoise commented 1 year ago

It would be really nice for esbuild to support typescript's new decorators (the proposal one) without the experimentalDecorators flag.

I ported my project to vite/esbuild from tsc and came across annoying problem that made me bang my head to a wall for too long :

Typescript (tsc 5.x) supports the class decorator syntax like this :

export @decorator class Test {}

But with esbuild this leads to the dreaded 'Unexpected "@"...' error. This can be fixed by moving the "export" to separate line :

@decorator class Test {}
export { Test }

Hope this helps to protect someone else's head.

justinfagnani commented 1 year ago

Standard decorators are now implemented in TypeScript and Babel, and at least Firefox is also implementing now. I think Chrome is at least implementing the accessor keyword.

iyobo commented 1 year ago

So I guess no esbuild for any serious typescript development, given that most major frameworks for typescript use decorators.

shigma commented 1 year ago

most major frameworks for typescript use decorators

@iyobo Those frameworks at least did not use the RIGHT decorators in a long term. I don't think they represent the whole TypeScript ecosystem.

I program in TypeScript, not DecoratorScript.

iyobo commented 1 year ago

@shigma what sort of decorator is the RIGHT decorator?

Shakeskeyboarde commented 1 year ago

@shigma what sort of decorator is the RIGHT decorator?

Legacy vs experimental decorators: https://devblogs.microsoft.com/typescript/announcing-typescript-5-0/#decorators#differences-with-experimental-legacy-decorators

iyobo commented 1 year ago

And your claim is that esbuild supports one over the other?

shigma commented 1 year ago

Of cource esbuild supports the decorator according to the ECMAScript specification.

itpropro commented 12 months ago

most major frameworks for typescript use decorators

@iyobo Those frameworks at least did not use the RIGHT decorators in a long term. I don't think they represent the whole TypeScript ecosystem.

I program in TypeScript, not DecoratorScript.

This is quite misleading as there were no other decorators available when most of the frameworks started integrating them. Decorators are an essential feature for many use cases and esbuild should support all the "legacy" versions of decorators supported by the official TypeScript config, namely "emitDecoratorMetadata" and "experimentalDecorators". There is no current replacement for the functionalities these provide, so there is in fact no "Right" decorator, as the experimental ones are the only ones supporting most use cases and are already used by many major TS frameworks for a reason.

shigma commented 11 months ago

So I guess no esbuild for any serious typescript development, given that most major frameworks for typescript use decorators.

@itpropro I'm just arguing against this statement. Someone thinks when we use typescript without decorators we are not in "serious" typescript development, and we are not "majority".

Reading the documentation of typescript, you will find that decorators are only mentioned in a very low proportion. "Major frameworks" like React and Vue do not commonly use decorators in their source code for development, even if they use typescript. Typescript is a superset of JavaScript. I don't think it is correct to claim that not using decorators is not "serious" development when JavaScript has not yet stably introduced decorators.

iyobo commented 11 months ago

@shigma You are clearly entitled to your opinion. No argument needed. That statement stands true more for backend typescript development.

evanw commented 11 months ago

I have an update: I'm starting to seriously investigate implementing JavaScript decorators in esbuild (not TypeScript experimental decorators, which have already been implemented in esbuild for a long time). My first step was to write a lot of tests: https://github.com/evanw/decorator-tests. I now understand the specification for decorators much better.

As far as I understand, the main existing implementations of this WIP specification are TypeScript and Babel. Both of them seem to have some subtle bugs and/or disagreements with how this feature is supposed to behave. The problems with these tools that I have found so far are documented by https://github.com/evanw/decorator-tests.

justinfagnani commented 11 months ago

That test suite is awesome @evanw!

This is a bit extra, but on our team we've seen a very large emitted code size increase from standard decorators over experimental TypeScript decorators. Babel isn't better here, and I think it's mostly irreducible due to accessor downleveling, needing fresh context objects for each application, per-decorated-member lists of initializers, etc.

So our team is also working on a custom TypeScript transform to compiler our decorators to their non-generic non-decorator equivalents, i.e. generate custom accessors directly.

We can of course do that for esbuild too, but it does require traversing every file that might contain our decorators. It would be very nice if we could somehow filter on our decorator usage, or write some specific decorator transform function.

evanw commented 11 months ago

Thanks for the heads up. I am sensitive to generated code size too, and I will try to do my best to minimize the code size overhead as I implement this. I have already seen the thread over at https://github.com/microsoft/TypeScript/issues/55688. It's unfortunate that the design for this feature isn't as compact as the previous design due to all of the extra features. Part of the problem also seems to be that there is no way to syntactically opt-of of some of the features that your decorators may not even use (e.g. to skip access and/or addInitializer).

However, I'm planning to implement the specification as it is (or at least as it ends up being) without deviating from it. I think it's better for the ecosystem to coalesce around the same standard behavior instead of allowing a high level of customization. So while esbuild will have two decorator implementations (one for JavaScript decorators and one for TypeScript experimental decorators), I'm not currently planning to add the ability to have additional custom decorator implementations within esbuild itself.

Edit: Another remark is that part of the bloat from TypeScript is also to make it easier to debug. But esbuild has a minification flag and can potentially use that make different decisions for production vs. development if necessary (as esbuild already does for other features). So I'm hopeful that esbuild can improve on this.

evanw commented 10 months ago

The behavior of JavaScript decorators continues to be adjusted. I just became aware of this additional (potential) change: https://github.com/pzuraq/ecma262/pull/12. Tracking it here as I will need to take it into consideration. See also https://github.com/microsoft/TypeScript/issues/56606.

ralyodio commented 8 months ago

any update on this?

emilio-toledo commented 8 months ago

Same as @ralyodio, this would be extremely helpful when using vitest in nestjs

what1s1ove commented 8 months ago

Same as @ralyodio, this would be extremely helpful when using vitest in nestjs

Hey @emilio-toledo !

ECMAScript decorators (which eabuild will support) and NestJS decorators (old typescript implementation) are totally different. You cannot migrate from one to the other. And as I know NestJS does not want to support ECMAScrip decorators.

emilio-toledo commented 8 months ago

@what1s1ove

Hey thanks for the quick response. Interesting, I am able to run it using SWC, maybe they support both? Either way I am running vitest with a nestjs project using unplugin-swc so I was thinking that if esbuild which powers vite/vitest supported typescript decorators I would be able to test my nestjs modules with vitest natively. Thanks for the info.

what1s1ove commented 8 months ago

@what1s1ove

Hey thanks for the quick response. Interesting, I am able to run it using SWC, maybe they support both? Either way I am running vitest with a nestjs project using unplugin-swc so I was thinking that if esbuild which powers vite/vitest supported typescript decorators I would be able to test my nestjs modules with vitest natively. Thanks for the info.

Ahh sorry, I do not know about all vite's plugins. But if you want to know more about ECMAScript decorators, you can take a look at one of my article about it:

https://dev.to/what1s1ove/ecmascript-decorators-the-ones-that-are-real-g96

kibertoad commented 7 months ago

@evanw https://github.com/evanw/esbuild/commit/30bed2d2d7572b58399a6c07643878f3377800fe doesn't mean that decorators are already supported? Is there something missing?

Obiwarn commented 6 months ago

The behavior of JavaScript decorators continues to be adjusted. I just became aware of this additional (potential) change: pzuraq/ecma262#12. Tracking it here as I will need to take it into consideration. See also microsoft/TypeScript#56606.

The issues linked by @evanw seem to be fixed in the meantime. Is there anything else holding back an implementation?

ssalbdivad commented 5 months ago

@evanw Any updates on this? TS has been moving heavily away from legacy decorators in favor of the standard.

I've been using esbuild viatsx which has been so great in general- zero issues with source maps or transpilation. That said, the lack of decorator support alone is enough that I'd probably end up investigating other options soon if there's not a solution, which would honestly suck.

cayter commented 5 months ago

@evanw Any updates on this? TS has been moving heavily away from legacy decorators in favor of the standard.

I've been using esbuild viatsx which has been so great in general- zero issues with source maps or transpilation. That said, the lack of decorator support alone is enough that I'd probably end up investigating other options soon if there's not a solution, which would honestly suck.

Our saviour has been working hard in the past 2 weeks. Let's give him some space.

https://github.com/evanw/decorator-tests

ssalbdivad commented 5 months ago

@cayter Amazing, thanks for the update!

It's a fine line between highlighting the relative importance of an issue (helpful) and adding undue stress on an issue the maintainer has already prioritized or is working on (unhelpful).

I'm very sorry if my comment came across as the latter. @evanw I deeply appreciate your work and just seeing this is actively being worked on alleviates my primary concern.

alex3683 commented 5 months ago

@ssalbdivad While waiting on this to be finished I'm successfully using this vite plugin as workaround to precompile typescript: https://github.com/herberttn/vite-plugin-typescript-transform I don't know whether you are using plain esbuild or as part of vite, so it may help or not, but maybe it helps others.