├── .editorconfig ├── .env ├── .env.development ├── .env.production ├── .gitignore ├── .lintstagedrc.cjs ├── .npmrc ├── .stylelintcache ├── .stylelintignore ├── .stylelintrc ├── .vscode ├── extensions.json └── settings.json ├── LICENSE ├── README.md ├── build ├── config │ ├── index.ts │ └── proxy.ts ├── plugins │ ├── index.ts │ ├── resolver.ts │ └── unplugin.ts └── utils.ts ├── commitlint.config.js ├── eslint.config.mjs ├── index.html ├── manifest.config.ts ├── netlify.toml ├── package.json ├── pages.config.ts ├── pnpm-lock.yaml ├── renovate.json ├── src ├── App.vue ├── api │ └── index.ts ├── components │ └── Counter.vue ├── composables │ └── useToken.ts ├── constants │ └── index.ts ├── layouts │ └── default.vue ├── main.ts ├── manifest.json ├── pages.json ├── pages │ ├── count │ │ └── count.vue │ └── index │ │ └── index.vue ├── plugins │ ├── dayjs.ts │ ├── index.ts │ └── vue-query.ts ├── service │ ├── helper.ts │ ├── index.ts │ └── types.ts ├── static │ ├── logo.png │ ├── vite.svg │ └── vue.svg ├── store │ ├── index.ts │ └── modules │ │ ├── app │ │ └── index.ts │ │ ├── auth │ │ └── index.ts │ │ ├── count │ │ └── index.ts │ │ └── index.ts ├── styles │ ├── reset.css │ └── variables.scss ├── theme.json ├── uni.scss └── utils │ ├── is.ts │ └── shared.ts ├── tsconfig.json ├── typings ├── common.d.ts ├── shime-uni.d.ts └── vite-env.d.ts ├── uno.config.ts └── vite.config.ts /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true -------------------------------------------------------------------------------- /.env: -------------------------------------------------------------------------------- 1 | VITE_APP_TITLE='' 2 | #服务启动端口 3 | VITE_PORT=5777 4 | 5 | -------------------------------------------------------------------------------- /.env.development: -------------------------------------------------------------------------------- 1 | ENV = "development" 2 | 3 | VITE_ALOVA_TIPS=0 4 | # 资源公共路径,需要以 /开头和结尾 5 | VITE_PUBLIC_PATH = '/' 6 | 7 | # 是否hash路由模式 8 | VITE_USE_HASH = false 9 | 10 | # base api 11 | VITE_BASE_API = 'https://api.github.com' 12 | 13 | 14 | 15 | 16 | # 是否启用代理(只对本地vite server生效,开启MOCK时可关闭代理) 17 | VITE_USE_PROXY = false 18 | 19 | # 代理类型(跟启动和构建环境无关) 'dev' | 'test' | 'prod' 20 | VITE_PROXY_TYPE = 'test' 21 | 22 | -------------------------------------------------------------------------------- /.env.production: -------------------------------------------------------------------------------- 1 | ENV = "production" 2 | 3 | # 资源公共路径,需要以 /开头和结尾 4 | VITE_PUBLIC_PATH = '/' 5 | 6 | # 是否hash路由模式 7 | VITE_USE_HASH = false 8 | 9 | # axios base api 10 | VITE_BASE_API = 'https://api.github.com/repos/yang1206' 11 | 12 | 13 | 14 | 15 | # 是否启用代理(只对本地vite server生效,开启MOCK时可关闭代理) 16 | VITE_USE_PROXY = false 17 | 18 | # 代理类型(跟启动和构建环境无关) 'dev' | 'test' | 'prod' 19 | VITE_PROXY_TYPE = 'test' -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | typings/auto-import.d.ts 11 | typings/uni-pages.d.ts 12 | typings/components.d.ts 13 | 14 | 15 | node_modules 16 | .DS_Store 17 | dist 18 | *.local 19 | coverage 20 | .eslintcache 21 | # Editor directories and files 22 | .idea 23 | *.suo 24 | *.ntvs* 25 | *.njsproj 26 | *.sln 27 | *.sw? 28 | -------------------------------------------------------------------------------- /.lintstagedrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | '*.{js,cjs,mjs,jsx,ts,cts,mts,tsx,vue}': 'eslint --fix --cache', 3 | '*.{scss,css,vue}': 'stylelint --fix --allow-empty-input', 4 | '*.{ts,cts,mts,tsx,vue}': () => 'vue-tsc --noEmit -p tsconfig.json --composite false', 5 | } 6 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | # public-hoist-pattern[]=@vue* 2 | strict-peer-dependencies=false 3 | auto-install-peers=true 4 | shamefully-hoist=true 5 | -------------------------------------------------------------------------------- /.stylelintcache: -------------------------------------------------------------------------------- 1 | [{"/Users/yangjunwei/codes/frontend/web/Project_Learn/mini-program/uniapp-vite/src/App.vue":"1","/Users/yangjunwei/codes/frontend/web/Project_Learn/mini-program/uniapp-vite/src/uni.scss":"2","/Users/yangjunwei/codes/frontend/web/Project_Learn/mini-program/uniapp-vite/src/styles/reset.css":"3","/Users/yangjunwei/codes/frontend/web/Project_Learn/mini-program/uniapp-vite/src/styles/variables.scss":"4","/Users/yangjunwei/codes/frontend/web/Project_Learn/mini-program/uniapp-vite/src/components/Counter.vue":"5","/Users/yangjunwei/codes/frontend/web/Project_Learn/mini-program/uniapp-vite/src/layouts/default.vue":"6","/Users/yangjunwei/codes/frontend/web/Project_Learn/mini-program/uniapp-vite/src/pages/count/count.vue":"7","/Users/yangjunwei/codes/frontend/web/Project_Learn/mini-program/uniapp-vite/src/pages/index/index.vue":"8"},{"size":1431,"mtime":1698888811952,"hashOfConfig":"9"},{"size":2251,"mtime":1700919780749,"hashOfConfig":"9"},{"size":127,"mtime":1700919780791,"hashOfConfig":"9"},{"size":1675,"mtime":1700919780791,"hashOfConfig":"9"},{"size":567,"mtime":1686929737039,"hashOfConfig":"9"},{"size":1335,"mtime":1694656381072,"hashOfConfig":"9"},{"size":372,"mtime":1700573207880,"hashOfConfig":"9"},{"size":1148,"mtime":1700919780807,"hashOfConfig":"9"},"45xzdr"] -------------------------------------------------------------------------------- /.stylelintignore: -------------------------------------------------------------------------------- 1 | dist 2 | es 3 | lib 4 | css 5 | example 6 | public 7 | cache 8 | node_modules 9 | .husky 10 | 11 | docs/.vitepress/theme 12 | 13 | *.js 14 | *.cjs 15 | *.mjs 16 | *.ts 17 | *.tsx 18 | *.svg 19 | *.gif 20 | *.md 21 | -------------------------------------------------------------------------------- /.stylelintrc: -------------------------------------------------------------------------------- 1 | { 2 | "defaultSeverity": "error", 3 | "extends": [ 4 | "stylelint-config-standard", 5 | "stylelint-config-standard-scss", 6 | "stylelint-config-recommended-vue", 7 | "stylelint-config-html", 8 | "stylelint-config-recess-order" 9 | ], 10 | "plugins": [ 11 | "stylelint-order" 12 | ], 13 | "rules": { 14 | "selector-class-pattern": [ 15 | "^([#a-z][$#{}a-z0-9]*)((-{1,2}|_{2})[$#{}a-z0-9]+)*$", 16 | { 17 | "message": "Expected class selector to be kebab-case" 18 | } 19 | ], 20 | "selector-pseudo-class-no-unknown": [ 21 | true, 22 | { 23 | "ignorePseudoClasses": [ 24 | "::v-deep", 25 | "deep", 26 | "v-deep" 27 | ] 28 | } 29 | ], 30 | "selector-type-no-unknown": [ 31 | true, 32 | { 33 | "ignoreTypes": [ 34 | "page", 35 | "rich-text", 36 | "scroll-view" 37 | ] 38 | } 39 | ], 40 | "unit-no-unknown":[ 41 | true, 42 | { 43 | "ignoreUnits": ["rpx","upx"] 44 | } 45 | ], 46 | "no-descending-specificity": null, 47 | "no-empty-source": null, 48 | "keyframes-name-pattern": "^[a-z]+([A-Z][a-z]*)*$" 49 | }, 50 | "ignoreFiles": [ 51 | "node_modules", 52 | "dist", 53 | "public", 54 | "output", 55 | "coverage", 56 | "temp", 57 | "*.js", 58 | "*.cjs", 59 | "*.mjs", 60 | "*.ts", 61 | "*.tsx", 62 | "*.svg", 63 | "*.gif", 64 | "*.md" 65 | ] 66 | } 67 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "dbaeumer.vscode-eslint", 4 | "uni-helper.uni-helper-vscode", 5 | "vue.volar", 6 | "antfu.unocss" 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "explorer.fileNesting.patterns": { 3 | "vite.config.*": "pages.config.*, manifest.config.*, unocss.config.*, volar.config.*, *.env, .env.*" 4 | }, 5 | "typescript.tsdk": "node_modules/typescript/lib", 6 | // "editor.defaultFormatter": "esbenp.prettier-vscode", 7 | "references.preferredLocation": "peek", 8 | // Auto fix 9 | "editor.codeActionsOnSave": { 10 | "source.fixAll.eslint": "explicit", 11 | "source.organizeImports": "never" 12 | }, 13 | // Silent the stylistic rules in you IDE, but still auto fix them 14 | "eslint.rules.customizations": [ 15 | { 16 | "rule": "style/*", 17 | "severity": "off" 18 | }, 19 | { 20 | "rule": "*-indent", 21 | "severity": "off" 22 | }, 23 | { 24 | "rule": "*-spacing", 25 | "severity": "off" 26 | }, 27 | { 28 | "rule": "*-spaces", 29 | "severity": "off" 30 | }, 31 | { 32 | "rule": "*-order", 33 | "severity": "off" 34 | }, 35 | { 36 | "rule": "*-dangle", 37 | "severity": "off" 38 | }, 39 | { 40 | "rule": "*-newline", 41 | "severity": "off" 42 | }, 43 | { 44 | "rule": "*quotes", 45 | "severity": "off" 46 | }, 47 | { 48 | "rule": "*semi", 49 | "severity": "off" 50 | } 51 | ], 52 | // Enable eslint for all supported languages 53 | "eslint.validate": [ 54 | "javascript", 55 | "javascriptreact", 56 | "typescript", 57 | "typescriptreact", 58 | "vue", 59 | "html", 60 | "markdown", 61 | "json", 62 | "jsonc", 63 | "yaml" 64 | ], 65 | "vue.codeActions.enabled": false 66 | } 67 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 yang1206 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 🚀🚀🚀 一个Uniapp的起始模版,Vite,Vue3,TypeScript 2 | 3 |
4 | 5 |

6 | 预览 7 |

8 | 9 | Inspired by [Vitesse](https://github.com/antfu/vitesse) ❤ 10 | 11 | ### Features 12 | 13 | - ⚡️ [Vue3](https://vuejs.org/), [Vite 4](https://github.com/vitejs/vite), [pnpm](https://pnpm.io/), [ESBuild](https://github.com/evanw/esbuild) - 就是快! 14 | - 🗂 [基于文件的路由](https://github.com/uni-helper/vite-plugin-uni-pages) 15 | - 📦 [组件自动化加载](https://github.com/uni-helper/vite-plugin-uni-components) 16 | - 🎨 [UnoCSS](https://github.com/antfu/unocss) - 高性能且极具灵活性的即时原子化 CSS 引擎 17 | - 😃 [各种图标集为你所用](https://github.com/antfu/unocss/tree/main/packages/preset-icons) 18 | - 🔥 使用 [新的 ` 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /manifest.config.ts: -------------------------------------------------------------------------------- 1 | import { defineManifestConfig } from '@uni-helper/vite-plugin-uni-manifest' 2 | 3 | export default defineManifestConfig({ 4 | 'name': 'uniapp-vite-template', 5 | 'appid': '', 6 | 'description': '', 7 | 'versionName': '1.0.0', 8 | 'versionCode': '100', 9 | 'transformPx': false, 10 | 'mp-weixin': { 11 | appid: '', 12 | setting: { 13 | urlCheck: false, 14 | es6: true, 15 | minified: true, 16 | postcss: true, 17 | ignoreDevUnusedFiles: false, 18 | ignoreUploadUnusedFiles: false, 19 | }, 20 | usingComponents: true, 21 | lazyCodeLoading: 'requiredComponents', 22 | darkmode: true, 23 | themeLocation: 'theme.json', 24 | libVersion: '3.4.3', 25 | 26 | }, 27 | /* 5+App特有相关 */ 28 | 'app-plus': { 29 | usingComponents: true, 30 | nvueStyleCompiler: 'uni-app', 31 | compilerVersion: 3, 32 | splashscreen: { 33 | alwaysShowBeforeRender: true, 34 | waiting: true, 35 | autoclose: true, 36 | delay: 0, 37 | }, 38 | /* 模块配置 */ 39 | modules: { 40 | /* 使用Canvas模块,需要添加下面这一行 */ 41 | Canvas: 'nvue canvas', 42 | }, 43 | /* 应用发布信息 */ 44 | distribute: { 45 | /* android打包配置 */ 46 | android: { 47 | permissions: [ 48 | '', 49 | '', 50 | '', 51 | '', 52 | '', 53 | '', 54 | '', 55 | '', 56 | '', 57 | '', 58 | '', 59 | '', 60 | ], 61 | }, 62 | /* ios打包配置 */ 63 | ios: {}, 64 | /* SDK配置 */ 65 | sdkConfigs: {}, 66 | }, 67 | }, 68 | /* 快应用特有相关 */ 69 | 'quickapp': {}, 70 | /* 小程序特有相关 */ 71 | 'mp-alipay': { 72 | usingComponents: true, 73 | }, 74 | 'mp-baidu': { 75 | usingComponents: true, 76 | }, 77 | 'mp-toutiao': { 78 | usingComponents: true, 79 | }, 80 | 'h5': { 81 | darkmode: true, 82 | themeLocation: 'theme.json', 83 | }, 84 | 'uniStatistics': { 85 | enable: false, 86 | }, 87 | 'vueVersion': '3', 88 | }) 89 | -------------------------------------------------------------------------------- /netlify.toml: -------------------------------------------------------------------------------- 1 | [build.environment] 2 | NPM_FLAGS = "--version" 3 | NODE_VERSION = "16" 4 | 5 | [build] 6 | publish = "dist/build/h5" 7 | command = "npx pnpm i --store=node_modules/.pnpm-store && npx pnpm run build:h5" 8 | 9 | [[redirects]] 10 | from = "/*" 11 | to = "/index.html" 12 | status = 200 -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "uniapp-vite-template", 3 | "version": "0.0.1", 4 | "license": "MIT", 5 | "engines": { 6 | "node": "20" 7 | }, 8 | "scripts": { 9 | "build:app": "cross-env VITE_MODE=production uni build -p app", 10 | "build:app-android": "cross-env VITE_MODE=production uni build -p app-android", 11 | "build:app-android:dev": "cross-env VITE_MODE=development uni build -p app-android", 12 | "build:app-android:prod": "npm run build:app-android", 13 | "build:app-android:staging": "cross-env VITE_MODE=staging uni build -p app-android", 14 | "build:app-ios": "cross-env VITE_MODE=production uni build -p app-ios", 15 | "build:app-ios:dev": "cross-env VITE_MODE=development uni build -p app-ios", 16 | "build:app-ios:prod": "npm run build:app-ios", 17 | "build:app-ios:staging": "cross-env VITE_MODE=staging uni build -p app-ios", 18 | "build:app:dev": "cross-env VITE_MODE=development uni build -p app", 19 | "build:app:prod": "npm run build:app", 20 | "build:app:staging": "cross-env VITE_MODE=staging uni build -p app", 21 | "build:h5": "cross-env VITE_MODE=production uni build", 22 | "build:h5:dev": "cross-env VITE_MODE=development uni build", 23 | "build:h5:prod": "npm run build:h5", 24 | "build:h5:ssr": "cross-env VITE_MODE=production uni build --ssr", 25 | "build:h5:ssr:dev": "cross-env VITE_MODE=development uni build --ssr", 26 | "build:h5:ssr:prod": "npm run build:h5:ssr", 27 | "build:h5:ssr:staging": "cross-env VITE_MODE=staging uni build --ssr", 28 | "build:h5:staging": "cross-env VITE_MODE=staging uni build", 29 | "build:mp-alipay": "cross-env VITE_MODE=production uni build -p mp-alipay", 30 | "build:mp-alipay:dev": "cross-env VITE_MODE=development uni build -p mp-alipay", 31 | "build:mp-alipay:prod": "npm run build:mp-alipay", 32 | "build:mp-alipay:staging": "cross-env VITE_MODE=staging uni build -p mp-alipay", 33 | "build:mp-baidu": "cross-env VITE_MODE=production uni build -p mp-baidu", 34 | "build:mp-baidu:dev": "cross-env VITE_MODE=development uni build -p mp-baidu", 35 | "build:mp-baidu:prod": "npm run build:mp-baidu", 36 | "build:mp-baidu:staging": "cross-env VITE_MODE=staging uni build -p mp-baidu", 37 | "build:mp-jd": "cross-env VITE_MODE=production uni build -p mp-jd", 38 | "build:mp-jd:dev": "cross-env VITE_MODE=development uni build -p mp-jd", 39 | "build:mp-jd:prod": "npm run build:mp-jd", 40 | "build:mp-jd:staging": "cross-env VITE_MODE=staging uni build -p mp-jd", 41 | "build:mp-kuaishou": "cross-env VITE_MODE=production uni build -p mp-kuaishou", 42 | "build:mp-kuaishou:dev": "cross-env VITE_MODE=development uni build -p mp-kuaishou", 43 | "build:mp-kuaishou:prod": "npm run build:mp-kuaishou", 44 | "build:mp-kuaishou:staging": "cross-env VITE_MODE=staging uni build -p mp-kuaishou", 45 | "build:mp-lark": "cross-env VITE_MODE=production uni build -p mp-lark", 46 | "build:mp-lark:dev": "cross-env VITE_MODE=development uni build -p mp-lark", 47 | "build:mp-lark:prod": "npm run build:mp-lark", 48 | "build:mp-lark:staging": "cross-env VITE_MODE=staging uni build -p mp-lark", 49 | "build:mp-qq": "cross-env VITE_MODE=production uni build -p mp-qq", 50 | "build:mp-qq:dev": "cross-env VITE_MODE=development uni build -p mp-qq", 51 | "build:mp-qq:prod": "npm run build:mp-qq", 52 | "build:mp-qq:staging": "cross-env VITE_MODE=staging uni build -p mp-qq", 53 | "build:mp-toutiao": "cross-env VITE_MODE=production uni build -p mp-toutiao", 54 | "build:mp-toutiao:dev": "cross-env VITE_MODE=development uni build -p mp-toutiao", 55 | "build:mp-toutiao:prod": "npm run build:mp-toutiao", 56 | "build:mp-toutiao:staging": "cross-env VITE_MODE=staging uni build -p mp-toutiao", 57 | "build:mp-weixin": "cross-env VITE_MODE=production uni build -p mp-weixin", 58 | "build:mp-weixin:dev": "cross-env VITE_MODE=development uni build -p mp-weixin", 59 | "build:mp-weixin:prod": "npm run build:mp-weixin", 60 | "build:mp-weixin:staging": "cross-env VITE_MODE=staging uni build -p mp-weixin", 61 | "build:quickapp-webview": "cross-env VITE_MODE=production uni build -p quickapp-webview", 62 | "build:quickapp-webview-huawei": "cross-env VITE_MODE=production uni build -p quickapp-webview-huawei", 63 | "build:quickapp-webview-huawei:dev": "cross-env VITE_MODE=development uni build -p quickapp-webview-huawei", 64 | "build:quickapp-webview-huawei:prod": "npm run build:quickapp-webview-huawei", 65 | "build:quickapp-webview-huawei:staging": "cross-env VITE_MODE=staging uni build -p quickapp-webview-huawei", 66 | "build:quickapp-webview-union": "cross-env VITE_MODE=production uni build -p quickapp-webview-union", 67 | "build:quickapp-webview-union:dev": "cross-env VITE_MODE=development uni build -p quickapp-webview-union", 68 | "build:quickapp-webview-union:prod": "npm run build:quickapp-webview-union", 69 | "build:quickapp-webview-union:staging": "cross-env VITE_MODE=staging uni build -p quickapp-webview-union", 70 | "build:quickapp-webview:dev": "cross-env VITE_MODE=development uni build -p quickapp-webview", 71 | "build:quickapp-webview:prod": "npm run build:quickapp-webview", 72 | "build:quickapp-webview:staging": "cross-env VITE_MODE=staging uni build -p quickapp-webview", 73 | "dev:app": "cross-env VITE_MODE=development uni -p app", 74 | "dev:app-android": "cross-env VITE_MODE=development uni -p app-android", 75 | "dev:app-android:dev": "npm run dev:app-android", 76 | "dev:app-android:prod": "cross-env VITE_MODE=production uni -p app-android", 77 | "dev:app-android:staging": "cross-env VITE_MODE=staging uni -p app-android", 78 | "dev:app-ios": "cross-env VITE_MODE=development uni -p app-ios", 79 | "dev:app-ios:dev": "npm run dev:app-ios", 80 | "dev:app-ios:prod": "cross-env VITE_MODE=production uni -p app-ios", 81 | "dev:app-ios:staging": "cross-env VITE_MODE=staging uni -p app-ios", 82 | "dev:app:dev": "npm run dev:app", 83 | "dev:app:prod": "cross-env VITE_MODE=production uni -p app", 84 | "dev:app:staging": "cross-env VITE_MODE=staging uni -p app", 85 | "dev:h5": "cross-env VITE_MODE=development uni", 86 | "dev:h5:dev": "npm run dev:h5", 87 | "dev:h5:prod": "cross-env VITE_MODE=production uni", 88 | "dev:h5:ssr": "cross-env VITE_MODE=development uni --ssr", 89 | "dev:h5:ssr:dev": "npm run dev:h5:ssr", 90 | "dev:h5:ssr:prod": "cross-env VITE_MODE=production uni --ssr", 91 | "dev:h5:ssr:staging": "cross-env VITE_MODE=staging uni --ssr", 92 | "dev:h5:staging": "cross-env VITE_MODE=staging uni", 93 | "dev:mp-alipay": "cross-env VITE_MODE=development uni -p mp-alipay", 94 | "dev:mp-alipay:dev": "npm run dev:mp-alipay", 95 | "dev:mp-alipay:prod": "cross-env VITE_MODE=production uni -p mp-alipay", 96 | "dev:mp-alipay:staging": "cross-env VITE_MODE=staging uni -p mp-alipay", 97 | "dev:mp-baidu": "cross-env VITE_MODE=development uni -p mp-baidu", 98 | "dev:mp-baidu:dev": "npm run dev:mp-baidu", 99 | "dev:mp-baidu:prod": "cross-env VITE_MODE=production uni -p mp-baidu", 100 | "dev:mp-baidu:staging": "cross-env VITE_MODE=staging uni -p mp-baidu", 101 | "dev:mp-jd": "cross-env VITE_MODE=development uni -p mp-jd", 102 | "dev:mp-jd:dev": "npm run dev:mp-jd", 103 | "dev:mp-jd:prod": "cross-env VITE_MODE=production uni -p mp-jd", 104 | "dev:mp-jd:staging": "cross-env VITE_MODE=staging uni -p mp-jd", 105 | "dev:mp-kuaishou": "cross-env VITE_MODE=development uni -p mp-kuaishou", 106 | "dev:mp-kuaishou:dev": "npm run dev:mp-kuaishou", 107 | "dev:mp-kuaishou:prod": "cross-env VITE_MODE=production uni -p mp-kuaishou", 108 | "dev:mp-kuaishou:staging": "cross-env VITE_MODE=staging uni -p mp-kuaishou", 109 | "dev:mp-lark": "cross-env VITE_MODE=development uni -p mp-lark", 110 | "dev:mp-lark:dev": "npm run dev:mp-lark", 111 | "dev:mp-lark:prod": "cross-env VITE_MODE=production uni -p mp-lark", 112 | "dev:mp-lark:staging": "cross-env VITE_MODE=staging uni -p mp-lark", 113 | "dev:mp-qq": "cross-env VITE_MODE=development uni -p mp-qq", 114 | "dev:mp-qq:dev": "npm run dev:mp-qq", 115 | "dev:mp-qq:prod": "cross-env VITE_MODE=production uni -p mp-qq", 116 | "dev:mp-qq:staging": "cross-env VITE_MODE=staging uni -p mp-qq", 117 | "dev:mp-toutiao": "cross-env VITE_MODE=development uni -p mp-toutiao", 118 | "dev:mp-toutiao:dev": "npm run dev:mp-toutiao", 119 | "dev:mp-toutiao:prod": "cross-env VITE_MODE=production uni -p mp-toutiao", 120 | "dev:mp-toutiao:staging": "cross-env VITE_MODE=staging uni -p mp-toutiao", 121 | "dev:mp-weixin": "cross-env VITE_MODE=development uni -p mp-weixin", 122 | "dev:mp-weixin:dev": "npm run dev:mp-weixin", 123 | "dev:mp-weixin:prod": "cross-env VITE_MODE=production uni -p mp-weixin", 124 | "dev:mp-weixin:staging": "cross-env VITE_MODE=staging uni -p mp-weixin", 125 | "dev:quickapp-webview": "cross-env VITE_MODE=development uni -p quickapp-webview", 126 | "dev:quickapp-webview-huawei": "cross-env VITE_MODE=development uni -p quickapp-webview-huawei", 127 | "dev:quickapp-webview-huawei:dev": "npm run dev:quickapp-webview-huawei", 128 | "dev:quickapp-webview-huawei:prod": "cross-env VITE_MODE=production uni -p quickapp-webview-huawei", 129 | "dev:quickapp-webview-huawei:staging": "cross-env VITE_MODE=staging uni -p quickapp-webview-huawei", 130 | "dev:quickapp-webview-union": "cross-env VITE_MODE=development uni -p quickapp-webview-union", 131 | "dev:quickapp-webview-union:dev": "npm run dev:quickapp-webview-union", 132 | "dev:quickapp-webview-union:prod": "cross-env VITE_MODE=production uni -p quickapp-webview-union", 133 | "dev:quickapp-webview-union:staging": "cross-env VITE_MODE=staging uni -p quickapp-webview-union", 134 | "dev:quickapp-webview:dev": "npm run dev:quickapp-webview", 135 | "dev:quickapp-webview:prod": "cross-env VITE_MODE=production uni -p quickapp-webview", 136 | "dev:quickapp-webview:staging": "cross-env VITE_MODE=staging uni -p quickapp-webview", 137 | "check:types": "vue-tsc --noEmit -p tsconfig.vitest.json --composite false", 138 | "check:deps": "taze -f", 139 | "postinstall": "npx simple-git-hooks", 140 | "lint": "eslint .", 141 | "lint:fix": "eslint . --fix", 142 | "lint:lint-staged": "lint-staged", 143 | "lint:style": "stylelint --cache \"**/*.{vue,scss,css}\" --fix", 144 | "commit": "git pull && git add -A && git-cz && git push" 145 | }, 146 | "dependencies": { 147 | "@dcloudio/uni-app": "3.0.0-alpha-4050220250208001", 148 | "@dcloudio/uni-app-harmony": "3.0.0-alpha-4050220250208001", 149 | "@dcloudio/uni-app-plus": "3.0.0-alpha-4050220250208001", 150 | "@dcloudio/uni-components": "3.0.0-alpha-4050220250208001", 151 | "@dcloudio/uni-h5": "3.0.0-alpha-4050220250208001", 152 | "@dcloudio/uni-mp-alipay": "3.0.0-alpha-4050220250208001", 153 | "@dcloudio/uni-mp-baidu": "3.0.0-alpha-4050220250208001", 154 | "@dcloudio/uni-mp-jd": "3.0.0-alpha-4050220250208001", 155 | "@dcloudio/uni-mp-kuaishou": "3.0.0-alpha-4050220250208001", 156 | "@dcloudio/uni-mp-lark": "3.0.0-alpha-4050220250208001", 157 | "@dcloudio/uni-mp-qq": "3.0.0-alpha-4050220250208001", 158 | "@dcloudio/uni-mp-toutiao": "3.0.0-alpha-4050220250208001", 159 | "@dcloudio/uni-mp-weixin": "3.0.0-alpha-4050220250208001", 160 | "@dcloudio/uni-mp-xhs": "3.0.0-alpha-4050220250208001", 161 | "@dcloudio/uni-quickapp-webview": "3.0.0-alpha-4050220250208001", 162 | "@dcloudio/uni-ui": "^1.5.7", 163 | "@tanstack/vue-query": "4.37.1", 164 | "@uni-helper/uni-network": "^0.20.0", 165 | "@uni-helper/uni-promises": "^0.2.1", 166 | "@uni-helper/uni-use": "^0.19.14", 167 | "@vueuse/core": "12.7.0", 168 | "change-case": "4.1.2", 169 | "core-js": "^3.40.0", 170 | "dayjs": "^1.11.13", 171 | "nutui-uniapp": "^1.8.2", 172 | "pinia": "2.0.36", 173 | "qs": "6.5.3", 174 | "vue": "3.5.13" 175 | }, 176 | "devDependencies": { 177 | "@antfu/eslint-config": "^4.3.0", 178 | "@commitlint/cli": "^19.7.1", 179 | "@commitlint/config-conventional": "^19.7.1", 180 | "@dcloudio/types": "^3.4.14", 181 | "@dcloudio/uni-automator": "3.0.0-alpha-4050220250208001", 182 | "@dcloudio/uni-cli-shared": "3.0.0-alpha-4050220250208001", 183 | "@dcloudio/uni-stacktracey": "3.0.0-alpha-4050220250208001", 184 | "@dcloudio/vite-plugin-uni": "3.0.0-alpha-4050220250208001", 185 | "@iconify/json": "^2.2.309", 186 | "@mini-types/alipay": "^3.0.14", 187 | "@types/node": "^20.17.19", 188 | "@types/qs": "^6.9.18", 189 | "@uni-helper/eslint-config": "^0.4.0", 190 | "@uni-helper/uni-app-types": "1.0.0-alpha.6", 191 | "@uni-helper/uni-env": "^0.1.7", 192 | "@uni-helper/uni-types": "1.0.0-alpha.4", 193 | "@uni-helper/unocss-preset-uni": "^0.2.11", 194 | "@uni-helper/vite-plugin-uni-components": "^0.2.0", 195 | "@uni-helper/vite-plugin-uni-layouts": "^0.1.10", 196 | "@uni-helper/vite-plugin-uni-manifest": "^0.2.7", 197 | "@uni-helper/vite-plugin-uni-pages": "^0.2.28", 198 | "@uni-helper/volar-service-uni-pages": "^0.2.28", 199 | "@unocss/eslint-config": "^66.0.0", 200 | "@unocss/preset-rem-to-px": "^66.0.0", 201 | "@vitejs/plugin-vue": "^5.2.1", 202 | "@vue/runtime-core": "3.5.13", 203 | "@vue/tsconfig": "^0.7.0", 204 | "cross-env": "^7.0.3", 205 | "cz-git": "^1.11.0", 206 | "eslint": "9.20.1", 207 | "lint-staged": "^15.4.3", 208 | "miniprogram-api-typings": "^4.0.5", 209 | "sass": "~1.78.0", 210 | "simple-git-hooks": "^2.11.1", 211 | "stylelint": "^16.9.0", 212 | "stylelint-config-html": "^1.1.0", 213 | "stylelint-config-recess-order": "^5.1.1", 214 | "stylelint-config-recommended-vue": "^1.5.0", 215 | "stylelint-config-standard": "^36.0.1", 216 | "stylelint-config-standard-scss": "^13.1.0", 217 | "stylelint-order": "^6.0.4", 218 | "taze": "^18.6.0", 219 | "type-fest": "^4.35.0", 220 | "typescript": "5.7.3", 221 | "unocss": "^66.0.0", 222 | "unplugin-auto-import": "^0.19.0", 223 | "unplugin-icons": "^0.22.0", 224 | "unplugin-vue-macros": "^2.14.2", 225 | "vite": "~5.4.14", 226 | "vite-plugin-uni-polyfill": "^0.1.0", 227 | "vue-i18n": "^9.14.2", 228 | "vue-tsc": "2.2.2" 229 | }, 230 | "simple-git-hooks": { 231 | "pre-commit": "pnpm lint:lint-staged", 232 | "commit-msg": "npx commitlint --edit ${1}" 233 | }, 234 | "config": { 235 | "commitizen": { 236 | "path": "node_modules/cz-git", 237 | "useEmoji": true 238 | } 239 | } 240 | } 241 | -------------------------------------------------------------------------------- /pages.config.ts: -------------------------------------------------------------------------------- 1 | import { isMpWeixin } from '@uni-helper/uni-env' 2 | import { defineUniPages } from '@uni-helper/vite-plugin-uni-pages' 3 | 4 | export default defineUniPages({ 5 | // 你也可以定义 pages 字段,它具有最高的优先级。 6 | pages: [ 7 | { 8 | path: 'pages/index/index', 9 | }, 10 | ], 11 | globalStyle: { 12 | navigationBarBackgroundColor: '@navBgColor', 13 | navigationBarTextStyle: '@navTxtStyle', 14 | navigationBarTitleText: 'uniapp-vite-template', 15 | backgroundColor: '@bgColor', 16 | backgroundTextStyle: '@bgTxtStyle', 17 | backgroundColorTop: '@bgColorTop', 18 | backgroundColorBottom: '@bgColorBottom', 19 | navigationStyle: 'custom', 20 | }, 21 | tabBar: { 22 | // 支付宝小程序自定义需要特殊处理 23 | custom: true, 24 | color: `rgba(${255}, ${255}, ${255}, ${0})` as any, 25 | selectedColor: `rgba(${255}, ${255}, ${255}, ${0})` as any, 26 | backgroundColor: `rgba(${255}, ${255}, ${255}, ${0})` as any, 27 | borderStyle: isMpWeixin ? 'white' : 'rgb(255,255,255,0)' as any, 28 | list: [ 29 | { 30 | pagePath: 'pages/index/index', 31 | text: 'Home', 32 | }, 33 | { 34 | pagePath: 'pages/count/count', 35 | text: 'Count', 36 | }, 37 | ], 38 | }, 39 | 40 | }) 41 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": [ 4 | "config:base", 5 | ":automergePatch", 6 | ":automergeTypes", 7 | ":automergeTesters", 8 | ":automergeLinters", 9 | ":rebaseStalePrs", 10 | ":semanticCommits", 11 | "schedule:quarterly" 12 | ], 13 | "packageRules": [ 14 | { 15 | "updateTypes": [ 16 | "major" 17 | ], 18 | "labels": [ 19 | "UPDATE-MAJOR" 20 | ] 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 39 | 40 | 43 | -------------------------------------------------------------------------------- /src/api/index.ts: -------------------------------------------------------------------------------- 1 | import type { QueryOptions } from '@tanstack/vue-query' 2 | import { unInstance } from '@/service' 3 | 4 | interface GITHUB { 5 | owner: { 6 | archive_url: string 7 | login: string 8 | } 9 | full_name: string 10 | html_url: string 11 | } 12 | 13 | export function fetchGitHubRepo(repo: string) { 14 | return { 15 | queryKey: [repo, 'repos'], 16 | queryFn: async () => (await unInstance.get(`repos/${repo}`)).data, 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/components/Counter.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 25 | -------------------------------------------------------------------------------- /src/composables/useToken.ts: -------------------------------------------------------------------------------- 1 | import { useStorageAsync } from '@uni-helper/uni-use' 2 | 3 | // import type { RemovableRef } from '@vueuse/core' 4 | import type { RemovableRef } from '@vueuse/core' 5 | import { DefaultToken, TokenKey } from '@/constants' 6 | 7 | /** 8 | * Generates a function comment for the given function body. 9 | * 10 | * @param {string} initialToken - the initial token value (optional, default: DefaultToken) 11 | * @return {RemovableRef} the token value 12 | */ 13 | export function useToken(initialToken: string = DefaultToken): RemovableRef { 14 | const token = useStorageAsync(TokenKey, initialToken) 15 | return token 16 | } 17 | -------------------------------------------------------------------------------- /src/constants/index.ts: -------------------------------------------------------------------------------- 1 | import { pascalCase } from 'change-case' 2 | import pkg from '@/../package.json' 3 | 4 | const ViteMode = import.meta.env.VITE_MODE || 'production' 5 | const PascalCaseViteMode = pascalCase(ViteMode) 6 | 7 | export { default as pkg } from '@/../package.json' 8 | 9 | // 请求 10 | /** 默认请求基地址 */ 11 | export const DefaultBaseUrl 12 | = import.meta.env.VITE_BASE_API || 'https://jsonplaceholder.typicode.com/' 13 | /** 默认请求头 */ 14 | export const DefaultHeaders = { 15 | 'Accept': 'application/json', 16 | 'Content-Type': 'application/json; charset=utf-8', 17 | 'X-Version': `${pkg.name}/${pkg.version}`, 18 | } 19 | 20 | /** 登录态键 */ 21 | export const TokenKey = `token${PascalCaseViteMode}` 22 | /** 默认登录态 */ 23 | export const DefaultToken = '' 24 | 25 | export const ThemeKey = `theme${PascalCaseViteMode}` 26 | -------------------------------------------------------------------------------- /src/layouts/default.vue: -------------------------------------------------------------------------------- 1 | 30 | 31 | 46 | 47 | 53 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | // check https://wechat-miniprogram.github.io/miniprogram-compat/ 2 | // import 'core-js/actual'; 3 | // import 'core-js/actual/structured-clone' 4 | 5 | // import 'core-js/actual/array/flat'; // since 2.16.1 6 | // import 'core-js/actual/array/flat-map'; // since 2.16.1 7 | // import 'core-js/actual/object/entries'; // since 2.16.1 8 | // import 'core-js/actual/object/from-entries'; // since 2.16.1 9 | // import 'core-js/actual/object/values'; // since 2.16.1 10 | // import 'core-js/actual/promise'; // since 2.11.0 11 | // import 'core-js/actual/promise/all-settled'; // since 2.16.1 12 | // import 'core-js/actual/promise/finally'; // since 2.16.1 13 | // import 'core-js/actual/string/pad-end'; // since 2.16.1 14 | // import 'core-js/actual/string/pad-start'; // since 2.16.1 15 | // import 'core-js/actual/string/replace-all' 16 | 17 | import { setupStore } from '@/store' 18 | // since 2.16.1 but consider other platforms 19 | // import 'core-js/actual/string/trim-end' 20 | // import 'core-js/actual/string/trim-start' 21 | import { createSSRApp } from 'vue' 22 | import App from './App.vue' 23 | import { dayjsPlugin, vueQueryPlugin } from './plugins' 24 | import 'uno.css' 25 | import '@/styles/reset.css' 26 | 27 | export function createApp() { 28 | const app = createSSRApp(App).use(dayjsPlugin).use(vueQueryPlugin) 29 | setupStore(app) 30 | return { 31 | app, 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/manifest.json: -------------------------------------------------------------------------------- 1 | {"name":"uniapp-vite-template","appid":"","description":"","versionName":"1.0.0","versionCode":"100","transformPx":false,"app-plus":{"usingComponents":true,"nvueStyleCompiler":"uni-app","compilerVersion":3,"splashscreen":{"alwaysShowBeforeRender":true,"waiting":true,"autoclose":true,"delay":0},"modules":{"Canvas":"nvue canvas"},"distribute":{"android":{"permissions":["","","","","","","","","","","",""]},"ios":{},"sdkConfigs":{}}},"quickapp":{},"mp-weixin":{"appid":"","setting":{"urlCheck":false,"es6":true,"minified":true,"postcss":true,"ignoreDevUnusedFiles":false,"ignoreUploadUnusedFiles":false},"usingComponents":true,"lazyCodeLoading":"requiredComponents","darkmode":true,"themeLocation":"theme.json","libVersion":"3.4.3"},"mp-alipay":{"usingComponents":true},"mp-baidu":{"usingComponents":true},"mp-toutiao":{"usingComponents":true},"uniStatistics":{"enable":false},"vueVersion":"3","h5":{"darkmode":true,"themeLocation":"theme.json"}} -------------------------------------------------------------------------------- /src/pages.json: -------------------------------------------------------------------------------- 1 | {"pages":[{"path":"pages/index/index","type":"home","style":{"navigationStyle":"default","navigationBarTitleText":"Home"}},{"path":"pages/count/count","type":"page","style":{"navigationStyle":"default","navigationBarTitleText":"Count"}}],"globalStyle":{"navigationBarBackgroundColor":"@navBgColor","navigationBarTextStyle":"@navTxtStyle","navigationBarTitleText":"uniapp-vite-template","backgroundColor":"@bgColor","backgroundTextStyle":"@bgTxtStyle","backgroundColorTop":"@bgColorTop","backgroundColorBottom":"@bgColorBottom","navigationStyle":"custom"},"tabBar":{"custom":true,"color":"rgba(255, 255, 255, 0)","selectedColor":"rgba(255, 255, 255, 0)","backgroundColor":"rgba(255, 255, 255, 0)","borderStyle":"rgb(255,255,255,0)","list":[{"pagePath":"pages/index/index","text":"Home"},{"pagePath":"pages/count/count","text":"Count"}]},"subPackages":[]} 2 | -------------------------------------------------------------------------------- /src/pages/count/count.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | { 9 | "style": { 10 | "navigationStyle": "default", 11 | "navigationBarTitleText": "Count" 12 | } 13 | } 14 | 15 | -------------------------------------------------------------------------------- /src/pages/index/index.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 36 | 37 | 38 | { 39 | "style": { 40 | "navigationStyle": "default", 41 | "navigationBarTitleText": "Home" 42 | } 43 | } 44 | 45 | 46 | 55 | -------------------------------------------------------------------------------- /src/plugins/dayjs.ts: -------------------------------------------------------------------------------- 1 | import dayjs from 'dayjs' 2 | import customParseFormat from 'dayjs/plugin/customParseFormat' 3 | import type { Plugin } from 'vue' 4 | 5 | /** 6 | * Installs the customParseFormat extension for dayjs. 7 | */ 8 | export const dayjsPlugin: Plugin = { 9 | install: () => { 10 | dayjs.extend(customParseFormat) 11 | }, 12 | } 13 | -------------------------------------------------------------------------------- /src/plugins/index.ts: -------------------------------------------------------------------------------- 1 | export * from './dayjs' 2 | export * from './vue-query' 3 | -------------------------------------------------------------------------------- /src/plugins/vue-query.ts: -------------------------------------------------------------------------------- 1 | import { VueQueryPlugin } from '@tanstack/vue-query' 2 | import type { Plugin } from 'vue' 3 | import { vueQueryPluginOptions } from '@/service' 4 | 5 | export const vueQueryPlugin: Plugin = { 6 | install: (app) => { 7 | app.use(VueQueryPlugin, vueQueryPluginOptions) 8 | }, 9 | } 10 | -------------------------------------------------------------------------------- /src/service/helper.ts: -------------------------------------------------------------------------------- 1 | let hasModal = false 2 | export function showNetworkError({ 3 | hasPrefix = true, 4 | message, 5 | response, 6 | error, 7 | type = 'modal' as IUnShowErrorType, 8 | success, 9 | fail, 10 | complete, 11 | }: 12 | | { 13 | hasPrefix?: boolean 14 | message?: string 15 | response?: IUnResponse 16 | error?: IUnError 17 | type?: 'modal' 18 | success?: UniApp.ShowModalOptions['success'] 19 | fail?: UniApp.ShowModalOptions['fail'] 20 | complete?: UniApp.ShowModalOptions['complete'] 21 | } 22 | | { 23 | hasPrefix?: boolean 24 | message?: string 25 | response?: IUnResponse 26 | error?: IUnError 27 | type: 'toast' 28 | success?: UniApp.ShowToastOptions['success'] 29 | fail?: UniApp.ShowToastOptions['fail'] 30 | complete?: UniApp.ShowToastOptions['complete'] 31 | } = {}) { 32 | // method 33 | const method 34 | = error?.config?.method 35 | ?? error?.task?.method 36 | // @ts-expect-error no types 37 | ?? error?.method 38 | ?? response?.config?.method 39 | ?? response?.task?.method 40 | // @ts-expect-error no types 41 | ?? response?.method 42 | ?? '' 43 | const methodText = method ? `请求方法:${method}` : '' 44 | 45 | // url 46 | const url 47 | = error?.config?.url 48 | ?? error?.task?.url 49 | // @ts-expect-error no types 50 | ?? error?.url 51 | ?? response?.config?.url 52 | ?? response?.task?.url 53 | // @ts-expect-error no types 54 | ?? response?.url 55 | ?? '' 56 | const urlText = url ? `请求地址:${url}` : '' 57 | 58 | // statusCode 59 | const statusCode 60 | = error?.status 61 | // @ts-expect-error no types 62 | ?? error?.statusCode 63 | // @ts-expect-error no types 64 | ?? error?.data?.status 65 | // @ts-expect-error no types 66 | ?? error?.data?.statusCode 67 | // @ts-expect-error no types 68 | ?? error?.data?.code 69 | ?? response?.status 70 | // @ts-expect-error no types 71 | ?? response?.statusCode 72 | ?? response?.data?.status 73 | ?? response?.data?.code 74 | // @ts-expect-error no types 75 | ?? response?.data?.statusCode 76 | ?? 0 77 | const statusCodeText = statusCode ? `状态代码:${statusCode}` : '' 78 | 79 | // errorCode 80 | const errorCode 81 | = error?.code 82 | // @ts-expect-error no types 83 | ?? error?.errno 84 | // @ts-expect-error no types 85 | ?? error?.data?.code 86 | // @ts-expect-error no types 87 | ?? error?.data?.errno 88 | // @ts-expect-error no types 89 | ?? response?.code 90 | ?? response?.errno 91 | ?? response?.data?.code 92 | // @ts-expect-error no types 93 | ?? response?.data?.errno 94 | ?? '' 95 | const errorCodeText = errorCode ? `错误代码:${errorCode}` : '' 96 | 97 | // errorMessage 98 | const errorMessage 99 | // @ts-expect-error no types 100 | = error?.data?.errMsg 101 | // @ts-expect-error no types 102 | ?? error?.data?.message 103 | // @ts-expect-error no types 104 | ?? error?.data?.msg 105 | // @ts-expect-error no types 106 | ?? error?.errMsg 107 | ?? error?.message 108 | // @ts-expect-error no types 109 | ?? error?.msg 110 | // @ts-expect-error no types 111 | ?? response?.data?.errMsg 112 | // @ts-expect-error no types 113 | ?? response?.data?.message 114 | ?? response?.data?.msg 115 | ?? response?.errMsg 116 | // @ts-expect-error no types 117 | ?? response?.message 118 | // @ts-expect-error no types 119 | ?? response?.msg 120 | ?? message 121 | ?? '' 122 | const errorMessageText = errorMessage ? `错误信息:${errorMessage}` : '' 123 | 124 | const content = `${[ 125 | hasPrefix ? '发生了错误。' : '', 126 | errorMessageText, 127 | errorCodeText, 128 | methodText, 129 | urlText, 130 | statusCodeText, 131 | ] 132 | .filter(item => !!item) 133 | .join('\r\n')}` 134 | 135 | if (type === 'toast') { 136 | uni.showToast({ 137 | title: content, 138 | success, 139 | fail, 140 | complete, 141 | }) 142 | return 143 | } 144 | if (type === 'modal' && !hasModal) { 145 | hasModal = true 146 | uni.showModal({ 147 | title: '错误', 148 | content, 149 | success: (result) => { 150 | success?.(result) 151 | hasModal = false 152 | }, 153 | fail: (result) => { 154 | fail?.(result) 155 | hasModal = false 156 | }, 157 | complete, 158 | }) 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /src/service/index.ts: -------------------------------------------------------------------------------- 1 | import type { VueQueryPluginOptions } from '@tanstack/vue-query' 2 | import { DefaultBaseUrl, DefaultHeaders } from '@/constants' 3 | import { useAuthStore } from '@/store' 4 | import { MutationCache, QueryCache, QueryClient } from '@tanstack/vue-query' 5 | import un from '@uni-helper/uni-network' 6 | import qs from 'qs' 7 | import { showNetworkError } from './helper' 8 | 9 | const instance = un.create({ 10 | baseUrl: DefaultBaseUrl, 11 | timeout: 30_000, 12 | paramsSerializer: (params: any) => { 13 | const query = qs.stringify( 14 | Object.fromEntries( 15 | Object.entries(params).filter( 16 | ([, v]) => !['undefined', 'null', undefined, null].includes((v as any)?.toString() ?? v), 17 | ), 18 | ), 19 | ) 20 | 21 | return query 22 | }, 23 | }) 24 | 25 | instance.interceptors.request.use((config) => { 26 | const authStore = useAuthStore() 27 | config.headers = { 28 | ...DefaultHeaders, 29 | 'token': authStore.token, 30 | 'X-Token': authStore.token, 31 | 'X-Access-Token': authStore.token, 32 | ...config.headers, 33 | } 34 | return config 35 | }) 36 | instance.interceptors.response.use((response) => { 37 | const data = response as IUnResponse 38 | 39 | // if (response.config?.showError ?? true) { 40 | // showNetworkError({ 41 | // response: response as unknown as IUnResponse, 42 | // error: data?.data as unknown as IUnError, 43 | // type: data.config?.showErrorType, 44 | // }) 45 | // } 46 | return data 47 | }) 48 | 49 | export { instance as unInstance } 50 | 51 | export const vueQueryClient = new QueryClient({ 52 | queryCache: new QueryCache({ 53 | onError: (error) => { 54 | if (un.isCancel(error)) 55 | return 56 | showNetworkError({ error: error as IUnError }) 57 | }, 58 | }), 59 | mutationCache: new MutationCache({ 60 | onError: (error) => { 61 | if (un.isCancel(error)) 62 | return 63 | showNetworkError({ error: error as IUnError }) 64 | }, 65 | }), 66 | }) 67 | 68 | export const vueQueryPluginOptions: VueQueryPluginOptions = { 69 | queryClient: vueQueryClient, 70 | } 71 | -------------------------------------------------------------------------------- /src/service/types.ts: -------------------------------------------------------------------------------- 1 | import type { UnConfig, UnError, UnResponse } from '@uni-helper/uni-network' 2 | 3 | type IUnShowErrorType_ = 'toast' | 'modal' 4 | 5 | type IUnRequestData_ = Record 6 | 7 | interface IUnResponseData_ { 8 | code: number 9 | msg: string 10 | status: boolean 11 | data: T 12 | } 13 | 14 | interface IUnConfig_ extends UnConfig { 15 | showError?: boolean 16 | showErrorType?: IUnShowErrorType_ 17 | } 18 | interface IUnResponse_ extends UnResponse { } 19 | 20 | type IUnPromise_ = Promise> 21 | 22 | interface IUnError_ extends UnError { 23 | response?: IUnResponse_ 24 | } 25 | 26 | export type { 27 | IUnConfig_ as IUnConfig, 28 | IUnError_ as IUnError, 29 | IUnPromise_ as IUnPromise, 30 | IUnRequestData_ as IUnRequestData, 31 | IUnResponse_ as IUnResponse, 32 | IUnResponseData_ as IUnResponseData, 33 | IUnShowErrorType_ as IUnShowErrorType, 34 | } 35 | 36 | declare global { 37 | type IUnShowErrorType = IUnShowErrorType_ 38 | type IUnResponseData = IUnResponseData_ 39 | interface IUnRequestData extends IUnRequestData_ { } 40 | interface IUnConfig extends IUnConfig_, D> { } 41 | interface IUnResponse extends IUnResponse_, D> { } 42 | type IUnPromise = IUnPromise_, D> 43 | interface IUnError extends IUnError_, D> { } 44 | } 45 | -------------------------------------------------------------------------------- /src/static/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yang1206/uniapp-template/00734bfdfd231d26db272ddd6bd3e456a97ef6ba/src/static/logo.png -------------------------------------------------------------------------------- /src/static/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/static/vue.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/store/index.ts: -------------------------------------------------------------------------------- 1 | import { createPinia } from 'pinia' 2 | import type { App } from 'vue' 3 | 4 | export const pinia = createPinia() 5 | export async function setupStore(app: App) { 6 | app.use(pinia) 7 | } 8 | 9 | export * from './modules' 10 | -------------------------------------------------------------------------------- /src/store/modules/app/index.ts: -------------------------------------------------------------------------------- 1 | interface MenuButtonBoundingClientRect { 2 | width: number 3 | height: number 4 | top: number 5 | left: number 6 | right: number 7 | bottom: number 8 | } 9 | 10 | export const useAppStore = defineStore( 11 | 'app', 12 | () => { 13 | const darkMode = ref(false) 14 | const statusBarHeight = ref(0) 15 | const menuButtonBounding = ref() 16 | const customBarHeight = computed( 17 | () => !menuButtonBounding.value 18 | ? 0 19 | : menuButtonBounding.value.bottom + menuButtonBounding.value.top - statusBarHeight.value, 20 | ) 21 | 22 | // #ifdef H5 23 | watch(darkMode, (isDark) => { 24 | isDark ? document.documentElement.classList.add('dark') : document.documentElement.classList.remove('dark') 25 | }, { 26 | immediate: true, 27 | }) 28 | // #endif 29 | 30 | return { 31 | darkMode, 32 | statusBarHeight, 33 | customBarHeight, 34 | menuButtonBounding, 35 | } 36 | }, 37 | ) 38 | -------------------------------------------------------------------------------- /src/store/modules/auth/index.ts: -------------------------------------------------------------------------------- 1 | import { defineStore } from 'pinia' 2 | import { useToken } from '@/composables/useToken' 3 | import { DefaultToken } from '@/constants' 4 | 5 | export const useAuthStore = defineStore('auth', () => { 6 | const token = useToken() 7 | const setToken = (newToken = DefaultToken) => { 8 | token.value = newToken 9 | } 10 | return { 11 | token, 12 | setToken, 13 | } 14 | }) 15 | -------------------------------------------------------------------------------- /src/store/modules/count/index.ts: -------------------------------------------------------------------------------- 1 | import { defineStore } from 'pinia' 2 | 3 | export const useCounterStore = defineStore('counter', () => { 4 | const count = ref(0) 5 | function inc() { 6 | count.value += 1 7 | } 8 | function dec() { 9 | count.value -= 1 10 | } 11 | async function asyncInc() { 12 | setTimeout(() => { 13 | inc() 14 | }, 300) 15 | } 16 | return { 17 | count, 18 | inc, 19 | dec, 20 | asyncInc, 21 | } 22 | }) 23 | -------------------------------------------------------------------------------- /src/store/modules/index.ts: -------------------------------------------------------------------------------- 1 | export * from './count' 2 | export * from './app' 3 | export * from './auth' 4 | -------------------------------------------------------------------------------- /src/styles/reset.css: -------------------------------------------------------------------------------- 1 | html, 2 | body, 3 | #app { 4 | height: 100%; 5 | padding: 0; 6 | margin: 0; 7 | } 8 | 9 | html{ 10 | font-size:8px; 11 | } 12 | 13 | html.dark { 14 | background: #121212; 15 | } -------------------------------------------------------------------------------- /src/styles/variables.scss: -------------------------------------------------------------------------------- 1 | /* 2 | * uni-app uni.scss 内容,可直接修改 3 | * 参考 https://uniapp.dcloud.io/collocation/uni-scss 4 | */ 5 | 6 | /* 颜色变量 */ 7 | // 行为相关颜色 8 | $uni-color-primary: #007aff; 9 | $uni-color-success: #4cd964; 10 | $uni-color-warning: #f0ad4e; 11 | $uni-color-error: #dd524d; 12 | 13 | // 文字基本颜色 14 | $uni-text-color: #333; // 基本色 15 | $uni-text-color-inverse: #fff; // 反色 16 | $uni-text-color-grey: #999; // 辅助灰色,如加载更多的提示信息 17 | $uni-text-color-placeholder: #808080; 18 | $uni-text-color-disable: #c0c0c0; 19 | 20 | // 背景颜色 21 | $uni-bg-color: #fff; 22 | $uni-bg-color-grey: #f8f8f8; 23 | $uni-bg-color-hover: #f1f1f1; // 点击状态颜色 24 | $uni-bg-color-mask: rgb(0 0 0 / 40%); // 遮罩颜色 25 | // 边框颜色 26 | $uni-border-color: #c8c7cc; 27 | 28 | /* 尺寸变量 */ 29 | // 文字尺寸 30 | $uni-font-size-sm: 12px; 31 | $uni-font-size-base: 14px; 32 | $uni-font-size-lg: 16px; 33 | 34 | // 图片尺寸 35 | $uni-img-size-sm: 20px; 36 | $uni-img-size-base: 26px; 37 | $uni-img-size-lg: 40px; 38 | 39 | /* 边框圆角 */ 40 | $uni-border-radius-sm: 2px; 41 | $uni-border-radius-base: 3px; 42 | $uni-border-radius-lg: 6px; 43 | $uni-border-radius-circle: 50%; 44 | 45 | /** 间距变量 */ 46 | // 水平间距 47 | $uni-spacing-row-sm: 5px; 48 | $uni-spacing-row-base: 10px; 49 | $uni-spacing-row-lg: 15px; 50 | 51 | // 垂直间距 52 | $uni-spacing-col-sm: 4px; 53 | $uni-spacing-col-base: 8px; 54 | $uni-spacing-col-lg: 12px; 55 | 56 | /* 透明度 */ 57 | $uni-opacity-disabled: 0.3; // 组件禁用态的透明度 58 | 59 | /* 文章场景相关 */ 60 | $uni-color-title: #2c405a; // 文章标题颜色 61 | $uni-font-size-title: 20px; 62 | $uni-color-subtitle: #555; // 二级标题颜色 63 | $uni-font-size-subtitle: 18px; 64 | $uni-color-paragraph: #3f536e; // 文章段落颜色 65 | $uni-font-size-paragraph: 15px; 66 | 67 | @import 'nutui-uniapp/styles/variables'; 68 | -------------------------------------------------------------------------------- /src/theme.json: -------------------------------------------------------------------------------- 1 | { 2 | "dark": { 3 | "navBgColor": "#373739", 4 | "navTxtStyle": "white", 5 | "bgColor": "#000", 6 | "bgTxtStyle": "light", 7 | "bgColorTop": "#000", 8 | "bgColorBottom": "#000" 9 | }, 10 | "light": { 11 | "navBgColor": "#FFFFFF", 12 | "navTxtStyle": "black", 13 | "bgColor": "#F3F4F6", 14 | "bgTxtStyle": "dark", 15 | "bgColorTop": "#F3F4F6", 16 | "bgColorBottom": "#F3F4F6" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/uni.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * 这里是uni-app内置的常用样式变量 3 | * 4 | * uni-app 官方扩展插件及插件市场(https://ext.dcloud.net.cn)上很多三方插件均使用了这些样式变量 5 | * 如果你是插件开发者,建议你使用scss预处理,并在插件代码中直接使用这些变量(无需 import 这个文件),方便用户通过搭积木的方式开发整体风格一致的App 6 | * 7 | */ 8 | 9 | /** 10 | * 如果你是App开发者(插件使用者),你可以通过修改这些变量来定制自己的插件主题,实现自定义主题功能 11 | * 12 | * 如果你的项目同样使用了scss预处理,你也可以直接在你的 scss 代码中使用如下变量,同时无需 import 这个文件 13 | */ 14 | 15 | /* 颜色变量 */ 16 | 17 | /* uni.scss */ 18 | 19 | /* 行为相关颜色 */ 20 | $uni-color-primary: #007aff; 21 | $uni-color-success: #4cd964; 22 | $uni-color-warning: #f0ad4e; 23 | $uni-color-error: #dd524d; 24 | 25 | /* 文字基本颜色 */ 26 | $uni-text-color: #333; // 基本色 27 | $uni-text-color-inverse: #fff; // 反色 28 | $uni-text-color-grey: #999; // 辅助灰色,如加载更多的提示信息 29 | $uni-text-color-placeholder: #808080; 30 | $uni-text-color-disable: #c0c0c0; 31 | 32 | /* 背景颜色 */ 33 | $uni-bg-color: #fff; 34 | $uni-bg-color-grey: #f8f8f8; 35 | $uni-bg-color-hover: #f1f1f1; // 点击状态颜色 36 | $uni-bg-color-mask: rgb(0 0 0 / 40%); // 遮罩颜色 37 | 38 | /* 边框颜色 */ 39 | $uni-border-color: #c8c7cc; 40 | 41 | /* 尺寸变量 */ 42 | 43 | /* 文字尺寸 */ 44 | $uni-font-size-sm: 12px; 45 | $uni-font-size-base: 14px; 46 | $uni-font-size-lg: 16; 47 | 48 | /* 图片尺寸 */ 49 | $uni-img-size-sm: 20px; 50 | $uni-img-size-base: 26px; 51 | $uni-img-size-lg: 40px; 52 | 53 | /* Border Radius */ 54 | $uni-border-radius-sm: 2px; 55 | $uni-border-radius-base: 3px; 56 | $uni-border-radius-lg: 6px; 57 | $uni-border-radius-circle: 50%; 58 | 59 | /* 水平间距 */ 60 | $uni-spacing-row-sm: 5px; 61 | $uni-spacing-row-base: 10px; 62 | $uni-spacing-row-lg: 15px; 63 | 64 | /* 垂直间距 */ 65 | $uni-spacing-col-sm: 4px; 66 | $uni-spacing-col-base: 8px; 67 | $uni-spacing-col-lg: 12px; 68 | 69 | /* 透明度 */ 70 | $uni-opacity-disabled: 0.3; // 组件禁用态的透明度 71 | 72 | /* 文章场景相关 */ 73 | $uni-color-title: #2c405a; // 文章标题颜色 74 | $uni-font-size-title: 20px; 75 | $uni-color-subtitle: #555; // 二级标题颜色 76 | $uni-font-size-subtitle: 18px; 77 | $uni-color-paragraph: #3f536e; // 文章段落颜色 78 | $uni-font-size-paragraph: 15px; 79 | -------------------------------------------------------------------------------- /src/utils/is.ts: -------------------------------------------------------------------------------- 1 | export const toString = Object.prototype.toString 2 | 3 | export function is(val: unknown, type: string): boolean { 4 | return toString.call(val) === `[object ${type}]` 5 | } 6 | 7 | export function isDef(val: any): boolean { 8 | return typeof val !== 'undefined' 9 | } 10 | 11 | export function isUndef(val: any): boolean { 12 | return typeof val === 'undefined' 13 | } 14 | 15 | export function isNull(val: any): boolean { 16 | return val === null 17 | } 18 | 19 | export function isWhitespace(val: any): boolean { 20 | return val === '' 21 | } 22 | 23 | export function isObject(val: any): boolean { 24 | return !isNull(val) && is(val, 'Object') 25 | } 26 | 27 | export function isArray(val: any): boolean { 28 | return val && Array.isArray(val) 29 | } 30 | 31 | export function isString(val: any): boolean { 32 | return is(val, 'String') 33 | } 34 | 35 | export function isNumber(val: any): boolean { 36 | return is(val, 'Number') 37 | } 38 | 39 | export function isBoolean(val: any): boolean { 40 | return is(val, 'Boolean') 41 | } 42 | 43 | export function isDate(val: any): boolean { 44 | return is(val, 'Date') 45 | } 46 | 47 | export function isRegExp(val: any): boolean { 48 | return is(val, 'RegExp') 49 | } 50 | 51 | export function isFunction(val: any): boolean { 52 | return typeof val === 'function' 53 | } 54 | 55 | export function isPromise(val: any): boolean { 56 | return is(val, 'Promise') && isObject(val) && isFunction(val.then) && isFunction(val.catch) 57 | } 58 | 59 | export function isElement(val: any): boolean { 60 | return isObject(val) && !!val.tagName 61 | } 62 | 63 | /** null or undefined */ 64 | export function isNullOrUndef(val: any): boolean { 65 | return isNull(val) || isUndef(val) 66 | } 67 | 68 | /** null or undefined or 空字符 */ 69 | export function isNullOrWhitespace(val: any): boolean { 70 | return isNullOrUndef(val) || isWhitespace(val) 71 | } 72 | 73 | /** 空数组 or 空字符 or 空map or 空set or 空对象 */ 74 | export function isEmpty(val: any): boolean { 75 | if (isArray(val) || isString(val)) 76 | return val.length === 0 77 | 78 | if (val instanceof Map || val instanceof Set) 79 | return val.size === 0 80 | 81 | if (isObject(val)) 82 | return Object.keys(val).length === 0 83 | 84 | return false 85 | } 86 | 87 | /** 88 | * 类似mysql的IFNULL函数 89 | * @description 当第一个参数为null/undefined/'' 则返回第二个参数作为备用值,否则返回第一个参数 90 | */ 91 | export function ifNull(val: any, def: any = '') { 92 | return isNullOrWhitespace(val) ? def : val 93 | } 94 | 95 | export function isUrl(path: string): boolean { 96 | const reg 97 | = /(((^https?:(?:\/\/)?)(?:[-;:&=+$,\w]+@)?[A-Za-z0-9.-]+(?::\d+)?|(?:www.|[-;:&=+$,\w]+@)[A-Za-z0-9.-]+)((?:\/[+~%/.\w-]*)?\??[-+=&;%@.\w]*(?:#\w*)?))$/ 98 | return reg.test(path) 99 | } 100 | 101 | export function isValidKey( 102 | key: string, 103 | object: object, 104 | ): key is keyof typeof object { 105 | return key in object 106 | } 107 | -------------------------------------------------------------------------------- /src/utils/shared.ts: -------------------------------------------------------------------------------- 1 | // 防止快速点击 2 | let lastClickTime = 0 3 | 4 | export function isFastClick(num = 1000) { 5 | const time = new Date().getTime() 6 | if (time - lastClickTime > num) 7 | return false 8 | 9 | lastClickTime = time 10 | return true 11 | } 12 | 13 | // 解析 path 14 | export function parseUrl(fullPath: string) { 15 | const [path, queryStr] = fullPath.split('?') 16 | const name = path.slice(path.lastIndexOf('/') + 1) 17 | const query: { [key: string]: unknown } = {} 18 | queryStr 19 | ?.split('&') 20 | .map(i => i.split('=')) 21 | .forEach(i => (query[i[0]] = i[1])) 22 | return { 23 | name, 24 | path, 25 | query, 26 | } 27 | } 28 | 29 | // 还原url 30 | export function restoreUrl(path: string, query: { [key: string]: unknown }) { 31 | let count = 0 32 | for (const key in query) { 33 | path += `${count === 0 ? '?' : '&'}${key}=${query[key]}` 34 | count += 1 35 | } 36 | return path 37 | } 38 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "jsx": "preserve", 5 | "jsxImportSource": "vue", 6 | "lib": [ 7 | "DOM", 8 | "DOM.Iterable", 9 | "ESNext" 10 | ], 11 | "useDefineForClassFields": true, 12 | "baseUrl": ".", 13 | "module": "ESNext", 14 | "moduleResolution": "Bundler", 15 | "paths": { 16 | "@/*": [ 17 | "src/*" 18 | ], 19 | "~/*": [ 20 | "./*" 21 | ] 22 | }, 23 | "resolveJsonModule": true, 24 | "types": [ 25 | "vite/client", 26 | "@dcloudio/types", 27 | "@mini-types/alipay", 28 | "miniprogram-api-typings", 29 | "unplugin-vue-macros/macros-global", 30 | "nutui-uniapp/global.d.ts", 31 | "unplugin-icons/types/vue", 32 | "type-fest", 33 | "@uni-helper/uni-types" 34 | ], 35 | "strict": true, 36 | "noImplicitThis": true, 37 | "esModuleInterop": true, 38 | "forceConsistentCasingInFileNames": true, 39 | "verbatimModuleSyntax": true, 40 | "skipLibCheck": true 41 | }, 42 | "vueCompilerOptions": { 43 | "plugins": [ 44 | "@uni-helper/uni-types/volar-plugin" 45 | ] 46 | }, 47 | "include": [ 48 | "typings/components.d.ts", 49 | "**/*.d.ts", 50 | "**/*.tsx", 51 | "**/*.ts", 52 | "**/*.vue", 53 | "package.json" 54 | ] 55 | } 56 | -------------------------------------------------------------------------------- /typings/common.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * 路由类型定义 3 | */ 4 | declare interface Route { 5 | path: string; 6 | name?: string; 7 | fullPath?: string; 8 | query: Query; 9 | [key: string]: any; 10 | } 11 | -------------------------------------------------------------------------------- /typings/shime-uni.d.ts: -------------------------------------------------------------------------------- 1 | export {} 2 | 3 | declare module "vue" { 4 | type Hooks = App.AppInstance & Page.PageInstance; 5 | interface ComponentCustomOptions extends Hooks {} 6 | } -------------------------------------------------------------------------------- /typings/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | type ProxyType = 'dev' | 'test' | 'prod' 4 | 5 | interface ProxyConfig { 6 | /** 匹配代理的前缀,接口地址匹配到此前缀将代理的target地址 */ 7 | prefix: string 8 | /** 代理目标地址,后端真实接口地址 */ 9 | target: string 10 | } 11 | 12 | interface ImportMetaEnv { 13 | readonly VITE_APP_TITLE: string 14 | readonly VITE_PORT: number 15 | readonly VITE_USE_PROXY?: boolean 16 | readonly VITE_PROXY_TYPE?: ProxyType 17 | readonly VITE_USE_HASH: 'true' | 'false' 18 | readonly VITE_BASE_API: string 19 | // 更多环境变量... 20 | } 21 | 22 | interface ImportMeta { 23 | readonly env: ImportMetaEnv 24 | } 25 | 26 | declare module '*.vue' { 27 | import type { DefineComponent } from 'vue' 28 | // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types 29 | const component: DefineComponent<{}, {}, any> 30 | export default component 31 | } 32 | -------------------------------------------------------------------------------- /uno.config.ts: -------------------------------------------------------------------------------- 1 | import { 2 | type PresetOrFactory, 3 | type UserConfig, 4 | defineConfig, 5 | presetIcons, 6 | transformerDirectives, 7 | transformerVariantGroup, 8 | } from 'unocss' 9 | import presetRemToPx from '@unocss/preset-rem-to-px' 10 | import { isH5, isMp } from '@uni-helper/uni-env' 11 | import { presetUni } from '@uni-helper/unocss-preset-uni' 12 | 13 | const darkMode = isH5 ? 'class' : 'media' 14 | 15 | const config: UserConfig = defineConfig({ 16 | content: { 17 | pipeline: { 18 | exclude: [ 19 | 'node_modules', 20 | '.git', 21 | '.github', 22 | '.husky', 23 | '.vscode', 24 | 'build', 25 | 'dist', 26 | 'mock', 27 | 'public', 28 | 'types', 29 | './stats.html', 30 | ], 31 | }, 32 | }, 33 | shortcuts: [ 34 | ['btn', 'w-60 h-60 flex items-center justify-center rounded-full bg-teal-600 text-white cursor-pointer'], 35 | ['wh-full', 'w-full h-full'], 36 | ['f-c-c', 'flex justify-center items-center'], 37 | ['flex-col', 'flex flex-col'], 38 | ['absolute-lt', 'absolute left-0 top-0'], 39 | ['absolute-lb', 'absolute left-0 bottom-0'], 40 | ['absolute-rt', 'absolute right-0 top-0'], 41 | ['absolute-rb', 'absolute right-0 bottom-0'], 42 | ['absolute-center', 'absolute-lt f-c-c wh-full'], 43 | ['text-ellipsis', 'truncate'], 44 | [ 45 | 'icon-btn', 46 | 'inline-block cursor-pointer select-none opacity-75 transition duration-200 ease-in-out hover:opacity-100 hover:text-teal-600', 47 | ], 48 | ], 49 | presets: [ 50 | presetUni({ 51 | uno: { 52 | dark: darkMode, 53 | variablePrefix: 'li-', 54 | }, 55 | attributify: { 56 | ignoreAttributes: ['block', 'fixed'], 57 | }, 58 | remRpx: { 59 | baseFontSize: 2, 60 | mode: isMp ? 'rem2rpx' : 'rpx2rem', 61 | }, 62 | }) as PresetOrFactory, 63 | presetIcons({ 64 | scale: 1.2, 65 | warn: true, 66 | extraProperties: { 67 | 'display': 'inline-block', 68 | 'vertical-align': 'middle', 69 | }, 70 | }), 71 | // 保持h5和微信小程序转换比例一致 72 | presetRemToPx({ baseFontSize: 2 }), 73 | ], 74 | transformers: [ 75 | transformerDirectives(), 76 | transformerVariantGroup(), 77 | ], 78 | safelist: 'prose prose-sm m-auto text-left'.split(' '), 79 | theme: { 80 | preflightRoot: isMp ? ['page,::before,::after'] : undefined, 81 | }, 82 | }) 83 | 84 | export default config 85 | -------------------------------------------------------------------------------- /vite.config.ts: -------------------------------------------------------------------------------- 1 | import type { ConfigEnv } from 'vite' 2 | import process from 'node:process' 3 | import { defineConfig, loadEnv } from 'vite' 4 | import { createViteProxy } from './build/config' 5 | import { setupVitePlugins } from './build/plugins' 6 | import { convertEnv, getRootPath, getSrcPath } from './build/utils' 7 | 8 | // https://vitejs.dev/config/ 9 | export default defineConfig(async (configEnv: ConfigEnv) => { 10 | const srcPath = getSrcPath() 11 | const rootPath = getRootPath() 12 | const viteEnv = convertEnv(loadEnv(configEnv.mode, process.cwd())) 13 | const { VITE_PORT, VITE_USE_PROXY, VITE_PROXY_TYPE } = viteEnv 14 | return { 15 | plugins: await setupVitePlugins(), 16 | server: { 17 | host: '0.0.0.0', 18 | port: VITE_PORT, 19 | open: false, 20 | proxy: createViteProxy(VITE_USE_PROXY, VITE_PROXY_TYPE as ProxyType), 21 | }, 22 | envPrefix: ['VITE_', 'UNI_'], 23 | build: { 24 | target: 'es6', 25 | cssTarget: 'chrome61', 26 | reportCompressedSize: false, 27 | sourcemap: false, 28 | chunkSizeWarningLimit: 1024, // chunk 大小警告的限制(单位kb) 29 | commonjsOptions: { 30 | ignoreTryCatch: false, 31 | }, 32 | }, 33 | optimizeDeps: { 34 | exclude: ['vue-demi'], 35 | }, 36 | css: { 37 | preprocessorOptions: { 38 | scss: { 39 | api: 'modern-compiler', 40 | additionalData: `@import '@/styles/variables.scss';`, 41 | }, 42 | }, 43 | }, 44 | resolve: { 45 | alias: { 46 | '~': rootPath, 47 | '@': srcPath, 48 | }, 49 | }, 50 | } 51 | }) 52 | --------------------------------------------------------------------------------