Skip to content

refactor: undo monorepo#260

Open
jderochervlk wants to merge 15 commits intomainfrom
unmonorepo-webapi-redo
Open

refactor: undo monorepo#260
jderochervlk wants to merge 15 commits intomainfrom
unmonorepo-webapi-redo

Conversation

@jderochervlk
Copy link
Copy Markdown
Collaborator

@jderochervlk jderochervlk commented Apr 22, 2026

Summary

This PR restructures the repo back into a single root package, @rescript/webapi, while keeping feature-gated source directories in the root rescript.json.

  • Removes the npm workspace/package split under packages/*.
  • Moves bindings into src/<Feature> directories controlled by root-level feature entries such as WebAPI.DOM, WebAPI.Fetch, WebAPI.Canvas, and WebAPI.WebWorkers.
  • Keeps generated helper modules ending in *Types and DOM/global helper files internal through explicit per-feature public lists in rescript.json.
  • Flattens the public module surface so consumers use modules such as WebAPI.Headers, WebAPI.Request, WebAPI.Element, WebAPI.Path2D, and WebAPI.ReadableStream directly.
  • Simplifies former Global / GlobalScope public names to owner modules such as WebAPI.Fetch, WebAPI.Canvas, WebAPI.Worker, WebAPI.SharedWorkerScope, and WebAPI.ServiceWorkerScope.
  • Adds a public WebAPI.VisualViewport module and updates Window.visualViewport to return WebAPI.VisualViewport.t.
  • Updates docs, packaging, CI, examples, and migration helper tests for the single-package layout.

Current public API shape

Install the package and add it to rescript.json:

{
  "dependencies": [
    "@rescript/webapi"
  ]
}

Use public owner modules directly under WebAPI:

let location = WebAPI.Window.current->WebAPI.Window.location
let href = location.href
location->WebAPI.Location.reload

Fetch and request bodies:

let response = await WebAPI.Fetch.fetch(
  "https://example.com/api",
  ~init={
    method: "POST",
    headers: WebAPI.HeadersInit.fromDict(
      dict{"Content-Type": "application/json"},
    ),
    body: WebAPI.BodyInit.fromString(`{"hello":"world"}`),
  },
)

let text = await response->WebAPI.Response.text

Headers can be constructed from common JavaScript shapes and still expose typed methods:

let headers = WebAPI.Headers.fromDict(dict{"Accept": "application/json"})
headers->WebAPI.Headers.set(~name="X-Request-ID", ~value="abc-123")

switch headers->WebAPI.Headers.get("Accept") {
| Null.Value(value) => Console.log(value)
| Null => Console.log("missing")
}

Requests and responses keep their typed constructors and body readers:

let req = WebAPI.Request.fromURL(
  "https://example.com/form",
  ~init={
    method: "POST",
    body: WebAPI.BodyInit.fromString("name=ReScript"),
  },
)

let response = await WebAPI.Fetch.fetchWithRequest(req)
let cloned: WebAPI.Request.t = req->WebAPI.Request.clone
let bodyText = await cloned->WebAPI.Request.text

let created = WebAPI.Response.fromString(
  "created",
  ~init={status: 201},
)

DOM usage goes through public interface modules rather than generated type modules:

let document = WebAPI.Window.current->WebAPI.Window.document

let maybeButton = document
->WebAPI.Document.querySelector("button")
->Null.toOption

switch maybeButton {
| Some(button) =>
  switch button->WebAPI.Element.getAttribute("data-user-id") {
  | Null.Value(id) => Console.log(id)
  | Null => Console.log("anonymous")
  }
| None => Console.log("button not found")
}

Worker global-scope APIs use simplified scope modules:

let worker = WebAPI.Worker.current
let workerResponse = await worker->WebAPI.Worker.fetch("https://example.com/data")

let sharedWorker = WebAPI.SharedWorkerScope.current
sharedWorker->WebAPI.SharedWorkerScope.close

let serviceWorker = WebAPI.ServiceWorkerScope.current
await serviceWorker->WebAPI.ServiceWorkerScope.skipWaiting

Visual viewport has a public wrapper type:

let maybeViewport = WebAPI.Window.current
->WebAPI.Window.visualViewport
->Null.toOption

switch maybeViewport {
| Some(viewport) => Console.log(Float.toString(viewport.scale))
| None => Console.log("visual viewport unavailable")
}

Canvas constructors and helpers use owner modules:

let path = WebAPI.Path2D.make()
path->WebAPI.Path2D.moveTo(~x=0., ~y=0.)
path->WebAPI.Path2D.lineTo(~x=100., ~y=100.)

let copiedPath = WebAPI.Path2D.fromPath2D(path)
let svgPath = WebAPI.Path2D.fromString("M0 0 L10 10")

URL helpers expose constructors and static functions on the same public module:

let url = WebAPI.URL.make(~url="/docs", ~base="https://rescript-lang.org")
let canParse = WebAPI.URL.canParse(~url="/docs", ~base="https://rescript-lang.org")
let json = url->WebAPI.URL.toJSON

Generic Web API types stay typed through their public owner modules:

let stream: WebAPI.ReadableStream.t<string> = WebAPI.ReadableStream.make()
let reader = stream->WebAPI.ReadableStream.getReader

Public surface checks

The root rescript.json now sets a public list for every src/<Feature> entry. Those lists are generated from the feature source files and filter out every module whose name ends in Types, so modules such as DomTypes, FetchTypes, EventTypes, and UiEventsTypes are internal implementation modules.

The public lists also avoid Global and GlobalScope module names. DOM globals are reached through public owner modules such as WebAPI.Window, while feature-specific global helpers are exposed as simplified owner modules like WebAPI.Fetch and WebAPI.Worker.

The generated API/LLM docs use the same rescript.json public lists so internal helper files do not get published as API pages.

Verification

  • node --test tests/unmonorepo/*.test.mjs
  • npm run build
  • npm test
  • ASTRO_TELEMETRY_DISABLED=1 npm run build:docs
  • npm run format:check
  • git diff --check

Comment thread docs/content/docs/index.mdx Outdated
Comment thread docs/content/docs/index.mdx Outdated
Comment thread docs/content/docs/philosophy.mdx Outdated
Comment thread docs/content/docs/philosophy.mdx Outdated
Comment thread docs/content/docs/philosophy.mdx Outdated
@fhammerschmidt
Copy link
Copy Markdown
Member

oh no! why?

@jderochervlk jderochervlk requested review from brnrdog and tsnobip April 23, 2026 11:45
@jderochervlk
Copy link
Copy Markdown
Collaborator Author

oh no! why?

We won't need to ship separate npm packages because of this: rescript-lang/rescript#8379

Copy link
Copy Markdown
Member

@tsnobip tsnobip left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Undoing the monorepo would allow to have have a structure quite similar to what it was before, just with extracted "base" types. Now we should really think about how we want to call these base types (Base.DOM, BaseDOM, other?). I'm wondering if we couldn't come up with an even smarter structure with the features.

Edit: I'm quite excited to see we're close to finally reach the alpha haha

Comment thread src/DOM/DOM.res Outdated
Comment thread docs/superpowers/specs/2026-04-22-unmonorepo-webapi-design.md
Comment thread docs/superpowers/specs/2026-04-22-unmonorepo-webapi-design.md
@jderochervlk
Copy link
Copy Markdown
Collaborator Author

Undoing the monorepo would allow to have have a structure quite similar to what it was before, just with extracted "base" types. Now we should really think about how we want to call these base types (Base.DOM, BaseDOM, other?). I'm wondering if we couldn't come up with an even smarter structure with the features.

Edit: I'm quite excited to see we're close to finally reach the alpha haha

I think using DOM as a module would be good for things like element, document, etc...

@jderochervlk
Copy link
Copy Markdown
Collaborator Author

@codex

@jderochervlk jderochervlk requested a review from tsnobip May 5, 2026 18:13
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fde4ee8d4a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread tests/index.js
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants