diff --git a/README.md b/README.md index 9495137..5023ee8 100644 --- a/README.md +++ b/README.md @@ -20,25 +20,10 @@ npm install @domstack/static - 🌎 [domstack docs website](https://domstack.net) - 💬 [Discord Chat](https://discord.gg/AVTsPRGeR9) -- 📢 [v11 - top-bun is now domstack](./docs/v11-migration.md) +- 📢 [v12 Migration Guide](docs/v12-migration.md) - 📢 [v7 Announcement](https://bret.io/blog/2023/reintroducing-top-bun/) - 📘 [Full TypeScript Support](#typescript-support) -## Migrating from top-bun - -domstack v11 is a major release that renames the project from `top-bun` to `@domstack/static`. The full migration guide is at [docs/v11-migration.md](docs/v11-migration.md). Key changes at a glance: - -- **Package**: `top-bun` → `@domstack/static` -- **CLI**: `top-bun`/`tb` → `domstack`/`dom` -- **Programmatic API**: `TopBun` class → `DomStack`, all `TopBun*` types/errors/warnings renamed to `DomStack*` -- **`postVars` removed**: migrate `postVars` exports from `page.vars.js` files to a single `global.data.js` with a default export -- **New reserved filenames**: `global.data.js`, `markdown-it.settings.js`, `page.md`, `*.worker.{js,ts}` are now special — rename any colliding files -- **Default layout**: switched from `uhtml-isomorphic` to `preact`; add `uhtml-isomorphic` to your own deps if you import it directly -- **Output paths**: `top-bun-esbuild-meta.json` → `domstack-esbuild-meta.json`, `top-bun-defaults/` → `domstack-defaults/` -- **Conflict now throws**: using both `browser` in `global.vars.js` and `define` in `esbuild.settings.js` is now a hard error - -See [docs/v11-migration.md](docs/v11-migration.md) for the complete migration guide with code examples. - ## Table of Contents [[toc]] @@ -61,14 +46,14 @@ Usage: domstack [options] --copy path to directories to copy into dist; can be used multiple times --help, -h show help --version, -v show version information -domstack (v11.0.0) +domstack (v12.0.0) ``` `domstack` builds a `src` directory into a `dest` directory (default: `public`). `domstack` is also aliased to a `dom` bin. - Running `domstack` will result in a `build` by default. -- Running `domstack --watch` or `domstack -w` will build the site and start an auto-reloading development web-server that watches for changes (provided by [Browsersync](https://browsersync.io)). +- Running `domstack --watch` or `domstack -w` will build the site and start an auto-reloading development web-server that watches for changes (provided by [`@domstack/sync`][domstack-sync]). - Running `domstack --eject` or `domstack -e` will extract the default layout, global styles, and client-side JavaScript into your source directory and add the necessary dependencies to your package.json. `domstack` is primarily a unix `bin` written for the [Node.js](https://nodejs.org) runtime that is intended to be installed from `npm` as a `devDependency` inside a `package.json` committed to a `git` repository. @@ -277,11 +262,12 @@ const page: PageFunction = async ({ export default page ``` -It is recommended to use some level of template processing over raw string templates so that HTML is well-formed and variable values are properly escaped. Here is a more realistic TypeScript example that uses [`preact`](https://preactjs.com/) with [`htm`](https://github.com/developit/htm) and `domstack` page introspection. +It is recommended to use some level of template processing over raw string templates so that HTML is well-formed and variable values are properly escaped. DOMStack's default layout uses [`fragtml`][fragtml], a safe-by-default HTML tagged template library. Here is a more realistic TypeScript example that uses `fragtml` and `domstack` page introspection. ```typescript -import { html } from 'htm/preact' +import { html } from 'fragtml' +import type { HtmlResult } from 'fragtml/types.js' import { dirname, basename } from 'node:path' import type { PageFunction } from '@domstack/static' @@ -293,7 +279,7 @@ export const vars = { favoriteCake: 'Chocolate Cloud Cake' } -const blogIndex: PageFunction = async ({ +const blogIndex: PageFunction = async ({ vars: { favoriteCake }, pages }) => { @@ -355,8 +341,24 @@ await funnyLibrary() #### .tsx/.jsx -Client bundles support .jsx and .tsx. They default to preact, so if you want mainlain react, customize your esbuild settings to load that instead. -See the [react](./examples/react/) example for more details. +Client bundles support .jsx and .tsx through esbuild. DOMStack does not include a JSX runtime by default; install the runtime you want and configure it with `esbuild.settings`. +See the [react](./examples/react/) and [preact-isomorphic](./examples/preact-isomorphic/) examples for more details. + +For example, to use [Preact][preact] in browser JSX/TSX bundles, add it to your project and opt into Preact's automatic JSX runtime: + +```console +npm install preact +``` + +```js +// src/esbuild.settings.js +export default async function esbuildSettingsOverride (esbuildSettings) { + esbuildSettings.jsx = 'automatic' + esbuildSettings.jsxImportSource = 'preact' + + return esbuildSettings +} +``` ### Page variable files @@ -488,13 +490,13 @@ It is always passed a single object argument with the following entries: - `pages`: An array of page data that you can use to generate index pages with, or any other page-introspection based content that you desire. - `page`: An object with metadata and other facts about the current page being rendered into the template. This will also be found somewhere in the `pages` array. -The default `root.layout.ts` is featured below, and is implemented with [`preact`](https://preactjs.com/) and [`htm`](https://github.com/developit/htm), though it could just be done with a template literal or any other template system that runs in Node.js. +The default `root.layout.ts` is featured below, and is implemented with [`fragtml`][fragtml], though it could just be done with a template literal or any other template system that runs in Node.js. See the [`fragtml` docs][fragtml-docs] for escaping, raw HTML, rendering, and fragment usage. `root.layout.ts` can live anywhere in the `src` directory. ```typescript -import { html } from 'htm/preact' -import { render } from 'preact-render-to-string' +import { html, raw, render } from 'fragtml' +import type { HtmlResult } from 'fragtml/types.js' import type { LayoutFunction } from '@domstack/static' type RootLayoutVars = { @@ -504,7 +506,7 @@ type RootLayoutVars = { basePath?: string } -const defaultRootLayout: LayoutFunction = ({ +const defaultRootLayout: LayoutFunction = ({ vars: { title, siteName = 'Domstack', @@ -517,32 +519,25 @@ const defaultRootLayout: LayoutFunction = ({ pages, page, }) => { - return /* html */` + return render(html` - ${render(html` - - - ${title ? `${title}` : ''}${title && siteName ? ' | ' : ''}${siteName} - - ${scripts - ? scripts.map(script => html``) + : null} + ${styles + ? styles.map(style => html``) + : null} + + +
${typeof children === 'string' ? raw(children) : children}
+ - ` + `) } export default defaultRootLayout @@ -558,8 +553,8 @@ For example, you could define a `blog.layout.ts` that re-uses the `root.layout.t ```typescript import defaultRootLayout from './root.layout.js' -import { html } from 'htm/preact' -import { render } from 'preact-render-to-string' +import { html, raw, render } from 'fragtml' +import type { HtmlResult } from 'fragtml/types.js' import type { LayoutFunction } from '@domstack/static' // Import the type from root layout @@ -575,23 +570,23 @@ interface BlogLayoutVars extends RootLayoutVars { updatedDate?: string; } -const blogLayout: LayoutFunction = (layoutVars) => { +const blogLayout: LayoutFunction = (layoutVars) => { const { children: innerChildren, ...rest } = layoutVars const vars = layoutVars.vars const children = render(html` -
-
-

${vars.title}

-
-
- ${typeof children === 'string' - ? html`
` - : children - } + ${typeof children === 'string' ? raw(children) : children}