diff --git a/README.md b/README.md index 60ae90b..01a2c5e 100644 --- a/README.md +++ b/README.md @@ -70,7 +70,7 @@ src % tree │ ├── client.js # nested pages are just pages, so they also can have a page scoped client and style. │ └── style.css ├── html-page -│ ├── client.js +│ ├── client.jsx # client bundles can also be written in .jsx/.tsx │ ├── page.html # Raw html pages are also supported. They support handlebars template blocks. │ ├── page.vars.js # pages can define page variables in a page.vars.js. │ └── style.css @@ -316,6 +316,10 @@ await someHelper() await funnyLibrary() ``` +#### .tsx/.jsx + +Client bundles support .jsx and .tsx. They default to preact, so if you want mainlain recat, customize your esbuild settings to load that instead. + ### Page variable files Each page can also have a `page.vars.js` file that exports a `default` function or object that contains page specific variables. @@ -1184,7 +1188,7 @@ Some notable features are included below, see the [roadmap](https://github.com/u - [x] Esbuild settings escape hatch - [x] Copy folders - [x] Full Typescript support via native type stripping -- [ ] JSX support in client bundles +- [x] JSX+TSX support in client bundles - ...[See roadmap](https://github.com/users/bcomnes/projects/3/) ## History diff --git a/examples/preact/src/README.md b/examples/preact/src/README.md index d9c4051..93af148 100644 --- a/examples/preact/src/README.md +++ b/examples/preact/src/README.md @@ -2,4 +2,5 @@ This is a preact example. -[Isomorphic Component Rendering](./isomorphic/) +- [Isomorphic Component Rendering](./isomorphic/) +- [JSX-page](./jsx-page/) diff --git a/examples/preact/src/jsx-page/client.jsx b/examples/preact/src/jsx-page/client.jsx new file mode 100644 index 0000000..fa47236 --- /dev/null +++ b/examples/preact/src/jsx-page/client.jsx @@ -0,0 +1,12 @@ +import { render } from 'preact' + +export const page = () => { + return ( +
+ look ma, client side jsx! +
+ ) +} + +const renderTarget = document.querySelector('.jsx-app') +render(page(), renderTarget) diff --git a/examples/preact/src/jsx-page/page.html b/examples/preact/src/jsx-page/page.html new file mode 100644 index 0000000..bf0074d --- /dev/null +++ b/examples/preact/src/jsx-page/page.html @@ -0,0 +1,4 @@ +
+

This is an html page, with a client.jsx that mounts onto it

+
+
diff --git a/examples/type-stripping/src/README.md b/examples/type-stripping/src/README.md index d9c4051..f922c8c 100644 --- a/examples/type-stripping/src/README.md +++ b/examples/type-stripping/src/README.md @@ -2,4 +2,5 @@ This is a preact example. -[Isomorphic Component Rendering](./isomorphic/) +- [Isomorphic Component Rendering](./isomorphic/) +- [tsx-client]('./isomorphic/') diff --git a/examples/type-stripping/src/tsx-page/client.tsx b/examples/type-stripping/src/tsx-page/client.tsx new file mode 100644 index 0000000..497ef69 --- /dev/null +++ b/examples/type-stripping/src/tsx-page/client.tsx @@ -0,0 +1,14 @@ +import { render } from 'preact' + +export const page = () => { + return ( +
+ look ma, client side jsx! +
+ ) +} + +const renderTarget = document.querySelector('.jsx-app') +if (renderTarget) { + render(page(), renderTarget) +} diff --git a/examples/type-stripping/src/tsx-page/page.html b/examples/type-stripping/src/tsx-page/page.html new file mode 100644 index 0000000..bf0074d --- /dev/null +++ b/examples/type-stripping/src/tsx-page/page.html @@ -0,0 +1,4 @@ +
+

This is an html page, with a client.jsx that mounts onto it

+
+
diff --git a/examples/type-stripping/tsconfig.json b/examples/type-stripping/tsconfig.json index 9aca575..c0a6886 100644 --- a/examples/type-stripping/tsconfig.json +++ b/examples/type-stripping/tsconfig.json @@ -5,7 +5,9 @@ "erasableSyntaxOnly": true, "allowImportingTsExtensions": true, "rewriteRelativeImportExtensions": true, - "verbatimModuleSyntax": true + "verbatimModuleSyntax": true, + "jsx": "react-jsx", + "jsxImportSource": "preact" }, "include": [ "**/*", diff --git a/lib/build-esbuild/index.js b/lib/build-esbuild/index.js index 08e4df8..3f356cb 100644 --- a/lib/build-esbuild/index.js +++ b/lib/build-esbuild/index.js @@ -91,6 +91,8 @@ export async function buildEsbuild (src, dest, siteData, opts) { metafile: true, entryNames: '[dir]/[name]-[hash]', chunkNames: 'chunks/[ext]/[name]-[hash]', + jsx: 'automatic', + jsxImportSource: 'preact' } const esbuildSettingsExtends = siteData.esbuildSettings diff --git a/lib/identify-pages.js b/lib/identify-pages.js index ecb214b..d2acb29 100644 --- a/lib/identify-pages.js +++ b/lib/identify-pages.js @@ -31,8 +31,8 @@ const jsPageDraftNames = hasTS : ['page.draft.js', 'page.draft.mjs', 'page.draft.cjs'] const pageClientNames = hasTS - ? ['client.ts', 'client.mts', 'client.cts', 'client.js', 'client.mjs', 'client.cjs'] - : ['client.js', 'client.mjs', 'client.cjs'] + ? ['client.tsx', 'client.ts', 'client.mts', 'client.cts', 'client.jsx', 'client.js', 'client.mjs', 'client.cjs'] + : ['client.jsx', 'client.js', 'client.mjs', 'client.cjs'] const pageVarsNames = hasTS ? ['page.vars.ts', 'page.vars.mts', 'page.vars.cts', diff --git a/package.json b/package.json index 270a66d..a75f03e 100644 --- a/package.json +++ b/package.json @@ -48,6 +48,7 @@ "p-map": "^7.0.2", "package-json": "^10.0.0", "pkg-dir": "^8.0.0", + "preact": "^10.26.6", "pretty": "^2.0.0", "pretty-tree": "^1.0.0", "read-pkg": "^9.0.1", diff --git a/test-cases/general-features/src/blog/2025/a-blog-post-from-2025/client.tsx b/test-cases/general-features/src/blog/2025/a-blog-post-from-2025/client.tsx new file mode 100644 index 0000000..8304912 --- /dev/null +++ b/test-cases/general-features/src/blog/2025/a-blog-post-from-2025/client.tsx @@ -0,0 +1,14 @@ +import { render } from 'preact' + +export const page = () => { + return ( +
+ look ma, client side jsx! +
+ ) +} + +const renderTarget = document.querySelector('.tsx-app') +if (renderTarget) { + render(page(), renderTarget) +} diff --git a/test-cases/general-features/src/blog/2025/a-blog-post-from-2025/page.ts b/test-cases/general-features/src/blog/2025/a-blog-post-from-2025/page.ts index 305856f..d882874 100644 --- a/test-cases/general-features/src/blog/2025/a-blog-post-from-2025/page.ts +++ b/test-cases/general-features/src/blog/2025/a-blog-post-from-2025/page.ts @@ -1,5 +1,8 @@ export default function () { - return `Hello world, from 2025. Also typescript` + return ` + Hello world, from 2025. Also typescript +
+ ` } export const vars = { diff --git a/tsconfig.json b/tsconfig.json index 4eff7ad..f78f4c8 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,7 +1,9 @@ { "extends": "@voxpelli/tsconfig/node20.json", "compilerOptions": { - "skipLibCheck": true + "skipLibCheck": true, + "jsx": "react-jsx", + "jsxImportSource": "preact" }, "include": [ "lib/**/*",