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

Error Unexpected token '{' after upgrade [email protected] to [email protected] #13863

Closed
7 tasks done
mosofsky opened this issue Jul 15, 2023 · 23 comments · Fixed by #13992
Closed
7 tasks done

Error Unexpected token '{' after upgrade [email protected] to [email protected] #13863

mosofsky opened this issue Jul 15, 2023 · 23 comments · Fixed by #13992
Labels
p3-minor-bug An edge case that only affects very specific usage (priority) regression The issue only appears after a new release

Comments

@mosofsky
Copy link

Describe the bug

I tried to upgrade [email protected] to [email protected] but Cypress could not longer run tests because of the error Unexpected token '{' (see logs section for more detailed stack trace).

Reproduction

sorry none at this time

Steps to reproduce

I will write more detailed steps to reproduce if this upgrade becomes more important.

I suspect the following would work:

  1. Create a react app using TypeScript
  2. yarn add [email protected] (note, I'm stuck on this old Cypress version)
  3. Create a simple Cypress test
  4. Try to run the Cypress test against the react app
  5. Observe error in the Cypress console

System Info

"cypress": "8.5.0",
"vite-tsconfig-paths": "^4.2.0",

Used Package Manager

yarn

Logs

Vite Logs

See google doc, it was too long to paste into the message body.

Cypress Console Log

Error seen in Cypress console:

SyntaxError: Unexpected token '{'

More detail by printing the Cypress log to the console log:

cypress_runner.js:190988 SyntaxError: The following error originated from your application code, not from Cypress.

  > Unexpected token '{'

When Cypress detects uncaught errors originating from your application it will automatically fail the current test.

This behavior is configurable, and you can choose to turn this off by listening to the `uncaught:exception` event.
SyntaxError: The following error originated from your application code, not from Cypress.

  > Unexpected token '{'

When Cypress detects uncaught errors originating from your application it will automatically fail the current test.

This behavior is configurable, and you can choose to turn this off by listening to the `uncaught:exception` event.
From previous event:
    at Object.run (http://localhost:3000/__cypress/runner/cypress_runner.js:182821:23)
    at Object.run (http://localhost:3000/__cypress/runner/cypress_runner.js:168727:17)
    at $Cy.cy.<computed> [as wait] (http://localhost:3000/__cypress/runner/cypress_runner.js:169897:19)
    at __stackReplacementMarker (http://localhost:3000/__cypress/runner/cypress_runner.js:169205:13)
    at Context.runnable.fn (http://localhost:3000/__cypress/runner/cypress_runner.js:170121:23)
    at callFn (http://localhost:3000/__cypress/runner/cypress_runner.js:122959:21)
    at Test.../driver/node_modules/mocha/lib/runnable.js.Runnable.run (http://localhost:3000/__cypress/runner/cypress_runner.js:122946:7)
    at http://localhost:3000/__cypress/runner/cypress_runner.js:176663:30
From previous event:
    at Object.onRunnableRun (http://localhost:3000/__cypress/runner/cypress_runner.js:176648:19)
    at $Cypress.action (http://localhost:3000/__cypress/runner/cypress_runner.js:166202:28)
    at Test.Runnable.run (http://localhost:3000/__cypress/runner/cypress_runner.js:174382:13)
    at Runner.../driver/node_modules/mocha/lib/runner.js.Runner.runTest (http://localhost:3000/__cypress/runner/cypress_runner.js:123618:10)
    at http://localhost:3000/__cypress/runner/cypress_runner.js:123744:12
    at next (http://localhost:3000/__cypress/runner/cypress_runner.js:123527:14)
    at http://localhost:3000/__cypress/runner/cypress_runner.js:123537:7
    at next (http://localhost:3000/__cypress/runner/cypress_runner.js:123439:14)
    at http://localhost:3000/__cypress/runner/cypress_runner.js:123505:5
    at timeslice (http://localhost:3000/__cypress/runner/cypress_runner.js:117431:27)

Validations

@github-actions
Copy link

Hello @mosofsky. Please provide a minimal reproduction using a GitHub repository or StackBlitz. Issues marked with need reproduction will be closed if they have no activity within 3 days.

@natematykiewicz
Copy link

I'm having this same issue in Safari 16.3 using StimulusJS and vite-rails.

This typescript:

export default class extends Controller {
  static targets = ['menu']
}

Is being turned into this:

export default class extends Controller {
  static {
    this.targets = ["menu"];
  }
}

And Safari says SyntaxError: Unexpected token '{' about the static {.

@natematykiewicz
Copy link

I recently upgraded from 4.3.0 to 4.4.4. After doing a few downgrades, 4.3.9 works fine, but 4.4.0 produces this error.

@ffxsam
Copy link

ffxsam commented Jul 19, 2023

We're getting this error as well, only in Safari 15 and earlier (in our Astro + Vue app). @mosofsky would you mind updating the title of this issue, since it's not just about Cypress? It affects production applications.

@natematykiewicz
Copy link

@ffxsam are you also using Typescript?

@ffxsam
Copy link

ffxsam commented Jul 19, 2023

@natematykiewicz Yessir.

@natematykiewicz
Copy link

https://github.com/evanw/esbuild/blob/main/CHANGELOG.md#0180

I think this is the real problem:
"TypeScript's target no longer affects esbuild's target"
evanw/esbuild#2628

But I can't figure out the right way to set the esbuild target via Vite.

@natematykiewicz
Copy link

I'm having this same issue in Safari 16.3 using StimulusJS and vite-rails.

This typescript:

export default class extends Controller {
  static targets = ['menu']
}

Is being turned into this:

export default class extends Controller {
  static {
    this.targets = ["menu"];
  }
}

And Safari says SyntaxError: Unexpected token '{' about the static {.

Under Vite 4.3.9 this Typescript becomes this:

export default class dropdown_menu_controller_default extends Controller {
}
dropdown_menu_controller_default.targets = ["menu"];

@ffxsam
Copy link

ffxsam commented Jul 19, 2023

I can't tell what's going on in my situation. Our stack is Astro + Vue, and the Astro Vue integration depends on Vite 4.4.x. When I load up our app in Safari 15 or earlier, I get this:

CleanShot 2023-07-19 at 10 42 46@2x CleanShot 2023-07-19 at 10 41 39@2x

@natematykiewicz
Copy link

natematykiewicz commented Jul 19, 2023

What's your build target in tsconfig.json? Ours is es2015, and I'm assuming we're no longer getting es2015 with the esbuild 0.18 upgrade.

@ffxsam
Copy link

ffxsam commented Jul 19, 2023

Since we have to support Safari (probably as early as version 12 or 13—ugh), our target is es2015 as well. We also import core-js/stable to polyfill all the things.

@mosofsky mosofsky changed the title Cypress error Unexpected token '{' after upgrade [email protected] to [email protected] Error Unexpected token '{' after upgrade [email protected] to [email protected] Jul 20, 2023
@bluwy
Copy link
Member

bluwy commented Jul 20, 2023

Can someone help provide a repro for this? I made a stackblitz, but I can't quite repro the difference between Vite 4.3.9 and 4.4.0. Couple questions:

  1. Is tsconfig.json compilerOptions.target set?
  2. Is esbuild.target Vite config set?
  3. Is the static property code coming from your source code or a dependency?

I think I have a fix, but I'm not sure what regression it's fixing. Also related #13756

"TypeScript's target no longer affects esbuild's target"

As noted in #13525:

This is not a breaking change for us. We always set esbuild's target so target in tsconfig was never used.

Which I can also confirm, that I'm not sure if we have a regression here.

@ffxsam
Copy link

ffxsam commented Jul 20, 2023

So far I've been unable to put together a reproduction from scratch. So I think I'm gonna work the other way around: take my project, make a branch, and start cutting chunks away until the problem goes away. Then I'll have a better idea of how to create a reproduction—hopefully.

@natematykiewicz
Copy link

natematykiewicz commented Jul 20, 2023

  1. Yes. tsconfig.json
{
  "compilerOptions": {
    "target": "es2015",
    "lib": [
      "dom",
      "dom.iterable",
      "es2015"
    ],
    "allowJs": true,
    "skipLibCheck": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "esModuleInterop": true,
    "noEmit": true,
    "module": "esnext",
    "sourceMap": true,
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "downlevelIteration": true,
    "allowSyntheticDefaultImports": true,
    "noUnusedLocals": true,
    "types": [
      "vite/client"
    ]
  },
  "include": [
    "app/javascript/**/*.ts",
    "vite.config.ts"
  ],
  "exclude": [
    "node_modules"
  ]
}
  1. No. vite.config.ts
import { defineConfig } from 'vite'
import RubyPlugin from 'vite-plugin-ruby'

export default defineConfig({
  plugins: [RubyPlugin()],
})
  1. My source code

@github-actions github-actions bot closed this as not planned Won't fix, can't repro, duplicate, stale Jul 24, 2023
@bluwy
Copy link
Member

bluwy commented Jul 24, 2023

Re-opening since there seems to be a regression somewhere, but I'm still unsure how it happens.

@natematykiewicz Thanks for the response. IIUC the "target": "es2015" tsconfig setting shouldn't be respected in other versions of Vite too. If you use Vite 4.3.9 and set "target": "esnext" instead, would you get the same error too? If it does, that's really confusing to me 😅

@bluwy bluwy reopened this Jul 24, 2023
@natematykiewicz
Copy link

natematykiewicz commented Jul 24, 2023

Changing the compiler options target on 4.3.9 is definitely changing my output JS.

Given this typescript:

import { Controller } from '@hotwired/stimulus'
import { useClickOutside } from 'stimulus-use'
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
import { enter, leave } from 'el-transition'

export default class extends Controller {
  static targets = ['menu']

  declare menuTarget: HTMLElement

  connect() {
    useClickOutside(this, { element: this.menuTarget })
  }

  show() {
    this.menuTarget.classList.remove('hidden')
    enter(this.menuTarget)
  }

  hide() {
    Promise.all([leave(this.menuTarget)]).then(() => {
      this.menuTarget.classList.add('hidden')
    })
  }

  toggle() {
    if (this.menuTarget.classList.contains('hidden')) {
      this.show()
    } else {
      this.hide()
    }
  }

  clickOutside() {
    this.hide()
  }
}

And this section of tsconfig.json:

{
  "compilerOptions": {
    "target": "es2015",
  }
}

es2015

import { Controller } from "/vite-dev/@fs/.../node_modules/.vite/deps/@hotwired_stimulus.js?v=11d7a1aa";
import { useClickOutside } from "/vite-dev/@fs/.../node_modules/.vite/deps/stimulus-use.js?v=11d7a1aa";
import { enter, leave } from "/vite-dev/@fs/.../node_modules/.vite/deps/el-transition.js?v=11d7a1aa";
export default class dropdown_menu_controller_default extends Controller {
    connect()
    {
        useClickOutside(this, {
            element: this.menuTarget
        });
    }
    show()
    {
        this.menuTarget.classList.remove("hidden");
        enter(this.menuTarget);
    }
    hide()
    {
        Promise.all([leave(this.menuTarget)]).then(() => {
            this.menuTarget.classList.add("hidden");
        });
    }
    toggle()
    {
        if (this.menuTarget.classList.contains("hidden")) {
            this.show();
        } else {
            this.hide();
        }
    }
    clickOutside()
    {
        this.hide();
    }
}
dropdown_menu_controller_default.targets = ["menu"];

esnext

import { Controller } from "/vite-dev/@fs/.../node_modules/.vite/deps/@hotwired_stimulus.js?v=11d7a1aa";
import { useClickOutside } from "/vite-dev/@fs/.../node_modules/.vite/deps/stimulus-use.js?v=11d7a1aa";
import { enter, leave } from "/vite-dev/@fs/.../node_modules/.vite/deps/el-transition.js?v=11d7a1aa";
export default class extends Controller {
  static targets = ["menu"];
  connect() {
    useClickOutside(this, { element: this.menuTarget });
  }
  show() {
    this.menuTarget.classList.remove("hidden");
    enter(this.menuTarget);
  }
  hide() {
    Promise.all([leave(this.menuTarget)]).then(() => {
      this.menuTarget.classList.add("hidden");
    });
  }
  toggle() {
    if (this.menuTarget.classList.contains("hidden")) {
      this.show();
    } else {
      this.hide();
    }
  }
  clickOutside() {
    this.hide();
  }
}

Omitting the compilerOptions:

import { Controller } from "/vite-dev/@fs/.../node_modules/.vite/deps/@hotwired_stimulus.js?v=11d7a1aa";
import { useClickOutside } from "/vite-dev/@fs/.../node_modules/.vite/deps/stimulus-use.js?v=11d7a1aa";
import { enter, leave } from "/vite-dev/@fs/.../node_modules/.vite/deps/el-transition.js?v=11d7a1aa";
export default class dropdown_menu_controller_default extends Controller {
    connect()
    {
        useClickOutside(this, {
            element: this.menuTarget
        });
    }
    show()
    {
        this.menuTarget.classList.remove("hidden");
        enter(this.menuTarget);
    }
    hide()
    {
        Promise.all([leave(this.menuTarget)]).then(() => {
            this.menuTarget.classList.add("hidden");
        });
    }
    toggle()
    {
        if (this.menuTarget.classList.contains("hidden")) {
            this.show();
        } else {
            this.hide();
        }
    }
    clickOutside()
    {
        this.hide();
    }
}
dropdown_menu_controller_default.targets = ["menu"];

It's worth noting, every time I change my tsconfig.json while my server is running, I see this log line:

3:48:41 PM [vite] changed tsconfig file detected: /my_path/tsconfig.json - Clearing cache and forcing full-reload to ensure TypeScript is compiled with updated config values.

On Vite 4.4.7, with "es2015" the file is:

import { Controller } from "/vite-dev/@fs/.../node_modules/.vite/deps/@hotwired_stimulus.js?v=c8bdaac7";
import { useClickOutside } from "/vite-dev/@fs/.../node_modules/.vite/deps/stimulus-use.js?v=24b8e4a2";
import { enter, leave } from "/vite-dev/@fs/.../node_modules/.vite/deps/el-transition.js?v=b7575016";
export default class extends Controller {
  static {
    this.targets = ["menu"];
  }
  connect() {
    useClickOutside(this, { element: this.menuTarget });
  }
  show() {
    this.menuTarget.classList.remove("hidden");
    enter(this.menuTarget);
  }
  hide() {
    Promise.all([leave(this.menuTarget)]).then(() => {
      this.menuTarget.classList.add("hidden");
    });
  }
  toggle() {
    if (this.menuTarget.classList.contains("hidden")) {
      this.show();
    } else {
      this.hide();
    }
  }
  clickOutside() {
    this.hide();
  }
}

This errors. Safari does not seem to understand this part:

static {
}

I tried "esnext" and the file is:

import { Controller } from "/vite-dev/@fs/.../node_modules/.vite/deps/@hotwired_stimulus.js?v=a996cf86";
import { useClickOutside } from "/vite-dev/@fs/.../node_modules/.vite/deps/stimulus-use.js?v=a996cf86";
import { enter, leave } from "/vite-dev/@fs/.../node_modules/.vite/deps/el-transition.js?v=a996cf86";
export default class extends Controller {
  static targets = ["menu"];
  connect() {
    useClickOutside(this, { element: this.menuTarget });
  }
  show() {
    this.menuTarget.classList.remove("hidden");
    enter(this.menuTarget);
  }
  hide() {
    Promise.all([leave(this.menuTarget)]).then(() => {
      this.menuTarget.classList.add("hidden");
    });
  }
  toggle() {
    if (this.menuTarget.classList.contains("hidden")) {
      this.show();
    } else {
      this.hide();
    }
  }
  clickOutside() {
    this.hide();
  }
}

I tried a bunch of different values for compilerOptions target, and es2021 errors (same output as es2015), but es2022 works fine (same output as esnext).

This is so strange.

I'm sure it's obvious, but by updating Vite from 4.3 to 4.4, it also updated esbuild from 0.17 to 0.18.

@bluwy bluwy added p3-minor-bug An edge case that only affects very specific usage (priority) regression The issue only appears after a new release labels Jul 31, 2023
@bluwy
Copy link
Member

bluwy commented Jul 31, 2023

I've found the bug and opened #13992 to fix it. It was useDefineForClassFields that's causing the transpilation that I didn't see in the repro, which had that turned on to true. Setting it to false revealed it.

But it is still true that the target isn't what's Vite is transpiling to, the target just so happen to toggle the default value of useDefineForClassFields in Vite 4.3.9 that causes the issue.

@ffxsam
Copy link

ffxsam commented Jul 31, 2023

@bluwy Awesome, thank you for the fix!!

About target: the whole purpose of tsconfig's target is to affect how the TS code is transpiled. Are you saying that Vite ignores this? Isn't that confusing, if folks are expecting the tsconfig target property to do something? If we change that to es2015, it does seem to actually work. But let me know if we're supposed to use build.target in the vite config instead—or update both the vite config & tsconfig.

Thanks!

@bluwy
Copy link
Member

bluwy commented Jul 31, 2023

@ffxsam I've touched on that at #13756 (comment). Maybe in future versions tsconfig target will affect TS, because I think that's a better default too. But for build.target, it's a build-only setting so it shouldn't affect dev. Most of the build.* options implicitly has this rule so we can't change that.

@ffxsam
Copy link

ffxsam commented Jul 31, 2023

@bluwy Gotcha. It's strange, we're not specifying build.target, but just "target": "es2015" in tsconfig.json, and it's definitely transpiling for es2015. I suppose it wouldn't hurt to just set build: { target: 'es2015' } in addition to that, just to be safe?

@bluwy
Copy link
Member

bluwy commented Aug 1, 2023

Yeah it'd be better to resort to the Vite configuration whenever possible, I'm not sure how it's picking up that es2015 config today though.

@natematykiewicz
Copy link

natematykiewicz commented Aug 1, 2023

I was able to upgrade from 4.3.9 to 4.4.8 without any problems. So it looks like you fixed whatever was happening. Thanks!

I agree with ffxsam. I feel like I'm not configuring something right. I'm not setting any targets in my Vite config, but when I had tried, they didn't seem to help my problem.

@ffxsam
Copy link

ffxsam commented Aug 1, 2023

I just tried build.target: "es2015" in the Vite config (for my Astro site), and it did not go well. 😅

Transforming async generator functions to the configured target environment ("es2015" + 2 overrides) is not supported yet
1297|  function isPromise(value) {
1298|    return !!value && typeof value === "object" && typeof value.then === "function";
1299|  }
   |    ^
1300|  async function* streamAsyncIterator(stream) {
   |  ^
1301|    const reader = stream.getReader();

Transforming async generator functions to the configured target environment ("es2015" + 2 overrides) is not supported yet
1786|    return typeof obj === "object" && !!obj[astroComponentInstanceSym];
1787|  }
1788|
   |   ^
1789|  async function* renderChild(child) {
   |  ^
1790|    child = await child;

These errors look like they're coming from third-party libraries, so I have no control over this.

@github-actions github-actions bot locked and limited conversation to collaborators Aug 16, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
p3-minor-bug An edge case that only affects very specific usage (priority) regression The issue only appears after a new release
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants