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
- Wouter (with-wouter)
- React Router (with-react-router)
Data Fetching
- React Query (with-react-query)
CSS
- Stitches (with-stitches)
- Twind (with-twind)
Head
- React Helmet Async (with-react-helmet-async)
API Routes
- Hono (with-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",
});
});
- Zero-JS™ (bogus-marketing-or-blog)
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:
- Create a
.ultra
dir inside of your project - Transpile your TypeScript and JSX to vanilla JS.
- Vendor all of your dependencies
- Version your source and public files
- Auto generate 2 (two) production import maps (One for client/hydration, and the other for server)
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"]