diff --git a/create-vite-express/src/templates.ts b/create-vite-express/src/templates.ts
index 63f6ee2..526d6d7 100644
--- a/create-vite-express/src/templates.ts
+++ b/create-vite-express/src/templates.ts
@@ -6,5 +6,6 @@ type Template = prompts.Choice & { color: (msg: string) => string };
export const TEMPLATES: Template[] = [
{ title: "Vanilla", value: "vanilla", color: kolorist.yellow },
{ title: "React", value: "react", color: kolorist.cyan },
+ { title: "Preact", value: "preact", color: kolorist.magenta },
{ title: "Vue", value: "vue", color: kolorist.green },
];
diff --git a/create-vite-express/templates/preact-ts/_gitignore b/create-vite-express/templates/preact-ts/_gitignore
new file mode 100644
index 0000000..a547bf3
--- /dev/null
+++ b/create-vite-express/templates/preact-ts/_gitignore
@@ -0,0 +1,24 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+lerna-debug.log*
+
+node_modules
+dist
+dist-ssr
+*.local
+
+# Editor directories and files
+.vscode/*
+!.vscode/extensions.json
+.idea
+.DS_Store
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?
diff --git a/create-vite-express/templates/preact-ts/index.html b/create-vite-express/templates/preact-ts/index.html
new file mode 100644
index 0000000..e45de6a
--- /dev/null
+++ b/create-vite-express/templates/preact-ts/index.html
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+ Vite + Preact + TS
+
+
+
+
+
+
diff --git a/create-vite-express/templates/preact-ts/package.json b/create-vite-express/templates/preact-ts/package.json
new file mode 100644
index 0000000..d6b9337
--- /dev/null
+++ b/create-vite-express/templates/preact-ts/package.json
@@ -0,0 +1,25 @@
+{
+ "name": "vite-preact-typescript-starter",
+ "private": true,
+ "version": "0.0.0",
+ "type": "module",
+ "scripts": {
+ "dev": "nodemon -w src/server -x tsx src/server/main.ts",
+ "start": "NODE_ENV=production tsx src/server/main.ts",
+ "build": "vite build"
+ },
+ "dependencies": {
+ "express": "^4.18.2",
+ "preact": "^10.23.1",
+ "vite-express": "*"
+ },
+ "devDependencies": {
+ "@types/express": "^4.17.21",
+ "@types/node": "^20.9.3",
+ "@preact/preset-vite": "^2.9.0",
+ "tsx": "^4.5.0",
+ "typescript": "^5.5.3",
+ "nodemon": "^3.0.1",
+ "vite": "^5.4.1"
+ }
+}
diff --git a/create-vite-express/templates/preact-ts/public/vite.svg b/create-vite-express/templates/preact-ts/public/vite.svg
new file mode 100644
index 0000000..e7b8dfb
--- /dev/null
+++ b/create-vite-express/templates/preact-ts/public/vite.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/create-vite-express/templates/preact-ts/src/client/app.css b/create-vite-express/templates/preact-ts/src/client/app.css
new file mode 100644
index 0000000..088ed3a
--- /dev/null
+++ b/create-vite-express/templates/preact-ts/src/client/app.css
@@ -0,0 +1,25 @@
+#app {
+ max-width: 1280px;
+ margin: 0 auto;
+ padding: 2rem;
+ text-align: center;
+}
+
+.logo {
+ height: 6em;
+ padding: 1.5em;
+}
+.logo:hover {
+ filter: drop-shadow(0 0 2em #646cffaa);
+}
+.logo.preact:hover {
+ filter: drop-shadow(0 0 2em #673ab8aa);
+}
+
+.card {
+ padding: 2em;
+}
+
+.read-the-docs {
+ color: #888;
+}
diff --git a/create-vite-express/templates/preact-ts/src/client/app.tsx b/create-vite-express/templates/preact-ts/src/client/app.tsx
new file mode 100644
index 0000000..b1f47a1
--- /dev/null
+++ b/create-vite-express/templates/preact-ts/src/client/app.tsx
@@ -0,0 +1,33 @@
+import { useState } from 'preact/hooks'
+import preactLogo from './assets/preact.svg'
+import viteLogo from '/vite.svg'
+import './app.css'
+
+export function App() {
+ const [count, setCount] = useState(0)
+
+ return (
+ <>
+
+ Vite + Preact
+
+
+
+ Edit src/app.tsx
and save to test HMR
+
+
+
+ Click on the Vite and Preact logos to learn more
+
+ >
+ )
+}
diff --git a/create-vite-express/templates/preact-ts/src/client/assets/preact.svg b/create-vite-express/templates/preact-ts/src/client/assets/preact.svg
new file mode 100644
index 0000000..908f17d
--- /dev/null
+++ b/create-vite-express/templates/preact-ts/src/client/assets/preact.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/create-vite-express/templates/preact-ts/src/client/index.css b/create-vite-express/templates/preact-ts/src/client/index.css
new file mode 100644
index 0000000..6119ad9
--- /dev/null
+++ b/create-vite-express/templates/preact-ts/src/client/index.css
@@ -0,0 +1,68 @@
+:root {
+ font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
+ line-height: 1.5;
+ font-weight: 400;
+
+ color-scheme: light dark;
+ color: rgba(255, 255, 255, 0.87);
+ background-color: #242424;
+
+ font-synthesis: none;
+ text-rendering: optimizeLegibility;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+}
+
+a {
+ font-weight: 500;
+ color: #646cff;
+ text-decoration: inherit;
+}
+a:hover {
+ color: #535bf2;
+}
+
+body {
+ margin: 0;
+ display: flex;
+ place-items: center;
+ min-width: 320px;
+ min-height: 100vh;
+}
+
+h1 {
+ font-size: 3.2em;
+ line-height: 1.1;
+}
+
+button {
+ border-radius: 8px;
+ border: 1px solid transparent;
+ padding: 0.6em 1.2em;
+ font-size: 1em;
+ font-weight: 500;
+ font-family: inherit;
+ background-color: #1a1a1a;
+ cursor: pointer;
+ transition: border-color 0.25s;
+}
+button:hover {
+ border-color: #646cff;
+}
+button:focus,
+button:focus-visible {
+ outline: 4px auto -webkit-focus-ring-color;
+}
+
+@media (prefers-color-scheme: light) {
+ :root {
+ color: #213547;
+ background-color: #ffffff;
+ }
+ a:hover {
+ color: #747bff;
+ }
+ button {
+ background-color: #f9f9f9;
+ }
+}
diff --git a/create-vite-express/templates/preact-ts/src/client/main.tsx b/create-vite-express/templates/preact-ts/src/client/main.tsx
new file mode 100644
index 0000000..846cd1e
--- /dev/null
+++ b/create-vite-express/templates/preact-ts/src/client/main.tsx
@@ -0,0 +1,5 @@
+import { render } from 'preact'
+import { App } from './app.tsx'
+import './index.css'
+
+render(, document.getElementById('app')!)
diff --git a/create-vite-express/templates/preact-ts/src/client/vite-env.d.ts b/create-vite-express/templates/preact-ts/src/client/vite-env.d.ts
new file mode 100644
index 0000000..11f02fe
--- /dev/null
+++ b/create-vite-express/templates/preact-ts/src/client/vite-env.d.ts
@@ -0,0 +1 @@
+///
diff --git a/create-vite-express/templates/preact-ts/src/server/main.ts b/create-vite-express/templates/preact-ts/src/server/main.ts
new file mode 100644
index 0000000..3e7b4d8
--- /dev/null
+++ b/create-vite-express/templates/preact-ts/src/server/main.ts
@@ -0,0 +1,12 @@
+import express from "express";
+import ViteExpress from "vite-express";
+
+const app = express();
+
+app.get("/hello", (_, res) => {
+ res.send("Hello Vite + React + TypeScript!");
+});
+
+ViteExpress.listen(app, 3000, () =>
+ console.log("Server is listening on port 3000..."),
+);
diff --git a/create-vite-express/templates/preact-ts/tsconfig.app.json b/create-vite-express/templates/preact-ts/tsconfig.app.json
new file mode 100644
index 0000000..7a21d18
--- /dev/null
+++ b/create-vite-express/templates/preact-ts/tsconfig.app.json
@@ -0,0 +1,29 @@
+{
+ "compilerOptions": {
+ "target": "ES2020",
+ "useDefineForClassFields": true,
+ "module": "ESNext",
+ "lib": ["ES2020", "DOM", "DOM.Iterable"],
+ "skipLibCheck": true,
+ "paths": {
+ "react": ["./node_modules/preact/compat/"],
+ "react-dom": ["./node_modules/preact/compat/"]
+ },
+
+ /* Bundler mode */
+ "moduleResolution": "bundler",
+ "allowImportingTsExtensions": true,
+ "isolatedModules": true,
+ "moduleDetection": "force",
+ "noEmit": true,
+ "jsx": "react-jsx",
+ "jsxImportSource": "preact",
+
+ /* Linting */
+ "strict": true,
+ "noUnusedLocals": true,
+ "noUnusedParameters": true,
+ "noFallthroughCasesInSwitch": true
+ },
+ "include": ["src"]
+}
diff --git a/create-vite-express/templates/preact-ts/tsconfig.json b/create-vite-express/templates/preact-ts/tsconfig.json
new file mode 100644
index 0000000..c452f43
--- /dev/null
+++ b/create-vite-express/templates/preact-ts/tsconfig.json
@@ -0,0 +1,7 @@
+{
+ "files": [],
+ "references": [
+ { "path": "./tsconfig.app.json" },
+ { "path": "./tsconfig.node.json" }
+ ]
+}
\ No newline at end of file
diff --git a/create-vite-express/templates/preact-ts/tsconfig.node.json b/create-vite-express/templates/preact-ts/tsconfig.node.json
new file mode 100644
index 0000000..0d3d714
--- /dev/null
+++ b/create-vite-express/templates/preact-ts/tsconfig.node.json
@@ -0,0 +1,22 @@
+{
+ "compilerOptions": {
+ "target": "ES2022",
+ "lib": ["ES2023"],
+ "module": "ESNext",
+ "skipLibCheck": true,
+
+ /* Bundler mode */
+ "moduleResolution": "bundler",
+ "allowImportingTsExtensions": true,
+ "isolatedModules": true,
+ "moduleDetection": "force",
+ "noEmit": true,
+
+ /* Linting */
+ "strict": true,
+ "noUnusedLocals": true,
+ "noUnusedParameters": true,
+ "noFallthroughCasesInSwitch": true
+ },
+ "include": ["vite.config.ts"]
+}
diff --git a/create-vite-express/templates/preact-ts/vite.config.ts b/create-vite-express/templates/preact-ts/vite.config.ts
new file mode 100644
index 0000000..29b326f
--- /dev/null
+++ b/create-vite-express/templates/preact-ts/vite.config.ts
@@ -0,0 +1,7 @@
+import { defineConfig } from 'vite'
+import preact from '@preact/preset-vite'
+
+// https://vitejs.dev/config/
+export default defineConfig({
+ plugins: [preact()],
+})
diff --git a/create-vite-express/templates/preact/_gitignore b/create-vite-express/templates/preact/_gitignore
new file mode 100644
index 0000000..a547bf3
--- /dev/null
+++ b/create-vite-express/templates/preact/_gitignore
@@ -0,0 +1,24 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+lerna-debug.log*
+
+node_modules
+dist
+dist-ssr
+*.local
+
+# Editor directories and files
+.vscode/*
+!.vscode/extensions.json
+.idea
+.DS_Store
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?
diff --git a/create-vite-express/templates/preact/index.html b/create-vite-express/templates/preact/index.html
new file mode 100644
index 0000000..f6f28a1
--- /dev/null
+++ b/create-vite-express/templates/preact/index.html
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+ Vite + Preact
+
+
+
+
+
+
diff --git a/create-vite-express/templates/preact/package.json b/create-vite-express/templates/preact/package.json
new file mode 100644
index 0000000..e46709f
--- /dev/null
+++ b/create-vite-express/templates/preact/package.json
@@ -0,0 +1,21 @@
+{
+ "name": "vite-preact-starter",
+ "private": true,
+ "version": "0.0.0",
+ "type": "module",
+ "scripts": {
+ "dev": "nodemon src/server/main.js -w src/server",
+ "start": "NODE_ENV=production node src/server/main.js",
+ "build": "vite build"
+ },
+ "dependencies": {
+ "express": "^4.18.2",
+ "preact": "^10.23.1",
+ "vite-express": "*"
+ },
+ "devDependencies": {
+ "@preact/preset-vite": "^2.9.0",
+ "nodemon": "^3.0.1",
+ "vite": "^5.4.1"
+ }
+}
diff --git a/create-vite-express/templates/preact/public/vite.svg b/create-vite-express/templates/preact/public/vite.svg
new file mode 100644
index 0000000..e7b8dfb
--- /dev/null
+++ b/create-vite-express/templates/preact/public/vite.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/create-vite-express/templates/preact/src/client/app.css b/create-vite-express/templates/preact/src/client/app.css
new file mode 100644
index 0000000..088ed3a
--- /dev/null
+++ b/create-vite-express/templates/preact/src/client/app.css
@@ -0,0 +1,25 @@
+#app {
+ max-width: 1280px;
+ margin: 0 auto;
+ padding: 2rem;
+ text-align: center;
+}
+
+.logo {
+ height: 6em;
+ padding: 1.5em;
+}
+.logo:hover {
+ filter: drop-shadow(0 0 2em #646cffaa);
+}
+.logo.preact:hover {
+ filter: drop-shadow(0 0 2em #673ab8aa);
+}
+
+.card {
+ padding: 2em;
+}
+
+.read-the-docs {
+ color: #888;
+}
diff --git a/create-vite-express/templates/preact/src/client/app.jsx b/create-vite-express/templates/preact/src/client/app.jsx
new file mode 100644
index 0000000..343021a
--- /dev/null
+++ b/create-vite-express/templates/preact/src/client/app.jsx
@@ -0,0 +1,33 @@
+import { useState } from 'preact/hooks'
+import preactLogo from './assets/preact.svg'
+import viteLogo from '/vite.svg'
+import './app.css'
+
+export function App() {
+ const [count, setCount] = useState(0)
+
+ return (
+ <>
+
+ Vite + Preact
+
+
+
+ Edit src/app.jsx
and save to test HMR
+
+
+
+ Click on the Vite and Preact logos to learn more
+
+ >
+ )
+}
diff --git a/create-vite-express/templates/preact/src/client/assets/preact.svg b/create-vite-express/templates/preact/src/client/assets/preact.svg
new file mode 100644
index 0000000..908f17d
--- /dev/null
+++ b/create-vite-express/templates/preact/src/client/assets/preact.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/create-vite-express/templates/preact/src/client/index.css b/create-vite-express/templates/preact/src/client/index.css
new file mode 100644
index 0000000..6119ad9
--- /dev/null
+++ b/create-vite-express/templates/preact/src/client/index.css
@@ -0,0 +1,68 @@
+:root {
+ font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
+ line-height: 1.5;
+ font-weight: 400;
+
+ color-scheme: light dark;
+ color: rgba(255, 255, 255, 0.87);
+ background-color: #242424;
+
+ font-synthesis: none;
+ text-rendering: optimizeLegibility;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+}
+
+a {
+ font-weight: 500;
+ color: #646cff;
+ text-decoration: inherit;
+}
+a:hover {
+ color: #535bf2;
+}
+
+body {
+ margin: 0;
+ display: flex;
+ place-items: center;
+ min-width: 320px;
+ min-height: 100vh;
+}
+
+h1 {
+ font-size: 3.2em;
+ line-height: 1.1;
+}
+
+button {
+ border-radius: 8px;
+ border: 1px solid transparent;
+ padding: 0.6em 1.2em;
+ font-size: 1em;
+ font-weight: 500;
+ font-family: inherit;
+ background-color: #1a1a1a;
+ cursor: pointer;
+ transition: border-color 0.25s;
+}
+button:hover {
+ border-color: #646cff;
+}
+button:focus,
+button:focus-visible {
+ outline: 4px auto -webkit-focus-ring-color;
+}
+
+@media (prefers-color-scheme: light) {
+ :root {
+ color: #213547;
+ background-color: #ffffff;
+ }
+ a:hover {
+ color: #747bff;
+ }
+ button {
+ background-color: #f9f9f9;
+ }
+}
diff --git a/create-vite-express/templates/preact/src/client/main.jsx b/create-vite-express/templates/preact/src/client/main.jsx
new file mode 100644
index 0000000..b088b63
--- /dev/null
+++ b/create-vite-express/templates/preact/src/client/main.jsx
@@ -0,0 +1,5 @@
+import { render } from 'preact'
+import { App } from './app.jsx'
+import './index.css'
+
+render(, document.getElementById('app'))
diff --git a/create-vite-express/templates/preact/src/server/main.js b/create-vite-express/templates/preact/src/server/main.js
new file mode 100644
index 0000000..d206c9c
--- /dev/null
+++ b/create-vite-express/templates/preact/src/server/main.js
@@ -0,0 +1,12 @@
+import express from "express";
+import ViteExpress from "vite-express";
+
+const app = express();
+
+app.get("/hello", (req, res) => {
+ res.send("Hello Vite + React!");
+});
+
+ViteExpress.listen(app, 3000, () =>
+ console.log("Server is listening on port 3000..."),
+);
\ No newline at end of file
diff --git a/create-vite-express/templates/preact/vite.config.js b/create-vite-express/templates/preact/vite.config.js
new file mode 100644
index 0000000..29b326f
--- /dev/null
+++ b/create-vite-express/templates/preact/vite.config.js
@@ -0,0 +1,7 @@
+import { defineConfig } from 'vite'
+import preact from '@preact/preset-vite'
+
+// https://vitejs.dev/config/
+export default defineConfig({
+ plugins: [preact()],
+})
diff --git a/tests/templates.ts b/tests/templates.ts
index 26585f7..fa1f747 100644
--- a/tests/templates.ts
+++ b/tests/templates.ts
@@ -29,11 +29,23 @@ export const TEMPLATES: Template[] = [
},
{
index: 2,
+ name: "preact",
+ hmrTestFilePath: "./src/client/app.jsx",
+ },
+ {
+ index: 2,
+ name: "preact-ts",
+ ts: true,
+ typecheck: false,
+ hmrTestFilePath: "./src/client/app.tsx",
+ },
+ {
+ index: 3,
name: "vue",
hmrTestFilePath: "./src/client/components/HelloWorld.vue",
},
{
- index: 2,
+ index: 3,
name: "vue-ts",
ts: true,
typecheck: false,