@inglorious/create-app 1.1.2 → 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 (45) hide show
  1. package/README.md +15 -7
  2. package/bin/index.js +34 -39
  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 +31 -0
  8. package/bin/lib/constants.js +3 -3
  9. package/bin/lib/features.js +142 -0
  10. package/bin/lib/imports.js +64 -0
  11. package/bin/lib/mobile.js +19 -1
  12. package/bin/lib/pwa.js +50 -4
  13. package/bin/lib/questions.js +184 -0
  14. package/bin/lib/source.js +58 -0
  15. package/package.json +3 -3
  16. package/templates/js/package.json +4 -4
  17. package/templates/js/vite.config.js +2 -1
  18. package/templates/js-jsx/package.json +4 -4
  19. package/templates/js-jsx/vite.config.js +2 -1
  20. package/templates/js-vue/package.json +4 -4
  21. package/templates/js-vue/vite.config.js +2 -1
  22. package/templates/ssx-js/package.json +8 -7
  23. package/templates/ssx-js/src/site.config.js +2 -1
  24. package/templates/ssx-ts/package.json +9 -7
  25. package/templates/ssx-ts/src/site.config.ts +1 -0
  26. package/templates/ts/package.json +7 -6
  27. package/templates/ts/src/app.ts +4 -2
  28. package/templates/ts/tsconfig.app.json +2 -0
  29. package/templates/ts/tsconfig.node.json +2 -0
  30. package/templates/ts/types/index.d.ts +4 -1
  31. package/templates/ts/vite.config.ts +2 -1
  32. package/templates/ts-jsx/package.json +7 -6
  33. package/templates/ts-jsx/src/app.tsx +2 -2
  34. package/templates/ts-jsx/tsconfig.app.json +2 -0
  35. package/templates/ts-jsx/tsconfig.node.json +2 -0
  36. package/templates/ts-jsx/types/index.d.ts +3 -1
  37. package/templates/ts-jsx/types/vite-end.d.ts +1 -0
  38. package/templates/ts-jsx/vite.config.ts +2 -1
  39. package/templates/ts-vue/eslint.config.ts +1 -1
  40. package/templates/ts-vue/package.json +7 -6
  41. package/templates/ts-vue/src/store/middlewares.ts +5 -2
  42. package/templates/ts-vue/tsconfig.app.json +2 -0
  43. package/templates/ts-vue/tsconfig.node.json +2 -0
  44. package/templates/ts-vue/types/index.d.ts +3 -1
  45. package/templates/ts-vue/vite.config.ts +2 -1
package/bin/lib/pwa.js CHANGED
@@ -34,7 +34,7 @@ export function injectServiceWorkerRegistration(targetDir) {
34
34
  let main = fs.readFileSync(mainPath, "utf-8")
35
35
 
36
36
  if (!main.includes("./pwa")) {
37
- main = injectAfterImport(main, "@inglorious/web", `import "./pwa"`)
37
+ main = injectSideEffectImport(main, `import "./pwa"`)
38
38
  }
39
39
 
40
40
  fs.writeFileSync(mainPath, main)
@@ -50,17 +50,28 @@ export function injectPwaPluginConfig(targetDir, projectName) {
50
50
  let viteConfig = fs.readFileSync(viteConfigPath, "utf-8")
51
51
 
52
52
  if (!viteConfig.includes("vite-plugin-pwa")) {
53
+ // Right after the image optimizer, where the imports' alphabetical order
54
+ // puts it.
53
55
  viteConfig = injectAfterImport(
54
56
  viteConfig,
55
- "vite",
57
+ viteConfig.includes("vite-plugin-image-optimizer")
58
+ ? "vite-plugin-image-optimizer"
59
+ : "vite",
56
60
  `import { VitePWA } from "vite-plugin-pwa"`,
57
61
  )
58
62
  }
59
63
 
60
64
  if (!viteConfig.includes("VitePWA(")) {
65
+ // One plugin per line, as Prettier prints a list this long.
61
66
  viteConfig = viteConfig.replace(
62
- /plugins: \[/,
63
- `plugins: [${EOL} ${createVitePwaConfig(projectName)},`,
67
+ /plugins: \[(.*)\],/,
68
+ (_, plugins) =>
69
+ `plugins: [${EOL}${[
70
+ createVitePwaConfig(projectName),
71
+ ...splitPlugins(plugins),
72
+ ]
73
+ .map((plugin) => ` ${plugin},`)
74
+ .join(EOL)}${EOL} ],`,
64
75
  )
65
76
  }
66
77
 
@@ -120,3 +131,38 @@ export function createVitePwaConfig(projectName) {
120
131
  },
121
132
  })`
122
133
  }
134
+
135
+ // The plugins of a one-line `plugins: [a(), b({ c: 1 })]`, split at the
136
+ // top-level commas.
137
+ function splitPlugins(source) {
138
+ const plugins = []
139
+ let depth = 0
140
+ let current = ""
141
+ for (const char of source) {
142
+ if ("([{".includes(char)) depth++
143
+ if (")]}".includes(char)) depth--
144
+ if (char === "," && !depth) {
145
+ plugins.push(current.trim())
146
+ current = ""
147
+ } else {
148
+ current += char
149
+ }
150
+ }
151
+ if (current.trim()) plugins.push(current.trim())
152
+ return plugins
153
+ }
154
+
155
+ // A side-effect import goes with the others at the top, in the order they
156
+ // come, as eslint-plugin-simple-import-sort keeps them.
157
+ function injectSideEffectImport(source, newImport) {
158
+ const lastSideEffect = source
159
+ .split(EOL)
160
+ .findLast((line) => /^import ["']/.test(line))
161
+ if (lastSideEffect) {
162
+ return source.replace(
163
+ `${lastSideEffect}${EOL}`,
164
+ `${lastSideEffect}${EOL}${newImport}${EOL}`,
165
+ )
166
+ }
167
+ return `${newImport}${EOL}${EOL}${source}`
168
+ }
@@ -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.2",
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
40
  "@inglorious/eslint-config": "1.1.2",
41
- "prettier": "^3.6.2"
41
+ "prettier": "^3.9.6"
42
42
  },
43
43
  "scripts": {
44
44
  "format": "prettier --write .",
@@ -20,12 +20,12 @@
20
20
  "devDependencies": {
21
21
  "@inglorious/eslint-config": "workspace:*",
22
22
  "@inglorious/vite-plugin-hmr": "workspace:*",
23
- "eslint": "^10.9.1",
24
- "prettier": "^3.9.6",
23
+ "eslint": "^10.13.0",
24
+ "prettier": "^3.9.10",
25
25
  "rollup-plugin-minify-template-literals": "^2.2.0",
26
- "sharp": "^0.35.4",
26
+ "sharp": "^0.35.5",
27
27
  "svgo": "^4.1.0",
28
- "vite": "^8.2.2",
28
+ "vite": "^8.3.4",
29
29
  "vite-plugin-image-optimizer": "^2.0.3"
30
30
  },
31
31
  "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 { 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: {
@@ -21,12 +21,12 @@
21
21
  "@inglorious/eslint-config": "workspace:*",
22
22
  "@inglorious/vite-plugin-hmr": "workspace:*",
23
23
  "@inglorious/vite-plugin-jsx": "workspace:*",
24
- "eslint": "^10.9.1",
25
- "prettier": "^3.9.6",
24
+ "eslint": "^10.13.0",
25
+ "prettier": "^3.9.10",
26
26
  "rollup-plugin-minify-template-literals": "^2.2.0",
27
- "sharp": "^0.35.4",
27
+ "sharp": "^0.35.5",
28
28
  "svgo": "^4.1.0",
29
- "vite": "^8.2.2",
29
+ "vite": "^8.3.4",
30
30
  "vite-plugin-image-optimizer": "^2.0.3"
31
31
  },
32
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 { 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: {
@@ -21,12 +21,12 @@
21
21
  "@inglorious/eslint-config": "workspace:*",
22
22
  "@inglorious/vite-plugin-hmr": "workspace:*",
23
23
  "@inglorious/vite-plugin-vue": "workspace:*",
24
- "eslint": "^10.9.1",
25
- "prettier": "^3.9.6",
24
+ "eslint": "^10.13.0",
25
+ "prettier": "^3.9.10",
26
26
  "rollup-plugin-minify-template-literals": "^2.2.0",
27
- "sharp": "^0.35.4",
27
+ "sharp": "^0.35.5",
28
28
  "svgo": "^4.1.0",
29
- "vite": "^8.2.2",
29
+ "vite": "^8.3.4",
30
30
  "vite-plugin-image-optimizer": "^2.0.3"
31
31
  },
32
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": "^10.9.1",
29
- "prettier": "^3.9.6",
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": "^10.9.1",
29
- "prettier": "^3.9.6",
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",
@@ -20,14 +20,15 @@
20
20
  "devDependencies": {
21
21
  "@inglorious/eslint-config": "workspace:*",
22
22
  "@inglorious/vite-plugin-hmr": "workspace:*",
23
- "@types/node": "^25.0.9",
24
- "eslint": "^10.9.1",
25
- "prettier": "^3.9.6",
23
+ "@types/node": "^22.20.5",
24
+ "eslint": "^10.13.0",
25
+ "jiti": "^2.7.0",
26
+ "prettier": "^3.9.10",
26
27
  "rollup-plugin-minify-template-literals": "^2.2.0",
27
- "sharp": "^0.35.4",
28
+ "sharp": "^0.35.5",
28
29
  "svgo": "^4.1.0",
29
- "typescript": "^5.9.2",
30
- "vite": "^8.2.2",
30
+ "typescript": "^7.0.2",
31
+ "vite": "^8.3.4",
31
32
  "vite-plugin-image-optimizer": "^2.0.3"
32
33
  },
33
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: {
@@ -22,14 +22,15 @@
22
22
  "@inglorious/jsx": "workspace:*",
23
23
  "@inglorious/vite-plugin-hmr": "workspace:*",
24
24
  "@inglorious/vite-plugin-jsx": "workspace:*",
25
- "@types/node": "^25.0.9",
26
- "eslint": "^10.9.1",
27
- "prettier": "^3.9.6",
25
+ "@types/node": "^22.20.5",
26
+ "eslint": "^10.13.0",
27
+ "jiti": "^2.7.0",
28
+ "prettier": "^3.9.10",
28
29
  "rollup-plugin-minify-template-literals": "^2.2.0",
29
- "sharp": "^0.35.4",
30
+ "sharp": "^0.35.5",
30
31
  "svgo": "^4.1.0",
31
- "typescript": "^5.9.2",
32
- "vite": "^8.2.2",
32
+ "typescript": "^7.0.2",
33
+ "vite": "^8.3.4",
33
34
  "vite-plugin-image-optimizer": "^2.0.3"
34
35
  },
35
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 */}