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

esbuild support #731

Closed
abrvsk opened this issue May 19, 2020 · 45 comments
Closed

esbuild support #731

abrvsk opened this issue May 19, 2020 · 45 comments

Comments

@abrvsk
Copy link

abrvsk commented May 19, 2020

Feature Request

Add support for esbuild as the build system.

Is your feature request related to a problem? Please describe.

Building modules on large project takes sizeable amount of time, which makes debugging a bit slow. esbuild can potentially increase the build speed up to 86 times.

Describe the solution you'd like

Include esbuild into the list of supported build systems.

Teachability, Documentation, Adoption, Migration Strategy

esbuild repo

What is the motivation / use case for changing the behavior?

Speed. Speed. Speed.

@kamilmysliwiec kamilmysliwiec transferred this issue from nestjs/nest May 19, 2020
@jmcdo29
Copy link
Member

jmcdo29 commented May 19, 2020

This looks pretty impressive, but a major problem is that it does not support decorators, which would kind of go against how Nest does all of its DI. I'm definitely going to keep an eye on the library though. @kamilmysliwiec if this ever gets to a point where it could support Nest, what would you think?

@kamilmysliwiec
Copy link
Member

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.

evanw/esbuild#104 (comment)

It seems that TS decorators might be supported at some point. Let's circle back when it's implemented. For now, esbuild isn't compatible with Nest

@aelbore
Copy link

aelbore commented May 26, 2020

This looks pretty impressive, but a major problem is that it does not support decorators, which would kind of go against how Nest does all of its DI. I'm definitely going to keep an eye on the library though. @kamilmysliwiec if this ever gets to a point where it could support Nest, what would you think?

have you tried @swc/core? they support decorators
https://swc-project.github.io

@techvlad
Copy link

techvlad commented Jun 6, 2020

This looks pretty impressive, but a major problem is that it does not support decorators, which would kind of go against how Nest does all of its DI. I'm definitely going to keep an eye on the library though. @kamilmysliwiec if this ever gets to a point where it could support Nest, what would you think?

have you tried @swc/core? they support decorators
https://swc-project.github.io

SWC has an issue with decorators
swc-project/swc#666

@tooolbox
Copy link

tooolbox commented Jun 8, 2020

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.

evanw/esbuild#104 (comment)

@jmcdo29
Copy link
Member

jmcdo29 commented Jun 8, 2020

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.

evanw/esbuild#104 (comment)

This still doesn't support emitDecoratorMetadata, which Nest makes use of, so I don't think it can be used yet. Also, it doesn't support commonjs unless working with bundles which also becomes a problem due to Nest's optional require statements

@dethereum
Copy link

I think swc does work with nestjs now. Using the @swc/cli @swc/core packages and this .swcrc configuration

{
    "jsc": {
      "loose": true,
      "target": "es2020",
      "parser": {
        "syntax": "typescript",
        "decorators": true
      },
      "transform": {
        "legacyDecorator": true,
        "decoratorMetadata": true
      }
    },
    "module": {
        "type": "commonjs",
        "strict": true,
        "strictMode": true,
        "lazy": true,
        "noInterop": true
    }
  }

I run these commands and everything works fine. See this PR

 "build": "swc src -s -d ./dist",
 "start": "pnpm build && node dist/main.js",

@kamilmysliwiec
Copy link
Member

Using either swc and esbuild with Nest should be doable. The biggest issue with these compilers is a lack of type-checking which is one of the major benefits of TS. We currently don't plan to swap tsc with either one, but you should be able to safely use them in your projects.

@axe-me
Copy link

axe-me commented Feb 4, 2021

Can we use swc or esbuild in dev server only? but still, use tsc in production build?
In dev, we can rely on IDEs to do type checks. This will gain a lot DX from fast rebuild.

@jmcdo29
Copy link
Member

jmcdo29 commented Feb 4, 2021

Sure, just depends on the scripts you set up and where you run the production build. You can absolutely use swc or esbuild in dev (though I think esbuild still doesn't emit metadata) and let typescript be your CI/CD compiler. Scripts lead to versatility, right? All about customization.

@wxs77577
Copy link

wxs77577 commented Mar 3, 2021

@dethereum Could you please tell me how to use swc with nestjs monorepo?

@techvlad
Copy link

techvlad commented Apr 5, 2021

For those who find this Issue, I created an example with esbuild and swc for local development
https://github.com/techvlad/nestjs-build
@axe-me @abrvsk

@axe-me
Copy link

axe-me commented Apr 5, 2021

@techvlad that esbuild plugin you use is using tsc to compile ts file with decorators.

@techvlad
Copy link

techvlad commented Apr 5, 2021

@axe-me I'm using https://github.com/anatine/esbuildnx/tree/main/packages/esbuild-decorators plugin, this plugin doesn't use tsc

@peterfication
Copy link

I tried to get the solution of @techvlad running with TypeORM but had no luck unfortunately.

See techvlad/nestjs-build#2

@axe-me
Copy link

axe-me commented Aug 11, 2021

@techvlad this one clearly using tsc to compile ts file with decorator inside, see: https://github.com/anatine/esbuildnx/blob/main/packages/esbuild-decorators/src/lib/esbuild-decorators.ts#L11

I just made a vitejs plugin to run my dev server with super fast HMR. it supports Nestjs out of box. However you have to set the tsCompiler to swc in order to make decorators works.
Repo: https://github.com/axe-me/vite-plugin-node

@TheRusskiy
Copy link

@kamilmysliwiec
Hey Kamil, any chance we can resurrect this thread about SWC support?

@jmcdo29
Copy link
Member

jmcdo29 commented Oct 28, 2021

As of right now, I don't believe we plan on changing out the nest build command to work with swc or esbuild. It works with tsc and webpack, so if there's a way to make webpack run either of those, then technically it's already supported.

If you'd like to implement your own build pipeline, it should be pretty doable with the combination of concurrently and nodemon or something similar.

@michael-land
Copy link

for swc users, this might be issue if you're using class-transform

swc-project/swc#2117

@nartc
Copy link

nartc commented Nov 3, 2021

Hi all, I'm late for the party here.

I've been working on swc support for Nx, specifically Node, Express, and NestJS. And swc works pretty well. Things that don't work are Transformers (nestjs/swagger/plugin etc...) because currently swc doesn't provide a way to hook into the compilation process, and some decorators like class-transformer decorators.

For webpack, swc has a loader (https://swc.rs/docs/usage-swc-loader) to use with webpack, it's pretty much plug and play. People can still benefit from type-check with ForkTsCheckerWebpackPlugin.

@tonivj5
Copy link

tonivj5 commented Nov 3, 2021

@nartc out of curiosity, only the decorators of class-transformer/validator are broken? 😆

@nartc
Copy link

nartc commented Nov 3, 2021

@nartc out of curiosity, only the decorators of class-transformer/validator are broken? 😆

Well, the Controller and stuff from NestJS works lol. My automapper's decorator also works.

@michael-land
Copy link

@nartc out of curiosity, only the decorators of class-transformer/validator are broken? 😆

my workaround is always provide a default value undefined as any

export class CreateUserDto {
  @IsEmail()
  email: string = undefined as any;
}

@tonivj5
Copy link

tonivj5 commented Nov 3, 2021

The problem is related to optional properties ? and the code generated around them. I was wondering if it only happened with class-transformer/validator (who knows 😆) or it's general...

@yharaskrik
Copy link

@nartc out of curiosity, only the decorators of class-transformer/validator are broken? 😆

my workaround is always provide a default value undefined as any

export class CreateUserDto {
  @IsEmail()
  email: string = undefined as any;
}

I can confirm that assigning a default value to each prop does indeed make it work (obviously this is less than ideal but it is something). class-validator seems to work regardless but class-transformer specifically plainToClass needs a default value. As @nartc mentioned this is also an issue with swc

@RIP21
Copy link

RIP21 commented Dec 14, 2021

Another option is to fix it on the class-transformer side is by using patch-package
https://github.com/ds300/patch-package
And apply this fix using it.
typestack/class-transformer#1007

Here is the patch I've got at the end, it's for class-transformer 0.4.0:

diff --git a/node_modules/class-transformer/cjs/TransformOperationExecutor.js b/node_modules/class-transformer/cjs/TransformOperationExecutor.js
index 81aec2a..9c1e13b 100644
--- a/node_modules/class-transformer/cjs/TransformOperationExecutor.js
+++ b/node_modules/class-transformer/cjs/TransformOperationExecutor.js
@@ -251,7 +251,7 @@ class TransformOperationExecutor {
                     if ((this.transformationType === enums_1.TransformationType.PLAIN_TO_CLASS ||
                         this.transformationType === enums_1.TransformationType.CLASS_TO_CLASS) &&
                         // eslint-disable-next-line @typescript-eslint/unbound-method
-                        ((descriptor && !descriptor.set) || newValue[newValueKey] instanceof Function))
+                        ((descriptor && !descriptor.set && !('value' in descriptor)) || newValue[newValueKey] instanceof Function))
                         //  || TransformationType === TransformationType.CLASS_TO_CLASS
                         continue;
                 }
diff --git a/node_modules/class-transformer/esm2015/TransformOperationExecutor.js b/node_modules/class-transformer/esm2015/TransformOperationExecutor.js
index 0ce77a6..0fb863c 100644
--- a/node_modules/class-transformer/esm2015/TransformOperationExecutor.js
+++ b/node_modules/class-transformer/esm2015/TransformOperationExecutor.js
@@ -248,7 +248,7 @@ export class TransformOperationExecutor {
                     if ((this.transformationType === TransformationType.PLAIN_TO_CLASS ||
                         this.transformationType === TransformationType.CLASS_TO_CLASS) &&
                         // eslint-disable-next-line @typescript-eslint/unbound-method
-                        ((descriptor && !descriptor.set) || newValue[newValueKey] instanceof Function))
+                        ((descriptor && !descriptor.set && !('value' in descriptor)) || newValue[newValueKey] instanceof Function))
                         //  || TransformationType === TransformationType.CLASS_TO_CLASS
                         continue;
                 }
diff --git a/node_modules/class-transformer/esm5/TransformOperationExecutor.js b/node_modules/class-transformer/esm5/TransformOperationExecutor.js
index a92e6d5..7283f0c 100644
--- a/node_modules/class-transformer/esm5/TransformOperationExecutor.js
+++ b/node_modules/class-transformer/esm5/TransformOperationExecutor.js
@@ -251,7 +251,7 @@ var TransformOperationExecutor = /** @class */ (function () {
                     if ((this_1.transformationType === TransformationType.PLAIN_TO_CLASS ||
                         this_1.transformationType === TransformationType.CLASS_TO_CLASS) &&
                         // eslint-disable-next-line @typescript-eslint/unbound-method
-                        ((descriptor && !descriptor.set) || newValue[newValueKey] instanceof Function))
+                        ((descriptor && !descriptor.set && !('value' in descriptor)) || newValue[newValueKey] instanceof Function))
                         return "continue";
                 }
                 if (!this_1.options.enableCircularCheck || !this_1.isCircular(subValue)) {

And surely get subscribed to swc-project/swc#2117 to know when this is fixed from swc side as I guess tsc output is considered a single source of truth.

@tonivj5
Copy link

tonivj5 commented Feb 7, 2022

for swc users, this might be issue if you're using class-transform

swc-project/swc#2117

This has been fixed by swc swc-project/swc#3459 🚀 Waiting for the next release https://github.com/swc-project/swc/releases/tag/v1.2.137 🎉

@pharindoko
Copy link

It should be possible to use decorators with esbuild, right ?
evanw/esbuild#104 (comment)
is this still the showstopper ?

@jmcdo29
Copy link
Member

jmcdo29 commented Feb 16, 2022

image

The emitDecoratorMetadata flag must be supported for Nest to work properly. Looks like it won't really be supported any time soon either, due to not having the same type system as typescript

@pharindoko
Copy link

You're damn right :-/ @jmcdo29

@thomaschaaf
Copy link

But you can just compile using the plugin I built. It will use tsc for the files which contain decorators and esbuild for everything else. It's still A LOT quicker. (https://github.com/thomaschaaf/esbuild-plugin-tsc)

@kamilmysliwiec
Copy link
Member

@thomaschaaf I believe 90% of files in Nest codebases will contain decorators. Could you share some benchmarks? 🙌

@michael-land
Copy link

michael-land commented Feb 17, 2022

I’m curious why not just use swc if you want speed up? What’s the benefit choose esbuild?

@manuschillerdev
Copy link

manuschillerdev commented Feb 20, 2022

I am trying to evaluate the possibilites for using swc with nestjs. Currently, it looks very promising, since swc support emitDecoratorMetaData now :)

https://github.com/manuschillerdev/nestjs-swc
Try npm run start:dev for an experimental dev server.

Since I am not the most experience nestjs developer - what would be the edge cases to test here?

TLDR;

  • Tests seem to work without any problems with @swc/jest 🎉
  • The app seems to work great as well in dev - typeorm sometimes loses the connection, though.
  • Production builds work as well

Might write something on dev.to about the experiment, if someone is interested?

Demo: Updating a repository plus hot reloading the server is around 30-50ms, but may sometimes need longer. Sometimes app.close() takes around 300ms alone..

Screen.Recording.2022-02-20.at.14.28.22.mov

@kamilmysliwiec
Copy link
Member

Thanks @manuschillerdev!

I think the most substantial caveat is that CLI plugins (@nestjs/swagger and @nestjs/graphql) won't work as expected with SWC as they require tsc AST transformations to be applied.

@manuschillerdev
Copy link

ah I see - thanks @kamilmysliwiec
swc has several compat approaches (e.g. https://crates.io/crates/swc_estree_compat), but I'm sure it would be a massive effort to either produce a valid TSC Ast by swc, oder rewrite your mentioned plugins to use another AST format :/

@Karibash
Copy link

When build with swc, there seems to be a problem with DI for property decorators.
swc-project/swc#3592

@jackpordi jackpordi mentioned this issue Feb 28, 2022
1 task
@jackpordi
Copy link

I've made this issue #1549 in order to track SWC support specifically, since ESBuild looks like a dead end in the medium term due to not supporting emitDecoratorMetadata.

@yharaskrik
Copy link

I've made this issue #1549 in order to track SWC support specifically, since ESBuild looks like a dead end in the medium term due to not supporting emitDecoratorMetadata.

I have been using SWC to compile Nest recently and it seems to be working (all my code is managed in an Nx monorepo and we are using the @nrwl/js plugin with the swc compiler for buildable libraries)

@jackpordi
Copy link

@yharaskrik are you using CLI plugins like swagger?

@yharaskrik
Copy link

@yharaskrik are you using CLI plugins like swagger?

Ah, I'm actually only using it to compile e2e tests. Our deployed code with swagger is still using the regular builders no swc. We are only using swc to compile plain node libs right now in deployed code.

@Nickersoft
Copy link

I'd just like to chime in here and say that I have been using @swc/cli to compile my production NestJS repo for months now and it seems to work perfectly. I use @nestjs/graphql extensively, as my app is primarily a GraphQL server. I run the build in tandem with tsc --noEmit using concurrently.

Here is my .swcrc:

{
  "module": {
    "type": "es6"
  },
  "jsc": {
    "baseUrl": ".",
    "target": "es2020",
    "parser": {
      "syntax": "typescript",
      "decorators": true,
      "importMeta": true
    },
    "transform": {
      "legacyDecorator": true,
      "decoratorMetadata": true
    },
    "keepClassNames": true,
  }
}

I mostly was forced to go with a solution like swc because some of my dependencies are ESM-only, which Webpack doesn't have great support for.

@sebastiangug
Copy link

@Nickersoft did you find a way to be able to use the CLI plugin?

I've been using vite + swc pretty alright but the right way of enabling that functionality has eluded me

@gerardolima
Copy link

esbuild version 0.18.5 was just released. This version supports decorators. Is support to building with esbuild still being considered?

@jmcdo29
Copy link
Member

jmcdo29 commented Jun 20, 2023

@gerardolima This looks to just be for the new JS decorator syntax, which Nest doesn't use. WE still use "legacy" decorators from Typescript because we need the emitted metadata that Typescript providers. If you're looking for a faster compilation cycle, Nest supports SWC in version 10 directly with the -b swc flag to the CLI

@nestjs nestjs locked and limited conversation to collaborators Jun 20, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests