@inglorious/create-app 1.1.1 → 1.2.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 (46) hide show
  1. package/README.md +25 -8
  2. package/bin/index.js +79 -401
  3. package/bin/lib/app-jsx.js +280 -0
  4. package/bin/lib/app-lit.js +275 -0
  5. package/bin/lib/app-vue.js +239 -0
  6. package/bin/lib/app.js +402 -0
  7. package/bin/lib/cli.js +49 -0
  8. package/bin/lib/constants.js +14 -0
  9. package/bin/lib/features.js +142 -0
  10. package/bin/lib/file.js +88 -0
  11. package/bin/lib/imports.js +64 -0
  12. package/bin/lib/mobile.js +140 -0
  13. package/bin/lib/pwa.js +168 -0
  14. package/bin/lib/questions.js +184 -0
  15. package/bin/lib/source.js +58 -0
  16. package/package.json +4 -4
  17. package/templates/js/package.json +8 -7
  18. package/templates/js/vite.config.js +2 -1
  19. package/templates/js-jsx/package.json +8 -7
  20. package/templates/js-jsx/vite.config.js +2 -1
  21. package/templates/js-vue/package.json +7 -6
  22. package/templates/js-vue/vite.config.js +2 -1
  23. package/templates/ssx-js/package.json +8 -7
  24. package/templates/ssx-js/src/site.config.js +2 -1
  25. package/templates/ssx-ts/package.json +9 -7
  26. package/templates/ssx-ts/src/site.config.ts +1 -0
  27. package/templates/ts/package.json +10 -8
  28. package/templates/ts/src/app.ts +4 -2
  29. package/templates/ts/tsconfig.app.json +2 -0
  30. package/templates/ts/tsconfig.node.json +2 -0
  31. package/templates/ts/types/index.d.ts +4 -1
  32. package/templates/ts/vite.config.ts +2 -1
  33. package/templates/ts-jsx/package.json +10 -8
  34. package/templates/ts-jsx/src/app.tsx +2 -2
  35. package/templates/ts-jsx/tsconfig.app.json +2 -0
  36. package/templates/ts-jsx/tsconfig.node.json +2 -0
  37. package/templates/ts-jsx/types/index.d.ts +3 -1
  38. package/templates/ts-jsx/types/vite-end.d.ts +1 -0
  39. package/templates/ts-jsx/vite.config.ts +2 -1
  40. package/templates/ts-vue/eslint.config.ts +1 -1
  41. package/templates/ts-vue/package.json +10 -8
  42. package/templates/ts-vue/src/store/middlewares.ts +5 -2
  43. package/templates/ts-vue/tsconfig.app.json +2 -0
  44. package/templates/ts-vue/tsconfig.node.json +2 -0
  45. package/templates/ts-vue/types/index.d.ts +3 -1
  46. package/templates/ts-vue/vite.config.ts +2 -1
@@ -0,0 +1,184 @@
1
+ import prompts from "prompts"
2
+
3
+ import { ICON_PACKS, LANGUAGES, THEMES } from "./features.js"
4
+
5
+ /**
6
+ * Asks about the app's features, skipping any a command-line flag answered.
7
+ * Resolves to null when the user cancels.
8
+ *
9
+ * @param {ReturnType<import("./cli.js").parseCliOptions>} flags
10
+ */
11
+ export async function askAppFeatures(flags) {
12
+ let canceled = false
13
+ const onCancel = () => {
14
+ canceled = true
15
+ return false
16
+ }
17
+ const ask = async (question) => {
18
+ const answers = await prompts({ ...question, name: "value" }, { onCancel })
19
+ return answers.value
20
+ }
21
+
22
+ const features = {
23
+ ui: false,
24
+ theme: "inglorious",
25
+ mobile: false,
26
+ routing: false,
27
+ transitions: false,
28
+ icons: [],
29
+ languages: [],
30
+ pwa: false,
31
+ }
32
+
33
+ features.ui =
34
+ flags.ui ??
35
+ (await ask({
36
+ type: "confirm",
37
+ message: "Use Inglorious UI?",
38
+ initial: true,
39
+ }))
40
+ if (canceled) return null
41
+
42
+ if (features.ui) {
43
+ features.theme =
44
+ flags.theme ??
45
+ (await ask({
46
+ type: "select",
47
+ message: "Which theme?",
48
+ choices: Object.entries(THEMES).map(([value, theme]) => ({
49
+ value,
50
+ ...theme,
51
+ })),
52
+ }))
53
+ if (canceled) return null
54
+ }
55
+
56
+ features.mobile =
57
+ flags.mobile ??
58
+ (await ask({
59
+ type: "confirm",
60
+ message: "Is it a mobile app? (adds Capacitor for Android and iOS)",
61
+ initial: false,
62
+ }))
63
+ if (canceled) return null
64
+
65
+ features.routing =
66
+ flags.routing ??
67
+ (await ask({
68
+ type: "confirm",
69
+ message: "Add routing?",
70
+ initial: true,
71
+ }))
72
+ if (canceled) return null
73
+
74
+ if (features.routing && features.ui) {
75
+ features.transitions =
76
+ flags.transitions ??
77
+ (await ask({
78
+ type: "confirm",
79
+ message: "Animate page transitions?",
80
+ initial: true,
81
+ }))
82
+ if (canceled) return null
83
+ }
84
+
85
+ if (features.ui) {
86
+ features.icons =
87
+ flags.icons ??
88
+ (await ask({
89
+ type: "multiselect",
90
+ message: "Which icon packs?",
91
+ hint: "Space to select, Enter to confirm. None is fine too.",
92
+ instructions: false,
93
+ choices: Object.entries(ICON_PACKS).map(([value, pack]) => ({
94
+ value,
95
+ title: pack.title,
96
+ selected: value === "material",
97
+ })),
98
+ }))
99
+ if (canceled) return null
100
+ }
101
+
102
+ const i18n =
103
+ flags.i18n ??
104
+ (flags.languages ? Boolean(flags.languages.length) : null) ??
105
+ (await ask({
106
+ type: "confirm",
107
+ message: "Translate the app into several languages?",
108
+ initial: false,
109
+ }))
110
+ if (canceled) return null
111
+
112
+ if (i18n) {
113
+ features.languages =
114
+ flags.languages ?? (await askLanguages(ask, () => canceled))
115
+ if (canceled || !features.languages) return null
116
+ }
117
+
118
+ features.pwa =
119
+ flags.pwa ??
120
+ (await ask({
121
+ type: "confirm",
122
+ message: "Enable PWA support?",
123
+ initial: false,
124
+ }))
125
+ if (canceled) return null
126
+
127
+ return validate(features)
128
+ }
129
+
130
+ // The languages, with the default first.
131
+ async function askLanguages(ask, isCanceled) {
132
+ const languages = await ask({
133
+ type: "multiselect",
134
+ message: "Which languages?",
135
+ hint: "Space to select, Enter to confirm.",
136
+ instructions: false,
137
+ min: 1,
138
+ choices: Object.entries(LANGUAGES).map(([value, language]) => ({
139
+ value,
140
+ title: language.title,
141
+ selected: value === "en",
142
+ })),
143
+ })
144
+ if (isCanceled()) return null
145
+ const [, ...others] = languages
146
+ if (!others.length) return languages
147
+
148
+ const defaultLanguage = await ask({
149
+ type: "select",
150
+ message: "Which is the default language?",
151
+ choices: languages.map((value) => ({
152
+ value,
153
+ title: LANGUAGES[value].title,
154
+ })),
155
+ })
156
+ if (isCanceled()) return null
157
+ return [defaultLanguage, ...languages.filter((l) => l !== defaultLanguage)]
158
+ }
159
+
160
+ // Flags can name things that do not exist, or combine what cannot go together.
161
+ function validate(features) {
162
+ if (!THEMES[features.theme]) {
163
+ throw new Error(
164
+ `Unknown theme "${features.theme}". Choose one of: ${Object.keys(THEMES).join(", ")}.`,
165
+ )
166
+ }
167
+ const unknownIcons = features.icons.filter((key) => !ICON_PACKS[key])
168
+ if (unknownIcons.length) {
169
+ throw new Error(
170
+ `Unknown icon packs: ${unknownIcons.join(", ")}. Choose from: ${Object.keys(ICON_PACKS).join(", ")}.`,
171
+ )
172
+ }
173
+ const unknownLanguages = features.languages.filter((key) => !LANGUAGES[key])
174
+ if (unknownLanguages.length) {
175
+ throw new Error(
176
+ `Unknown languages: ${unknownLanguages.join(", ")}. Choose from: ${Object.keys(LANGUAGES).join(", ")}.`,
177
+ )
178
+ }
179
+ // Transitions animate navigations, with Inglorious UI's stylesheet; icons
180
+ // are drawn by its Icon component.
181
+ if (!features.routing || !features.ui) features.transitions = false
182
+ if (!features.ui) features.icons = []
183
+ return features
184
+ }
@@ -0,0 +1,58 @@
1
+ // What the generated app's components share, whatever their syntax: the pages,
2
+ // the icons they show, and helpers that print code the way Prettier would.
3
+
4
+ import { ICON_PACKS } from "./features.js"
5
+
6
+ // Prettier's line width, which generated files are written to fit.
7
+ export const LINE_WIDTH = 80
8
+
9
+ /**
10
+ * The parts of the app the components draw: the two pages, the icons on the
11
+ * tabs (from the first icon pack) and one icon from each pack for the home
12
+ * page.
13
+ */
14
+ export function appModel(app) {
15
+ const [navPack] = app.icons
16
+ const navIcons = app.tabs && navPack ? ICON_PACKS[navPack].nav : null
17
+ return {
18
+ navIcons,
19
+ pages: [
20
+ { path: "/", key: "nav.home", text: "Home", icon: navIcons?.home },
21
+ {
22
+ path: "/about",
23
+ key: "nav.about",
24
+ text: "About",
25
+ icon: navIcons?.about,
26
+ },
27
+ ],
28
+ showcase: app.icons.map((key) => ICON_PACKS[key].showcase),
29
+ }
30
+ }
31
+
32
+ // `name(args)` on one line when it fits, one argument per line otherwise, as
33
+ // Prettier prints a call.
34
+ export function call(name, args, indent, trailing) {
35
+ const line = `${indent}${name}(${args.join(", ")})${trailing}`
36
+ if (line.length <= LINE_WIDTH) return line
37
+ return `${indent}${name}(
38
+ ${args.map((arg) => `${indent} ${arg},`).join("\n")}
39
+ ${indent})${trailing}`
40
+ }
41
+
42
+ // `export type Name = A | B`, broken after the `=` when too long, as Prettier
43
+ // prints it.
44
+ export function union(name, members) {
45
+ const line = `export type ${name} = ${members.join(" | ")}`
46
+ if (line.length <= LINE_WIDTH) return line
47
+ return `export type ${name} =
48
+ ${members.join(" | ")}`
49
+ }
50
+
51
+ // Indents every non-empty line of a block.
52
+ export function indent(block, spaces) {
53
+ const pad = " ".repeat(spaces)
54
+ return block
55
+ .split("\n")
56
+ .map((line) => (line ? pad + line : line))
57
+ .join("\n")
58
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inglorious/create-app",
3
- "version": "1.1.1",
3
+ "version": "1.2.0",
4
4
  "description": "A scaffolding tool to quickly create a new app with Inglorious Web.",
5
5
  "author": "Matteo Antony Mistretta <antony.mistretta@gmail.com> (https://ingloriouscoderz.it)",
6
6
  "license": "MIT",
@@ -33,12 +33,12 @@
33
33
  "access": "public"
34
34
  },
35
35
  "dependencies": {
36
- "ora": "^9.0.0",
36
+ "ora": "^9.4.1",
37
37
  "prompts": "^2.4.2"
38
38
  },
39
39
  "devDependencies": {
40
- "prettier": "^3.6.2",
41
- "@inglorious/eslint-config": "1.1.2"
40
+ "@inglorious/eslint-config": "1.1.2",
41
+ "prettier": "^3.9.6"
42
42
  },
43
43
  "scripts": {
44
44
  "format": "prettier --write .",
@@ -19,13 +19,14 @@
19
19
  },
20
20
  "devDependencies": {
21
21
  "@inglorious/eslint-config": "workspace:*",
22
- "eslint": "^9.39.1",
23
- "prettier": "^3.6.2",
24
- "rollup-plugin-minify-template-literals": "^1.1.7",
25
- "sharp": "^0.34.5",
26
- "svgo": "^4.0.0",
27
- "vite-plugin-image-optimizer": "^2.0.3",
28
- "vite": "^7.1.6"
22
+ "@inglorious/vite-plugin-hmr": "workspace:*",
23
+ "eslint": "^10.13.0",
24
+ "prettier": "^3.9.10",
25
+ "rollup-plugin-minify-template-literals": "^2.2.0",
26
+ "sharp": "^0.35.5",
27
+ "svgo": "^4.1.0",
28
+ "vite": "^8.3.4",
29
+ "vite-plugin-image-optimizer": "^2.0.3"
29
30
  },
30
31
  "packageManager": "pnpm@10.15.0",
31
32
  "engines": {
@@ -1,6 +1,7 @@
1
1
  import path from "node:path"
2
2
  import { fileURLToPath } from "node:url"
3
3
 
4
+ import { hmr } from "@inglorious/vite-plugin-hmr"
4
5
  import { minifyTemplateLiterals } from "rollup-plugin-minify-template-literals"
5
6
  import { defineConfig } from "vite"
6
7
  import { ViteImageOptimizer } from "vite-plugin-image-optimizer"
@@ -10,7 +11,7 @@ const __dirname = path.dirname(__filename)
10
11
 
11
12
  // https://vite.dev/config/
12
13
  export default defineConfig({
13
- plugins: [ViteImageOptimizer()],
14
+ plugins: [ViteImageOptimizer(), hmr()],
14
15
 
15
16
  build: {
16
17
  rollupOptions: {
@@ -19,14 +19,15 @@
19
19
  },
20
20
  "devDependencies": {
21
21
  "@inglorious/eslint-config": "workspace:*",
22
+ "@inglorious/vite-plugin-hmr": "workspace:*",
22
23
  "@inglorious/vite-plugin-jsx": "workspace:*",
23
- "eslint": "^9.39.1",
24
- "prettier": "^3.6.2",
25
- "rollup-plugin-minify-template-literals": "^1.1.7",
26
- "sharp": "^0.34.5",
27
- "svgo": "^4.0.0",
28
- "vite-plugin-image-optimizer": "^2.0.3",
29
- "vite": "^7.1.6"
24
+ "eslint": "^10.13.0",
25
+ "prettier": "^3.9.10",
26
+ "rollup-plugin-minify-template-literals": "^2.2.0",
27
+ "sharp": "^0.35.5",
28
+ "svgo": "^4.1.0",
29
+ "vite": "^8.3.4",
30
+ "vite-plugin-image-optimizer": "^2.0.3"
30
31
  },
31
32
  "packageManager": "pnpm@10.15.0",
32
33
  "engines": {
@@ -1,6 +1,7 @@
1
1
  import path from "node:path"
2
2
  import { fileURLToPath } from "node:url"
3
3
 
4
+ import { hmr } from "@inglorious/vite-plugin-hmr"
4
5
  import { jsx } from "@inglorious/vite-plugin-jsx"
5
6
  import { minifyTemplateLiterals } from "rollup-plugin-minify-template-literals"
6
7
  import { defineConfig } from "vite"
@@ -11,7 +12,7 @@ const __dirname = path.dirname(__filename)
11
12
 
12
13
  // https://vite.dev/config/
13
14
  export default defineConfig({
14
- plugins: [ViteImageOptimizer(), jsx()],
15
+ plugins: [ViteImageOptimizer(), jsx(), hmr()],
15
16
 
16
17
  build: {
17
18
  rollupOptions: {
@@ -19,13 +19,14 @@
19
19
  },
20
20
  "devDependencies": {
21
21
  "@inglorious/eslint-config": "workspace:*",
22
+ "@inglorious/vite-plugin-hmr": "workspace:*",
22
23
  "@inglorious/vite-plugin-vue": "workspace:*",
23
- "eslint": "^9.39.1",
24
- "prettier": "^3.6.2",
25
- "rollup-plugin-minify-template-literals": "^1.1.7",
26
- "sharp": "^0.34.5",
27
- "svgo": "^4.0.0",
28
- "vite": "^7.1.6",
24
+ "eslint": "^10.13.0",
25
+ "prettier": "^3.9.10",
26
+ "rollup-plugin-minify-template-literals": "^2.2.0",
27
+ "sharp": "^0.35.5",
28
+ "svgo": "^4.1.0",
29
+ "vite": "^8.3.4",
29
30
  "vite-plugin-image-optimizer": "^2.0.3"
30
31
  },
31
32
  "packageManager": "pnpm@10.15.0",
@@ -1,6 +1,7 @@
1
1
  import path from "node:path"
2
2
  import { fileURLToPath } from "node:url"
3
3
 
4
+ import { hmr } from "@inglorious/vite-plugin-hmr"
4
5
  import { vue } from "@inglorious/vite-plugin-vue"
5
6
  import { minifyTemplateLiterals } from "rollup-plugin-minify-template-literals"
6
7
  import { defineConfig } from "vite"
@@ -11,7 +12,7 @@ const __dirname = path.dirname(__filename)
11
12
 
12
13
  // https://vite.dev/config/
13
14
  export default defineConfig({
14
- plugins: [ViteImageOptimizer(), vue()],
15
+ plugins: [ViteImageOptimizer(), vue(), hmr()],
15
16
 
16
17
  build: {
17
18
  rollupOptions: {
@@ -15,19 +15,20 @@
15
15
  },
16
16
  "dependencies": {
17
17
  "@inglorious/ssx": "workspace:*",
18
+ "@inglorious/store": "workspace:*",
18
19
  "@inglorious/web": "workspace:*",
19
20
  "gray-matter": "^4.0.3",
20
- "highlight.js": "^11.11.1",
21
- "katex": "^0.16.27",
22
- "markdown-it": "^14.1.0",
21
+ "highlight.js": "^11.12.0",
22
+ "katex": "^0.19.0",
23
+ "markdown-it": "^15.0.3",
23
24
  "markdown-it-texmath": "^1.0.0",
24
- "mermaid": "^11.12.2"
25
+ "mermaid": "^12.2.0"
25
26
  },
26
27
  "devDependencies": {
27
28
  "@inglorious/eslint-config": "workspace:*",
28
- "eslint": "^9.39.1",
29
- "prettier": "^3.6.2",
30
- "serve": "^14.2.1"
29
+ "eslint": "^10.13.0",
30
+ "prettier": "^3.9.10",
31
+ "serve": "^14.2.6"
31
32
  },
32
33
  "packageManager": "pnpm@10.15.0",
33
34
  "engines": {
@@ -1,6 +1,7 @@
1
- /** @type {import('@inglorious/ssx/site.config').SiteConfig} */
1
+ /** @type {import('@inglorious/ssx').SiteConfig} */
2
2
  export default {
3
3
  title: "My SSX App",
4
+ favicon: "/logo.png",
4
5
  meta: {
5
6
  description: "Built with @inglorious/ssx",
6
7
  viewport: "width=device-width, initial-scale=1.0, viewport-fit=cover",
@@ -15,19 +15,21 @@
15
15
  },
16
16
  "dependencies": {
17
17
  "@inglorious/ssx": "workspace:*",
18
+ "@inglorious/store": "workspace:*",
18
19
  "@inglorious/web": "workspace:*",
19
20
  "gray-matter": "^4.0.3",
20
- "highlight.js": "^11.11.1",
21
- "katex": "^0.16.27",
22
- "markdown-it": "^14.1.0",
21
+ "highlight.js": "^11.12.0",
22
+ "katex": "^0.19.0",
23
+ "markdown-it": "^15.0.3",
23
24
  "markdown-it-texmath": "^1.0.0",
24
- "mermaid": "^11.12.2"
25
+ "mermaid": "^12.2.0"
25
26
  },
26
27
  "devDependencies": {
27
28
  "@inglorious/eslint-config": "workspace:*",
28
- "eslint": "^9.39.1",
29
- "prettier": "^3.6.2",
30
- "serve": "^14.2.1"
29
+ "eslint": "^10.13.0",
30
+ "prettier": "^3.9.10",
31
+ "serve": "^14.2.6",
32
+ "typescript": "^7.0.2"
31
33
  },
32
34
  "packageManager": "pnpm@10.15.0",
33
35
  "engines": {
@@ -2,6 +2,7 @@ import type { SiteConfig } from "@inglorious/ssx"
2
2
 
3
3
  const siteConfig: SiteConfig = {
4
4
  title: "My SSX App",
5
+ favicon: "/logo.png",
5
6
  meta: {
6
7
  description: "Built with @inglorious/ssx",
7
8
  viewport: "width=device-width, initial-scale=1.0, viewport-fit=cover",
@@ -19,14 +19,16 @@
19
19
  },
20
20
  "devDependencies": {
21
21
  "@inglorious/eslint-config": "workspace:*",
22
- "@types/node": "^25.0.9",
23
- "eslint": "^9.39.1",
24
- "prettier": "^3.6.2",
25
- "rollup-plugin-minify-template-literals": "^1.1.7",
26
- "sharp": "^0.34.5",
27
- "svgo": "^4.0.0",
28
- "typescript": "^5.9.2",
29
- "vite": "^7.1.6",
22
+ "@inglorious/vite-plugin-hmr": "workspace:*",
23
+ "@types/node": "^22.20.5",
24
+ "eslint": "^10.13.0",
25
+ "jiti": "^2.7.0",
26
+ "prettier": "^3.9.10",
27
+ "rollup-plugin-minify-template-literals": "^2.2.0",
28
+ "sharp": "^0.35.5",
29
+ "svgo": "^4.1.0",
30
+ "typescript": "^7.0.2",
31
+ "vite": "^8.3.4",
30
32
  "vite-plugin-image-optimizer": "^2.0.3"
31
33
  },
32
34
  "packageManager": "pnpm@10.15.0",
@@ -1,7 +1,9 @@
1
- import { type Api, html } from "@inglorious/web"
1
+ import { html } from "@inglorious/web"
2
+
3
+ import type { AppApi } from "../types"
2
4
 
3
5
  export const App = {
4
- render(props: Record<string, unknown> | null, api: Api) {
6
+ render(props: Record<string, unknown> | null, api: AppApi) {
5
7
  return html`<h1>
6
8
  ${api.render("message1")}, ${api.render("message2")},
7
9
  ${api.render("message3")}!
@@ -1,9 +1,11 @@
1
1
  {
2
2
  "extends": "./tsconfig.json",
3
3
  "compilerOptions": {
4
+ "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
4
5
  "module": "ESNext",
5
6
  "moduleResolution": "bundler",
6
7
  "target": "ES2020",
8
+ "noEmit": true,
7
9
  "verbatimModuleSyntax": true
8
10
  },
9
11
  "include": ["src"]
@@ -1,8 +1,10 @@
1
1
  {
2
2
  "compilerOptions": {
3
3
  "composite": true,
4
+ "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
4
5
  "module": "ESNext",
5
6
  "moduleResolution": "bundler",
7
+ "noEmit": true,
6
8
  "types": ["node"],
7
9
  "skipLibCheck": true
8
10
  },
@@ -1,6 +1,7 @@
1
1
  import "./vite-end"
2
2
 
3
3
  import { BaseEntity, EntitiesState } from "@inglorious/store"
4
+ import { Api, TemplateResult } from "@inglorious/web"
4
5
 
5
6
  // Define your entity types
6
7
  export interface MessageEntity extends BaseEntity {
@@ -20,8 +21,10 @@ export interface AppState extends EntitiesState<AppEntity> {
20
21
  message3: MessageEntity
21
22
  }
22
23
 
24
+ export type AppApi = Api<AppEntity, AppState>
25
+
23
26
  // Types configuration
24
27
  export interface MessageType {
25
28
  click: (entity: MessageEntity) => void
26
- render: (entity: MessageEntity, api: Api) => TemplateResult | null
29
+ render: (entity: MessageEntity, api: AppApi) => TemplateResult | null
27
30
  }
@@ -1,6 +1,7 @@
1
1
  import path from "node:path"
2
2
  import { fileURLToPath } from "node:url"
3
3
 
4
+ import { hmr } from "@inglorious/vite-plugin-hmr"
4
5
  import { minifyTemplateLiterals } from "rollup-plugin-minify-template-literals"
5
6
  import { defineConfig } from "vite"
6
7
  import { ViteImageOptimizer } from "vite-plugin-image-optimizer"
@@ -13,7 +14,7 @@ export default defineConfig({
13
14
  // @see https://github.com/vitejs/vite/issues/1973
14
15
  define: { "process.env": {} },
15
16
 
16
- plugins: [ViteImageOptimizer()],
17
+ plugins: [ViteImageOptimizer(), hmr()],
17
18
 
18
19
  build: {
19
20
  rollupOptions: {
@@ -20,15 +20,17 @@
20
20
  "devDependencies": {
21
21
  "@inglorious/eslint-config": "workspace:*",
22
22
  "@inglorious/jsx": "workspace:*",
23
+ "@inglorious/vite-plugin-hmr": "workspace:*",
23
24
  "@inglorious/vite-plugin-jsx": "workspace:*",
24
- "@types/node": "^25.0.9",
25
- "eslint": "^9.39.1",
26
- "prettier": "^3.6.2",
27
- "rollup-plugin-minify-template-literals": "^1.1.7",
28
- "sharp": "^0.34.5",
29
- "svgo": "^4.0.0",
30
- "typescript": "^5.9.2",
31
- "vite": "^7.1.6",
25
+ "@types/node": "^22.20.5",
26
+ "eslint": "^10.13.0",
27
+ "jiti": "^2.7.0",
28
+ "prettier": "^3.9.10",
29
+ "rollup-plugin-minify-template-literals": "^2.2.0",
30
+ "sharp": "^0.35.5",
31
+ "svgo": "^4.1.0",
32
+ "typescript": "^7.0.2",
33
+ "vite": "^8.3.4",
32
34
  "vite-plugin-image-optimizer": "^2.0.3"
33
35
  },
34
36
  "packageManager": "pnpm@10.15.0",
@@ -1,9 +1,9 @@
1
- import type { Api } from "@inglorious/web"
1
+ import type { AppApi } from "../types"
2
2
 
3
3
  import { Message } from "./types/message"
4
4
 
5
5
  export const App = {
6
- render(props: Record<string, unknown> | null, api: Api) {
6
+ render(props: Record<string, unknown> | null, api: AppApi) {
7
7
  return (
8
8
  <h1>
9
9
  {/* @ts-expect-error - JSX components are entity type names, not imports */}
@@ -1,9 +1,11 @@
1
1
  {
2
2
  "extends": "./tsconfig.json",
3
3
  "compilerOptions": {
4
+ "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
4
5
  "module": "ESNext",
5
6
  "moduleResolution": "bundler",
6
7
  "target": "ES2020",
8
+ "noEmit": true,
7
9
  "verbatimModuleSyntax": true,
8
10
  "jsx": "preserve"
9
11
  },
@@ -1,8 +1,10 @@
1
1
  {
2
2
  "compilerOptions": {
3
3
  "composite": true,
4
+ "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
4
5
  "module": "ESNext",
5
6
  "moduleResolution": "bundler",
7
+ "noEmit": true,
6
8
  "types": ["node"],
7
9
  "skipLibCheck": true
8
10
  },
@@ -21,8 +21,10 @@ export interface AppState extends EntitiesState<AppEntity> {
21
21
  message3: MessageEntity
22
22
  }
23
23
 
24
+ export type AppApi = Api<AppEntity, AppState>
25
+
24
26
  // Types configuration
25
27
  export interface MessageType {
26
28
  click: (entity: MessageEntity) => void
27
- render: (entity: MessageEntity, api: Api) => TemplateResult | null
29
+ render: (entity: MessageEntity, api: AppApi) => TemplateResult | null
28
30
  }
@@ -1 +1,2 @@
1
1
  /// <reference types="vite/client" />
2
+ /// <reference types="@inglorious/jsx/jsx-runtime" />