react.dev
react.dev copied to clipboard
MVP: Support Sandpack snippets in TypeScript
Preview:
The selected "target language" (JS or TS) is selected globally and defaults to TS. It's not persisted at the moment but should be (cookie or localStorage?).
If no TS version is available, we disable the toggle and display the toggle as if JS is selected:

~Right now we require duplicating codeblocks in TS and JS (Approach A). This was mainly motivated by having CoreMirror decorations that may not be easy to convert from TS decorations to JS decorations. Though it's unclear yet whether we use them and how we would use them for multiple target languages.~
~Alternatively (approach B), we would either have the codeblocks in TypeScript (and transpile them to JS automatically) or just JavaScript (i.e. not have a TS version (yet)).~
Right now we transpile+format the TS version when parsing MDX to produce the JS version. This is nice from a snippet author perspective (just need to write TS) but results in inconsistent formatting (e.g. bracket spacing). Either we accept that, or revisit https://github.com/reactjs/reactjs.org/pull/5192.
IIRC @gaearon was against formatting the snippets which makes both approaches a bit more tricky since A. We can't easily determine if TS and JS are out-of-sync (by checking the transpiled+formatted TS version against the JS version). B. Just having a TS version would go against formatting since now the JS version is auto-formatted.
TODO (this PR):
- [x] don't allow switching target language if only JS is available
- [x] how to keep in sync (depends on implementation approach A or B). Answer: Only allow either JS version or TS version. Produce JS from TS (via Babel+Prettier).
- [x] throw or warn when compiling TS version fails? Throwing since it prevents a deploy and should therefore be caught before merge in most scenarios: https://vercel.com/fbopensource/beta-reactjs-org/CX5xir7i1toJubsXn29zFYWEEWfj
- [x] Test: TypeScript does not allow file extension in import and would not transpile it. Does this break codesandbox compat?
- [ ] Question: TypeScript does not allow file extension in import and would not transpile it. Is future ESM compat an issue?
- [ ] Missing "Download" action
- [ ] Type checking
TODO (not necessarily this PR):
- [ ] persistence
- [ ] track progress (to drive community effort (should start before or after release?))
The latest updates on your projects. Learn more about Vercel for Git ↗︎
| Name | Status | Preview | Updated |
|---|---|---|---|
| beta-reactjs-org | 🔄 Building (Inspect) | Jan 1, 2023 at 9:40AM (UTC) | |
| reactjs-org | 🔄 Building (Inspect) | Jan 1, 2023 at 9:40AM (UTC) |
Size Changes
📦 Next.js Bundle Analysis
This analysis was generated by the next.js bundle analysis action 🤖
⚠️ Global Bundle Size Increased
| Page | Size (compressed) |
|---|---|
global |
89.16 KB (🟡 +21 B) |
Details
The global bundle is the javascript bundle that loads alongside every page. It is in its own category because its impact is much higher - an increase to its size means that every page on your website loads slower, and a decrease means every page loads faster.
Any third party scripts you have added directly to your app using the <script> tag are not accounted for in this analysis
If you want further insight into what is behind the changes, give @next/bundle-analyzer a try!
Three Pages Changed Size
The following pages changed size from the code in this PR compared to its base branch:
| Page | Size (compressed) | First Load |
|---|---|---|
/404 |
43.99 KB (🟡 +360 B) |
133.15 KB |
/500 |
43.97 KB (🟡 +360 B) |
133.13 KB |
/[[...markdownPath]] |
44.06 KB (🟡 +360 B) |
133.21 KB |
Details
Only the gzipped size is provided here based on an expert tip.
First Load is the size of the global bundle plus the bundle for the individual page. If a user were to show up to your website and land on a given page, the first load size represents the amount of javascript that user would need to download. If next/link is used, subsequent page loads would only need to download that page's bundle (the number in the "Size" column), since the global bundle has already been downloaded.
Any third party scripts you have added directly to your app using the <script> tag are not accounted for in this analysis
Next to the size is how much the size has increased or decreased compared with the base branch of this PR. If this percentage has increased by 10% or more, there will be a red status indicator applied, indicating that special attention should be given to this.
https://github.com/reactjs/reactjs.org/pull/4720 @eps1lon Are you implementing something similar to this?
#4720 @eps1lon Are you implementing something similar to this?
I don't think so. My PR just about having the Sandpack snippets in TypeScript. From the PR description in #4720, it doesn't sound like we have any overlap.
Though #4720 will eventually benefit from this PR since the snippets will have more accurate completions for snippets written in TypeScript.
It would be interesting to explore a version that compiles from just TS source. For line or character highlights we can use inline syntax like special comments so that they are automatically translated. I guess auto-formatting is the way to go in that case.
For line or character highlights we can use inline syntax like special comments so that they are automatically translated.
Do you have an example where we currently use line or character highlights? Just so I can test different implementations.
@gaearon Now compiles from just the TS version. Produces inconsistent formatting though:
Right now we transpile+format the TS version when parsing MDX to produce the JS version. This is nice from a snippet author perspective (just need to write TS) but results in inconsistent formatting (e.g. bracket spacing). Either we accept that, or revisit https://github.com/reactjs/reactjs.org/pull/5192.
Are there any other sites that do this with good UX? I find it a bit confusing that toggling resets the edits although I get why. It's also confusing I don't see actual type errors if I make a mistake though I assume that's fixable. I do agree that we should probably just enable formatting everywhere and use a consistent Prettier setting.
Are there any other sites that do this with good UX? I find it a bit confusing that toggling resets the edits although I get why.
Yeah I haven't thought about it. I think it's mostly an issue if you accidentally change the language. I think this is going to be quite the effort to save edits so that you can restore them when you change back the language.
It's also confusing I don't see actual type errors if I make a mistake though I assume that's fixable.
Hopefully just a setting for the Sandbox I need to enable. Will do in this PR. Do we lint the snippets?
Are there any other sites that do this with good UX?
MUI has it but I did this as well so not so sure about the "good UX" part 😁 Doesn't have editable when I last checked. Ant design has a switch as well but also not editable.
Do we lint the snippets?
Yeah, we load ESLint with code splitting.
I think this is going to be quite the effort to save edits so that you can restore them when you change back the language.
Yeah I don't think we should save them, but I do think the way it works is a bit confusing. It's not clear if it "translates" from TS to JS or if it resets. I know it resets but I initially thought it would translate what I wrote lol.
I know it resets but I initially thought it would translate what I wrote lol.
I think magically "upcasting" the JS+edits to TS+edits is out-of-scope (everybody switching to TS needs that 😉 ). For pristine snippets we don't have to do anything though.
When there are edits, we should probably ask if the user wants to keep the edits (potentially causing type-errors) or start fresh with the TypeScript code from the snippet. Not sure if that's easily doable (I remember something about prompts from iframes being deprecated?).
Though what do we do when the user resets a snippet that started as JS, had edits and then switched to TypeScripts? Reset to JS or reset to TS?
I think we'd need a bit of designer help on this. We're busy with the landing but remind me to ask for help after.