2812

docs

Welp, if you've made it here, you probably have a basic Ultra project running. If not try this...

deno run -A -r https://deno.land/x/ultra/create.ts
FYI: You can pass custom options after this script to make this quicker in the future

react-query wouter react-router twind stitches

Use it like...

deno run -A -r https://deno.land/x/ultra/create.ts twind react-query

Extending Ultra

Ultra gives you the control to use (or not use) many of the most popular React libraries out there. You will probably need to update your importMap.json, server.tsx and client.tsx

We've prepared the following examples for you:

Routing

Data Fetching

CSS

or just use plain old CSS, it's way underrated.

API Routes

Middleware

Since Ultra uses Hono under-the-covers, it includes middleware support. Here is an example snippet added to server.tsx that will add a 'Server' header to every response:

server.use('*', async (c, next) => {
  c.res.headers.set("Server", "Ultra Hono");
  await next();
});

If you look in the Dev Tools Network tab and click on localhost, you'll see this line in the Headers tab added to the Response Headers section:

server: Ultra Hono

See the Hono middleware docs for more details.

Zero-JS™

Ultra has route-based server options which can be configured to disable hydration, as well as not ship any JS to your users. Great for you young guns making your spammy marketing pages.

server.get("/", async (context) => {
  const result = await server.render(<Home />, {
    generateStaticHTML: true,
    disableHydration: true,
  });
  return context.body(result, 200, {
    "content-type": "text/html",
  });
});
As these options are route-based, you can make an app which mixes both types of routes/hydration. See what happens.

More examples can be found here

If there is an existing library that you want to use, there is a good chance you can create a custom integration. Use some of the examples above as a guide -- open a PR if you are keen.


Ultra Hooks

useAsset

import useAsset from "ultra/hooks/use-asset.js";

<link rel="preload" as="style" href={useAsset("/style.css")} />

useAsset allows Ultra to version your assets during build for deploying to production. In development it's a non-op.

useServerInsertedHTML

import useServerInsertedHTML from "ultra/hooks/use-server-inserted-html.js";


const ServerApp = function () {
  /**
   * useServerInsertedHTML will inject the returned output into the rendered stream.
   */
  useServerInsertedHTML(() => {
    // ...
  });

  return (
    <App />
  );
};

Similar to the hook available in Next.js, for integrating 3rd party libraries with React 18 + Suspense.

usePreload

import usePreload from "ultra/hooks/use-preload.js";

usePreload(${href})

This hook will insert a <link rel="preload" /> tag into the head of the server render document. During client side transitions, this won't do anything.


Building for production

To run Ultra in production, we recommened using ultra/build.ts. It will do the following:

There are many existing build files in our example repos.

Running production

You can cd into .ultra and run deno task start to see the production server running.

Production builds run with --no-remote 🔥


Deploying

⏳ Support for more edge providers coming soon!

Deno Deploy

Use this GitHub Action:

name: Deploy
on: [push]

jobs:
  deploy:
    name: Deploy
    runs-on: ubuntu-latest
    permissions:
      id-token: write # Needed for auth with Deno Deploy
      contents: read # Needed to clone the repository

    steps:
      - name: Clone repository
        uses: actions/checkout@v2

      - name: Install Deno
        uses: denoland/setup-deno@main
        with:
          deno-version: 1.25.1

      - name: Build site
        run: deno run -A ./build.ts # Your build script

      - name: Upload to Deno Deploy
        uses: denoland/deployctl@v1
        with:
          project: "PROJECT_NAME" # Your deploy project name
          entrypoint: "server.js"
          root: .ultra
          import-map: importMap.server.json

Fly/Docker

Use this Dockerfile. It is multi-stage, and will both build and run the production ready app.

FROM denoland/deno:1.25.0 as builder
WORKDIR /app
COPY . /app
RUN deno task build

FROM denoland/deno:1.25.0
EXPOSE 8000
COPY --from=builder /app/.ultra /app
WORKDIR /app
CMD ["deno", "task", "start"]

You can modify this as needed, another possible Dockerfile assumes you commit your build artifacts, or deploy locally from built files.

FROM denoland/deno:1.25.0
EXPOSE 8000
WORKDIR /app
COPY .ultra /app
CMD ["deno", "task", "start"]