rvx
Version:
A signal based rendering library
176 lines (130 loc) • 4.91 kB
Markdown
# Environments
Rvx accesses all browser related APIs through the `ENV` context which provides a `window` like object.
```jsx
import { ENV } from "rvx";
// Set the global default:
ENV.default = someAPI;
// Or use a different DOM API in a specific context:
ENV.inject(someAPI, () => {
// ...
});
// Access the current DOM API:
ENV.current.document.createElement("div");
```
## Rvx DOM
The `"rvx/dom"` module provides a fast minimal DOM implementation with the single purpose of rendering HTML strings on the server or during a build process.
!!! tip
A minimal project template for static site generation using rvx dom and vite can be found [here](https://github.com/mxjp/rvx/tree/main/templates/vite-ssg).
The `renderToString` utility can be used to synchronously render a [component](./core/components.md) to HTML:
```jsx
import { renderToString } from "rvx/dom";
const html = renderToString(() => {
return <h1>Hello World!</h1>;
});
console.log(html); // "<h1>Hello World!</h1>"
```
To wait for [`<Async>`](./async-utilities/async.md) parts to complete, use `renderToStringAsync`:
```jsx
import { renderToStringAsync } from "rvx/dom";
const html = await renderToStringAsync(() => {
return <Async source={Promise.resolve("Hello World!")}>
{title => <h1>{title}</h1>}
</Async>;
});
console.log(html); // "<h1>Hello World!</h1>"
```
The [lifecycle](./core/lifecycle.md) of rendered components is disposed immediately after rendering the HTML string.
!!! warning
This module is **not** in any way optimized for code size and probably should not be used in a real browser.
!!! danger
In order to be fast, this implementation skips some validations that a browser would usually perform:
+ DOM node hierachy is not validated. This can be used to create cyclically nested nodes.
+ Class list tokens and inline css properties are not validated. This can be used to create invalid `class` or `style` attributes.
### Replacing Pre-Rendered HTML
Rvx does not directly support hydration. Instead, you can render content off screen and replace entire parts of the page when complete:
=== "JSX"
```jsx
import { render } from "rvx";
const app = render(
<h1>Hello World!</h1>
);
// Replace a specific element:
document.getElementById("app-root").replace(app.detach());
// Replace the entire page:
document.body.replaceChildren(app.detach());
```
=== "No Build"
```jsx
import { render, e } from "./rvx.js";
const app = render(
e("h1").append("Hello World!"),
);
// Replace a specific element:
document.getElementById("app-root").replace(app.detach());
// Replace the entire page:
document.body.replaceChildren(app.detach());
```
If needed, you can wait for [`<Async>`](./async-utilities/async.md) parts to complete before replacing any elements:
=== "JSX"
```jsx
import { render } from "rvx";
import { ASYNC, Async, AsyncContext } from "rvx/async";
const asyncCtx = new AsyncContext();
const app = ASYNC.inject(asyncCtx, () => {
return render(
<Async source={Promise.resolve("Hello World!")}>
{title => <h1>{title}</h1>}
</Async>
);
});
// Wait for all "<Async>" parts to complete:
await asyncCtx.complete();
// Replace the entire page:
document.body.replaceChildren(app.detach());
```
=== "No Build"
```jsx
import { e, render } from "./rvx.js";
import { ASYNC, Async, AsyncContext } from "./rvx.async.js";
const asyncCtx = new AsyncContext();
const app = ASYNC.inject(asyncCtx, () => {
return render(
Async({
source: Promise.resolve("Hello World!"),
children: title => e("h1").append(title),
})
);
});
// Wait for all "<Async>" parts to complete:
await asyncCtx.complete();
// Replace the entire page:
document.body.replaceChildren(app.detach());
```
### Detecting Rvx DOM
The `isRvxDom` function can be used to detect if rvx dom is enabled in the current context. When using a bundler with tree shaking, this will not include the rvx dom implementation.
=== "JSX"
```jsx
import { isRvxDom } from "rvx/dom";
console.log(isRvxDom());
```
=== "No Build"
```jsx
import { isRvxDom } from "./rvx.dom.js";
console.log(isRvxDom());
```
## JSDOM
The [JSDOM](https://www.npmjs.com/package/jsdom) library can emulate a subset of browser APIs in NodeJS and is fully supported as an environment for rvx. This can be used for testing without using a real browser.
```jsx
import { JSDOM } from "jsdom";
import { ENV } from "rvx";
ENV.default = new JSDOM().window;
mount(ENV.current.document.body, <h1>Hello World!</h1>);
```
## Web Components
The `rvx/element` module always uses the global default at module load time. To use it in a non-browser environment, you need to ensure that the global default is set before loading that module:
```jsx
import { ENV } from "rvx";
ENV.default = someAPI;
const { RvxElement } = await import("rvx/element");
class SomeWebComponent extends RvxElement { ... }
```