@harperfast/template-vue-ts-studio 1.7.4 → 1.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agents/skills/harper-best-practices/AGENTS.md +66 -47
- package/.agents/skills/harper-best-practices/rules/serving-web-content.md +69 -50
- package/.gitignore +1 -2
- package/README.md +1 -1
- package/config.yaml +16 -3
- package/package.json +8 -1
- package/skills-lock.json +1 -1
- package/vite.config.ts +1 -1
- package/deploy-template/config.yaml +0 -10
- package/deploy-template/fastify/static.js +0 -14
- package/deploy-template/package.json +0 -5
|
@@ -1617,59 +1617,78 @@ Instructions for the agent to follow when serving web content from Harper.
|
|
|
1617
1617
|
|
|
1618
1618
|
#### When to Use
|
|
1619
1619
|
|
|
1620
|
-
Use this skill when you need to serve a frontend (HTML, CSS, JS, or a React app) directly from your Harper instance.
|
|
1620
|
+
Use this skill when you need to serve a frontend (HTML, CSS, JS, or a React/Vue app) directly from your Harper instance — either plain static files or an integrated Vite app with hot module replacement (HMR) in development and a real production build when deployed.
|
|
1621
1621
|
|
|
1622
1622
|
#### How It Works
|
|
1623
1623
|
|
|
1624
|
-
|
|
1625
|
-
2. **Option A: Static Plugin (Simple)**:
|
|
1626
|
-
- Add to `config.yaml`:
|
|
1627
|
-
```yaml
|
|
1628
|
-
static:
|
|
1629
|
-
files: 'web/*'
|
|
1630
|
-
```
|
|
1631
|
-
- Place files in a `web/` folder in the project root.
|
|
1632
|
-
- Files are served at the root URL (e.g., `http://localhost:9926/index.html`).
|
|
1633
|
-
3. **Option B: Vite Plugin (Advanced/Development)**:
|
|
1634
|
-
- Add to `config.yaml`:
|
|
1635
|
-
```yaml
|
|
1636
|
-
'@harperfast/vite-plugin':
|
|
1637
|
-
package: '@harperfast/vite-plugin'
|
|
1638
|
-
```
|
|
1639
|
-
- Ensure `vite.config.ts` and `index.html` are in the project root.
|
|
1624
|
+
There are two building blocks. Harper's built-in `static` plugin **serves** files; the `@harperfast/vite` plugin **builds** (and, for SSR, **renders**) a Vite app. For a Vite app they work **together** — the plugin builds into a directory and `static` serves that same directory.
|
|
1640
1625
|
|
|
1641
|
-
|
|
1642
|
-
import vue from '@vitejs/plugin-vue';
|
|
1643
|
-
import path from 'node:path';
|
|
1644
|
-
import { defineConfig } from 'vite';
|
|
1645
|
-
|
|
1646
|
-
// https://vite.dev/config/
|
|
1647
|
-
export default defineConfig({
|
|
1648
|
-
plugins: [vue()],
|
|
1649
|
-
resolve: {
|
|
1650
|
-
alias: {
|
|
1651
|
-
'@': path.resolve(import.meta.dirname, './src'),
|
|
1652
|
-
},
|
|
1653
|
-
},
|
|
1654
|
-
build: {
|
|
1655
|
-
outDir: 'web',
|
|
1656
|
-
emptyOutDir: true,
|
|
1657
|
-
rolldownOptions: {
|
|
1658
|
-
external: ['**/*.test.*', '**/*.spec.*'],
|
|
1659
|
-
},
|
|
1660
|
-
},
|
|
1661
|
-
});
|
|
1662
|
-
```
|
|
1626
|
+
##### Option A: Static plugin only (simple, pre-built assets)
|
|
1663
1627
|
|
|
1664
|
-
|
|
1665
|
-
- Then `harper run .` will start up Harper and Vite with HMR. Vite does _not_ need to be executed separately.
|
|
1628
|
+
For a plain static site or already-built assets, use `static` on its own:
|
|
1666
1629
|
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1630
|
+
```yaml
|
|
1631
|
+
static:
|
|
1632
|
+
files: 'web/*'
|
|
1633
|
+
```
|
|
1634
|
+
|
|
1635
|
+
- Place files in a `web/` folder in the project root; they are served from the root URL (e.g. `http://localhost:9926/index.html`).
|
|
1636
|
+
- Static files are matched first; if none matches, Harper falls through to your resource and table APIs.
|
|
1637
|
+
|
|
1638
|
+
##### Option B: Vite plugin + static plugin (integrated Vite app)
|
|
1639
|
+
|
|
1640
|
+
> **Renamed in v1:** the plugin was previously `@harperfast/vite-plugin`. From `1.0.0` on it is **`@harperfast/vite`** (same key and `package`). It now pairs with the `static` plugin instead of building into `web/` itself.
|
|
1641
|
+
|
|
1642
|
+
`@harperfast/vite` **builds** your app — in `harper dev` it runs Vite in middleware mode with HMR; in `harper run` it runs `vite build` and rebuilds when watched files change (and renders HTML for SSR). The `static` plugin **serves** the built output. Point both at the same directory (`output`, default `dist`) — that shared directory is the only contract between them.
|
|
1643
|
+
|
|
1644
|
+
**SPA `config.yaml`** — list the plugin first so its dev server wins in `harper dev`; `notFound` + `fallthrough: false` makes client-side routing work:
|
|
1645
|
+
|
|
1646
|
+
```yaml
|
|
1647
|
+
'@harperfast/vite':
|
|
1648
|
+
package: '@harperfast/vite'
|
|
1649
|
+
files: 'src/**/*'
|
|
1650
|
+
output: 'dist'
|
|
1651
|
+
|
|
1652
|
+
static:
|
|
1653
|
+
files: 'dist/**'
|
|
1654
|
+
notFound:
|
|
1655
|
+
file: 'index.html'
|
|
1656
|
+
statusCode: 200
|
|
1657
|
+
fallthrough: false
|
|
1658
|
+
```
|
|
1659
|
+
|
|
1660
|
+
**SSR `config.yaml`** — add an `ssr` entry so the plugin renders `index.html`, and set `index: false` on `static` so it serves assets only:
|
|
1661
|
+
|
|
1662
|
+
```yaml
|
|
1663
|
+
'@harperfast/vite':
|
|
1664
|
+
package: '@harperfast/vite'
|
|
1665
|
+
files: 'src/**/*'
|
|
1666
|
+
output: 'dist'
|
|
1667
|
+
ssr: 'src/entry-server.tsx'
|
|
1668
|
+
|
|
1669
|
+
static:
|
|
1670
|
+
files: 'dist/**'
|
|
1671
|
+
index: false
|
|
1672
|
+
```
|
|
1673
|
+
|
|
1674
|
+
- Install dependencies: `npm install --save-dev vite @harperfast/vite @vitejs/plugin-react` (swap in your framework's Vite plugin, e.g. `@vitejs/plugin-vue`).
|
|
1675
|
+
- Then `harper dev .` runs the app with HMR and `harper run .` runs the production build. Vite does _not_ need to be executed separately.
|
|
1676
|
+
|
|
1677
|
+
#### Deploying to Production
|
|
1678
|
+
|
|
1679
|
+
Because `@harperfast/vite` builds on the node and `static` serves the output, deploy the component as-is — no manual build-and-move step is needed:
|
|
1680
|
+
|
|
1681
|
+
```json
|
|
1682
|
+
{
|
|
1683
|
+
"scripts": {
|
|
1684
|
+
"dev": "harper dev .",
|
|
1685
|
+
"start": "harper run .",
|
|
1686
|
+
"deploy": "harper deploy_component . restart=true replicated=true"
|
|
1687
|
+
}
|
|
1688
|
+
}
|
|
1689
|
+
```
|
|
1690
|
+
|
|
1691
|
+
On deploy the plugin runs `vite build` at startup (and rebuilds when `files` change) while `static` serves the result. If you prefer to build in CI, commit the build output, point `static` at it, and omit `files` so the plugin stays idle while `static` serves the prebuilt assets. Either way, `npm create harper@latest` scaffolds a working setup for you.
|
|
1673
1692
|
|
|
1674
1693
|
### 4.5 Harper Logging
|
|
1675
1694
|
|
|
@@ -11,56 +11,75 @@ Instructions for the agent to follow when serving web content from Harper.
|
|
|
11
11
|
|
|
12
12
|
## When to Use
|
|
13
13
|
|
|
14
|
-
Use this skill when you need to serve a frontend (HTML, CSS, JS, or a React app) directly from your Harper instance.
|
|
14
|
+
Use this skill when you need to serve a frontend (HTML, CSS, JS, or a React/Vue app) directly from your Harper instance — either plain static files or an integrated Vite app with hot module replacement (HMR) in development and a real production build when deployed.
|
|
15
15
|
|
|
16
16
|
## How It Works
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
18
|
+
There are two building blocks. Harper's built-in `static` plugin **serves** files; the `@harperfast/vite` plugin **builds** (and, for SSR, **renders**) a Vite app. For a Vite app they work **together** — the plugin builds into a directory and `static` serves that same directory.
|
|
19
|
+
|
|
20
|
+
### Option A: Static plugin only (simple, pre-built assets)
|
|
21
|
+
|
|
22
|
+
For a plain static site or already-built assets, use `static` on its own:
|
|
23
|
+
|
|
24
|
+
```yaml
|
|
25
|
+
static:
|
|
26
|
+
files: 'web/*'
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
- Place files in a `web/` folder in the project root; they are served from the root URL (e.g. `http://localhost:9926/index.html`).
|
|
30
|
+
- Static files are matched first; if none matches, Harper falls through to your resource and table APIs.
|
|
31
|
+
|
|
32
|
+
### Option B: Vite plugin + static plugin (integrated Vite app)
|
|
33
|
+
|
|
34
|
+
> **Renamed in v1:** the plugin was previously `@harperfast/vite-plugin`. From `1.0.0` on it is **`@harperfast/vite`** (same key and `package`). It now pairs with the `static` plugin instead of building into `web/` itself.
|
|
35
|
+
|
|
36
|
+
`@harperfast/vite` **builds** your app — in `harper dev` it runs Vite in middleware mode with HMR; in `harper run` it runs `vite build` and rebuilds when watched files change (and renders HTML for SSR). The `static` plugin **serves** the built output. Point both at the same directory (`output`, default `dist`) — that shared directory is the only contract between them.
|
|
37
|
+
|
|
38
|
+
**SPA `config.yaml`** — list the plugin first so its dev server wins in `harper dev`; `notFound` + `fallthrough: false` makes client-side routing work:
|
|
39
|
+
|
|
40
|
+
```yaml
|
|
41
|
+
'@harperfast/vite':
|
|
42
|
+
package: '@harperfast/vite'
|
|
43
|
+
files: 'src/**/*'
|
|
44
|
+
output: 'dist'
|
|
45
|
+
|
|
46
|
+
static:
|
|
47
|
+
files: 'dist/**'
|
|
48
|
+
notFound:
|
|
49
|
+
file: 'index.html'
|
|
50
|
+
statusCode: 200
|
|
51
|
+
fallthrough: false
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
**SSR `config.yaml`** — add an `ssr` entry so the plugin renders `index.html`, and set `index: false` on `static` so it serves assets only:
|
|
55
|
+
|
|
56
|
+
```yaml
|
|
57
|
+
'@harperfast/vite':
|
|
58
|
+
package: '@harperfast/vite'
|
|
59
|
+
files: 'src/**/*'
|
|
60
|
+
output: 'dist'
|
|
61
|
+
ssr: 'src/entry-server.tsx'
|
|
62
|
+
|
|
63
|
+
static:
|
|
64
|
+
files: 'dist/**'
|
|
65
|
+
index: false
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
- Install dependencies: `npm install --save-dev vite @harperfast/vite @vitejs/plugin-react` (swap in your framework's Vite plugin, e.g. `@vitejs/plugin-vue`).
|
|
69
|
+
- Then `harper dev .` runs the app with HMR and `harper run .` runs the production build. Vite does _not_ need to be executed separately.
|
|
70
|
+
|
|
71
|
+
## Deploying to Production
|
|
72
|
+
|
|
73
|
+
Because `@harperfast/vite` builds on the node and `static` serves the output, deploy the component as-is — no manual build-and-move step is needed:
|
|
74
|
+
|
|
75
|
+
```json
|
|
76
|
+
{
|
|
77
|
+
"scripts": {
|
|
78
|
+
"dev": "harper dev .",
|
|
79
|
+
"start": "harper run .",
|
|
80
|
+
"deploy": "harper deploy_component . restart=true replicated=true"
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
On deploy the plugin runs `vite build` at startup (and rebuilds when `files` change) while `static` serves the result. If you prefer to build in CI, commit the build output, point `static` at it, and omit `files` so the plugin stays idle while `static` serves the prebuilt assets. Either way, `npm create harper@latest` scaffolds a working setup for you.
|
package/.gitignore
CHANGED
package/README.md
CHANGED
|
@@ -73,7 +73,7 @@ These schemas are the heart of a great Harper app, specifying which tables you w
|
|
|
73
73
|
|
|
74
74
|
### View Your Website
|
|
75
75
|
|
|
76
|
-
Pop open [http://localhost:9926](http://localhost:9926) to view [
|
|
76
|
+
Pop open [http://localhost:9926](http://localhost:9926) to view [index.html](./index.html) in your browser.
|
|
77
77
|
|
|
78
78
|
### Use Your API
|
|
79
79
|
|
package/config.yaml
CHANGED
|
@@ -20,6 +20,19 @@ jsResource:
|
|
|
20
20
|
files: 'resources/*.ts'
|
|
21
21
|
|
|
22
22
|
# Generates types for the schema so your code is schema-aware
|
|
23
|
-
# Bootstraps Vite to build your frontend to HTML/JS/CSS
|
|
24
|
-
|
|
25
|
-
|
|
23
|
+
# Bootstraps Vite to build your frontend to HTML/JS/CSS.
|
|
24
|
+
# In production it builds your app (and recompiles when files in `files` change); the `static`
|
|
25
|
+
# component below serves the built output. Listed before `static` so its dev server wins in `harper dev`.
|
|
26
|
+
'@harperfast/vite':
|
|
27
|
+
package: '@harperfast/vite'
|
|
28
|
+
files: 'src/**/*'
|
|
29
|
+
output: 'dist'
|
|
30
|
+
|
|
31
|
+
# Serves the built frontend from Vite's output directory. `notFound` + `fallthrough: false` makes
|
|
32
|
+
# client-side routing work (unmatched routes return index.html); the REST routes above take precedence.
|
|
33
|
+
static:
|
|
34
|
+
files: 'dist/**'
|
|
35
|
+
notFound:
|
|
36
|
+
file: 'index.html'
|
|
37
|
+
statusCode: 200
|
|
38
|
+
fallthrough: false
|
package/package.json
CHANGED
|
@@ -1,8 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@harperfast/template-vue-ts-studio",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.8.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"repository": "github:HarperFast/create-harper",
|
|
6
6
|
"scripts": {},
|
|
7
|
+
"dependencies": {
|
|
8
|
+
"@harperfast/schema-codegen": "^1.0.10",
|
|
9
|
+
"@harperfast/vite": "^1.1.0",
|
|
10
|
+
"@vitejs/plugin-vue": "^6.0.5",
|
|
11
|
+
"vite": "^8.0.0",
|
|
12
|
+
"vue": "^3.5.29"
|
|
13
|
+
},
|
|
7
14
|
"devDependencies": {}
|
|
8
15
|
}
|
package/skills-lock.json
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
"source": "harperfast/skills",
|
|
6
6
|
"sourceType": "github",
|
|
7
7
|
"skillPath": "harper-best-practices/SKILL.md",
|
|
8
|
-
"computedHash": "
|
|
8
|
+
"computedHash": "8aa6811090a5ef3721428b048f3c1208fc50d93b5fe03acad27d89a416a081a1"
|
|
9
9
|
}
|
|
10
10
|
}
|
|
11
11
|
}
|
package/vite.config.ts
CHANGED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import fastifyStatic from '@fastify/static';
|
|
2
|
-
import { join } from 'path';
|
|
3
|
-
|
|
4
|
-
export default async (fastify) => {
|
|
5
|
-
fastify.register(fastifyStatic, {
|
|
6
|
-
root: join(import.meta.dirname, '../web'),
|
|
7
|
-
maxAge: '30d',
|
|
8
|
-
immutable: true,
|
|
9
|
-
});
|
|
10
|
-
|
|
11
|
-
fastify.get('/', function(req, reply) {
|
|
12
|
-
reply.sendFile('index.html', { maxAge: '1m', immutable: false });
|
|
13
|
-
});
|
|
14
|
-
};
|