@govela/create 0.0.0-stage → 0.7.0

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.
Files changed (68) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +17 -2
  3. package/bin/create.js +146 -0
  4. package/package.json +24 -4
  5. package/templates/app/base/AGENTS.md +44 -0
  6. package/templates/app/base/README.md +19 -0
  7. package/templates/app/base/_github/workflows/ci.yml +23 -0
  8. package/templates/app/base/_gitignore +7 -0
  9. package/templates/app/base/cmd/server/main.go +53 -0
  10. package/templates/app/base/go.mod +8 -0
  11. package/templates/app/base/server/routes/load.go +30 -0
  12. package/templates/app/base/vela.config.json +6 -0
  13. package/templates/app/base/vite.config.js +11 -0
  14. package/templates/app/base/vitest.setup.__EXT__ +5 -0
  15. package/templates/app/js/eslint.config.js +12 -0
  16. package/templates/app/js/package.json +32 -0
  17. package/templates/app/js/src/routes/Layout.vela +24 -0
  18. package/templates/app/js/src/routes/Page.test.js +13 -0
  19. package/templates/app/js/src/routes/Page.vela +10 -0
  20. package/templates/app/ts/eslint.config.js +14 -0
  21. package/templates/app/ts/package.json +34 -0
  22. package/templates/app/ts/src/routes/Layout.vela +26 -0
  23. package/templates/app/ts/src/routes/Page.test.ts +13 -0
  24. package/templates/app/ts/src/routes/Page.vela +12 -0
  25. package/templates/app/ts/tsconfig.json +4 -0
  26. package/templates/app/ts/vela.app.json +1 -0
  27. package/templates/default/base/AGENTS.md +28 -0
  28. package/templates/default/base/README.md +17 -0
  29. package/templates/default/base/_github/workflows/ci.yml +20 -0
  30. package/templates/default/base/_gitignore +2 -0
  31. package/templates/default/base/index.html +12 -0
  32. package/templates/default/base/vite.config.js +9 -0
  33. package/templates/default/base/vitest.setup.__EXT__ +5 -0
  34. package/templates/default/js/eslint.config.js +12 -0
  35. package/templates/default/js/package.json +28 -0
  36. package/templates/default/js/src/App.vela +25 -0
  37. package/templates/default/js/src/Counter.test.js +20 -0
  38. package/templates/default/js/src/Counter.vela +23 -0
  39. package/templates/default/js/src/main.js +4 -0
  40. package/templates/default/ts/eslint.config.js +14 -0
  41. package/templates/default/ts/package.json +30 -0
  42. package/templates/default/ts/src/App.vela +25 -0
  43. package/templates/default/ts/src/Counter.test.ts +20 -0
  44. package/templates/default/ts/src/Counter.vela +27 -0
  45. package/templates/default/ts/src/main.ts +4 -0
  46. package/templates/default/ts/tsconfig.json +18 -0
  47. package/templates/ssr/base/AGENTS.md +34 -0
  48. package/templates/ssr/base/README.md +30 -0
  49. package/templates/ssr/base/_github/workflows/ci.yml +23 -0
  50. package/templates/ssr/base/_gitignore +4 -0
  51. package/templates/ssr/base/cmd/server/main.go +57 -0
  52. package/templates/ssr/base/go.mod +5 -0
  53. package/templates/ssr/base/vela.config.json +6 -0
  54. package/templates/ssr/base/vite.config.js +11 -0
  55. package/templates/ssr/base/vitest.setup.__EXT__ +5 -0
  56. package/templates/ssr/js/eslint.config.js +12 -0
  57. package/templates/ssr/js/package.json +30 -0
  58. package/templates/ssr/js/src/App.vela +27 -0
  59. package/templates/ssr/js/src/Counter.test.js +20 -0
  60. package/templates/ssr/js/src/Counter.vela +23 -0
  61. package/templates/ssr/js/src/client.js +5 -0
  62. package/templates/ssr/ts/eslint.config.js +14 -0
  63. package/templates/ssr/ts/package.json +32 -0
  64. package/templates/ssr/ts/src/App.vela +27 -0
  65. package/templates/ssr/ts/src/Counter.test.ts +20 -0
  66. package/templates/ssr/ts/src/Counter.vela +27 -0
  67. package/templates/ssr/ts/src/client.ts +5 -0
  68. package/templates/ssr/ts/tsconfig.json +18 -0
@@ -0,0 +1,28 @@
1
+ # Agent instructions
2
+
3
+ This is a Vela application. Before you create or edit a `.vela` component,
4
+ read the Vela authoring guide of the compiler version this project uses:
5
+
6
+ https://github.com/elauven/vela/blob/v__VERSION__/AGENTS.md
7
+
8
+ It defines the component shape, the runes (`$state`, `$derived`,
9
+ `$effect`, `$bindable`), the template syntax (`:attr={…}`, `@event={…}`,
10
+ `{#if}`, `{#each}`) and what Vela does not support. When a compiler
11
+ diagnostic disagrees with an example, trust the diagnostic.
12
+
13
+ ## This project
14
+
15
+ - Components live in `src/`; `src/main.__EXT__` mounts `src/App.vela`.
16
+ - Tests are `*.test.__EXT__` files next to the components, run by Vitest with
17
+ `@govela/testing` (`render`, `fireEvent`).
18
+
19
+ ## Before handing off
20
+
21
+ ```sh
22
+ npm run check # vela check: compiler diagnostics (and types, in TypeScript)
23
+ npm run lint # eslint: the code of the components and modules
24
+ npm test # vitest run
25
+ npm run build # vite build
26
+ ```
27
+
28
+ All of them must pass.
@@ -0,0 +1,17 @@
1
+ # __NAME__
2
+
3
+ A [Vela](https://github.com/elauven/vela) application: Vite with
4
+ `@govela/unplugin`, Vitest with `@govela/testing`, ESLint with
5
+ `@govela/eslint-plugin`.
6
+
7
+ ```sh
8
+ npm install
9
+ npm run dev # http://localhost:5173
10
+ npm test # component tests
11
+ npm run check # compiler diagnostics
12
+ npm run lint # eslint
13
+ npm run build # production build into dist/
14
+ ```
15
+
16
+ `.github/workflows/ci.yml` runs the check, the linter, the tests and the build on every
17
+ push.
@@ -0,0 +1,20 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ pull_request:
6
+
7
+ jobs:
8
+ test:
9
+ runs-on: ubuntu-latest
10
+ steps:
11
+ - uses: actions/checkout@v5
12
+ - uses: actions/setup-node@v5
13
+ with:
14
+ node-version: '24'
15
+ cache: npm
16
+ - run: npm ci
17
+ - run: npm run check
18
+ - run: npm run lint
19
+ - run: npm test
20
+ - run: npm run build
@@ -0,0 +1,2 @@
1
+ /node_modules/
2
+ /dist/
@@ -0,0 +1,12 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
6
+ <title>__NAME__</title>
7
+ </head>
8
+ <body>
9
+ <div id="app"></div>
10
+ <script type="module" src="/src/main.__EXT__"></script>
11
+ </body>
12
+ </html>
@@ -0,0 +1,9 @@
1
+ import vela from '@govela/unplugin/vite';
2
+
3
+ export default {
4
+ plugins: [vela()],
5
+ test: {
6
+ environment: 'happy-dom',
7
+ setupFiles: ['./vitest.setup.__EXT__'],
8
+ },
9
+ };
@@ -0,0 +1,5 @@
1
+ import { afterEach } from 'vitest';
2
+ import { cleanup } from '@govela/testing';
3
+
4
+ // Every test starts with an empty document.
5
+ afterEach(cleanup);
@@ -0,0 +1,12 @@
1
+ import { defineConfig } from 'eslint/config';
2
+ import js from '@eslint/js';
3
+ import globals from 'globals';
4
+ import vela from '@govela/eslint-plugin';
5
+
6
+ export default defineConfig(
7
+ { ignores: ['dist/', 'out/', 'build/', 'src/_app/'] },
8
+ js.configs.recommended,
9
+ vela.configs.recommended,
10
+ { files: ['src/**/*.js', '**/*.vela/*.js'], languageOptions: { globals: globals.browser } },
11
+ { files: ['*.config.js'], languageOptions: { globals: globals.node } },
12
+ );
@@ -0,0 +1,28 @@
1
+ {
2
+ "name": "__NAME__",
3
+ "private": true,
4
+ "type": "module",
5
+ "scripts": {
6
+ "dev": "vite",
7
+ "check": "vela check --project src",
8
+ "lint": "eslint .",
9
+ "test": "vitest run",
10
+ "build": "vite build",
11
+ "preview": "vite preview"
12
+ },
13
+ "dependencies": {
14
+ "@govela/runtime": "__VERSION__"
15
+ },
16
+ "devDependencies": {
17
+ "@eslint/js": "^10.0.1",
18
+ "@govela/compiler": "__VERSION__",
19
+ "@govela/eslint-plugin": "__VERSION__",
20
+ "@govela/testing": "__VERSION__",
21
+ "@govela/unplugin": "__VERSION__",
22
+ "eslint": "^10.14.0",
23
+ "globals": "^17.0.0",
24
+ "happy-dom": "^21.0.4",
25
+ "vite": "^8.3.5",
26
+ "vitest": "^5.1.0"
27
+ }
28
+ }
@@ -0,0 +1,25 @@
1
+ <script>
2
+ import Counter from './Counter.vela';
3
+
4
+ let total = $state(0);
5
+
6
+ function changed(event) {
7
+ total = event.detail;
8
+ }
9
+ </script>
10
+
11
+ <template>
12
+ <main>
13
+ <h1>Vela</h1>
14
+ <Counter :step={1} @on:change={changed}>Clicks</Counter>
15
+ <p class="total">Total: {total}</p>
16
+ </main>
17
+ </template>
18
+
19
+ <style>
20
+ main {
21
+ font-family: system-ui, sans-serif;
22
+ max-width: 32rem;
23
+ margin: 4rem auto;
24
+ }
25
+ </style>
@@ -0,0 +1,20 @@
1
+ import { expect, test } from 'vitest';
2
+ import { fireEvent, render } from '@govela/testing';
3
+ import Counter from './Counter.vela';
4
+
5
+ test('counts by its step and reports the count', async () => {
6
+ const counts = [];
7
+ const { container } = render(Counter, {
8
+ props: { step: 2 },
9
+ slots: { default: 'Clicks' },
10
+ events: { change: (event) => counts.push(event.detail) },
11
+ });
12
+ const button = container.querySelector('button');
13
+ expect(button.textContent).toBe('Clicks: 0');
14
+
15
+ await fireEvent.click(button);
16
+ await fireEvent.click(button);
17
+
18
+ expect(button.textContent).toBe('Clicks: 4');
19
+ expect(counts).toEqual([2, 4]);
20
+ });
@@ -0,0 +1,23 @@
1
+ <script>
2
+ export let step = 1;
3
+
4
+ let count = $state(0);
5
+
6
+ function increment() {
7
+ count += step;
8
+ $$dispatch('change', count);
9
+ }
10
+ </script>
11
+
12
+ <template>
13
+ <button @click={increment}>
14
+ <slot>Count</slot>: {count}
15
+ </button>
16
+ </template>
17
+
18
+ <style>
19
+ button {
20
+ font: inherit;
21
+ padding: 0.5rem 1rem;
22
+ }
23
+ </style>
@@ -0,0 +1,4 @@
1
+ import { mount } from '@govela/runtime';
2
+ import App from './App.vela';
3
+
4
+ mount(App, { target: document.getElementById('app') });
@@ -0,0 +1,14 @@
1
+ import { defineConfig } from 'eslint/config';
2
+ import js from '@eslint/js';
3
+ import globals from 'globals';
4
+ import tseslint from 'typescript-eslint';
5
+ import vela from '@govela/eslint-plugin';
6
+
7
+ export default defineConfig(
8
+ { ignores: ['dist/', 'out/', 'build/', 'src/_app/'] },
9
+ js.configs.recommended,
10
+ tseslint.configs.recommended,
11
+ vela.configs.recommended,
12
+ { files: ['src/**/*.ts', '**/*.vela/*.ts'], languageOptions: { globals: globals.browser } },
13
+ { files: ['*.config.js'], languageOptions: { globals: globals.node } },
14
+ );
@@ -0,0 +1,30 @@
1
+ {
2
+ "name": "__NAME__",
3
+ "private": true,
4
+ "type": "module",
5
+ "scripts": {
6
+ "dev": "vite",
7
+ "check": "vela check --project src --types",
8
+ "lint": "eslint .",
9
+ "test": "vitest run",
10
+ "build": "vite build",
11
+ "preview": "vite preview"
12
+ },
13
+ "dependencies": {
14
+ "@govela/runtime": "__VERSION__"
15
+ },
16
+ "devDependencies": {
17
+ "@eslint/js": "^10.0.1",
18
+ "@govela/compiler": "__VERSION__",
19
+ "@govela/eslint-plugin": "__VERSION__",
20
+ "@govela/testing": "__VERSION__",
21
+ "@govela/unplugin": "__VERSION__",
22
+ "eslint": "^10.14.0",
23
+ "globals": "^17.0.0",
24
+ "happy-dom": "^21.0.4",
25
+ "typescript": "^6.0.3",
26
+ "typescript-eslint": "^8.72.1",
27
+ "vite": "^8.3.5",
28
+ "vitest": "^5.1.0"
29
+ }
30
+ }
@@ -0,0 +1,25 @@
1
+ <script lang="ts">
2
+ import Counter from './Counter.vela';
3
+
4
+ let total = $state(0);
5
+
6
+ function changed(event: CustomEvent<number>): void {
7
+ total = event.detail;
8
+ }
9
+ </script>
10
+
11
+ <template>
12
+ <main>
13
+ <h1>Vela</h1>
14
+ <Counter :step={1} @on:change={changed}>Clicks</Counter>
15
+ <p class="total">Total: {total}</p>
16
+ </main>
17
+ </template>
18
+
19
+ <style>
20
+ main {
21
+ font-family: system-ui, sans-serif;
22
+ max-width: 32rem;
23
+ margin: 4rem auto;
24
+ }
25
+ </style>
@@ -0,0 +1,20 @@
1
+ import { expect, test } from 'vitest';
2
+ import { fireEvent, render } from '@govela/testing';
3
+ import Counter from './Counter.vela';
4
+
5
+ test('counts by its step and reports the count', async () => {
6
+ const counts: number[] = [];
7
+ const { container } = render(Counter, {
8
+ props: { step: 2 },
9
+ slots: { default: 'Clicks' },
10
+ events: { change: (event) => counts.push(event.detail) },
11
+ });
12
+ const button = container.querySelector('button')!;
13
+ expect(button.textContent).toBe('Clicks: 0');
14
+
15
+ await fireEvent.click(button);
16
+ await fireEvent.click(button);
17
+
18
+ expect(button.textContent).toBe('Clicks: 4');
19
+ expect(counts).toEqual([2, 4]);
20
+ });
@@ -0,0 +1,27 @@
1
+ <script lang="ts">
2
+ interface $$Events {
3
+ change: number;
4
+ }
5
+
6
+ export let step: number = 1;
7
+
8
+ let count = $state(0);
9
+
10
+ function increment(): void {
11
+ count += step;
12
+ $$dispatch('change', count);
13
+ }
14
+ </script>
15
+
16
+ <template>
17
+ <button @click={increment}>
18
+ <slot>Count</slot>: {count}
19
+ </button>
20
+ </template>
21
+
22
+ <style>
23
+ button {
24
+ font: inherit;
25
+ padding: 0.5rem 1rem;
26
+ }
27
+ </style>
@@ -0,0 +1,4 @@
1
+ import { mount } from '@govela/runtime';
2
+ import App from './App.vela';
3
+
4
+ mount(App, { target: document.getElementById('app')! });
@@ -0,0 +1,18 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "ESNext",
5
+ "moduleResolution": "bundler",
6
+ "strict": true,
7
+ "noEmit": true,
8
+ "isolatedModules": true,
9
+ "verbatimModuleSyntax": true,
10
+ "erasableSyntaxOnly": true,
11
+ "allowImportingTsExtensions": true,
12
+ "useDefineForClassFields": true,
13
+ "skipLibCheck": true,
14
+ "lib": ["ES2022", "DOM", "DOM.Iterable"],
15
+ "types": ["@govela/runtime/ambient"]
16
+ },
17
+ "include": ["src"]
18
+ }
@@ -0,0 +1,34 @@
1
+ # Agent instructions
2
+
3
+ This is a server-rendered Vela application. Before you create or edit a
4
+ `.vela` component, read the Vela authoring guide of the compiler version
5
+ this project uses:
6
+
7
+ https://github.com/elauven/vela/blob/v__VERSION__/AGENTS.md
8
+
9
+ It defines the component shape, the runes, the template syntax, the rules
10
+ of server rendering and what Vela does not support. When a compiler
11
+ diagnostic disagrees with an example, trust the diagnostic.
12
+
13
+ ## This project
14
+
15
+ - Components live in `src/`. `vela` (configured by `vela.config.json`)
16
+ compiles them to Go renderers in `out/server`; `cmd/server` renders
17
+ `App` with them; `src/client.__EXT__` hydrates the HTML in the browser.
18
+ - Code that runs during the first render is translated to Go: keep it free
19
+ of browser APIs (`window`, `document`, `Date.now()`). Put browser work in
20
+ handlers, `$effect` or `onMount`. Treat every `VELA-SSR-*` diagnostic as
21
+ an error to fix.
22
+ - Tests are `*.test.__EXT__` files next to the components, run by Vitest with
23
+ `@govela/testing` (`render`, `fireEvent`).
24
+
25
+ ## Before handing off
26
+
27
+ ```sh
28
+ npm run check # vela check --ssr: compiler and server-rendering diagnostics (and types)
29
+ npm run lint # eslint: the code of the components and modules
30
+ npm test # vitest run
31
+ npm run build # vela, vite build and go build
32
+ ```
33
+
34
+ All of them must pass.
@@ -0,0 +1,30 @@
1
+ # __NAME__
2
+
3
+ A server-rendered [Vela](https://github.com/elauven/vela) application: the
4
+ Go server in `cmd/server` renders the components, Vite with
5
+ `@govela/unplugin` builds the client that hydrates them, Vitest with
6
+ `@govela/testing` tests them.
7
+
8
+ ```sh
9
+ npm install
10
+ go mod tidy
11
+ ```
12
+
13
+ Development, three processes:
14
+
15
+ ```sh
16
+ npm run dev:vela # vela --watch: Go renderers into out/
17
+ npm run dev # Vite on http://localhost:5173
18
+ npm run dev:server # the Go server on http://127.0.0.1:8080
19
+ ```
20
+
21
+ Restart the Go server after a change of a component (`out/.vela-ready`
22
+ is written after every successful build).
23
+
24
+ ```sh
25
+ npm test # component tests
26
+ npm run check # compiler and server-rendering diagnostics
27
+ npm run lint # eslint
28
+ npm run build # out/, dist/ and build/server
29
+ npm start # the production server, serving dist/
30
+ ```
@@ -0,0 +1,23 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ pull_request:
6
+
7
+ jobs:
8
+ test:
9
+ runs-on: ubuntu-latest
10
+ steps:
11
+ - uses: actions/checkout@v5
12
+ - uses: actions/setup-go@v6
13
+ with:
14
+ go-version-file: go.mod
15
+ - uses: actions/setup-node@v5
16
+ with:
17
+ node-version: '24'
18
+ cache: npm
19
+ - run: npm ci
20
+ - run: npm run check
21
+ - run: npm run lint
22
+ - run: npm test
23
+ - run: npm run build
@@ -0,0 +1,4 @@
1
+ /node_modules/
2
+ /dist/
3
+ /out/
4
+ /build/
@@ -0,0 +1,57 @@
1
+ // The server: renders App with the Go renderer `vela` generates into
2
+ // out/server, and adds the client from the Vite dev server (-dev) or from
3
+ // the output of vite build (-dist).
4
+ package main
5
+
6
+ import (
7
+ "flag"
8
+ "fmt"
9
+ "log"
10
+ "net"
11
+ "net/http"
12
+ "path/filepath"
13
+
14
+ "github.com/elauven/vela/ssr_runtime/vite"
15
+
16
+ components "__MODULE__/out/server/components"
17
+ )
18
+
19
+ func main() {
20
+ addr := flag.String("addr", "127.0.0.1:8080", "listen address")
21
+ dev := flag.String("dev", "", "URL of the Vite dev server; serve dist/ when empty")
22
+ dist := flag.String("dist", "dist", "output directory of vite build")
23
+ flag.Parse()
24
+
25
+ mux := http.NewServeMux()
26
+ var assets *vite.Assets
27
+ if *dev != "" {
28
+ assets = vite.Dev(*dev)
29
+ } else {
30
+ var err error
31
+ if assets, err = vite.Load(filepath.Join(*dist, ".vite", "manifest.json"), "/"); err != nil {
32
+ log.Fatal(err)
33
+ }
34
+ mux.Handle("/assets/", http.FileServer(http.Dir(*dist)))
35
+ }
36
+ tags, err := assets.Tags("src/client.__EXT__")
37
+ if err != nil {
38
+ log.Fatal(err)
39
+ }
40
+
41
+ mux.HandleFunc("/{$}", func(w http.ResponseWriter, r *http.Request) {
42
+ w.Header().Set("Content-Type", "text/html; charset=utf-8")
43
+ fmt.Fprintf(w, "<!doctype html><html><head><meta charset=\"utf-8\">%s</head><body><div id=\"app\">", tags)
44
+ props := components.AppProps{Set: map[string]bool{"title": true}, Title: "Vela"}
45
+ if err := components.RenderAppContext(r.Context(), w, props, components.AppSlots{}); err != nil {
46
+ log.Print(err)
47
+ }
48
+ fmt.Fprint(w, "</div></body></html>")
49
+ })
50
+
51
+ listener, err := net.Listen("tcp", *addr)
52
+ if err != nil {
53
+ log.Fatal(err)
54
+ }
55
+ fmt.Println("http://" + listener.Addr().String() + "/")
56
+ log.Fatal(http.Serve(listener, mux))
57
+ }
@@ -0,0 +1,5 @@
1
+ module __MODULE__
2
+
3
+ go 1.25
4
+
5
+ require github.com/elauven/vela/ssr_runtime v__VERSION__
@@ -0,0 +1,6 @@
1
+ {
2
+ "project": "src",
3
+ "out": "out",
4
+ "ssr": true,
5
+ "ssrModule": "__MODULE__/out/server"
6
+ }
@@ -0,0 +1,11 @@
1
+ import vela from '@govela/unplugin/vite';
2
+
3
+ export default {
4
+ plugins: [vela()],
5
+ server: { origin: 'http://localhost:5173' },
6
+ build: { manifest: true, rollupOptions: { input: 'src/client.__EXT__' } },
7
+ test: {
8
+ environment: 'happy-dom',
9
+ setupFiles: ['./vitest.setup.__EXT__'],
10
+ },
11
+ };
@@ -0,0 +1,5 @@
1
+ import { afterEach } from 'vitest';
2
+ import { cleanup } from '@govela/testing';
3
+
4
+ // Every test starts with an empty document.
5
+ afterEach(cleanup);
@@ -0,0 +1,12 @@
1
+ import { defineConfig } from 'eslint/config';
2
+ import js from '@eslint/js';
3
+ import globals from 'globals';
4
+ import vela from '@govela/eslint-plugin';
5
+
6
+ export default defineConfig(
7
+ { ignores: ['dist/', 'out/', 'build/', 'src/_app/'] },
8
+ js.configs.recommended,
9
+ vela.configs.recommended,
10
+ { files: ['src/**/*.js', '**/*.vela/*.js'], languageOptions: { globals: globals.browser } },
11
+ { files: ['*.config.js'], languageOptions: { globals: globals.node } },
12
+ );
@@ -0,0 +1,30 @@
1
+ {
2
+ "name": "__NAME__",
3
+ "private": true,
4
+ "type": "module",
5
+ "scripts": {
6
+ "dev": "vite",
7
+ "dev:vela": "vela --watch",
8
+ "dev:server": "go run ./cmd/server -dev http://localhost:5173",
9
+ "check": "vela check --project src --ssr",
10
+ "lint": "eslint .",
11
+ "test": "vitest run",
12
+ "build": "vela && vite build && go build -o build/server ./cmd/server",
13
+ "start": "./build/server"
14
+ },
15
+ "dependencies": {
16
+ "@govela/runtime": "__VERSION__"
17
+ },
18
+ "devDependencies": {
19
+ "@eslint/js": "^10.0.1",
20
+ "@govela/compiler": "__VERSION__",
21
+ "@govela/eslint-plugin": "__VERSION__",
22
+ "@govela/testing": "__VERSION__",
23
+ "@govela/unplugin": "__VERSION__",
24
+ "eslint": "^10.14.0",
25
+ "globals": "^17.0.0",
26
+ "happy-dom": "^21.0.4",
27
+ "vite": "^8.3.5",
28
+ "vitest": "^5.1.0"
29
+ }
30
+ }
@@ -0,0 +1,27 @@
1
+ <script>
2
+ import Counter from './Counter.vela';
3
+
4
+ export let title = 'Vela';
5
+
6
+ let total = $state(0);
7
+
8
+ function changed(event) {
9
+ total = event.detail;
10
+ }
11
+ </script>
12
+
13
+ <template>
14
+ <main>
15
+ <h1>{title}</h1>
16
+ <Counter :step={1} @on:change={changed}>Clicks</Counter>
17
+ <p class="total">Total: {total}</p>
18
+ </main>
19
+ </template>
20
+
21
+ <style>
22
+ main {
23
+ font-family: system-ui, sans-serif;
24
+ max-width: 32rem;
25
+ margin: 4rem auto;
26
+ }
27
+ </style>
@@ -0,0 +1,20 @@
1
+ import { expect, test } from 'vitest';
2
+ import { fireEvent, render } from '@govela/testing';
3
+ import Counter from './Counter.vela';
4
+
5
+ test('counts by its step and reports the count', async () => {
6
+ const counts = [];
7
+ const { container } = render(Counter, {
8
+ props: { step: 2 },
9
+ slots: { default: 'Clicks' },
10
+ events: { change: (event) => counts.push(event.detail) },
11
+ });
12
+ const button = container.querySelector('button');
13
+ expect(button.textContent).toBe('Clicks: 0');
14
+
15
+ await fireEvent.click(button);
16
+ await fireEvent.click(button);
17
+
18
+ expect(button.textContent).toBe('Clicks: 4');
19
+ expect(counts).toEqual([2, 4]);
20
+ });