Repository: TypeScript
Issue: Developing a JSX framework and jsxImportSource makes TypeScript slow
Labels: Needs Investigation,Rescheduled

# Bug Report

I created [mini-jsx](https://gitlab.com/appsemble/mini-jsx), a tiny library for creating native DOM nodes using JSX syntax, written in TypeScript.

Since I changed the code to define a classic runtime to an automatic runtime, TypeScript is 10x slower when run inside the project.

To try it, clone and setup the project:

```sh
$ git clone https://gitlab.com/appsemble/mini-jsx.git
$ cd mini-jsx
$ yarn
```

Run `tsc` and notice it takes a long time. Also opening it in VS Code will make the editor unresponsive.

```
$ yarn tsc  
yarn run v1.22.5
$ /home/remco/Projects/mini-jsx/node_modules/.bin/tsc
✨  Done in 11.56s.
```

Now switch to the branch before the automatic runtime was introduced, and notice everything works fine:

```sh
$ git checkout 19ded3c749fcbea5347b2cf3d30942ee0957ae41
$ yarn tsc
yarn run v1.22.5
$ /home/remco/Projects/mini-jsx/node_modules/.bin/tsc
✨  Done in 1.65s.
```

### 🔎 Search Terms

- `jsxImportSource`
- `jsx import source`
- `jsx automatic runtime`

### 🕗 Version & Regression Information

The issue has existed from the moment support for the automatic runtime was added in TypeScript 4.1, and still exists in version 4.2.x.

- I was unable to test this on prior versions because this feature didn’t exist then

### ⏯ Playground Link

The playground doesn’t offer the options needed to show the problem.

### 💻 Code

[jsx-runtime.ts](https://gitlab.com/appsemble/mini-jsx/-/blob/master/jsx-runtime.ts)

```ts
export const jsx = <T extends keyof HTMLElementTagNameMap>(
  tag: T,
  { children, ref, ...props }: Props<T> = {}
): HTMLElementTagNameMap[T] => {
  const node = document.createElement(tag);
  const appendChildren = (child: Children): void => {
    if (Array.isArray(child)) {
      child.forEach(appendChildren);
    } else if (child != null && child !== true && child !== false) {
      node.append(child as Node);
    }
  };
  Object.entries(props).forEach(([key, value]) => {
    if (key in node) {
      type Key = keyof typeof node;
      if (node[key as Key] instanceof Object && value instanceof Object) {
        Object.assign(node[key as Key], value);
      } else {
        node[key as Key] = value as typeof node[Key];
      }
    } else {
      node.setAttribute(key, value as string);
    }
  });
  appendChildren(children);
  if (ref) {
    ref(node);
  }
  return node;
};

export const jsxs = jsx;
```

[jsx-runtime.test.ts](https://gitlab.com/appsemble/mini-jsx/-/blob/master/jsx-runtime.test.ts)

```ts
import "./jsx-runtime";

it("assign properties", () => {
  const button = <button className="is-primary" type="button" />;
  expect(button).toBeInstanceOf(HTMLButtonElement);
  expect(button.className).toBe("is-primary");
});
```

### 🙁 Actual behavior

Running `tsc` takes 10x longer to run, VS Code becomed slow and unresponsive when working on the project, lag, pending code actions from ESLint, and TypeScript actions on save.

### 🙂 Expected behavior

Given this project is very small, running `tsc` takes about 1 second and VSCode is snappy.