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

Transforming JavaScript decorators to the configured target environment ("es2015") is not supported yet #3482

Closed
Mqxx opened this issue Nov 9, 2023 · 6 comments

Comments

@Mqxx
Copy link

Mqxx commented Nov 9, 2023

Hey I'm currently trying to bundle a new project (Lit Framework) with ESBuild. The TypeScript version of the Lit Framework uses @decorator, how can I bundle it with ESBuild for the browser? If I use the --target=es5 or --target=es6 flag I get an error and if I do not use the flag then I get a syntax error in the browser.

Perhaps I have also set a setting of ESBuild incorrectly! I hope that someone can help me with this.

CLI command used:

deno run -A https://deno.land/x/esbuild@v0.19.4/mod.js --bundle --minify --target=es6 --outdir=dist/ --entry-names=\"[dir]/bundle.min\" ./**/index.ts"

Error output:

X [ERROR] Transforming JavaScript decorators to the configured target environment ("es2015") is not supported yet

    src/client/index.ts:4:0:
      4 │ @customElement('simple-greeting')
        ╵ ^

X [ERROR] Transforming JavaScript decorators to the configured target environment ("es2015") is not supported yet

    src/client/index.ts:14:2:
      14 │   @property()
         ╵   ^

2 errors

How to reproduce:
Use this Components overview section from the original Lit website or any other code example where @decorator is used and try to bundle this code using the CLI command from above.

import {LitElement, css, html} from 'https://esm.sh/lit@3.0.2';
import {customElement, property} from 'https://esm.sh/lit@3.0.2/decorators.js';

@customElement('simple-greeting')
export class SimpleGreeting extends LitElement {
  // Define scoped styles right with your component, in plain CSS
  static styles = css`
    :host {
      color: blue;
    }
  `;

  // Declare reactive properties
  @property()
  name?: string = 'World';

  // Render the UI as a function of component state
  render() {
    return html`<p>Hello, ${this.name}!</p>`;
  }
}
@hyrious
Copy link

hyrious commented Nov 9, 2023

There're 2 kinds of decorators, one is defined by TypeScript as a tsconfig field experimentalDecorators, another one is a proposal to JavaScript (which is not implemented in any environment yet). Currently esbuild only implements the lowering of the experimentalDecorators case.

To enable it, you should add this config to your tsconfig.json:

{
  "compilerOptions": {
    "experimentalDecorators": true
  }
}

@Mqxx
Copy link
Author

Mqxx commented Nov 9, 2023

Thanks, that works like a charm.

The only problem I have now is that I get the following error in the browser:

Uncaught Error: Dynamic require of "https://esm.sh/lit@3.0.2" is not supported

I'm not sure if this has something to do with ESBuild or with ESM.sh...

Should I open a separate issue for this?

@hyrious
Copy link

hyrious commented Nov 9, 2023

I guess you just import your bundled js into HTML via the <script> element. To understand this situation, you need to know…

  1. esbuild externalizes URLs by default, which means these resources won't be fetched during build and be inlined into your final bundle, instead they are left as import statements or require() calls.
  2. In the browser, there's no global require() function so the later case does not work. There is support for import statements which should be put in <script type="module">, in which case you should change your build option to with --format=esm.
  3. The default format of esbuild is iife, which transforms those import statements with require() calls because the import keyword is simply not allowed in this context. Using require() at least allows you to polyfill this function by yourself so that your code still have a chance to run.
  4. If you want to inline these resources, you need an HTTP plugin (similar one written on Deno) and your build command should be switched to use scripts since plugins cannot be passed in through CLI.
  5. If you want to use the default format (iife) and still externalize these URLs, you can change your import statements with import() calls. This is the asynchronous way to load es modules in any environment.

@Mqxx
Copy link
Author

Mqxx commented Nov 9, 2023

Many thanks for the support. It was because I had not set --format=esm. That's great, now it works! Thanks a lot!

@lastmjs
Copy link

lastmjs commented Jul 2, 2024

Hey so I am running into this issue with a JavaScript file that uses decorators...how can we overcome this? Shouldn't esbuild be able to treat decorators in a JavaScript file as TypeScript experimental decorators?

@evanw
Copy link
Owner

evanw commented Jul 2, 2024

Decorators in JavaScript files have been supported since version 0.21.0, which came out in May. It implements the JavaScript decorator proposal, which is different than the TypeScript experimental decorator proposal. So likely all you need to do is update your version of esbuild to the latest one and set your target correctly, and decorators should start working in JavaScript files (I'm assuming your problem is that you're using an old version of esbuild).

The JavaScript decorator proposal is going to be the way decorators work going forward while the TypeScript experimental decorator proposal is only around for legacy reasons and will never be the way decorators work going forward, so I recommend using JavaScript decorators. But if you need to force esbuild to use TypeScript decorators in JavaScript files for some reason, then you can force esbuild to parse JavaScript files as TypeScript using something like --loader:.js=ts and then enable TypeScript legacy decorators with experimentalDecorators in tsconfig.json.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants