react.dev icon indicating copy to clipboard operation
react.dev copied to clipboard

Editor: Add hover tooltips, intelligent completions, auto formatting, diagnostics

Open justjake opened this issue 2 years ago โ€ข 25 comments

This PR adds the following features based on tsserver to the Sandpack code editor.

  • Hover tooltips. These are styled similar to VS Code, and follow the Sandpack editor's syntax theme. image

  • Format the current file: cmd-s, Shift-Alt-f

  • Tab completion, including auto-imports. For example, typing useSta<tab> should import useState and insert the rest of the word.

  • Diagnostics such as type errors as well as warnings like "unused variable".

https://user-images.githubusercontent.com/296279/171644905-32963bca-ad79-45e4-8ae3-d2a93549bc30.mp4

This work is based on my improvements to @danilowoz's https://github.com/danilowoz/sandpack-tsserver

Implementation notes

We run tsserver in a Web Worker to avoid blocking the UI thread when asking for completions, etc. On every editor change, we send the new file state to the tsserver worker, and then ask for completions & linting at a throttled rate. Calls between the worker thread and UI thread are type-safe at the expense of some tricky types in ChannelBridge.

The type data used by tsserver is automatically downloaded from a Sandpack CDN, and are cached by the UI thread in localStorage. Dependencies in the web worker are loaded using importScripts from unpkg.com instead of bundled by Next, although I'm not sure this is the best call.

The codemirror plugin code that runs on the UI thread is factored into sub-extensions, so it should be able to disable unwanted features easily.

Mechanics TODOs

  • [x] ๐Ÿ› Currently completion is cleared whenever Sandpack reloads to show a build error. This feels very buggy and annoying. I attempted to fix this with React.memo, but that didn't help after I rebased. ยฏ\_(ใƒ„)_/ยฏ need to figure this out.
    • Appears to be a Sandpack issue with showInlineErrors, see comment below.
  • [x] Test production build. Check for code size regressions, etc.
  • [x] Evaluate normal dependency imports instead of importScript(...unpkg...)
    • This seems fine!
  • [x] Evaluate sharing a single worker thread between all editors, which could reduce resource use.
    • This is complicated, but could work by creating a new TSServerWorker instance per editor and connecting the editor to a specific instance using the MessageChannel API. Each editor would get a reference to the global worker (react context?), create a channel, and then call globalWorker.makeNewEditor(channel). Could do as a follow-up or if maintainers feel strongly about it.
    • [x] Make sure we actually need a worker??
      • Yep, it's janky without a worker.
  • [x] Figure out how to draw tooltips over the sandbox iframe.
  • [x] ๐Ÿšฎ Remove debugging statements and debug NPM dependency. Currently this branch spews colorful "jake.tl" messages into the console. (I will do this after all other tasks because the debugging is very helpful)
  • [x] Evaluate pre-packaging common type definitions to avoid dynamic resolution from 3rd party CDN. Like, we know we want @types/[email protected]. We should resolve the file at or before build time instead of doing it once per editor on app boot.
  • [x] Fix ts-libs cache: sore back the cache from ts-libs into localStorage.

UX/Policy TODOs

  • [x] Tooltips, but ideally it would just be a sentence
    • [x] A link to the beta docs, overriding the existing React typings that use the production docs.
  • [x] Autocomplete shouldn't include a myriad of global browser APIs. They're not useful in 99.9% cases here.
  • [x] tune linting
    • [x] Import/export linting
    • [x] Remove "unused variable" check.
    • [x] Remove most type errors because most docs don't typecheck
  • [x] Automatic formatting, but not on "save". It's not obvious "save" even works here. Maybe on Enter? It should preserve the cursor position.

justjake avatar Jun 02 '22 14:06 justjake

@danilowoz showInlineErrors={true} causes autocompletion to dismiss when the line first detects an error. I haven't dug into why yet.

With showInlineErrors:

https://user-images.githubusercontent.com/296279/171656095-8e891073-4b8a-4679-b6fe-72867da176fd.mp4

Removing that prop resolves the issue.

justjake avatar Jun 02 '22 14:06 justjake

Hey Great work! Would you like to fix the TS errors? So that the previews are built?

harish-sethuraman avatar Jun 02 '22 15:06 harish-sethuraman

@harish-sethuraman yep.... been dealing with plane wifi preventing me from pushing ๐Ÿ˜ฑ turns out https git push works though.

justjake avatar Jun 02 '22 15:06 justjake

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 105.5 KB (๐Ÿ”ด +20.84 KB)
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!

One Hundred Eighty-nine Pages Changed Size

The following pages changed size from the code in this PR compared to its base branch:

Page Size (compressed) First Load
/ 47.99 KB (๐ŸŸก +28 B) 153.5 KB
/404 47.09 KB (๐ŸŸก +28 B) 152.6 KB
/apis 47.88 KB (๐ŸŸก +28 B) 153.38 KB
/apis/createcontext 49.63 KB (๐ŸŸก +28 B) 155.13 KB
/apis/reactdom 47.82 KB (๐ŸŸก +28 B) 153.32 KB
/apis/render 49.86 KB (๐ŸŸก +28 B) 155.36 KB
/apis/usecontext 55.58 KB (๐ŸŸก +28 B) 161.09 KB
/apis/usereducer 55.22 KB (๐ŸŸก +28 B) 160.72 KB
/apis/useref 52.91 KB (๐ŸŸก +28 B) 158.42 KB
/apis/usestate 58.86 KB (๐ŸŸก +35 B) 164.37 KB
/blog/2013/06/02/jsfiddle-integration 57.9 KB (๐ŸŸก +28 B) 163.41 KB
/blog/2013/06/05/why-react 59.63 KB (๐ŸŸก +28 B) 165.14 KB
/blog/2013/06/12/community-roundup 59.33 KB (๐ŸŸก +28 B) 164.84 KB
/blog/2013/06/19/community-roundup-2 60 KB (๐ŸŸก +28 B) 165.5 KB
/blog/2013/06/21/react-v0-3-3 58.05 KB (๐ŸŸก +28 B) 163.55 KB
/blog/2013/06/27/community-roundup-3 60.37 KB (๐ŸŸก +28 B) 165.87 KB
/blog/2013/07/02/react-v0-4-autobind-by-default 58.67 KB (๐ŸŸก +28 B) 164.17 KB
/blog/2013/07/03/community-roundup-4 59.74 KB (๐ŸŸก +28 B) 165.24 KB
/blog/2013/07/11/react-v0-4-prop-validation-and-default-values 58.54 KB (๐ŸŸก +28 B) 164.04 KB
/blog/2013/07/17/react-v0-4-0 59.25 KB (๐ŸŸก +28 B) 164.76 KB
/blog/2013/07/23/community-roundup-5 60.13 KB (๐ŸŸก +28 B) 165.63 KB
/blog/2013/07/26/react-v0-4-1 58.02 KB (๐ŸŸก +28 B) 163.52 KB
/blog/2013/07/30/use-react-and-jsx-in-ruby-on-rails 58.62 KB (๐ŸŸก +28 B) 164.12 KB
/blog/2013/08/05/community-roundup-6 59.43 KB (๐ŸŸก +28 B) 164.93 KB
/blog/2013/08/19/use-react-and-jsx-in-python-applications 58.63 KB (๐ŸŸก +28 B) 164.14 KB
/blog/2013/08/26/community-roundup-7 59.59 KB (๐ŸŸก +28 B) 165.1 KB
/blog/2013/09/24/community-roundup-8 61.03 KB (๐ŸŸก +28 B) 166.53 KB
/blog/2013/10/03/community-roundup-9 59.96 KB (๐ŸŸก +28 B) 165.46 KB
/blog/2013/10/16/react-v0.5.0 59.65 KB (๐ŸŸก +28 B) 165.15 KB
/blog/2013/10/29/react-v0-5-1 58 KB (๐ŸŸก +28 B) 163.51 KB
/blog/2013/11/06/community-roundup-10 61.62 KB (๐ŸŸก +28 B) 167.13 KB
/blog/2013/11/18/community-roundup-11 60.7 KB (๐ŸŸก +28 B) 166.21 KB
/blog/2013/12/18/react-v0.5.2-v0.4.2 58.48 KB (๐ŸŸก +28 B) 163.98 KB
/blog/2013/12/19/react-v0.8.0 58.9 KB (๐ŸŸก +28 B) 164.4 KB
/blog/2013/12/23/community-roundup-12 60.36 KB (๐ŸŸก +28 B) 165.86 KB
/blog/2013/12/30/community-roundup-13 60.14 KB (๐ŸŸก +28 B) 165.64 KB
/blog/2014/01/02/react-chrome-developer-tools 58.4 KB (๐ŸŸก +28 B) 163.9 KB
/blog/2014/01/06/community-roundup-14 59.73 KB (๐ŸŸก +28 B) 165.24 KB
/blog/2014/02/05/community-roundup-15 60.95 KB (๐ŸŸก +28 B) 166.46 KB
/blog/2014/02/15/community-roundup-16 60.66 KB (๐ŸŸก +28 B) 166.16 KB
/blog/2014/02/16/react-v0.9-rc1 61.07 KB (๐ŸŸก +28 B) 166.57 KB
/blog/2014/02/20/react-v0.9 61.51 KB (๐ŸŸก +28 B) 167.02 KB
/blog/2014/02/24/community-roundup-17 60.38 KB (๐ŸŸก +28 B) 165.88 KB
/blog/2014/03/14/community-roundup-18 61.34 KB (๐ŸŸก +28 B) 166.85 KB
/blog/2014/03/19/react-v0.10-rc1 59.65 KB (๐ŸŸก +28 B) 165.16 KB
/blog/2014/03/21/react-v0.10 59.67 KB (๐ŸŸก +28 B) 165.18 KB
/blog/2014/03/28/the-road-to-1.0 59.79 KB (๐ŸŸก +28 B) 165.29 KB
/blog/2014/04/04/reactnet 58.43 KB (๐ŸŸก +28 B) 163.93 KB
/blog/2014/05/06/flux 58.55 KB (๐ŸŸก +28 B) 164.06 KB
/blog/2014/05/29/one-year-of-open-source-react 58.78 KB (๐ŸŸก +28 B) 164.28 KB
/blog/2014/06/27/community-roundup-19 60.32 KB (๐ŸŸก +28 B) 165.83 KB
/blog/2014/07/13/react-v0.11-rc1 60.71 KB (๐ŸŸก +28 B) 166.21 KB
/blog/2014/07/17/react-v0.11 61.96 KB (๐ŸŸก +28 B) 167.46 KB
/blog/2014/07/25/react-v0.11.1 58.91 KB (๐ŸŸก +28 B) 164.41 KB
/blog/2014/07/28/community-roundup-20 60.46 KB (๐ŸŸก +28 B) 165.97 KB
/blog/2014/07/30/flux-actions-and-the-dispatcher 60.1 KB (๐ŸŸก +28 B) 165.6 KB
/blog/2014/08/03/community-roundup-21 60.13 KB (๐ŸŸก +28 B) 165.64 KB
/blog/2014/09/03/introducing-the-jsx-specification 58.14 KB (๐ŸŸก +28 B) 163.64 KB
/blog/2014/09/12/community-round-up-22 60.61 KB (๐ŸŸก +28 B) 166.12 KB
/blog/2014/09/16/react-v0.11.2 58.91 KB (๐ŸŸก +28 B) 164.41 KB
/blog/2014/09/24/testing-flux-applications 62.09 KB (๐ŸŸก +28 B) 167.59 KB
/blog/2014/10/14/introducing-react-elements 61.04 KB (๐ŸŸก +28 B) 166.55 KB
/blog/2014/10/16/react-v0.12-rc1 61.01 KB (๐ŸŸก +28 B) 166.51 KB
/blog/2014/10/17/community-roundup-23 61.58 KB (๐ŸŸก +28 B) 167.08 KB
/blog/2014/10/27/react-js-conf 58.18 KB (๐ŸŸก +28 B) 163.69 KB
/blog/2014/10/28/react-v0.12 60.95 KB (๐ŸŸก +28 B) 166.45 KB
/blog/2014/11/24/react-js-conf-updates 58.57 KB (๐ŸŸก +28 B) 164.07 KB
/blog/2014/11/25/community-roundup-24 61.81 KB (๐ŸŸก +28 B) 167.31 KB
/blog/2014/12/18/react-v0.12.2 58.6 KB (๐ŸŸก +28 B) 164.1 KB
/blog/2014/12/19/react-js-conf-diversity-scholarship 58.99 KB (๐ŸŸก +28 B) 164.5 KB
/blog/2015/01/27/react-v0.13.0-beta-1 59.96 KB (๐ŸŸก +28 B) 165.46 KB
/blog/2015/02/18/react-conf-roundup-2015 61.94 KB (๐ŸŸก +28 B) 167.45 KB
/blog/2015/02/20/introducing-relay-and-graphql 61.1 KB (๐ŸŸก +28 B) 166.6 KB
/blog/2015/02/24/react-v0.13-rc1 60 KB (๐ŸŸก +28 B) 165.5 KB
/blog/2015/02/24/streamlining-react-elements 62.55 KB (๐ŸŸก +28 B) 168.05 KB
/blog/2015/03/03/react-v0.13-rc2 59.33 KB (๐ŸŸก +28 B) 164.84 KB
/blog/2015/03/04/community-roundup-25 60.29 KB (๐ŸŸก +28 B) 165.8 KB
/blog/2015/03/10/react-v0.13 60.61 KB (๐ŸŸก +28 B) 166.11 KB
/blog/2015/03/16/react-v0.13.1 58.43 KB (๐ŸŸก +28 B) 163.94 KB
/blog/2015/03/19/building-the-facebook-news-feed-with-relay 61.19 KB (๐ŸŸก +28 B) 166.69 KB
/blog/2015/03/26/introducing-react-native 58.33 KB (๐ŸŸก +28 B) 163.83 KB
/blog/2015/03/30/community-roundup-26 60.26 KB (๐ŸŸก +28 B) 165.76 KB
/blog/2015/04/17/react-native-v0.4 59.17 KB (๐ŸŸก +28 B) 164.68 KB
/blog/2015/04/18/react-v0.13.2 58.51 KB (๐ŸŸก +28 B) 164.01 KB
/blog/2015/05/01/graphql-introduction 63 KB (๐ŸŸก +28 B) 168.5 KB
/blog/2015/05/08/react-v0.13.3 58.4 KB (๐ŸŸก +28 B) 163.9 KB
/blog/2015/05/22/react-native-release-process 58.55 KB (๐ŸŸก +28 B) 164.05 KB
/blog/2015/06/12/deprecating-jstransform-and-react-tools 59 KB (๐ŸŸก +28 B) 164.5 KB
/blog/2015/07/03/react-v0.14-beta-1 60.51 KB (๐ŸŸก +28 B) 166.01 KB
/blog/2015/08/03/new-react-devtools-beta 59.11 KB (๐ŸŸก +28 B) 164.62 KB
/blog/2015/08/11/relay-technical-preview 59.18 KB (๐ŸŸก +28 B) 164.68 KB
/blog/2015/08/13/reacteurope-roundup 60.76 KB (๐ŸŸก +28 B) 166.27 KB
/blog/2015/09/02/new-react-developer-tools 58.53 KB (๐ŸŸก +28 B) 164.03 KB
/blog/2015/09/10/react-v0.14-rc1 64.22 KB (๐ŸŸก +28 B) 169.72 KB
/blog/2015/09/14/community-roundup-27 60.69 KB (๐ŸŸก +28 B) 166.19 KB
/blog/2015/10/01/react-render-and-top-level-api 59.66 KB (๐ŸŸก +28 B) 165.17 KB
/blog/2015/10/07/react-v0.14 64.7 KB (๐ŸŸก +28 B) 170.2 KB
/blog/2015/10/19/reactiflux-is-moving-to-discord 60.41 KB (๐ŸŸก +28 B) 165.92 KB
/blog/2015/10/28/react-v0.14.1 58.42 KB (๐ŸŸก +28 B) 163.93 KB
/blog/2015/11/02/react-v0.14.2 58.45 KB (๐ŸŸก +28 B) 163.96 KB
/blog/2015/11/18/react-v0.14.3 58.57 KB (๐ŸŸก +28 B) 164.08 KB
/blog/2015/12/04/react-js-conf-2016-diversity-scholarship 59.45 KB (๐ŸŸก +28 B) 164.95 KB
/blog/2015/12/16/ismounted-antipattern 59.05 KB (๐ŸŸก +28 B) 164.55 KB
/blog/2015/12/18/react-components-elements-and-instances 62.97 KB (๐ŸŸก +28 B) 168.47 KB
/blog/2015/12/29/react-v0.14.4 58.24 KB (๐ŸŸก +28 B) 163.75 KB
/blog/2016/01/08/A-implies-B-does-not-imply-B-implies-A 59.26 KB (๐ŸŸก +28 B) 164.76 KB
/blog/2016/01/12/discontinuing-ie8-support 58.07 KB (๐ŸŸก +28 B) 163.58 KB
/blog/2016/02/19/new-versioning-scheme 59.45 KB (๐ŸŸก +28 B) 164.95 KB
/blog/2016/03/07/react-v15-rc1 62.2 KB (๐ŸŸก +28 B) 167.71 KB
/blog/2016/03/16/react-v15-rc2 59.07 KB (๐ŸŸก +28 B) 164.57 KB
/blog/2016/03/29/react-v0.14.8 58.2 KB (๐ŸŸก +28 B) 163.71 KB
/blog/2016/04/07/react-v15 66.39 KB (๐ŸŸก +28 B) 171.89 KB
/blog/2016/04/08/react-v15.0.1 58.96 KB (๐ŸŸก +28 B) 164.46 KB
/blog/2016/07/11/introducing-reacts-error-code-system 58.67 KB (๐ŸŸก +28 B) 164.17 KB
/blog/2016/07/13/mixins-considered-harmful 66.82 KB (๐ŸŸก +28 B) 172.32 KB
/blog/2016/07/22/create-apps-with-no-configuration 62.15 KB (๐ŸŸก +28 B) 167.65 KB
/blog/2016/08/05/relay-state-of-the-state 62.19 KB (๐ŸŸก +28 B) 167.69 KB
/blog/2016/09/28/our-first-50000-stars 63.64 KB (๐ŸŸก +28 B) 169.14 KB
/blog/2016/11/16/react-v15.4.0 61.59 KB (๐ŸŸก +28 B) 167.09 KB
/blog/2017/04/07/react-v15.5.0 62.15 KB (๐ŸŸก +28 B) 167.66 KB
/blog/2017/05/18/whats-new-in-create-react-app 61.55 KB (๐ŸŸก +28 B) 167.05 KB
/blog/2017/06/13/react-v15.6.0 60.17 KB (๐ŸŸก +28 B) 165.68 KB
/blog/2017/07/26/error-handling-in-react-16 60.52 KB (๐ŸŸก +28 B) 166.03 KB
/blog/2017/09/08/dom-attributes-in-react-16 60.95 KB (๐ŸŸก +28 B) 166.46 KB
/blog/2017/09/25/react-v15.6.2 59.28 KB (๐ŸŸก +28 B) 164.79 KB
/blog/2017/09/26/react-v16.0 64.42 KB (๐ŸŸก +28 B) 169.92 KB
/blog/2017/11/28/react-v16.2.0-fragment-support 62.35 KB (๐ŸŸก +28 B) 167.85 KB
/blog/2017/12/07/introducing-the-react-rfc-process 58.87 KB (๐ŸŸก +28 B) 164.37 KB
/blog/2017/12/15/improving-the-repository-infrastructure 74.66 KB (๐ŸŸก +28 B) 180.16 KB
/blog/2018/03/01/sneak-peek-beyond-react-16 58.83 KB (๐ŸŸก +28 B) 164.33 KB
/blog/2018/03/27/update-on-async-rendering 64.07 KB (๐ŸŸก +28 B) 169.57 KB
/blog/2018/03/29/react-v-16-3 60.89 KB (๐ŸŸก +28 B) 166.39 KB
/blog/2018/05/23/react-v-16-4 61.03 KB (๐ŸŸก +28 B) 166.53 KB
/blog/2018/06/07/you-probably-dont-need-derived-state 64.69 KB (๐ŸŸก +28 B) 170.19 KB
/blog/2018/08/01/react-v-16-4-2 59.68 KB (๐ŸŸก +28 B) 165.18 KB
/blog/2018/09/10/introducing-the-react-profiler 61.29 KB (๐ŸŸก +28 B) 166.79 KB
/blog/2018/10/01/create-react-app-v2 61.76 KB (๐ŸŸก +28 B) 167.27 KB
/blog/2018/10/23/react-v-16-6 60.96 KB (๐ŸŸก +28 B) 166.47 KB
/blog/2018/11/13/react-conf-recap 58.68 KB (๐ŸŸก +28 B) 164.18 KB
/blog/2018/11/27/react-16-roadmap 64.87 KB (๐ŸŸก +28 B) 170.37 KB
/blog/2018/12/19/react-v-16-7 59.8 KB (๐ŸŸก +28 B) 165.3 KB
/blog/2019/02/06/react-v16.8.0 62.07 KB (๐ŸŸก +28 B) 167.57 KB
/blog/2019/02/23/is-react-translated-yet 61.63 KB (๐ŸŸก +28 B) 167.13 KB
/blog/2019/08/08/react-v16.9.0 64.56 KB (๐ŸŸก +28 B) 170.06 KB
/blog/2019/08/15/new-react-devtools 59.17 KB (๐ŸŸก +28 B) 164.67 KB
/blog/2019/10/22/react-release-channels 60.99 KB (๐ŸŸก +28 B) 166.49 KB
/blog/2019/11/06/building-great-user-experiences-with-concurrent-mode-and-suspense 65.68 KB (๐ŸŸก +28 B) 171.19 KB
/blog/2020/02/26/react-v16.13.0 61.91 KB (๐ŸŸก +28 B) 167.41 KB
/blog/2020/08/10/react-v17-rc 68.19 KB (๐ŸŸก +28 B) 173.69 KB
/community 47.69 KB (๐ŸŸก +28 B) 153.19 KB
/community/acknowledgements 48.87 KB (๐ŸŸก +28 B) 154.38 KB
/community/meet-the-team 49.57 KB (๐ŸŸก +28 B) 155.08 KB
/learn 52.65 KB (๐ŸŸก +28 B) 158.15 KB
/learn/add-react-to-a-website 52.76 KB (๐ŸŸก +28 B) 158.27 KB
/learn/adding-interactivity 54.33 KB (๐ŸŸก +28 B) 159.84 KB
/learn/choosing-the-state-structure 60.05 KB (๐ŸŸก +28 B) 165.56 KB
/learn/conditional-rendering 52.28 KB (๐ŸŸก +28 B) 157.79 KB
/learn/describing-the-ui 51.5 KB (๐ŸŸก +28 B) 157 KB
/learn/editor-setup 48.96 KB (๐ŸŸก +28 B) 154.47 KB
/learn/escape-hatches 47.01 KB (๐ŸŸก +28 B) 152.52 KB
/learn/extracting-state-logic-into-a-reducer 57.69 KB (๐ŸŸก +28 B) 163.19 KB
/learn/importing-and-exporting-components 50.68 KB (๐ŸŸก +28 B) 156.19 KB
/learn/installation 48.29 KB (๐ŸŸก +28 B) 153.79 KB
/learn/javascript-in-jsx-with-curly-braces 50.76 KB (๐ŸŸก +28 B) 156.26 KB
/learn/keeping-components-pure 54.89 KB (๐ŸŸก +28 B) 160.39 KB
/learn/managing-state 53.61 KB (๐ŸŸก +28 B) 159.11 KB
/learn/manipulating-the-dom-with-refs 55.86 KB (๐ŸŸก +28 B) 161.36 KB
/learn/passing-data-deeply-with-context 55.41 KB (๐ŸŸก +28 B) 160.92 KB
/learn/passing-props-to-a-component 54.46 KB (๐ŸŸก +28 B) 159.96 KB
/learn/preserving-and-resetting-state 58.43 KB (๐ŸŸก +28 B) 163.93 KB
/learn/queueing-a-series-of-state-updates 52.25 KB (๐ŸŸก +28 B) 157.76 KB
/learn/react-developer-tools 48.25 KB (๐ŸŸก +28 B) 153.75 KB
/learn/reacting-to-input-with-state 56.87 KB (๐ŸŸก +28 B) 162.37 KB
/learn/referencing-values-with-refs 53.77 KB (๐ŸŸก +28 B) 159.28 KB
/learn/render-and-commit 50.75 KB (๐ŸŸก +28 B) 156.26 KB
/learn/rendering-lists 54.84 KB (๐ŸŸก +28 B) 160.35 KB
/learn/responding-to-events 53.78 KB (๐ŸŸก +28 B) 159.28 KB
/learn/scaling-up-with-reducer-and-context 51.82 KB (๐ŸŸก +28 B) 157.33 KB
/learn/sharing-state-between-components 52.9 KB (๐ŸŸก +28 B) 158.41 KB
/learn/start-a-new-react-project 49.32 KB (๐ŸŸก +28 B) 154.83 KB
/learn/state-a-components-memory 57.98 KB (๐ŸŸก +28 B) 163.48 KB
/learn/state-as-a-snapshot 51.56 KB (๐ŸŸก +28 B) 157.06 KB
/learn/synchronizing-with-effects 64.63 KB (๐ŸŸก +28 B) 170.13 KB
/learn/thinking-in-react 53.62 KB (๐ŸŸก +28 B) 159.12 KB
/learn/updating-arrays-in-state 55.85 KB (๐ŸŸก +28 B) 161.36 KB
/learn/updating-objects-in-state 55.58 KB (๐ŸŸก +28 B) 161.09 KB
/learn/writing-markup-with-jsx 51 KB (๐ŸŸก +28 B) 156.51 KB
/learn/you-might-not-need-an-effect 62.68 KB (๐ŸŸก +28 B) 168.18 KB
/learn/your-first-component 51.59 KB (๐ŸŸก +28 B) 157.09 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.

github-actions[bot] avatar Jun 02 '22 15:06 github-actions[bot]

https://github.com/reactjs/reactjs.org/pull/4307/ - Can I merge this as part of your PR? This enables TSX template in sandpack. Or you can use the same in your PR if needed.

harish-sethuraman avatar Jun 02 '22 15:06 harish-sethuraman

@harish-sethuraman

https://github.com/reactjs/reactjs.org/pull/4307 - Can I merge this as part of your PR?

I prefer not to expand the scope of this PR any further. It seems fine if you merge your change afterwards.

justjake avatar Jun 02 '22 16:06 justjake

@danilowoz

currently, the bundler is not able to handle the TS types because we need to tell it to deal with TS types properly

Why is this needed? I havenโ€™t noticed the bundler breaking while using the editing features added here. My goal here is to bring autocomplete etc to the existing JS documentation, not to change all the documentation to use typescript.

If desired, we could do this in a follow-up PR unless Iโ€™m mistaken.

justjake avatar Jun 03 '22 14:06 justjake

My main concern with this is it feels very TS-centric (for obvious reasons). E.g. you hover over <button> and see (โ€‹propertyโ€‹) JSX.IntrinsicElements.button: React.DetailedHTMLProps<โ€‹React.ButtonHTMLAttributes<โ€‹HTMLButtonElementโ€‹>, HTMLButtonElementโ€‹>. This is overwhelming and not particularly useful (IMO) to people who aren't TS experts.

Do you share this concern?

gaearon avatar Jun 03 '22 14:06 gaearon

Yeah, I want to strike a good balance for this integration to provide meaningful help to React learners without overloading them with a second subject to study (Typescript).

I think we have three jobs to do in this PR:

  1. Figure out if this effort is worth-while. If there's not enough promise in these features to warrant effort to iterate, it's fine to close.
  2. Review/iterate on the mechanics. Is performance impact acceptable? Is code too complex to accept in this project? Is the architecture okay?
  3. Review/iterate on the UX & policy. Currently I've cloned these features from VS Code, plus rounded corners. We should refine it further for the learner use-case.

I think the hover tooltip can be very helpful to learners if it surfaces understandable or actionable information, and harmful in cases like the <button> type. Even for a Typescript expert (?me?), this hover tip isn't actionable. Looking at this, all I know is "it's some kind of react thing related to HTMLButtonElement"; and the only action I can take when presented with complex types like this is to go read the type definition using "Go to type definition", which we can't do in reactjs.org.

There are many ways we can adjust this feature, and other features to avoid overwhelming learners, with different tradeoffs. For example, we could hide all the type information, and only show doc comments. useState and other hooks have succinct descriptions; showing doc comments avoids students needing a second window/tab to look at reference material in many cases. The downside is that we miss out on type hovers that are understandable to a large degree such as primitive types or JSX property names.

justjake avatar Jun 03 '22 15:06 justjake

I think ideally I'd like to see:

  • Automatic formatting, but not on "save". It's not obvious "save" even works here. Maybe on Enter? It should preserve the cursor position.
  • Auto-import but you shouldn't need to know to press cmd+space. It should "notice" when you're typing useState, for example.
  • Tooltips, but ideally it would just be a sentence + the link should somehow go to the beta docs. (Can we override it?)
  • Autocomplete shouldn't include a myriad of global browser APIs. They're not useful in 99.9% cases here.
  • Import/export linting is good. I don't think we need the "unused variable" check though.

gaearon avatar Jun 03 '22 16:06 gaearon

Hover & imports without types:

image image

Without @see, @version. It looks lonely to me since I'm used to VS Code, but removes even more clutter.

image image

justjake avatar Jun 03 '22 16:06 justjake

version does seem useless to me... see is ok if it linked to the right thing but if we can't make it yet then it's better without it.

Would be nice if backticks turned into inline code style.

gaearon avatar Jun 03 '22 16:06 gaearon

@gaearon do you have an existing plan for migrating links from the old docs URLs to the new docs? Do you have any kind of route mapping already written? If so, we could try applying the migration plan to all the URLs in TSDoc.

Otherwise, we can remove @see, then render a link to /apis/${identifier.toLowerCase()} if the identifier is imported from 'react' or 'react-dom'

justjake avatar Jun 03 '22 17:06 justjake

added a quick hack to replace @see URLs with Docs: <link to beta docs>

https://user-images.githubusercontent.com/296279/171918409-cea813e6-193a-46ee-a7f1-9ecbdc298ff9.mp4

justjake avatar Jun 03 '22 17:06 justjake

added a quick hack to replace @see URLs with Docs:

this looks great

gaearon avatar Jun 03 '22 17:06 gaearon

@danilowoz Curious why you implemented type acquisition yourself versus re-using https://github.com/microsoft/TypeScript-Website/tree/v2/packages/ata, which is used by https://www.typescriptlang.org/play. It fetches files from jsdelivr.

justjake avatar Jun 03 '22 21:06 justjake

First of all this is super cool, great work.

One of the reasons I didn't build it this way on the TypeScript website is because it means each code sample using this technique needs ~8mb of downloaded JS to work at runtime. That's a lot of JS for something which is structurally opt-in (e.g. you have to start interacting with the code sample for it to be useful) which has both download costs, and adds to the memory usage for each page. For example: loading up a page like https://beta-reactjs-cg21dnj16-fbopensource.vercel.app/learn/describing-the-ui triggers hundreds of JS requests (a lot are cache hits though) and at least one web worker per code sample (~10)

As this is all still early, it might be worth looking into whether you could share one tsserver across all code samples, or incrementally loading in the tsserver code on demand

orta avatar Jun 05 '22 07:06 orta

@orta:

As this is all still early, it might be worth looking into whether you could share one tsserver across all code samples, or incrementally loading in the tsserver code on demand

Yeah, I agree. I lifted the worker into a provider so we only need a single worker for the lifetime of the app. The worker is created only when needed by an editor.

I tried two strategies for lazy loading:

  1. Load the worker as soon as an editor mounts (at https://github.com/reactjs/reactjs.org/pull/4720/commits/b0d2eb2b15cdb3cbb7cfe1b8de1e49f908686768). This is simple but works well.
  2. Load the worker once the user hovers or focuses an editor. This is more optimal from a resource use perspective, but has some issues. On slower connections these features feel more inconsistent since we trigger loading later.

@danilowoz Is there a better way to override Sandpack's styling of the Codemirror tooltip style than using !important in my own extension?

Without a lot of !important, lazy-loading my plugin leads to inconsistent CSS ordering seen here:

https://user-images.githubusercontent.com/296279/172221096-b135fb13-d2f7-400a-ba3f-0c421c00a311.mp4

justjake avatar Jun 06 '22 18:06 justjake

Okay folks! This is ready for another review pass. I believe I've completed all the mechanical and UX TODOs I noted from previous comments. Thanks for the feedback so far, keep it coming.

For now I've left config.ts intact with the hope that the code size for the debug features/config options is worth leaving these in; and that it makes it easier for @danilowoz to extract and generalize this work if they want to do so. Happy to remove once the next review pass is done and I won't need to debug/change UX any more ๐Ÿ˜„.

justjake avatar Jun 07 '22 07:06 justjake

Hey @justjake, here are the following up about some issues:

  • Tooltip CSS override: actually, these styles come from the React Docs website and not from the Sandpack package, so that you can update it in the following file. Please take into account that it might affect the eslint tooltip too, and maybe it's worth syncing its styles in order to keep both tooltips consistent: https://github.com/justjake/reactjs.org/blob/jake--tsserver/beta/src/styles/sandpack.css#L107-L110
  • The showInlineErrors bug has been fixed on 0.19.8-experimental.6;

Although a lot of performance improvements were made, the worker is still using a significant amount of memory (~300MB on /learn/describing-the-ui, other pages might be less). Maybe it's because it only uses a single worker now?

danilowoz avatar Jun 07 '22 15:06 danilowoz

Please take into account that it might affect the eslint tooltip too, and maybe it's worth syncing its styles in order to keep both tooltips consistent: https://github.com/justjake/reactjs.org/blob/jake--tsserver/beta/src/styles/sandpack.css#L107-L110

๐Ÿคฆ๐Ÿป thanks for pointing that out!

Although a lot of performance improvements were made, the worker is still using a significant amount of memory (~300MB on /learn/describing-the-ui, other pages might be less). Maybe it's because it only uses a single worker now?

I can do some more work on lazy instantiation of the the Typescript features per editor. Right now once any editor receives interaction, all the editors boot up and create typescript environments in the shared worker. I think I can do more by lazily instantiating language services per editor only after interaction.

justjake avatar Jun 07 '22 18:06 justjake

Typescript environments are now created on first interaction. There's an initial cost of ~60MB heap to boot the tsserver worker and create the first environment, and an additional ~30MB cost per additional environment. Numbers from my M1 Mac, Chrome 102.

Environments are dereferenced when their Sandpack editor is scrolled off-screen and returns to the "idle" state. Memory use can peak up to ~300MB, but dereferenced environments are cleaned up, so usage returns to around ~80mb on /learn/describing-the-ui if I scroll around and click on each editor to force Typescript environment (re)creation.

justjake avatar Jun 07 '22 22:06 justjake

Hello โ€“ I have some free time coming up that I'd like to use finishing this work. @gaearon @harish-sethuraman @danilowoz What are the blockers here that I need to resolve?

justjake avatar Jun 21 '22 17:06 justjake

Is there an up-to-date summary of the exact features being added? Since we went back and forth a few times. There is a lot of code and I worry about how to balance the complexity being added vs the payoff. The things that seems most useful to me are autoformatting and possibility of doing TypeScript sandboxes (that works, right?) Can you show how it works with TS code?

gaearon avatar Jun 23 '22 21:06 gaearon

@gaearon

JS Features

These apply to all the existing JS code examples:

  • Report syntax errors and import-related errors with red squiggles. Other kinds of errors, especially type errors, are ignored.
  • Intelligent type-ahead completion, including smart imports. Autocomplete doesn't suggest a bunch of random browser globals.
  • Hover tooltips for tokens that have documentation.
  • All tooltips (hover & import) show documentation and links to beta.reactjs.org/apis/name. Tooltips don't show Typescript syntax.
  • Auto-format the file (preserving cursor position) on newline, Cmd-S (muscle memory matches CodeSandbox.com & VS Code), or Shift-Alt-F (matches VS Code)
image image image

Optimizations

  • This system uses a single WebWorker, shared via React Context.
  • The worker is lazily instantiated when a user interacts with a Sandpack example for the first time
  • The worker creates new typescript environments for each example, and then dereferences them if the example is scrolled off-screen to conserve memory overall.

In my testing, these changes add ~55mb of Javascript heap once the user interacts with a code editor and while that editor remains on-screen. This brings total heap size from ~70mb to 125mb while editing a sandbox.

Typescript

Write App.tsx examples in Typescript, via ```typescript code fences. This automatically enables the following features:

  • Full type error reporting for Typescript code.
  • Build each .tsx file to JS, and show the JS as a tab.
  • The JS version stays in-sync with the TSX version until the user edits the JS version. Then, it's independent until the user presses "Reset".
  • When the JS version of a file is selected, it's used in the bundle instead of the JS version.
  • When the TSX version of a file is selected, it's used in the bundle instead of the JS version.

https://user-images.githubusercontent.com/296279/175845725-6fb8aa9b-5041-40c3-9042-9e791fc0b842.mp4

justjake avatar Jun 24 '22 00:06 justjake