oven-sh / bun

Incredibly fast JavaScript runtime, bundler, test runner, and package manager – all in one
https://bun.sh
Other
74.07k stars 2.76k forks source link

Support DOM APIs on the Server #8621

Open rossrobino opened 9 months ago

rossrobino commented 9 months ago

What is the problem this feature would solve?

This feature would have two major benefits I can think of:

  1. Testing - replacing and speeding up tests that currently use libraries like JSDOM.
  2. Server Rendering - Having the DOM APIs on the server would enable server-side rendering without adding any extra dependencies. You could do things like SSR web components and replace libraries like LinkeDOM.

What is the feature you are proposing to solve the problem?

Bun would need a new method to create a window like JSDOM. Something like this:

const { document } = Bun.dom("<!DOCTYPE html><p>Hello world</p>");

const p = document.querySelector("p");

p.textContent = "Hello bun";

document.toString(); // "<!DOCTYPE html><p>Hello bun</p>"

Alternatively, it would be even great if the window was a global. Then you could import from client side libraries directly into Bun without getting document is not defined errors.

What alternatives have you considered?

Use JSDOM, LinkeDOM, Happy dom and make tradeoffs between library size, speed, and feature support.

paperdave commented 9 months ago

I dont think we can ever make window a global by default, or else many libraries will think Bun is a browser, and take undesired code paths due to this.

I think one of the alternatives is a better approach for this would be one of these libraries.

You could do things like SSR web components and replace libraries like LinkeDOM.

I think it is a terrible idea to simulate the entire DOM for the purpose of SSR.

huseeiin commented 9 months ago

I dont think we can ever make window a global by default, or else many libraries will think Bun is a browser, and take undesired code paths due to this.

I think one of the alternatives is a better approach for this would be one of these libraries.

You could do things like SSR web components and replace libraries like LinkeDOM.

I think it is a terrible idea to simulate the entire DOM for the purpose of SSR.

thank god you aren't implementing this :pray:

rossrobino commented 9 months ago

I dont think we can ever make window a global by default, or else many libraries will think Bun is a browser, and take undesired code paths due to this.

Yes, perhaps a configuration option would be better if it was a global, or just having it be apart of Bun instead.


I think one of the alternatives is a better approach for this would be one of these libraries.

You could do things like SSR web components and replace libraries like LinkeDOM.

I think it is a terrible idea to simulate the entire DOM for the purpose of SSR.

To each their own. I've found doing SSR using LinkeDOM effective. The strongest aspect of the JavaScript language is DOM manipulation/rendering HTML. One of the strongest cases for using JS on the server is for SSR. To have access to the DOM APIs on the server allows you to not have to deal with templating languages like JSX.

For example, I ran into an issue where I was rendering markdown and needed to add a div around every table element to prevent overflow. With access to querySelectorAll it was easy to manipulate all of them with the same code I would write on the client. Most JS developers can look at the code and understand exactly what's occurring, since it's just the DOM APIs.

const tables = document.querySelectorAll("table");
tables.forEach((table) => {
  const wrapper = document.createElement("div");
  wrapper.classList.add("overflow-x-auto");
  table.parentNode?.insertBefore(wrapper, table);
  wrapper.appendChild(table);
});

To accomplish this on the server without DOM APIs, the implementation would vary by framework.


Here's another example, you need to update the title tag in the head of the document on the server.

With DOM APIs:

document.title = "Title";

Here's a few examples in different frameworks I found:


Another case is server rendering custom elements is currently not possible without access to the DOM APIs.


Appreciate the feedback, feel free to close if there isn't interest. It is still possible to use the mentioned libraries to accomplish the same goal.