vợ bảo okeoke

This commit is contained in:
2026-01-02 22:00:50 +07:00
parent 16f64c5e4b
commit 2b0f88fa16
19 changed files with 415 additions and 87 deletions

90
auto-imports.d.ts vendored Normal file
View File

@@ -0,0 +1,90 @@
/* eslint-disable */
/* prettier-ignore */
// @ts-nocheck
// noinspection JSUnusedGlobalSymbols
// Generated by unplugin-auto-import
// biome-ignore lint: disable
export {}
declare global {
const EffectScope: typeof import('vue').EffectScope
const acceptHMRUpdate: typeof import('pinia').acceptHMRUpdate
const computed: typeof import('vue').computed
const createApp: typeof import('vue').createApp
const createPinia: typeof import('pinia').createPinia
const customRef: typeof import('vue').customRef
const defineAsyncComponent: typeof import('vue').defineAsyncComponent
const defineComponent: typeof import('vue').defineComponent
const defineStore: typeof import('pinia').defineStore
const effectScope: typeof import('vue').effectScope
const getActivePinia: typeof import('pinia').getActivePinia
const getCurrentInstance: typeof import('vue').getCurrentInstance
const getCurrentScope: typeof import('vue').getCurrentScope
const getCurrentWatcher: typeof import('vue').getCurrentWatcher
const h: typeof import('vue').h
const inject: typeof import('vue').inject
const isProxy: typeof import('vue').isProxy
const isReactive: typeof import('vue').isReactive
const isReadonly: typeof import('vue').isReadonly
const isRef: typeof import('vue').isRef
const isShallow: typeof import('vue').isShallow
const mapActions: typeof import('pinia').mapActions
const mapGetters: typeof import('pinia').mapGetters
const mapState: typeof import('pinia').mapState
const mapStores: typeof import('pinia').mapStores
const mapWritableState: typeof import('pinia').mapWritableState
const markRaw: typeof import('vue').markRaw
const nextTick: typeof import('vue').nextTick
const onActivated: typeof import('vue').onActivated
const onBeforeMount: typeof import('vue').onBeforeMount
const onBeforeRouteLeave: typeof import('vue-router').onBeforeRouteLeave
const onBeforeRouteUpdate: typeof import('vue-router').onBeforeRouteUpdate
const onBeforeUnmount: typeof import('vue').onBeforeUnmount
const onBeforeUpdate: typeof import('vue').onBeforeUpdate
const onDeactivated: typeof import('vue').onDeactivated
const onErrorCaptured: typeof import('vue').onErrorCaptured
const onMounted: typeof import('vue').onMounted
const onRenderTracked: typeof import('vue').onRenderTracked
const onRenderTriggered: typeof import('vue').onRenderTriggered
const onScopeDispose: typeof import('vue').onScopeDispose
const onServerPrefetch: typeof import('vue').onServerPrefetch
const onUnmounted: typeof import('vue').onUnmounted
const onUpdated: typeof import('vue').onUpdated
const onWatcherCleanup: typeof import('vue').onWatcherCleanup
const provide: typeof import('vue').provide
const reactive: typeof import('vue').reactive
const readonly: typeof import('vue').readonly
const ref: typeof import('vue').ref
const resolveComponent: typeof import('vue').resolveComponent
const setActivePinia: typeof import('pinia').setActivePinia
const setMapStoreSuffix: typeof import('pinia').setMapStoreSuffix
const shallowReactive: typeof import('vue').shallowReactive
const shallowReadonly: typeof import('vue').shallowReadonly
const shallowRef: typeof import('vue').shallowRef
const storeToRefs: typeof import('pinia').storeToRefs
const toRaw: typeof import('vue').toRaw
const toRef: typeof import('vue').toRef
const toRefs: typeof import('vue').toRefs
const toValue: typeof import('vue').toValue
const triggerRef: typeof import('vue').triggerRef
const unref: typeof import('vue').unref
const useAttrs: typeof import('vue').useAttrs
const useCssModule: typeof import('vue').useCssModule
const useCssVars: typeof import('vue').useCssVars
const useId: typeof import('vue').useId
const useLink: typeof import('vue-router').useLink
const useModel: typeof import('vue').useModel
const useRoute: typeof import('vue-router').useRoute
const useRouter: typeof import('vue-router').useRouter
const useSlots: typeof import('vue').useSlots
const useTemplateRef: typeof import('vue').useTemplateRef
const watch: typeof import('vue').watch
const watchEffect: typeof import('vue').watchEffect
const watchPostEffect: typeof import('vue').watchPostEffect
const watchSyncEffect: typeof import('vue').watchSyncEffect
}
// for type re-export
declare global {
// @ts-ignore
export type { Component, Slot, Slots, ComponentPublicInstance, ComputedRef, DirectiveBinding, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, ShallowRef, MaybeRef, MaybeRefOrGetter, VNode, WritableComputedRef } from 'vue'
import('vue')
}

View File

@@ -30,6 +30,7 @@
"@vitejs/plugin-vue": "^6.0.3", "@vitejs/plugin-vue": "^6.0.3",
"@vitejs/plugin-vue-jsx": "^5.1.3", "@vitejs/plugin-vue-jsx": "^5.1.3",
"unocss": "^66.5.12", "unocss": "^66.5.12",
"unplugin-auto-import": "^20.3.0",
"unplugin-vue-components": "^30.0.0", "unplugin-vue-components": "^30.0.0",
"vite": "^7.3.0", "vite": "^7.3.0",
"vite-ssr-components": "^0.5.2", "vite-ssr-components": "^0.5.2",
@@ -654,7 +655,9 @@
"escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="], "escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="],
"estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="], "escape-string-regexp": ["escape-string-regexp@5.0.0", "", {}, "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw=="],
"estree-walker": ["estree-walker@3.0.3", "", { "dependencies": { "@types/estree": "^1.0.0" } }, "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g=="],
"exit-hook": ["exit-hook@2.2.1", "", {}, "sha512-eNTPlAD67BmP31LDINZ3U7HSF8l57TxOY2PmBJ1shpCvpnxBF93mWCE8YHBnXs8qiUZJc9WDcWIeC3a2HIAMfw=="], "exit-hook": ["exit-hook@2.2.1", "", {}, "sha512-eNTPlAD67BmP31LDINZ3U7HSF8l57TxOY2PmBJ1shpCvpnxBF93mWCE8YHBnXs8qiUZJc9WDcWIeC3a2HIAMfw=="],
@@ -752,6 +755,8 @@
"rollup": ["rollup@4.54.0", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.54.0", "@rollup/rollup-android-arm64": "4.54.0", "@rollup/rollup-darwin-arm64": "4.54.0", "@rollup/rollup-darwin-x64": "4.54.0", "@rollup/rollup-freebsd-arm64": "4.54.0", "@rollup/rollup-freebsd-x64": "4.54.0", "@rollup/rollup-linux-arm-gnueabihf": "4.54.0", "@rollup/rollup-linux-arm-musleabihf": "4.54.0", "@rollup/rollup-linux-arm64-gnu": "4.54.0", "@rollup/rollup-linux-arm64-musl": "4.54.0", "@rollup/rollup-linux-loong64-gnu": "4.54.0", "@rollup/rollup-linux-ppc64-gnu": "4.54.0", "@rollup/rollup-linux-riscv64-gnu": "4.54.0", "@rollup/rollup-linux-riscv64-musl": "4.54.0", "@rollup/rollup-linux-s390x-gnu": "4.54.0", "@rollup/rollup-linux-x64-gnu": "4.54.0", "@rollup/rollup-linux-x64-musl": "4.54.0", "@rollup/rollup-openharmony-arm64": "4.54.0", "@rollup/rollup-win32-arm64-msvc": "4.54.0", "@rollup/rollup-win32-ia32-msvc": "4.54.0", "@rollup/rollup-win32-x64-gnu": "4.54.0", "@rollup/rollup-win32-x64-msvc": "4.54.0", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-3nk8Y3a9Ea8szgKhinMlGMhGMw89mqule3KWczxhIzqudyHdCIOHw8WJlj/r329fACjKLEh13ZSk7oE22kyeIw=="], "rollup": ["rollup@4.54.0", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.54.0", "@rollup/rollup-android-arm64": "4.54.0", "@rollup/rollup-darwin-arm64": "4.54.0", "@rollup/rollup-darwin-x64": "4.54.0", "@rollup/rollup-freebsd-arm64": "4.54.0", "@rollup/rollup-freebsd-x64": "4.54.0", "@rollup/rollup-linux-arm-gnueabihf": "4.54.0", "@rollup/rollup-linux-arm-musleabihf": "4.54.0", "@rollup/rollup-linux-arm64-gnu": "4.54.0", "@rollup/rollup-linux-arm64-musl": "4.54.0", "@rollup/rollup-linux-loong64-gnu": "4.54.0", "@rollup/rollup-linux-ppc64-gnu": "4.54.0", "@rollup/rollup-linux-riscv64-gnu": "4.54.0", "@rollup/rollup-linux-riscv64-musl": "4.54.0", "@rollup/rollup-linux-s390x-gnu": "4.54.0", "@rollup/rollup-linux-x64-gnu": "4.54.0", "@rollup/rollup-linux-x64-musl": "4.54.0", "@rollup/rollup-openharmony-arm64": "4.54.0", "@rollup/rollup-win32-arm64-msvc": "4.54.0", "@rollup/rollup-win32-ia32-msvc": "4.54.0", "@rollup/rollup-win32-x64-gnu": "4.54.0", "@rollup/rollup-win32-x64-msvc": "4.54.0", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-3nk8Y3a9Ea8szgKhinMlGMhGMw89mqule3KWczxhIzqudyHdCIOHw8WJlj/r329fACjKLEh13ZSk7oE22kyeIw=="],
"scule": ["scule@1.3.0", "", {}, "sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g=="],
"semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], "semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
"sharp": ["sharp@0.33.5", "", { "dependencies": { "color": "^4.2.3", "detect-libc": "^2.0.3", "semver": "^7.6.3" }, "optionalDependencies": { "@img/sharp-darwin-arm64": "0.33.5", "@img/sharp-darwin-x64": "0.33.5", "@img/sharp-libvips-darwin-arm64": "1.0.4", "@img/sharp-libvips-darwin-x64": "1.0.4", "@img/sharp-libvips-linux-arm": "1.0.5", "@img/sharp-libvips-linux-arm64": "1.0.4", "@img/sharp-libvips-linux-s390x": "1.0.4", "@img/sharp-libvips-linux-x64": "1.0.4", "@img/sharp-libvips-linuxmusl-arm64": "1.0.4", "@img/sharp-libvips-linuxmusl-x64": "1.0.4", "@img/sharp-linux-arm": "0.33.5", "@img/sharp-linux-arm64": "0.33.5", "@img/sharp-linux-s390x": "0.33.5", "@img/sharp-linux-x64": "0.33.5", "@img/sharp-linuxmusl-arm64": "0.33.5", "@img/sharp-linuxmusl-x64": "0.33.5", "@img/sharp-wasm32": "0.33.5", "@img/sharp-win32-ia32": "0.33.5", "@img/sharp-win32-x64": "0.33.5" } }, "sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw=="], "sharp": ["sharp@0.33.5", "", { "dependencies": { "color": "^4.2.3", "detect-libc": "^2.0.3", "semver": "^7.6.3" }, "optionalDependencies": { "@img/sharp-darwin-arm64": "0.33.5", "@img/sharp-darwin-x64": "0.33.5", "@img/sharp-libvips-darwin-arm64": "1.0.4", "@img/sharp-libvips-darwin-x64": "1.0.4", "@img/sharp-libvips-linux-arm": "1.0.5", "@img/sharp-libvips-linux-arm64": "1.0.4", "@img/sharp-libvips-linux-s390x": "1.0.4", "@img/sharp-libvips-linux-x64": "1.0.4", "@img/sharp-libvips-linuxmusl-arm64": "1.0.4", "@img/sharp-libvips-linuxmusl-x64": "1.0.4", "@img/sharp-linux-arm": "0.33.5", "@img/sharp-linux-arm64": "0.33.5", "@img/sharp-linux-s390x": "0.33.5", "@img/sharp-linux-x64": "0.33.5", "@img/sharp-linuxmusl-arm64": "0.33.5", "@img/sharp-linuxmusl-x64": "0.33.5", "@img/sharp-wasm32": "0.33.5", "@img/sharp-win32-ia32": "0.33.5", "@img/sharp-win32-x64": "0.33.5" } }, "sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw=="],
@@ -766,6 +771,8 @@
"stoppable": ["stoppable@1.1.0", "", {}, "sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw=="], "stoppable": ["stoppable@1.1.0", "", {}, "sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw=="],
"strip-literal": ["strip-literal@3.1.0", "", { "dependencies": { "js-tokens": "^9.0.1" } }, "sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg=="],
"strnum": ["strnum@2.1.2", "", {}, "sha512-l63NF9y/cLROq/yqKXSLtcMeeyOfnSQlfMSlzFt/K73oIaD8DGaQWd7Z34X9GPiKqP5rbSh84Hl4bOlLcjiSrQ=="], "strnum": ["strnum@2.1.2", "", {}, "sha512-l63NF9y/cLROq/yqKXSLtcMeeyOfnSQlfMSlzFt/K73oIaD8DGaQWd7Z34X9GPiKqP5rbSh84Hl4bOlLcjiSrQ=="],
"superjson": ["superjson@2.2.6", "", { "dependencies": { "copy-anything": "^4" } }, "sha512-H+ue8Zo4vJmV2nRjpx86P35lzwDT3nItnIsocgumgr0hHMQ+ZGq5vrERg9kJBo5AWGmxZDhzDo+WVIJqkB0cGA=="], "superjson": ["superjson@2.2.6", "", { "dependencies": { "copy-anything": "^4" } }, "sha512-H+ue8Zo4vJmV2nRjpx86P35lzwDT3nItnIsocgumgr0hHMQ+ZGq5vrERg9kJBo5AWGmxZDhzDo+WVIJqkB0cGA=="],
@@ -796,10 +803,14 @@
"unhead": ["unhead@2.1.1", "", { "dependencies": { "hookable": "^5.5.3" } }, "sha512-NOt8n2KybAOxSLfNXegAVai4SGU8bPKqWnqCzNAvnRH2i8mW+0bbFjN/L75LBgCSTiOjJSpANe5w2V34Grr7Cw=="], "unhead": ["unhead@2.1.1", "", { "dependencies": { "hookable": "^5.5.3" } }, "sha512-NOt8n2KybAOxSLfNXegAVai4SGU8bPKqWnqCzNAvnRH2i8mW+0bbFjN/L75LBgCSTiOjJSpANe5w2V34Grr7Cw=="],
"unimport": ["unimport@5.6.0", "", { "dependencies": { "acorn": "^8.15.0", "escape-string-regexp": "^5.0.0", "estree-walker": "^3.0.3", "local-pkg": "^1.1.2", "magic-string": "^0.30.21", "mlly": "^1.8.0", "pathe": "^2.0.3", "picomatch": "^4.0.3", "pkg-types": "^2.3.0", "scule": "^1.3.0", "strip-literal": "^3.1.0", "tinyglobby": "^0.2.15", "unplugin": "^2.3.11", "unplugin-utils": "^0.3.1" } }, "sha512-8rqAmtJV8o60x46kBAJKtHpJDJWkA2xcBqWKPI14MgUb05o1pnpnCnXSxedUXyeq7p8fR5g3pTo2BaswZ9lD9A=="],
"unocss": ["unocss@66.5.12", "", { "dependencies": { "@unocss/astro": "66.5.12", "@unocss/cli": "66.5.12", "@unocss/core": "66.5.12", "@unocss/postcss": "66.5.12", "@unocss/preset-attributify": "66.5.12", "@unocss/preset-icons": "66.5.12", "@unocss/preset-mini": "66.5.12", "@unocss/preset-tagify": "66.5.12", "@unocss/preset-typography": "66.5.12", "@unocss/preset-uno": "66.5.12", "@unocss/preset-web-fonts": "66.5.12", "@unocss/preset-wind": "66.5.12", "@unocss/preset-wind3": "66.5.12", "@unocss/preset-wind4": "66.5.12", "@unocss/transformer-attributify-jsx": "66.5.12", "@unocss/transformer-compile-class": "66.5.12", "@unocss/transformer-directives": "66.5.12", "@unocss/transformer-variant-group": "66.5.12", "@unocss/vite": "66.5.12" }, "peerDependencies": { "@unocss/webpack": "66.5.12", "vite": "^2.9.0 || ^3.0.0-0 || ^4.0.0 || ^5.0.0-0 || ^6.0.0-0 || ^7.0.0-0 || ^8.0.0-0" }, "optionalPeers": ["@unocss/webpack", "vite"] }, "sha512-3WdSuM+SOjVpXDtffTuSvYTMuufpFzBehu2b4Tr7DcoIUxGouZn3mdxCLx3PiEuK0ih40Fo7Sjm+J4mccHfwLg=="], "unocss": ["unocss@66.5.12", "", { "dependencies": { "@unocss/astro": "66.5.12", "@unocss/cli": "66.5.12", "@unocss/core": "66.5.12", "@unocss/postcss": "66.5.12", "@unocss/preset-attributify": "66.5.12", "@unocss/preset-icons": "66.5.12", "@unocss/preset-mini": "66.5.12", "@unocss/preset-tagify": "66.5.12", "@unocss/preset-typography": "66.5.12", "@unocss/preset-uno": "66.5.12", "@unocss/preset-web-fonts": "66.5.12", "@unocss/preset-wind": "66.5.12", "@unocss/preset-wind3": "66.5.12", "@unocss/preset-wind4": "66.5.12", "@unocss/transformer-attributify-jsx": "66.5.12", "@unocss/transformer-compile-class": "66.5.12", "@unocss/transformer-directives": "66.5.12", "@unocss/transformer-variant-group": "66.5.12", "@unocss/vite": "66.5.12" }, "peerDependencies": { "@unocss/webpack": "66.5.12", "vite": "^2.9.0 || ^3.0.0-0 || ^4.0.0 || ^5.0.0-0 || ^6.0.0-0 || ^7.0.0-0 || ^8.0.0-0" }, "optionalPeers": ["@unocss/webpack", "vite"] }, "sha512-3WdSuM+SOjVpXDtffTuSvYTMuufpFzBehu2b4Tr7DcoIUxGouZn3mdxCLx3PiEuK0ih40Fo7Sjm+J4mccHfwLg=="],
"unplugin": ["unplugin@2.3.11", "", { "dependencies": { "@jridgewell/remapping": "^2.3.5", "acorn": "^8.15.0", "picomatch": "^4.0.3", "webpack-virtual-modules": "^0.6.2" } }, "sha512-5uKD0nqiYVzlmCRs01Fhs2BdkEgBS3SAVP6ndrBsuK42iC2+JHyxM05Rm9G8+5mkmRtzMZGY8Ct5+mliZxU/Ww=="], "unplugin": ["unplugin@2.3.11", "", { "dependencies": { "@jridgewell/remapping": "^2.3.5", "acorn": "^8.15.0", "picomatch": "^4.0.3", "webpack-virtual-modules": "^0.6.2" } }, "sha512-5uKD0nqiYVzlmCRs01Fhs2BdkEgBS3SAVP6ndrBsuK42iC2+JHyxM05Rm9G8+5mkmRtzMZGY8Ct5+mliZxU/Ww=="],
"unplugin-auto-import": ["unplugin-auto-import@20.3.0", "", { "dependencies": { "local-pkg": "^1.1.2", "magic-string": "^0.30.21", "picomatch": "^4.0.3", "unimport": "^5.5.0", "unplugin": "^2.3.11", "unplugin-utils": "^0.3.1" }, "peerDependencies": { "@nuxt/kit": "^4.0.0", "@vueuse/core": "*" }, "optionalPeers": ["@nuxt/kit", "@vueuse/core"] }, "sha512-RcSEQiVv7g0mLMMXibYVKk8mpteKxvyffGuDKqZZiFr7Oq3PB1HwgHdK5O7H4AzbhzHoVKG0NnMnsk/1HIVYzQ=="],
"unplugin-utils": ["unplugin-utils@0.3.1", "", { "dependencies": { "pathe": "^2.0.3", "picomatch": "^4.0.3" } }, "sha512-5lWVjgi6vuHhJ526bI4nlCOmkCIF3nnfXkCMDeMJrtdvxTs6ZFCM8oNufGTsDbKv/tJ/xj8RpvXjRuPBZJuJog=="], "unplugin-utils": ["unplugin-utils@0.3.1", "", { "dependencies": { "pathe": "^2.0.3", "picomatch": "^4.0.3" } }, "sha512-5lWVjgi6vuHhJ526bI4nlCOmkCIF3nnfXkCMDeMJrtdvxTs6ZFCM8oNufGTsDbKv/tJ/xj8RpvXjRuPBZJuJog=="],
"unplugin-vue-components": ["unplugin-vue-components@30.0.0", "", { "dependencies": { "chokidar": "^4.0.3", "debug": "^4.4.3", "local-pkg": "^1.1.2", "magic-string": "^0.30.19", "mlly": "^1.8.0", "tinyglobby": "^0.2.15", "unplugin": "^2.3.10", "unplugin-utils": "^0.3.1" }, "peerDependencies": { "@babel/parser": "^7.15.8", "@nuxt/kit": "^3.2.2 || ^4.0.0", "vue": "2 || 3" }, "optionalPeers": ["@babel/parser", "@nuxt/kit"] }, "sha512-4qVE/lwCgmdPTp6h0qsRN2u642tt4boBQtcpn4wQcWZAsr8TQwq+SPT3NDu/6kBFxzo/sSEK4ioXhOOBrXc3iw=="], "unplugin-vue-components": ["unplugin-vue-components@30.0.0", "", { "dependencies": { "chokidar": "^4.0.3", "debug": "^4.4.3", "local-pkg": "^1.1.2", "magic-string": "^0.30.19", "mlly": "^1.8.0", "tinyglobby": "^0.2.15", "unplugin": "^2.3.10", "unplugin-utils": "^0.3.1" }, "peerDependencies": { "@babel/parser": "^7.15.8", "@nuxt/kit": "^3.2.2 || ^4.0.0", "vue": "2 || 3" }, "optionalPeers": ["@babel/parser", "@nuxt/kit"] }, "sha512-4qVE/lwCgmdPTp6h0qsRN2u642tt4boBQtcpn4wQcWZAsr8TQwq+SPT3NDu/6kBFxzo/sSEK4ioXhOOBrXc3iw=="],
@@ -856,6 +867,10 @@
"@vitejs/plugin-vue-jsx/@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-beta.9-commit.d91dfb5", "", {}, "sha512-8sExkWRK+zVybw3+2/kBkYBFeLnEUWz1fT7BLHplpzmtqkOfTbAQ9gkt4pzwGIIZmg4Qn5US5ACjUBenrhezwQ=="], "@vitejs/plugin-vue-jsx/@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-beta.9-commit.d91dfb5", "", {}, "sha512-8sExkWRK+zVybw3+2/kBkYBFeLnEUWz1fT7BLHplpzmtqkOfTbAQ9gkt4pzwGIIZmg4Qn5US5ACjUBenrhezwQ=="],
"@vue/compiler-core/estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="],
"@vue/compiler-sfc/estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="],
"@vue/devtools-kit/perfect-debounce": ["perfect-debounce@1.0.0", "", {}, "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA=="], "@vue/devtools-kit/perfect-debounce": ["perfect-debounce@1.0.0", "", {}, "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA=="],
"miniflare/zod": ["zod@3.22.3", "", {}, "sha512-EjIevzuJRiRPbVH4mGc8nApb/lVLKVpmUhAaR5R5doKGfAnGJ6Gr3CViAVjP+4FWSxCsybeWQdcgCtbX+7oZug=="], "miniflare/zod": ["zod@3.22.3", "", {}, "sha512-EjIevzuJRiRPbVH4mGc8nApb/lVLKVpmUhAaR5R5doKGfAnGJ6Gr3CViAVjP+4FWSxCsybeWQdcgCtbX+7oZug=="],
@@ -866,10 +881,14 @@
"sharp/semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="], "sharp/semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="],
"strip-literal/js-tokens": ["js-tokens@9.0.1", "", {}, "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ=="],
"unconfig/quansync": ["quansync@1.0.0", "", {}, "sha512-5xZacEEufv3HSTPQuchrvV6soaiACMFnq1H8wkVioctoH3TRha9Sz66lOxRwPK/qZj7HPiSveih9yAyh98gvqA=="], "unconfig/quansync": ["quansync@1.0.0", "", {}, "sha512-5xZacEEufv3HSTPQuchrvV6soaiACMFnq1H8wkVioctoH3TRha9Sz66lOxRwPK/qZj7HPiSveih9yAyh98gvqA=="],
"unconfig-core/quansync": ["quansync@1.0.0", "", {}, "sha512-5xZacEEufv3HSTPQuchrvV6soaiACMFnq1H8wkVioctoH3TRha9Sz66lOxRwPK/qZj7HPiSveih9yAyh98gvqA=="], "unconfig-core/quansync": ["quansync@1.0.0", "", {}, "sha512-5xZacEEufv3HSTPQuchrvV6soaiACMFnq1H8wkVioctoH3TRha9Sz66lOxRwPK/qZj7HPiSveih9yAyh98gvqA=="],
"unimport/acorn": ["acorn@8.15.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg=="],
"unplugin/acorn": ["acorn@8.15.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg=="], "unplugin/acorn": ["acorn@8.15.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg=="],
"vue-router/@vue/devtools-api": ["@vue/devtools-api@6.6.4", "", {}, "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g=="], "vue-router/@vue/devtools-api": ["@vue/devtools-api@6.6.4", "", {}, "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g=="],

58
components.d.ts vendored Normal file
View File

@@ -0,0 +1,58 @@
/* eslint-disable */
// @ts-nocheck
// biome-ignore lint: disable
// oxlint-disable
// ------
// Generated by unplugin-vue-components
// Read more: https://github.com/vuejs/core/pull/3399
import { GlobalComponents } from 'vue'
export {}
/* prettier-ignore */
declare module 'vue' {
export interface GlobalComponents {
Add: typeof import('./src/components/icons/Add.vue')['default']
AddFilled: typeof import('./src/components/icons/AddFilled.vue')['default']
Bell: typeof import('./src/components/icons/Bell.vue')['default']
BellFilled: typeof import('./src/components/icons/BellFilled.vue')['default']
Button: typeof import('primevue/button')['default']
Checkbox: typeof import('primevue/checkbox')['default']
DashboardLayout: typeof import('./src/components/DashboardLayout.vue')['default']
Home: typeof import('./src/components/icons/Home.vue')['default']
HomeFilled: typeof import('./src/components/icons/HomeFilled.vue')['default']
InputText: typeof import('primevue/inputtext')['default']
Layout: typeof import('./src/components/icons/Layout.vue')['default']
LayoutFilled: typeof import('./src/components/icons/LayoutFilled.vue')['default']
Message: typeof import('primevue/message')['default']
Password: typeof import('primevue/password')['default']
RootLayout: typeof import('./src/components/RootLayout.vue')['default']
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
TestIcon: typeof import('./src/components/icons/TestIcon.vue')['default']
VueHead: typeof import('./src/components/VueHead.tsx')['default']
}
}
// For TSX support
declare global {
const Add: typeof import('./src/components/icons/Add.vue')['default']
const AddFilled: typeof import('./src/components/icons/AddFilled.vue')['default']
const Bell: typeof import('./src/components/icons/Bell.vue')['default']
const BellFilled: typeof import('./src/components/icons/BellFilled.vue')['default']
const Button: typeof import('primevue/button')['default']
const Checkbox: typeof import('primevue/checkbox')['default']
const DashboardLayout: typeof import('./src/components/DashboardLayout.vue')['default']
const Home: typeof import('./src/components/icons/Home.vue')['default']
const HomeFilled: typeof import('./src/components/icons/HomeFilled.vue')['default']
const InputText: typeof import('primevue/inputtext')['default']
const Layout: typeof import('./src/components/icons/Layout.vue')['default']
const LayoutFilled: typeof import('./src/components/icons/LayoutFilled.vue')['default']
const Message: typeof import('primevue/message')['default']
const Password: typeof import('primevue/password')['default']
const RootLayout: typeof import('./src/components/RootLayout.vue')['default']
const RouterLink: typeof import('vue-router')['RouterLink']
const RouterView: typeof import('vue-router')['RouterView']
const TestIcon: typeof import('./src/components/icons/TestIcon.vue')['default']
const VueHead: typeof import('./src/components/VueHead.tsx')['default']
}

View File

@@ -35,6 +35,7 @@
"@vitejs/plugin-vue": "^6.0.3", "@vitejs/plugin-vue": "^6.0.3",
"@vitejs/plugin-vue-jsx": "^5.1.3", "@vitejs/plugin-vue-jsx": "^5.1.3",
"unocss": "^66.5.12", "unocss": "^66.5.12",
"unplugin-auto-import": "^20.3.0",
"unplugin-vue-components": "^30.0.0", "unplugin-vue-components": "^30.0.0",
"vite": "^7.3.0", "vite": "^7.3.0",
"vite-ssr-components": "^0.5.2", "vite-ssr-components": "^0.5.2",

View File

@@ -0,0 +1,57 @@
import { TinyRpcClientAdapter, TinyRpcError } from "@hiogawa/tiny-rpc";
import { Result } from "@hiogawa/utils";
const GET_PAYLOAD_PARAM = "payload";
export function httpClientAdapter(opts: {
url: string;
pathsForGET?: string[];
}): TinyRpcClientAdapter {
return {
send: async (data) => {
const url = [opts.url, data.path].join("/");
const payload = JSON.stringify(data.args);
const method = opts.pathsForGET?.includes(data.path)
? "GET"
: "POST";
let req: Request;
if (method === "GET") {
req = new Request(
url +
"?" +
new URLSearchParams({ [GET_PAYLOAD_PARAM]: payload })
);
} else {
req = new Request(url, {
method: "POST",
body: payload,
headers: {
"content-type": "application/json; charset=utf-8",
},
credentials: "include",
});
}
let res: Response;
res = await fetch(req);
if (!res.ok) {
// throw new Error(`HTTP error: ${res.status}`);
throw new Error(
JSON.stringify({
status: res.status,
statusText: res.statusText,
data: { message: await res.text() },
internal: true,
})
);
// throw TinyRpcError.deserialize(res.status);
}
const result: Result<unknown, unknown> = JSON.parse(
await res.text()
);
if (!result.ok) {
throw TinyRpcError.deserialize(result.value);
}
return result.value;
},
};
}

View File

@@ -0,0 +1,69 @@
import { TinyRpcClientAdapter, TinyRpcError } from "@hiogawa/tiny-rpc";
import { Result } from "@hiogawa/utils";
import { tryGetContext } from "hono/context-storage";
const GET_PAYLOAD_PARAM = "payload";
export function httpClientAdapter(opts: {
url: string;
pathsForGET?: string[];
}): TinyRpcClientAdapter {
return {
send: async (data) => {
const url = [opts.url, data.path].join("/");
const payload = JSON.stringify(data.args);
const method = opts.pathsForGET?.includes(data.path)
? "GET"
: "POST";
let req: Request;
if (method === "GET") {
req = new Request(
url +
"?" +
new URLSearchParams({ [GET_PAYLOAD_PARAM]: payload })
);
} else {
req = new Request(url, {
method: "POST",
body: payload,
headers: {
"content-type": "application/json; charset=utf-8",
},
credentials: "include",
});
}
let res: Response;
if (import.meta.env.SSR) {
const c = tryGetContext<any>();
if (!c) {
throw new Error("Hono context not found in SSR");
}
Object.entries(c.req.header()).forEach(([k, v]) => {
req.headers.append(k, v);
});
res = await c.get("fetch")(req);
} else {
res = await fetch(req);
}
if (!res.ok) {
// throw new Error(`HTTP error: ${res.status}`);
throw new Error(
JSON.stringify({
status: res.status,
statusText: res.statusText,
data: { message: await res.text() },
internal: true,
})
);
// throw TinyRpcError.deserialize(res.status);
}
const result: Result<unknown, unknown> = JSON.parse(
await res.text()
);
if (!result.ok) {
throw TinyRpcError.deserialize(result.value);
}
return result.value;
},
};
}

View File

@@ -164,6 +164,7 @@ const login = async (username: string, password: string) => {
}; };
async function checkAuth() { async function checkAuth() {
console.log("Check auth called");
const context = getContext<HonoVarTypes>(); const context = getContext<HonoVarTypes>();
const token = getCookie(context, 'auth_token'); const token = getCookie(context, 'auth_token');
@@ -182,6 +183,7 @@ async function checkAuth() {
if (!userRecord) { if (!userRecord) {
return { authenticated: false, user: null }; return { authenticated: false, user: null };
} }
// console.log("Check auth called 2", userRecord);
return { return {
authenticated: true, authenticated: true,

View File

@@ -5,6 +5,8 @@ import {
} from "@hiogawa/tiny-rpc"; } from "@hiogawa/tiny-rpc";
import type { RpcRoutes } from "./rpc"; import type { RpcRoutes } from "./rpc";
import { Result } from "@hiogawa/utils"; import { Result } from "@hiogawa/utils";
import {httpClientAdapter} from "@httpClientAdapter";
// console.log("httpClientAdapter module:", httpClientAdapter.toString());
declare let __host__: string; declare let __host__: string;
const endpoint = "/rpc"; const endpoint = "/rpc";
const url = import.meta.env.SSR ? "http://localhost" : ""; const url = import.meta.env.SSR ? "http://localhost" : "";
@@ -15,65 +17,3 @@ export const client = proxyTinyRpc<RpcRoutes>({
pathsForGET: [], pathsForGET: [],
}), }),
}); });
const GET_PAYLOAD_PARAM = "payload";
function httpClientAdapter(opts: {
url: string;
pathsForGET?: string[];
}): TinyRpcClientAdapter {
return {
send: async (data) => {
const url = [opts.url, data.path].join("/");
const payload = JSON.stringify(data.args);
const method = opts.pathsForGET?.includes(data.path)
? "GET"
: "POST";
let req: Request;
if (method === "GET") {
req = new Request(
url +
"?" +
new URLSearchParams({ [GET_PAYLOAD_PARAM]: payload })
);
} else {
req = new Request(url, {
method: "POST",
body: payload,
headers: {
"content-type": "application/json; charset=utf-8",
},
credentials: "include",
});
}
let res: Response;
if (import.meta.env.SSR) {
const { getContext } = await import("hono/context-storage");
const c = getContext<any>();
Object.entries(c.req.header()).forEach(([k, v]) => {
req.headers.append(k, v);
});
res = await c.get("fetch")(req);
} else {
res = await fetch(req);
}
if (!res.ok) {
// throw new Error(`HTTP error: ${res.status}`);
throw new Error(
JSON.stringify({
status: res.status,
statusText: res.statusText,
data: { message: await res.text() },
internal: true,
})
);
// throw TinyRpcError.deserialize(res.status);
}
const result: Result<unknown, unknown> = JSON.parse(
await res.text()
);
if (!result.ok) {
throw TinyRpcError.deserialize(result.value);
}
return result.value;
},
};
}

View File

@@ -0,0 +1,15 @@
import { useHead, UseHeadInput, UseHeadOptions } from "@unhead/vue";
import { defineComponent, toRef } from "vue";
interface VueHeadProps {
input: UseHeadInput;
options?: UseHeadOptions;
}
export const VueHead = defineComponent<VueHeadProps>({
name: "VueHead",
props: ["input", "options"],
setup(props) {
useHead(toRef(props, "input") as any, props.options);
return () => null;
}
});
export default VueHead;

View File

@@ -8,11 +8,12 @@ import { contextStorage } from 'hono/context-storage';
import { cors } from "hono/cors"; import { cors } from "hono/cors";
import { jwtRpc, rpcServer } from './api/rpc'; import { jwtRpc, rpcServer } from './api/rpc';
import isMobile from 'is-mobile'; import isMobile from 'is-mobile';
import { useAuthStore } from './stores/auth';
const app = new Hono() const app = new Hono()
// app.use(renderer) // app.use(renderer)
app.use('*', contextStorage());
app.use(cors(), async (c, next) => { app.use(cors(), async (c, next) => {
c.set("fetch", app.request.bind(app)); c.set("fetch", app.request.bind(app));
const ua = c.req.header("User-Agent") const ua = c.req.header("User-Agent")
@@ -21,15 +22,20 @@ app.use(cors(), async (c, next) => {
}; };
c.set("isMobile", isMobile({ ua })); c.set("isMobile", isMobile({ ua }));
await next(); await next();
}, contextStorage(), rpcServer); }, rpcServer);
app.get("/.well-known/*", (c) => { app.get("/.well-known/*", (c) => {
return c.json({ ok: true }); return c.json({ ok: true });
}); });
app.get("*", async (c) => { app.get("*", async (c) => {
const url = new URL(c.req.url); const url = new URL(c.req.url);
const { app, router, head } = createApp(); const { app, router, head, pinia } = createApp();
router.push(url.pathname); app.provide("honoContext", c);
await router.isReady(); await router.push(url.pathname);
await router.isReady().then(() => {
const auth = useAuthStore();
auth.initialized = false;
auth.init();
});
return streamText(c, async (stream) => { return streamText(c, async (stream) => {
c.header("Content-Type", "text/html; charset=utf-8"); c.header("Content-Type", "text/html; charset=utf-8");
c.header("Content-Encoding", "Identity"); c.header("Content-Encoding", "Identity");
@@ -43,8 +49,8 @@ app.get("*", async (c) => {
await stream.write(buildBootstrapScript()); await stream.write(buildBootstrapScript());
await stream.write("</head><body class='font-sans bg-[#f9fafd] text-gray-800 antialiased flex flex-col min-h-screen'>"); await stream.write("</head><body class='font-sans bg-[#f9fafd] text-gray-800 antialiased flex flex-col min-h-screen'>");
await stream.pipe(appStream); await stream.pipe(appStream);
let json = htmlEscape(JSON.stringify(JSON.stringify(ctx))); await stream.write(`<script>window.__SSR_STATE__ = JSON.parse(${htmlEscape(JSON.stringify(JSON.stringify(ctx)))});</script>`);
await stream.write(`<script>window.__SSR_STATE__ = JSON.parse(${json});</script>`); await stream.write(`<script>window.__PINIA_STATE__ = JSON.parse(${htmlEscape(JSON.stringify(JSON.stringify(pinia.state.value)))});</script>`);
await stream.write("</body></html>"); await stream.write("</body></html>");
}); });
// return c.body(renderToWebStream(app, {})); // return c.body(renderToWebStream(app, {}));

View File

@@ -10,10 +10,10 @@ export function withErrorBoundary(WrappedComponent: any) {
<div class="p-8 space-y-lg max-w-lg w-full"> <div class="p-8 space-y-lg max-w-lg w-full">
<p> <p>
<b>500.&nbsp;</b> <b>500.&nbsp;</b>
<ins class="text-gray-500 decoration-none">Đã xảy ra lỗi.</ins> <ins class="text-gray-500 decoration-none">Something went wrong.</ins>
</p> </p>
<div class="font-thin"> <div class="font-thin">
<p>Máy chủ đang gặp sự cố tạm thời không thể xử yêu cầu của bạn. Vui lòng <a class="underline text-primary" href="/">thử lại</a> sau vài phút.</p> <p>The server is currently experiencing temporary issues and cannot process your request. Please <a class="underline text-primary" href="/">try again</a> in a few minutes.</p>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -10,18 +10,21 @@ import Aura from '@primeuix/themes/aura';
import { createPinia } from "pinia"; import { createPinia } from "pinia";
import { useAuthStore } from './stores/auth'; import { useAuthStore } from './stores/auth';
const pinia = createPinia();
export function createApp() { export function createApp() {
const pinia = createPinia();
const app = createSSRApp(withErrorBoundary(RouterView)); const app = createSSRApp(withErrorBoundary(RouterView));
const head = import.meta.env.SSR ? SSRHead() : CSRHead(); const head = import.meta.env.SSR ? SSRHead() : CSRHead();
app.use(head); app.use(head);
app.use(PrimeVue, { app.use(PrimeVue, {
// unstyled: true,
theme: { theme: {
preset: Aura, preset: Aura,
options: { options: {
darkModeSelector: '.my-app-dark', darkModeSelector: '.my-app-dark',
cssLayer: false,
prefix: 'pv-',
} }
} }
}); });
@@ -42,5 +45,5 @@ export function createApp() {
}); });
} }
return { app, router, head }; return { app, router, head, pinia };
} }

12
src/routes/NotFound.vue Normal file
View File

@@ -0,0 +1,12 @@
<template>
<vue-head :input="{title: '404 - Page Not Found'}"/>
<div class="mx-auto text-center mt-20 flex flex-col items-center gap-4">
<h1>404 - Page Not Found</h1>
<p>The page you are looking for does not exist.</p>
<router-link class="btn btn-primary" to="/">Go back to Home</router-link>
</div>
</template>
<script setup lang="ts">
import { VueHead } from "@/components/VueHead";
</script>

View File

@@ -75,6 +75,11 @@ const routes: RouteData[] = [
component: () => import("./add/Add.vue"), component: () => import("./add/Add.vue"),
}, },
], ],
},
{
path: "/:pathMatch(.*)*",
name: "not-found",
component: () => import("./NotFound.vue"),
} }
], ],
}, },
@@ -88,6 +93,7 @@ const router = createRouter({
router.beforeEach((to, from, next) => { router.beforeEach((to, from, next) => {
const auth = useAuthStore(); const auth = useAuthStore();
console.log("Call on server:", Math.random());
if (to.matched.some((record) => record.meta.requiresAuth)) { if (to.matched.some((record) => record.meta.requiresAuth)) {
if (!auth.user) { if (!auth.user) {
next({ name: "login" }); next({ name: "login" });

View File

@@ -20,10 +20,15 @@ export const useAuthStore = defineStore('auth', () => {
// Check auth status on init (reads from cookie) // Check auth status on init (reads from cookie)
async function init() { async function init() {
if (initialized.value) return; console.log("Auth store init called");
// if (initialized.value) return;
try { try {
const response = await client.checkAuth(); const response = await client.checkAuth().then((res) => {
console.log("call", res);
return res;
});
if (response.authenticated && response.user) { if (response.authenticated && response.user) {
user.value = response.user; user.value = response.user;
// Get CSRF token if authenticated // Get CSRF token if authenticated

10
src/type.d.ts vendored Normal file
View File

@@ -0,0 +1,10 @@
/// <reference types="vite/client" />
/// <reference types="unplugin-vue-components/types/vue" />
declare module "@httpClientAdapter" {
import { TinyRpcClientAdapter } from "@hiogawa/tiny-rpc";
export function httpClientAdapter(opts: {
url: string;
pathsForGET?: string[];
}): TinyRpcClientAdapter;
}

View File

@@ -32,6 +32,7 @@ export function clientFirstBuild(): Plugin {
// Client build first // Client build first
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (clientEnvironment) { if (clientEnvironment) {
// console.log("Client First Build Plugin: Building client...", clientEnvironment.resolve);
await builder.build(clientEnvironment); await builder.build(clientEnvironment);
} }
@@ -107,6 +108,16 @@ export default function ssrPlugin(): Plugin[] {
config(config) { config(config) {
config.define = config.define || {}; config.define = config.define || {};
}, },
resolveId(id, importer, options) {
if (!id.startsWith('@httpClientAdapter')) return
return path.resolve(
__dirname,
options?.ssr
? "./src/api/httpClientAdapter.server.ts"
: "./src/api/httpClientAdapter.client.ts"
);
},
async configResolved(config) { async configResolved(config) {
const viteConfig = config as any; const viteConfig = config as any;

View File

@@ -16,4 +16,11 @@
"@/*": ["./src/*"] "@/*": ["./src/*"]
} }
}, },
"include": [
"src/**/*.ts",
"src/**/*.tsx",
"src/**/*.vue",
"auto-imports.d.ts",
"components.d.ts"
]
} }

View File

@@ -1,30 +1,47 @@
import { cloudflare } from "@cloudflare/vite-plugin"; import { cloudflare } from "@cloudflare/vite-plugin";
import { defineConfig, Manifest, Plugin } from "vite"; import { PrimeVueResolver } from "@primevue/auto-import-resolver";
import vue from "@vitejs/plugin-vue"; import vue from "@vitejs/plugin-vue";
import vueJsx from "@vitejs/plugin-vue-jsx"; import vueJsx from "@vitejs/plugin-vue-jsx";
import unocss from "unocss/vite";
import path from "node:path"; import path from "node:path";
import unocss from "unocss/vite";
import Components from "unplugin-vue-components/vite";
import AutoImport from "unplugin-auto-import/vite";
import { defineConfig } from "vite";
import ssrPlugin from "./ssrPlugin"; import ssrPlugin from "./ssrPlugin";
import Components from 'unplugin-vue-components/vite';
import {PrimeVueResolver} from '@primevue/auto-import-resolver';
export default defineConfig((env) => { export default defineConfig((env) => {
// console.log("env:", env, import.meta.env);
return { return {
plugins: [ plugins: [
unocss(), unocss(),
vue(), vue(),
vueJsx(), vueJsx(),
AutoImport({
imports: ["vue", "vue-router", "pinia"], // Common presets
dts: true, // Generate TypeScript declaration file
}),
Components({
dirs: ["src/components"],
extensions: ["vue", "tsx"],
dts: true,
dtsTsx: true,
directives: false,
resolvers: [PrimeVueResolver()],
}),
ssrPlugin(), ssrPlugin(),
cloudflare(), cloudflare(),
Components({
resolvers: [
PrimeVueResolver()
]
}),
], ],
resolve: { resolve: {
alias: { alias: {
"@": path.resolve(__dirname, "./src"), "@": path.resolve(__dirname, "./src"),
// "httpClientAdapter": path.resolve(__dirname, "./src/api/httpClientAdapter.server.ts")
}, },
}, },
optimizeDeps: {
exclude: ["vue"],
},
ssr: {
noExternal: ["vue"],
},
}; };
}); });