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

tsx support #18

Open
Tanimodori opened this issue Sep 22, 2023 · 7 comments
Open

tsx support #18

Tanimodori opened this issue Sep 22, 2023 · 7 comments
Assignees
Labels
enhancement New feature or request

Comments

@Tanimodori
Copy link
Owner

Currently viteburner doesn't have tsx support out-of-box. We need extra config for vite and the template to let it pass the vite pipeline.

@Tanimodori Tanimodori added the enhancement New feature or request label Sep 22, 2023
@Tanimodori Tanimodori self-assigned this Sep 22, 2023
@predakanga
Copy link

I've got a working setup for this, but it has a few issues before it would be PR ready.

You can see the changes at https://github.com/predakanga/viteburner and https://github.com/predakanga/viteburner-template

With those minor changes, .jsx and .tsx files work perfectly, you can import React from 'react' and it just works.

The main problems are:

  • I had to copy refreshUtils.js from vite/plugin-react into viteburner's dist folder. I don't see any way around this, but it's automatable
  • You have to install @babel/preset-typescript into viteburner-template. I feel like this should be bundled into the viteburner script, but I don't know JS packaging well enough to fix it

@Tanimodori Tanimodori added this to the Viteburner 1.0 milestone Oct 12, 2023
@Tanimodori
Copy link
Owner Author

Tanimodori commented Oct 12, 2023

@predakanga Thanks for your information about how to implement jsx/tsx support! After digging into this issue I come up with the 1.0 milestone addressing some blockers of this issue:

There are other important infrastructure improves, but they are not related to this issue much.

I had to copy refreshUtils.js from vite/plugin-react into viteburner's dist folder.

Why do we need this js? I've tested locally with your changes to viteburner. It compiles tsx, although the extension name is incorrect. Does the compiled code missed something in runtime?

You have to install @babel/preset-typescript into viteburner-template.

We use vite in viteburner and have nothing to do with babel. Why do we need @babel/preset-typescript? It mainly works as a devDependency so no packaging is needed here.

@predakanga
Copy link

I had to copy refreshUtils.js from vite/plugin-react into viteburner's dist folder.

Why do we need this js? I've tested locally with your changes to viteburner.

It's loaded by vite-plugin-react when the plugin is instantiated (see here). It doesn't actually do anything in viteburner's usage, but I can't find a way to stop it loading the file.

It compiles tsx, although the extension name is incorrect.

I didn't realise the extension name is incorrect, what should it be?

We use vite in viteburner and have nothing to do with babel. Why do we need @babel/preset-typescript? It mainly works as a devDependency so no packaging is needed here.

The vite/plugin-react uses babel to do the JSX transformation, which is why it needs babel at all.

I agree it should only be needed as a devDependency, but if you don't have it installed in the template you get the following error:
8:28:05 pm [viteburner] Error: Cannot find module '@babel/preset-typescript/package.json'

I think it can be fixed in the viteburner build step, that throws a warning about the same file.
I'll investigate more when I get a chance, this was just a quick fix to get it working.

@Tanimodori
Copy link
Owner Author

@predakanga It generates .tsx files rather than .js files. The content is correct but the extension is incorrect.

@predakanga
Copy link

It should be generating .js files - I just cloned my viteburner-template fork and ran it with a fresh bitburner install and it's all .js for me:

4:35:44 pm [viteburner] hmr add src/demo.tsx -> @home:/demo.js (done)
4:35:44 pm [viteburner] hmr add src/template.ts -> @home:/template.js (done)
image

@predakanga
Copy link

After some more experimenting, I've found that we can just use @babel/preset-typescript as a dev dependency on viteburner, it's not required in the template at all.

I'm certain there's no way around the refreshUtils.js issue now, though - it uses a relative import ($require('./refreshUtils.js')) with a custom require function, I don't think there's a way to transform that.

I've also found another problem with my approach:

Because vite-plugin-externals transforms import React from react to const React = window['React'], the user doesn't have the option to use eval('window') to save RAM.

I'm sure that wouldn't be popular, so it may be a good idea to wait until after #21 to implement this.

@ZachHaber
Copy link

I figured out an approach to support JSX/TSX without any changes to viteburner - only the template.

This approach doesn't require any RAM as it doesn't import React for you. Instead it re-exports all of React from a file src/vendored/react.ts that needs to be distributed to the game. Then, in order to make it more convenient, I use vite's aliases to replace imports from 'react' to /src/vendored/react.js for the game's purposes.

The only other changes that need to be made would be to add react and react-dom as dependencies, and @types/react and @types/react-dom as dev dependencies, both set to version 17, as that's the version the game is using.

All of this can be done solely through the template!

src/vendored/react.ts
/* eslint-disable @typescript-eslint/ban-ts-comment */

// @ts-ignore
export default React;
// @ts-ignore
export type * from 'react';
// @ts-ignore
export const {
  Children,
  Fragment,
  Component,
  Profiler,
  PureComponent,
  cloneElement,
  createContext,
  createElement,
  createFactory,
  createRef,
  forwardRef,
  isValidElement,
  lazy,
  memo,
  useCallback,
  useContext,
  useDebugValue,
  useEffect,
  useImperativeHandle,
  useLayoutEffect,
  useMemo,
  useReducer,
  useRef,
  useState,
  version,
  Suspense,
  StrictMode,
  // @ts-ignore
} = React;

tsconfig.json

"compilerOptions":{
+  "jsx": "react",
},
"include":[
-  "src/**/*.ts",
+  "src/**/*",
]

vite.config.ts

resolve:{
  alias: {
+    react: resolve(__dirname, 'src', 'vendored', 'react.js'),
  }
},
viteburner: {
  watch: [
+    {
+      pattern: 'src/**/*.tsx',
+      transform: true,
+      location: (file) => ({ filename: file.replace(/[jt]sx?$/, 'js').replace(/^src/, '') }),
+    },
  ]
},
+esbuild: {
+  jsx: 'transform',
+}

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

No branches or pull requests

3 participants