@icebreakers/monorepo-templates 0.0.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 (201) hide show
  1. package/README.md +9 -0
  2. package/assets/.changeset/config.json +16 -0
  3. package/assets/.changeset/create-icebreaker-interactive.md +5 -0
  4. package/assets/.changeset/monorepo-templates-package.md +5 -0
  5. package/assets/.changeset/skills-sync-resources.md +5 -0
  6. package/assets/.dockerignore +44 -0
  7. package/assets/.editorconfig +12 -0
  8. package/assets/.gitattributes +218 -0
  9. package/assets/.github/FUNDING.yml +4 -0
  10. package/assets/.github/ISSUE_TEMPLATE/bug_report.yml +71 -0
  11. package/assets/.github/ISSUE_TEMPLATE/config.yml +17 -0
  12. package/assets/.github/workflows/ci.yml +62 -0
  13. package/assets/.github/workflows/release.yml +57 -0
  14. package/assets/.husky/commit-msg +4 -0
  15. package/assets/.husky/pre-commit +4 -0
  16. package/assets/.vscode/extensions.json +6 -0
  17. package/assets/.vscode/settings.json +172 -0
  18. package/assets/CODE_OF_CONDUCT.md +128 -0
  19. package/assets/CONTRIBUTING.md +3 -0
  20. package/assets/Dockerfile +27 -0
  21. package/assets/LICENSE +21 -0
  22. package/assets/SECURITY.md +21 -0
  23. package/assets/commitlint.config.ts +3 -0
  24. package/assets/eslint.config.js +7 -0
  25. package/assets/gitignore +38 -0
  26. package/assets/lint-staged.config.js +11 -0
  27. package/assets/monorepo.config.ts +22 -0
  28. package/assets/netlify.toml +14 -0
  29. package/assets/package.json +88 -0
  30. package/assets/pnpm-workspace.yaml +11 -0
  31. package/assets/renovate.json +28 -0
  32. package/assets/stylelint.config.js +3 -0
  33. package/assets/tsconfig.json +51 -0
  34. package/assets/turbo.json +74 -0
  35. package/assets/vitest.config.ts +123 -0
  36. package/assets-data.mjs +45 -0
  37. package/dist/index.d.mts +37 -0
  38. package/dist/index.mjs +287 -0
  39. package/package.json +51 -0
  40. package/skeleton/.editorconfig +12 -0
  41. package/skeleton/LICENSE +21 -0
  42. package/skeleton/commitlint.config.ts +3 -0
  43. package/skeleton/eslint.config.js +7 -0
  44. package/skeleton/gitignore +38 -0
  45. package/skeleton/lint-staged.config.js +11 -0
  46. package/skeleton/package.json +88 -0
  47. package/skeleton/pnpm-workspace.yaml +11 -0
  48. package/skeleton/renovate.json +28 -0
  49. package/skeleton/stylelint.config.js +3 -0
  50. package/skeleton/tsconfig.json +51 -0
  51. package/skeleton/turbo.json +74 -0
  52. package/skeleton/vitest.config.ts +123 -0
  53. package/template-data.mjs +10 -0
  54. package/templates/cli/bin/index.js +2 -0
  55. package/templates/cli/dev/index.ts +2 -0
  56. package/templates/cli/gitignore +2 -0
  57. package/templates/cli/package.json +35 -0
  58. package/templates/cli/src/cli.ts +4 -0
  59. package/templates/cli/src/index.ts +15 -0
  60. package/templates/cli/tsconfig.json +7 -0
  61. package/templates/cli/tsup.config.ts +13 -0
  62. package/templates/client/eslint.config.js +12 -0
  63. package/templates/client/gitignore +28 -0
  64. package/templates/client/index.html +13 -0
  65. package/templates/client/package.json +52 -0
  66. package/templates/client/public/vite.svg +1 -0
  67. package/templates/client/src/App.vue +11 -0
  68. package/templates/client/src/main.ts +16 -0
  69. package/templates/client/src/pages/index.vue +357 -0
  70. package/templates/client/src/query-keys.ts +4 -0
  71. package/templates/client/src/router/index.ts +13 -0
  72. package/templates/client/src/stores/i18n.ts +24 -0
  73. package/templates/client/src/stores/index.ts +15 -0
  74. package/templates/client/src/style.css +1 -0
  75. package/templates/client/src/trpc/index.ts +10 -0
  76. package/templates/client/src/vite-env.d.ts +2 -0
  77. package/templates/client/tsconfig.app.json +28 -0
  78. package/templates/client/tsconfig.json +8 -0
  79. package/templates/client/tsconfig.node.json +25 -0
  80. package/templates/client/tsconfig.worker.json +11 -0
  81. package/templates/client/vite.config.ts +57 -0
  82. package/templates/client/worker/app.ts +24 -0
  83. package/templates/client/worker/config.ts +1 -0
  84. package/templates/client/worker/fetch-entry.ts +5 -0
  85. package/templates/client/worker/node-entry.ts +13 -0
  86. package/templates/client/worker/trpc-router.ts +24 -0
  87. package/templates/client/wrangler.jsonc +24 -0
  88. package/templates/server/gitignore +2 -0
  89. package/templates/server/package.json +60 -0
  90. package/templates/server/src/app.ts +191 -0
  91. package/templates/server/src/config.ts +1 -0
  92. package/templates/server/src/fetch-entry.ts +5 -0
  93. package/templates/server/src/node-entry.ts +13 -0
  94. package/templates/server/test/index.test.ts +14 -0
  95. package/templates/server/tsconfig.json +24 -0
  96. package/templates/server/tsup.config.ts +13 -0
  97. package/templates/server/vitest.config.ts +15 -0
  98. package/templates/server/wrangler.jsonc +18 -0
  99. package/templates/tsdown/package.json +47 -0
  100. package/templates/tsdown/src/index.ts +5 -0
  101. package/templates/tsdown/test/index.test.ts +11 -0
  102. package/templates/tsdown/tsconfig.json +15 -0
  103. package/templates/tsdown/tsdown.config.ts +9 -0
  104. package/templates/tsdown/vitest.config.ts +15 -0
  105. package/templates/tsup/build.config.ts +24 -0
  106. package/templates/tsup/package.json +48 -0
  107. package/templates/tsup/src/index.ts +12 -0
  108. package/templates/tsup/test/index.test.ts +18 -0
  109. package/templates/tsup/tsconfig.json +15 -0
  110. package/templates/tsup/tsup.config.ts +18 -0
  111. package/templates/tsup/vitest.config.ts +15 -0
  112. package/templates/unbuild/build.config.ts +24 -0
  113. package/templates/unbuild/package.json +48 -0
  114. package/templates/unbuild/src/index.ts +9 -0
  115. package/templates/unbuild/src/utils.ts +3 -0
  116. package/templates/unbuild/test/index.test.ts +18 -0
  117. package/templates/unbuild/tsconfig.json +15 -0
  118. package/templates/unbuild/vitest.config.ts +15 -0
  119. package/templates/vitepress/.vitepress/config.ts +93 -0
  120. package/templates/vitepress/.vitepress/theme/index.ts +4 -0
  121. package/templates/vitepress/.vitepress/theme/tailwind.css +1 -0
  122. package/templates/vitepress/gitignore +1 -0
  123. package/templates/vitepress/index.md +127 -0
  124. package/templates/vitepress/monorepo/index.md +46 -0
  125. package/templates/vitepress/monorepo/manage.md +129 -0
  126. package/templates/vitepress/monorepo/publish.md +142 -0
  127. package/templates/vitepress/package.json +39 -0
  128. package/templates/vitepress/public/logo.jpg +0 -0
  129. package/templates/vitepress/thinking.md +88 -0
  130. package/templates/vitepress/tools/changeset.md +87 -0
  131. package/templates/vitepress/tools/husky.md +108 -0
  132. package/templates/vitepress/tools/lint-staged.md +79 -0
  133. package/templates/vitepress/tools/pnpm.md +101 -0
  134. package/templates/vitepress/tools/renovate.md +91 -0
  135. package/templates/vitepress/tools/turborepo.md +149 -0
  136. package/templates/vitepress/why/assets/npm-dt.svg +15 -0
  137. package/templates/vitepress/why/assets/npm-ts.svg +19 -0
  138. package/templates/vitepress/why/examples/0.npm-basic-package/index.js +10 -0
  139. package/templates/vitepress/why/examples/0.npm-basic-package/package.json +11 -0
  140. package/templates/vitepress/why/examples/1.npm-basic-package/index.cjs +12 -0
  141. package/templates/vitepress/why/examples/1.npm-basic-package/index.d.ts +1 -0
  142. package/templates/vitepress/why/examples/1.npm-basic-package/index.js +8 -0
  143. package/templates/vitepress/why/examples/1.npm-basic-package/package.json +19 -0
  144. package/templates/vitepress/why/examples/2.npm-basic-package/README.md +1 -0
  145. package/templates/vitepress/why/examples/2.npm-basic-package/package-lock.json +30 -0
  146. package/templates/vitepress/why/examples/2.npm-basic-package/package.json +35 -0
  147. package/templates/vitepress/why/examples/2.npm-basic-package/rename-ext.js +24 -0
  148. package/templates/vitepress/why/examples/2.npm-basic-package/src/index.ts +8 -0
  149. package/templates/vitepress/why/examples/2.npm-basic-package/tsconfig.cjs.json +8 -0
  150. package/templates/vitepress/why/examples/2.npm-basic-package/tsconfig.esm.json +7 -0
  151. package/templates/vitepress/why/examples/2.npm-basic-package/tsconfig.json +18 -0
  152. package/templates/vitepress/why/examples/3.npm-basic-package/README.md +1 -0
  153. package/templates/vitepress/why/examples/3.npm-basic-package/build.config.ts +24 -0
  154. package/templates/vitepress/why/examples/3.npm-basic-package/package-lock.json +3661 -0
  155. package/templates/vitepress/why/examples/3.npm-basic-package/package.json +32 -0
  156. package/templates/vitepress/why/examples/3.npm-basic-package/src/index.ts +8 -0
  157. package/templates/vitepress/why/examples/3.npm-basic-package/tsconfig.json +16 -0
  158. package/templates/vitepress/why/examples/3.npm-basic-package/tsup.config.ts +16 -0
  159. package/templates/vitepress/why/examples/usage-cjs/cjs.cjs +4 -0
  160. package/templates/vitepress/why/examples/usage-cjs/esm.mjs +4 -0
  161. package/templates/vitepress/why/examples/usage-cjs/index.js +12 -0
  162. package/templates/vitepress/why/examples/usage-cjs/package-lock.json +42 -0
  163. package/templates/vitepress/why/examples/usage-cjs/package.json +20 -0
  164. package/templates/vitepress/why/examples/usage-esm/cjs.cjs +4 -0
  165. package/templates/vitepress/why/examples/usage-esm/createRequire.js +7 -0
  166. package/templates/vitepress/why/examples/usage-esm/esm.mjs +4 -0
  167. package/templates/vitepress/why/examples/usage-esm/index.js +8 -0
  168. package/templates/vitepress/why/examples/usage-esm/package-lock.json +42 -0
  169. package/templates/vitepress/why/examples/usage-esm/package.json +21 -0
  170. package/templates/vitepress/why/how-to-reuse-js-code.md +250 -0
  171. package/templates/vitepress/why/index.md +1 -0
  172. package/templates/vitepress/why/js-cjs-mjs.md +99 -0
  173. package/templates/vitepress/why/js-keywords.md +132 -0
  174. package/templates/vitepress/why/modern/bundlers.md +79 -0
  175. package/templates/vitepress/why/modern/dts.md +93 -0
  176. package/templates/vitepress/why/modern/esm-vs-cjs.md +84 -0
  177. package/templates/vitepress/why/modern/index.md +55 -0
  178. package/templates/vitepress/why/modern/package-entry-points.md +128 -0
  179. package/templates/vitepress/why/modern/typescript.md +155 -0
  180. package/templates/vitepress/why/publish-basic-npm-package.md +146 -0
  181. package/templates/vitepress/why/what-is-npm-package.md +162 -0
  182. package/templates/vue-lib/eslint.config.js +12 -0
  183. package/templates/vue-lib/gitignore +1 -0
  184. package/templates/vue-lib/index.html +13 -0
  185. package/templates/vue-lib/lib/HelloWorld.vue +21 -0
  186. package/templates/vue-lib/lib/index.ts +3 -0
  187. package/templates/vue-lib/package.json +61 -0
  188. package/templates/vue-lib/src/App.vue +9 -0
  189. package/templates/vue-lib/src/main.ts +8 -0
  190. package/templates/vue-lib/src/pages/index.vue +7 -0
  191. package/templates/vue-lib/src/router/index.ts +11 -0
  192. package/templates/vue-lib/src/style.css +1 -0
  193. package/templates/vue-lib/src/vite-env.d.ts +2 -0
  194. package/templates/vue-lib/test/index.test.ts +13 -0
  195. package/templates/vue-lib/tsconfig.app.json +30 -0
  196. package/templates/vue-lib/tsconfig.json +14 -0
  197. package/templates/vue-lib/tsconfig.node.json +25 -0
  198. package/templates/vue-lib/tsconfig.test.json +40 -0
  199. package/templates/vue-lib/vite.config.ts +54 -0
  200. package/templates/vue-lib/vite.shared.config.ts +13 -0
  201. package/templates/vue-lib/vitest.config.ts +13 -0
@@ -0,0 +1,16 @@
1
+ import { VueQueryPlugin } from '@tanstack/vue-query'
2
+ import { createPinia } from 'pinia'
3
+ import { createApp } from 'vue'
4
+ import App from './App.vue'
5
+ import router from './router'
6
+ import { i18n } from './stores/i18n'
7
+ import './style.css'
8
+
9
+ const pinia = createPinia()
10
+ const app = createApp(App)
11
+ app.use(router)
12
+ app.use(pinia)
13
+ app.use(i18n)
14
+ app.use(VueQueryPlugin)
15
+
16
+ app.mount('#app')
@@ -0,0 +1,357 @@
1
+ <script setup lang="ts">
2
+ import { useQuery, useQueryClient } from '@tanstack/vue-query'
3
+ import { computed } from 'vue'
4
+ import { useI18n } from 'vue-i18n'
5
+ import { helloKeys } from '@/query-keys'
6
+ import { client } from '@/trpc'
7
+
8
+ type HelloResponse = Awaited<ReturnType<typeof client.hello.query>>
9
+
10
+ const { t, locale } = useI18n()
11
+ function changeLocale(lang: 'en' | 'zh') {
12
+ locale.value = lang
13
+ }
14
+
15
+ function toggleLocale() {
16
+ changeLocale(locale.value === 'en' ? 'zh' : 'en')
17
+ }
18
+
19
+ function formatTime(timestamp?: number) {
20
+ if (!timestamp) {
21
+ return '-'
22
+ }
23
+ return new Intl.DateTimeFormat(undefined, {
24
+ hour: '2-digit',
25
+ minute: '2-digit',
26
+ second: '2-digit',
27
+ }).format(new Date(timestamp))
28
+ }
29
+
30
+ const queryClient = useQueryClient()
31
+ const helloName = 'icebreakers' as const
32
+
33
+ const helloQuery = useQuery<HelloResponse>({
34
+ queryKey: helloKeys.detail(helloName),
35
+ queryFn: () => client.hello.query(helloName),
36
+ staleTime: 30_000,
37
+ gcTime: 5 * 60_000,
38
+ })
39
+
40
+ const liveData = computed(() => ({
41
+ message: helloQuery.data.value?.message ?? '-',
42
+ time: helloQuery.data.value?.time ?? null,
43
+ formattedTime: formatTime(helloQuery.data.value?.time),
44
+ }))
45
+
46
+ const cachedHello = computed<HelloResponse | undefined>(() => {
47
+ const cached = queryClient.getQueryData<HelloResponse>(
48
+ helloKeys.detail(helloName),
49
+ )
50
+ return helloQuery.data.value ?? cached
51
+ })
52
+
53
+ const queryMeta = computed(() => ({
54
+ status: helloQuery.status.value,
55
+ fetchStatus: helloQuery.fetchStatus.value,
56
+ isFetching: helloQuery.isFetching.value,
57
+ isStale: helloQuery.isStale.value,
58
+ dataUpdatedAt: helloQuery.dataUpdatedAt.value,
59
+ }))
60
+
61
+ const helloErrorMessage = computed(() => {
62
+ const error = helloQuery.error.value
63
+ if (!error) {
64
+ return ''
65
+ }
66
+ if (error instanceof Error) {
67
+ return error.message
68
+ }
69
+ return String(error)
70
+ })
71
+ </script>
72
+
73
+ <template>
74
+ <div class="min-h-screen bg-slate-950 text-slate-50">
75
+ <div class="mx-auto flex min-h-screen max-w-5xl flex-col gap-6 px-6 py-8">
76
+ <header
77
+ class="
78
+ rounded-2xl bg-linear-to-br from-slate-800 to-slate-900 p-6 shadow-xl
79
+ ring-1 ring-white/5
80
+ "
81
+ >
82
+ <div class="flex flex-wrap items-center justify-between gap-4">
83
+ <div class="space-y-2">
84
+ <p class="text-xs tracking-[0.2em] text-slate-400 uppercase">
85
+ TanStack Query + i18n
86
+ </p>
87
+ <h1 class="text-3xl/tight font-semibold">
88
+ {{ t('hello') }}
89
+ </h1>
90
+ <p class="text-sm text-slate-400">
91
+ Minimal data-fetch demo. Everything stays on screen for quick checks.
92
+ </p>
93
+ </div>
94
+ <div class="flex flex-wrap items-center gap-3">
95
+ <button
96
+ class="
97
+ rounded-full bg-white/15 px-4 py-2 text-sm font-medium
98
+ text-slate-50 shadow-sm transition
99
+ hover:scale-[1.02] hover:bg-white/25
100
+ "
101
+ @click="toggleLocale"
102
+ >
103
+ {{ t('toggleLocale') }}
104
+ </button>
105
+ <button
106
+ class="
107
+ rounded-full bg-emerald-500/90 px-4 py-2 text-sm font-semibold
108
+ text-emerald-950 shadow-sm transition
109
+ hover:scale-[1.02] hover:bg-emerald-400
110
+ disabled:opacity-60
111
+ "
112
+ :disabled="helloQuery.isFetching.value"
113
+ @click="helloQuery.refetch()"
114
+ >
115
+ {{ helloQuery.isFetching ? 'Refreshing…' : 'Refetch now' }}
116
+ </button>
117
+ </div>
118
+ </div>
119
+ <div
120
+ class="mt-4 flex flex-wrap items-center gap-3 text-xs text-slate-300"
121
+ >
122
+ <span
123
+ class="
124
+ inline-flex items-center gap-2 rounded-full bg-emerald-500/15 px-3
125
+ py-1 font-semibold text-emerald-200 ring-1 ring-emerald-500/30
126
+ "
127
+ >
128
+ <span class="size-2 rounded-full bg-emerald-400" />
129
+ Live data connected
130
+ </span>
131
+ <span
132
+ class="
133
+ rounded-full bg-white/5 px-3 py-1 font-semibold text-white/80
134
+ ring-1 ring-white/10
135
+ "
136
+ >
137
+ Status: {{ helloQuery.status }}
138
+ </span>
139
+ <span
140
+ v-if="helloQuery.isFetching"
141
+ class="
142
+ rounded-full bg-amber-500/15 px-3 py-1 font-semibold
143
+ text-amber-200 ring-1 ring-amber-500/30
144
+ "
145
+ >
146
+ Fetching…
147
+ </span>
148
+ </div>
149
+ </header>
150
+
151
+ <div
152
+ class="
153
+ grid gap-4
154
+ md:grid-cols-2
155
+ "
156
+ >
157
+ <section
158
+ class="rounded-2xl bg-slate-900/70 p-5 shadow-lg ring-1 ring-white/5"
159
+ >
160
+ <div class="flex items-center justify-between gap-3">
161
+ <div>
162
+ <h2 class="text-lg font-semibold">
163
+ Live data
164
+ </h2>
165
+ <p class="text-xs text-slate-400">
166
+ Latest response from the server
167
+ </p>
168
+ </div>
169
+ <span
170
+ class="
171
+ rounded-full bg-white/10 px-3 py-1 text-xs font-semibold
172
+ text-white/90 ring-1 ring-white/10
173
+ "
174
+ >
175
+ {{ helloQuery.fetchStatus }}
176
+ </span>
177
+ </div>
178
+ <dl
179
+ class="
180
+ mt-4 grid gap-3
181
+ sm:grid-cols-2
182
+ "
183
+ >
184
+ <div
185
+ class="
186
+ rounded-lg bg-white/5 px-3 py-2 text-sm text-slate-100 ring-1
187
+ ring-white/10
188
+ "
189
+ >
190
+ <dt class="text-xs tracking-wide text-slate-400 uppercase">
191
+ Message
192
+ </dt>
193
+ <dd class="mt-1 font-semibold">
194
+ {{ liveData.message }}
195
+ </dd>
196
+ </div>
197
+ <div
198
+ class="
199
+ rounded-lg bg-white/5 px-3 py-2 text-sm text-slate-100 ring-1
200
+ ring-white/10
201
+ "
202
+ >
203
+ <dt class="text-xs tracking-wide text-slate-400 uppercase">
204
+ Server time
205
+ </dt>
206
+ <dd class="mt-1 font-semibold">
207
+ {{ liveData.formattedTime }}
208
+ </dd>
209
+ </div>
210
+ </dl>
211
+ <pre
212
+ class="
213
+ mt-4 max-h-48 overflow-auto rounded-lg bg-black/40 p-3 text-left
214
+ text-xs/relaxed text-slate-100 ring-1 ring-white/10
215
+ "
216
+ >{{ JSON.stringify(liveData, null, 2) }}</pre>
217
+ <p v-if="helloErrorMessage" class="mt-3 text-sm text-rose-200">
218
+ {{ helloErrorMessage }}
219
+ </p>
220
+ </section>
221
+
222
+ <section
223
+ class="rounded-2xl bg-slate-900/70 p-5 shadow-lg ring-1 ring-white/5"
224
+ >
225
+ <div class="flex items-center justify-between gap-3">
226
+ <div>
227
+ <h2 class="text-lg font-semibold">
228
+ Cache snapshot
229
+ </h2>
230
+ <p class="text-xs text-slate-400">
231
+ Result from getQueryData
232
+ </p>
233
+ </div>
234
+ <span
235
+ class="
236
+ rounded-full bg-emerald-500/15 px-3 py-1 text-xs font-semibold
237
+ text-emerald-100 ring-1 ring-emerald-500/30
238
+ "
239
+ >
240
+ {{ cachedHello ? 'Cached' : 'Empty' }}
241
+ </span>
242
+ </div>
243
+ <div
244
+ class="
245
+ mt-3 rounded-lg bg-white/5 px-3 py-2 text-sm text-slate-100 ring-1
246
+ ring-white/10
247
+ "
248
+ >
249
+ <p class="text-xs tracking-wide text-slate-400 uppercase">
250
+ Time
251
+ </p>
252
+ <p class="mt-1 font-semibold">
253
+ {{ formatTime(cachedHello?.time) }}
254
+ </p>
255
+ </div>
256
+ <pre
257
+ class="
258
+ mt-4 max-h-48 overflow-auto rounded-lg bg-black/40 p-3 text-left
259
+ text-xs/relaxed text-slate-100 ring-1 ring-white/10
260
+ "
261
+ >{{ JSON.stringify(cachedHello ?? '-', null, 2) }}</pre>
262
+ </section>
263
+
264
+ <section
265
+ class="
266
+ rounded-2xl bg-slate-900/70 p-5 shadow-lg ring-1 ring-white/5
267
+ md:col-span-2
268
+ "
269
+ >
270
+ <div class="flex flex-wrap items-center justify-between gap-3">
271
+ <div>
272
+ <h2 class="text-lg font-semibold">
273
+ Query meta
274
+ </h2>
275
+ <p class="text-xs text-slate-400">
276
+ What TanStack Query is tracking
277
+ </p>
278
+ </div>
279
+ <span
280
+ class="
281
+ rounded-full bg-white/10 px-3 py-1 text-xs font-semibold
282
+ text-white/80 ring-1 ring-white/10
283
+ "
284
+ >
285
+ Updated: {{ formatTime(queryMeta.dataUpdatedAt) }}
286
+ </span>
287
+ </div>
288
+ <div
289
+ class="
290
+ mt-4 grid gap-3
291
+ sm:grid-cols-4
292
+ "
293
+ >
294
+ <div
295
+ class="
296
+ rounded-lg bg-white/5 px-3 py-2 text-xs text-slate-100 ring-1
297
+ ring-white/10
298
+ "
299
+ >
300
+ <p class="text-slate-400">
301
+ Status
302
+ </p>
303
+ <p class="mt-1 font-semibold">
304
+ {{ queryMeta.status }}
305
+ </p>
306
+ </div>
307
+ <div
308
+ class="
309
+ rounded-lg bg-white/5 px-3 py-2 text-xs text-slate-100 ring-1
310
+ ring-white/10
311
+ "
312
+ >
313
+ <p class="text-slate-400">
314
+ Fetch
315
+ </p>
316
+ <p class="mt-1 font-semibold">
317
+ {{ queryMeta.fetchStatus }}
318
+ </p>
319
+ </div>
320
+ <div
321
+ class="
322
+ rounded-lg bg-white/5 px-3 py-2 text-xs text-slate-100 ring-1
323
+ ring-white/10
324
+ "
325
+ >
326
+ <p class="text-slate-400">
327
+ Fetching?
328
+ </p>
329
+ <p class="mt-1 font-semibold">
330
+ {{ queryMeta.isFetching ? 'Yes' : 'No' }}
331
+ </p>
332
+ </div>
333
+ <div
334
+ class="
335
+ rounded-lg bg-white/5 px-3 py-2 text-xs text-slate-100 ring-1
336
+ ring-white/10
337
+ "
338
+ >
339
+ <p class="text-slate-400">
340
+ Stale?
341
+ </p>
342
+ <p class="mt-1 font-semibold">
343
+ {{ queryMeta.isStale ? 'Yes' : 'No' }}
344
+ </p>
345
+ </div>
346
+ </div>
347
+ <pre
348
+ class="
349
+ mt-4 max-h-48 overflow-auto rounded-lg bg-black/40 p-3 text-left
350
+ text-xs/relaxed text-slate-100 ring-1 ring-white/10
351
+ "
352
+ >{{ JSON.stringify(queryMeta, null, 2) }}</pre>
353
+ </section>
354
+ </div>
355
+ </div>
356
+ </div>
357
+ </template>
@@ -0,0 +1,4 @@
1
+ export const helloKeys = {
2
+ all: ['hello'] as const,
3
+ detail: (name: string) => [...helloKeys.all, { name }] as const,
4
+ }
@@ -0,0 +1,13 @@
1
+ import { createRouter, createWebHistory } from 'vue-router'
2
+ import { handleHotUpdate, routes } from 'vue-router/auto-routes'
3
+
4
+ const router = createRouter({
5
+ history: createWebHistory(),
6
+ routes,
7
+ })
8
+
9
+ if (import.meta.hot) {
10
+ handleHotUpdate(router)
11
+ }
12
+
13
+ export default router
@@ -0,0 +1,24 @@
1
+ import { defineStore } from 'pinia'
2
+
3
+ import { createI18n } from 'vue-i18n'
4
+
5
+ export const i18n = createI18n({
6
+ legacy: false,
7
+ locale: 'en',
8
+ messages: {
9
+ en: {
10
+ hello: 'Hello World',
11
+ toggleLocale: 'toggle locale',
12
+ },
13
+ zh: {
14
+ hello: '你好世界',
15
+ toggleLocale: '切换语言',
16
+ },
17
+ },
18
+ })
19
+
20
+ export const useI18nStore = defineStore('i18n', {
21
+ state: () => ({
22
+ i18n,
23
+ }),
24
+ })
@@ -0,0 +1,15 @@
1
+ import { defineStore } from 'pinia'
2
+
3
+ export const useCounterStore = defineStore('counter', {
4
+ state: () => ({
5
+ counter: 0,
6
+ }),
7
+ getters: {
8
+ doubleCount: state => state.counter * 2,
9
+ },
10
+ actions: {
11
+ increment() {
12
+ this.counter++
13
+ },
14
+ },
15
+ })
@@ -0,0 +1 @@
1
+ @import 'tailwindcss';
@@ -0,0 +1,10 @@
1
+ import type { AppRouter } from '~/worker/trpc-router'
2
+ import { createTRPCProxyClient, httpBatchLink } from '@trpc/client'
3
+
4
+ export const client = createTRPCProxyClient<AppRouter>({
5
+ links: [
6
+ httpBatchLink({
7
+ url: '/api/trpc',
8
+ }),
9
+ ],
10
+ })
@@ -0,0 +1,2 @@
1
+ /// <reference types="vite/client" />
2
+ /// <reference types="unplugin-vue-router/client" />
@@ -0,0 +1,28 @@
1
+ {
2
+ "extends": "@vue/tsconfig/tsconfig.dom.json",
3
+ "compilerOptions": {
4
+ "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
5
+
6
+ "paths": {
7
+ "@/*": [
8
+ "./src/*"
9
+ ],
10
+ "~/*": [
11
+ "./*"
12
+ ]
13
+ },
14
+ /* Linting */
15
+ "strict": true,
16
+ "noFallthroughCasesInSwitch": true,
17
+ "noUnusedLocals": true,
18
+ "noUnusedParameters": true,
19
+ "erasableSyntaxOnly": true,
20
+ "noUncheckedSideEffectImports": true
21
+ },
22
+ "include": [
23
+ "./worker-configuration.d.ts",
24
+ "src/**/*.ts",
25
+ "src/**/*.tsx",
26
+ "src/**/*.vue"
27
+ ]
28
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "references": [
3
+ { "path": "./tsconfig.app.json" },
4
+ { "path": "./tsconfig.node.json" },
5
+ { "path": "./tsconfig.worker.json" }
6
+ ],
7
+ "files": []
8
+ }
@@ -0,0 +1,25 @@
1
+ {
2
+ "compilerOptions": {
3
+ "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
4
+ "target": "ES2023",
5
+ "lib": ["ES2023"],
6
+ "moduleDetection": "force",
7
+ "module": "ESNext",
8
+
9
+ /* Bundler mode */
10
+ "moduleResolution": "bundler",
11
+ "allowImportingTsExtensions": true,
12
+
13
+ /* Linting */
14
+ "strict": true,
15
+ "noFallthroughCasesInSwitch": true,
16
+ "noUnusedLocals": true,
17
+ "noUnusedParameters": true,
18
+ "noEmit": true,
19
+ "verbatimModuleSyntax": true,
20
+ "erasableSyntaxOnly": true,
21
+ "skipLibCheck": true,
22
+ "noUncheckedSideEffectImports": true
23
+ },
24
+ "include": ["vite.config.ts"]
25
+ }
@@ -0,0 +1,11 @@
1
+ {
2
+ "extends": "./tsconfig.node.json",
3
+ "compilerOptions": {
4
+ "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.worker.tsbuildinfo",
5
+ "types": [
6
+ "./worker-configuration.d.ts",
7
+ "vite/client"
8
+ ]
9
+ },
10
+ "include": ["worker"]
11
+ }
@@ -0,0 +1,57 @@
1
+ import type { PluginOption } from 'vite'
2
+ import path from 'node:path'
3
+ import { cloudflare } from '@cloudflare/vite-plugin'
4
+ import Tailwindcss from '@tailwindcss/vite'
5
+ import Vue from '@vitejs/plugin-vue'
6
+ import VueJsx from '@vitejs/plugin-vue-jsx'
7
+ import VueRouter from 'unplugin-vue-router/vite'
8
+ import { defineConfig } from 'vite'
9
+ import VueDevTools from 'vite-plugin-vue-devtools'
10
+
11
+ const ensureVitePlugin = <T>(plugin: T) => plugin as unknown as PluginOption
12
+ // https://vite.dev/config/
13
+ export default defineConfig({
14
+ resolve: {
15
+ alias: {
16
+ '@': path.resolve(import.meta.dirname, 'src'),
17
+ '~': import.meta.dirname,
18
+ },
19
+ },
20
+ plugins: [
21
+ ensureVitePlugin(
22
+ VueRouter(
23
+ {
24
+ dts: path.resolve(import.meta.dirname, 'src/types/typed-router.d.ts'),
25
+ },
26
+ ),
27
+ ),
28
+ ensureVitePlugin(Vue()),
29
+ ensureVitePlugin(VueJsx()),
30
+ ensureVitePlugin(Tailwindcss()),
31
+ ensureVitePlugin(cloudflare()),
32
+ ensureVitePlugin(VueDevTools()),
33
+ ],
34
+ build: {
35
+ target: 'esnext',
36
+ minify: 'esbuild',
37
+ chunkSizeWarningLimit: 1000,
38
+ rollupOptions: {
39
+ output: {
40
+ manualChunks: {
41
+ 'vue-vendor': ['vue', 'vue-router', 'pinia'],
42
+ 'query-vendor': ['@tanstack/vue-query'],
43
+ 'trpc-vendor': ['@trpc/client'],
44
+ },
45
+ },
46
+ },
47
+ },
48
+ server: {
49
+ // proxy: {
50
+ // '/api': {
51
+ // target: `http://localhost:8787`,
52
+ // changeOrigin: true,
53
+ // // rewrite: path => path.replace(/^/api/, ''),
54
+ // },
55
+ // },
56
+ },
57
+ })
@@ -0,0 +1,24 @@
1
+ import { trpcServer } from '@hono/trpc-server'
2
+ import { Hono } from 'hono'
3
+ import { appRouter } from './trpc-router'
4
+
5
+ const app = new Hono()
6
+
7
+ app.get('/api', (c) => {
8
+ return c.json({
9
+ message: 'Hello World',
10
+ })
11
+ })
12
+
13
+ app.use(
14
+ '/api/trpc/*',
15
+ trpcServer({
16
+ endpoint: '/api/trpc',
17
+ router: appRouter,
18
+ }),
19
+ )
20
+
21
+ export {
22
+ app,
23
+
24
+ }
@@ -0,0 +1 @@
1
+ export const port = 8787
@@ -0,0 +1,5 @@
1
+ import { app } from './app'
2
+
3
+ export default {
4
+ fetch: app.fetch,
5
+ } satisfies ExportedHandler<Env>
@@ -0,0 +1,13 @@
1
+ import { serve } from '@hono/node-server'
2
+ import { consola } from 'consola'
3
+ import { logger } from 'hono/logger'
4
+ import { app } from './app'
5
+ import { port } from './config'
6
+
7
+ app.use(logger())
8
+ serve({
9
+ fetch: app.fetch,
10
+ port,
11
+ })
12
+
13
+ consola.success(`Server listening on http://localhost:${port}`)
@@ -0,0 +1,24 @@
1
+ import { initTRPC } from '@trpc/server'
2
+ import { z } from 'zod'
3
+
4
+ const t = initTRPC.create()
5
+
6
+ const publicProcedure = t.procedure
7
+ const router = t.router
8
+
9
+ export const appRouter = router({
10
+ hello: publicProcedure.input(z.string().nullish()).query(({ input }) => {
11
+ return {
12
+ message: `hello ${input || 'world'}`,
13
+ time: Date.now(),
14
+ }
15
+ }),
16
+ sayHello: publicProcedure
17
+ .input(z.object({ name: z.string() }))
18
+ .output(z.object({ greeting: z.string() }))
19
+ .query(({ input }) => {
20
+ return { greeting: `Hello ${input.name}!` }
21
+ }),
22
+ })
23
+
24
+ export type AppRouter = typeof appRouter
@@ -0,0 +1,24 @@
1
+ {
2
+ "$schema": "./node_modules/wrangler/config-schema.json",
3
+ "name": "monorepo-client",
4
+ "compatibility_date": "2025-10-16",
5
+ "main": "./worker/fetch-entry.ts",
6
+ "assets": {
7
+ "not_found_handling": "single-page-application",
8
+ "run_worker_first": [
9
+ "/api/*"
10
+ ]
11
+ },
12
+ "dev": {
13
+ "port": 8787
14
+ },
15
+ "routes": [
16
+ {
17
+ "custom_domain": true,
18
+ "pattern": "client.monorepo.icebreaker.top"
19
+ }
20
+ ],
21
+ "observability": {
22
+ "enabled": true
23
+ }
24
+ }