Skip to content

Dev playground with monaco-editor #1

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

Merged
merged 31 commits into from
Jan 11, 2024
Merged
Show file tree
Hide file tree
Changes from 29 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
49d1b26
playground with typescripts sandbox
gdamjan Dec 2, 2023
0d9d468
compile to a single amd file for playground
gdamjan Dec 27, 2023
24f099e
add esbuild and make the playground run with it
gdamjan Dec 28, 2023
c9267c8
use monaco-editor directly
gdamjan Dec 28, 2023
1bfa37c
run esbuild with pnpm
gdamjan Dec 28, 2023
94e445b
playground build steps in package.json
gdamjan Dec 28, 2023
18eb26e
remove serve, esbuild has its own server
gdamjan Dec 28, 2023
b2b7482
playground favicon, png, relative path
gdamjan Dec 28, 2023
5897300
debounced autosave on keyDown and ctrl-s saves
gdamjan Dec 30, 2023
8fe7f67
autoformat
gdamjan Dec 30, 2023
b7ae12f
global window.monacoEditor for debugging around
gdamjan Dec 30, 2023
d0ae4d9
side-by-side layout
gdamjan Dec 30, 2023
4f5b457
configure typescriptDefaults first thing in init()
gdamjan Dec 30, 2023
dc1705e
load types in the monaco editor
gdamjan Dec 30, 2023
fd1c3d6
increase autosave delay to 5s
gdamjan Dec 30, 2023
82d4f82
download in parallel (Promise.all)
gdamjan Dec 30, 2023
c842105
get javascript from the typescript worker
gdamjan Dec 30, 2023
e93575a
browser importmap: point "irclog-api" -> "./dist/index.js"
gdamjan Dec 31, 2023
34e6375
build esm modules for the playground
gdamjan Dec 31, 2023
5e80278
create a <script> with the transpiled code and insert it to the DOM
gdamjan Dec 31, 2023
60da45e
fix example.ts
gdamjan Dec 31, 2023
6736bc4
add some indenting of the json output
gdamjan Dec 31, 2023
774a4c4
rename playground/index.js to playground/playground.js
gdamjan Jan 1, 2024
bf70851
tab size 2 for the log output, and clear-log button
gdamjan Jan 1, 2024
05b74ff
add dts-bundle to create a single "bundled" index.d.ts file
gdamjan Jan 1, 2024
c29c2f1
load a single bundled index.d.ts file
gdamjan Jan 1, 2024
db801ca
load the vs.loader from cdnjs too, it's newer too
gdamjan Jan 1, 2024
0713705
update README files
gdamjan Jan 1, 2024
4e23f08
build project before bundling playground/dist/index.d.ts
gdamjan Jan 1, 2024
8e02de3
Update .github/workflows/playground.yml
gdamjan Jan 11, 2024
85942f2
Update playground/index.html
gdamjan Jan 11, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions .github/workflows/playground.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
name: Build Playground

on:
push:
branches: [playground]
workflow_dispatch:

jobs:
playground:
# Allow one concurrent deployment
concurrency:
group: 'pages'
cancel-in-progress: true

# Grant GITHUB_TOKEN the permissions required to make a Pages deployment
permissions:
pages: write # to deploy to Pages
id-token: write # to verify the deployment originates from an appropriate source

environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}

runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- uses: actions/setup-node@v4
with:
node-version: 18

- uses: pnpm/action-setup@v2
with:
run_install: true

- run: pnpm run '/^playground:.*/'

- name: Upload artifact
uses: actions/upload-pages-artifact@v1
with:
path: ./playground

- uses: actions/deploy-pages@v1
id: deployment
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
node_modules/
dist/
playground/types/
playground/dist/
.tsbuildinfo
21 changes: 15 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,31 @@
# `irclog-api`
# `@irclogs/api`

Typescript API to access the IrcLog CouchDB database. Mostly typed wrappers over the http api of CouchDB.


## Quick start for users

```
TBD
echo "@irclogs:registry=https://npm.pkg.github.com" >> .npmrc
npm install @irclogs/api
# or
yarn add @irclogs/api
# or
pnpm add @irclogs/api
```

## Quick start for developers
## API Playground

TBD
See https://irclogs.github.io/api/ to interactively play with the api in your browser.

To use the playground locally run:
```
pnpm install
pnpm dev
pnpm playground:types
pnpm play
```
and open http://localhost:8000


## References

Expand All @@ -27,6 +37,5 @@ pnpm dev

- naming: class name?
- documentation
- playground publish to gh-pages (https://www.typescriptlang.org/dev/sandbox/)
- package publish check auto-versioning schema
- validation on responses and typing (use zod)
11 changes: 8 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,20 @@
"/dist"
],
"scripts": {
"dist": "tsc",
"dist": "rm -rf dist/ && tsc",
"compile": "tsc --noEmit --pretty",
"prettier": "prettier src/",
"prettier:fix": "prettier src/ --write",
"play": "esbuild src/index.ts --bundle --outdir=playground/dist --watch --servedir=playground --format=esm",
"playground:dist": "esbuild src/index.ts --bundle --outdir=playground/dist --format=esm",
"playground:types": "$_ dist && dts-bundle --name @irclogs/api --baseDir ./dist/ --main dist/index.d.ts --out $PWD/playground/dist/index.d.ts",
"test": "echo Warning: no test specified for now!"
},
"devDependencies": {
"prettier": "^3.1.0",
"typescript": "^5.3.2"
"dts-bundle": "^0.7.3",
"esbuild": "^0.19.10",
"prettier": "^3.1.1",
"typescript": "^5.3.3"
},
"prettier": {
"printWidth": 120,
Expand Down
70 changes: 70 additions & 0 deletions playground/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# Playground implementation notes

## monaco-editor

The playground is based on the [monaco-editor](https://microsoft.github.io/monaco-editor/) and
it runs completely in the browser - no backend is needed. That makes it work on a site hosted
at Github Pages too.

Monaco-editor is used since it is a decent editor, has built-in support for javascript and typescript,
and runs in the browser.

The playground code is written in plain javascript and html.

> [!NOTE]
> Don't be fooled by the playground at https://www.typescriptlang.org/dev/sandbox/.
> Its documentation is incomplete, and installs quite old monaco-editor and typescript.


## type support in the editor

In order for monaco-editor to be aware about the types of our project, we need to build a bundled
`.d.ts` files. `tsc` itself doesn't know to properly bundle a `.d.ts` file useful for monaco-editor,
so had to use `dts-bundle` (see `playground:types` in package.json scripts).

The bundle is created at `playground/dist/index.d.ts`, loaded in the browser with `fetch` and
then loaded in the typescript server with `addExtraLib`, at a virtual path of
`file:///node_modules/@types/@irclogs/api/index.d.ts`.

Given that the edited content is virtually at `file:///example.ts`, the language server uses the node
module resolution algorithm, by looking for `node_modules`, then `@types/<your library>` etc.

ps.
there's an option to load each `.d.ts` file separately as created by `tsc`, and add them to the language
server. But that's a bit tedious and the list of files will need to be kept in sync with what `tsc` creates
from the source.


## running code in the browser

I wanted to enable running code in the browser as you would run it in any normal typescript module. That
includes top-level await and support for the `import` statement. For those reasons `eval` is not possible.

In order to actually run the code, first we call `getEmitOutput` on the editor to get transpiled typescript
to javascript. Then we create a `<script>` dom element, with `type=module`, and set the transpiled code
as it's content. Once the element is added to the DOM, the javascript code will run.

### import mapping

[importmap](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script/type/importmap) is used to
map the normal `import {} from "@irclogs/api"` usage, to actually load the module from a file via http.

esbuild was used to create the `esm` bundle in `playground/dist/index.js`, so that it's compatible with
the new-wave javascript module system (`import`).


### redirecting console.log

A preamble is added to the transpiled code to override `console.log` to actually add text into the
`#console-output` html element (a `<pre>` element). Seems hacky, but it works.



## Re-use of the playground

There's really only 3 places to change `@irclogs/api` in the playground code:
- in `example.ts` of-course
- in the `importmap` in `index.html`
- the virtual path `file:///node_modules/@types/@irclogs/api/index.d.ts` in the playground.js

and one in `package.json` when building the bundled `index.d.ts` file with dts-bundle `--name @irclogs/api`.
8 changes: 8 additions & 0 deletions playground/example.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import {CouchDB} from "@irclogs/api";

type T = "a" | "B";
let a: T = "a";

const db = new CouchDB("https://db.softver.org.mk/irclog/", "_design/log/_view/channel");
let res = await db.fetchChannelList();
console.log(res);
Binary file added playground/favicon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
82 changes: 82 additions & 0 deletions playground/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
<!doctype html>
<html lang="en">

<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Playground</title>
<link rel="icon" type="image/png" href="./favicon.png">
<script
src="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.45.0/min/vs/loader.min.js"
integrity="sha512-ZG31AN9z/CQD1YDDAK4RUAvogwbJHv6bHrumrnMLzdCrVu4HeAqrUX7Jsal/cbUwXGfaMUNmQU04tQ8XXl5Znw=="
crossorigin="anonymous"
referrerpolicy="no-referrer"
></script>
<script src="./playground.js" defer></script>
<script type="importmap">
{
"imports": {
"@irclogs/api": "./dist/index.js"
}
}
</script>

<style>
body {
overflow: hidden;
margin: 0;
}

#main {
font-size: 12pt;
width: 94%;
padding: 0pt;
margin: 1% 3% 5ex 3%;
}

#leftPane {
float: left;
height: 90vh;
width: 58%;
margin: 0;
background-color: rgb(255, 221, 227);

&>#monaco-editor {
height: 100%;
}
}

#rightPane {
float: right;
height: 90vh;
width: 40%;
margin: 0;
background-color: #eceff3;
/* border: 1px solid #ccc;
border-bottom: 0;
padding: 10px; */
display: flex;
flex-direction: column;

&>pre {
overflow: scroll;
flex-grow: 1;
tab-size: 2;
}
}
</style>
</head>

<body>
<div id="main">
<div id="leftPane">
<div id="monaco-editor"></div>
</div>
<div id="rightPane">
<div><button id="run-code">Run Code</button><button id="clear-log">Clear log</button></div>
<pre id="console-output"></pre>
</div>
</div>
</body>

</html>
Loading