Explorar o código

feat: 大量升级,v2.0.0

菲鸽 %!s(int64=2) %!d(string=hai) anos
pai
achega
28caa1dea3

+ 2 - 1
.eslintrc-auto-import.json

@@ -86,6 +86,7 @@
     "watch": true,
     "watchEffect": true,
     "watchPostEffect": true,
-    "watchSyncEffect": true
+    "watchSyncEffect": true,
+    "useRequest": true
   }
 }

+ 4 - 1
.stylelintrc.cjs

@@ -4,7 +4,8 @@ module.exports = {
   root: true,
   extends: [
     'stylelint-config-standard',
-    'stylelint-config-standard-scss', // tips: 本插件也可以替换成 stylelint-config-recommended-scss
+    // stylelint-config-standard-scss 替换成了更宽松的 stylelint-config-recommended-scss
+    'stylelint-config-recommended-scss',
     'stylelint-config-recommended-vue/scss',
     'stylelint-config-html/vue',
     'stylelint-config-recess-order',
@@ -49,5 +50,7 @@ module.exports = {
     'no-empty-source': null,
     'comment-no-empty': null,
     'no-duplicate-selectors': null,
+    'scss/comment-no-empty': null,
+    'selector-class-pattern': null,
   },
 }

+ 4 - 10
env/.env

@@ -1,18 +1,12 @@
 VITE_APP_TITLE = 'unibest'
 VITE_APP_PORT = 9000
 
-# github actions 部署地址根路径,用在 manifest.config.ts 里面的 h5.router.base
+# h5部署网站的base,配置到 manifest.config.ts 里的 h5.router.base
 VITE_APP_PUBLIC_BASE=/
 
-# TODO: 记得修改
-VITE_UNI_APPID = 'H5871D791'
+VITE_UNI_APPID = 'H57F2ACE4'
 VITE_WX_APPID = 'wxa2abb91f64032a2b'
 
-# fallback lacale:en, zh-Hans, zh-Hant 等
-# 必须要在 lacale 文件夹中配置对应的 json 文件!!!
-# 参考文档如下
-# https://uniapp.dcloud.net.cn/tutorial/i18n.html
-# https://uniapp.dcloud.net.cn/api/ui/locale.html#onlocalechange 打开页面后最下面的注意事项
-VITE_FALLBACK_LOCALE = 'zh-Hans'
-
+# 非h5端只能使用完整的baseurl,否则无法请求,本地proxy只支持h5端
+# VITE_SERVER_BASEURL = '/api'
 VITE_SERVER_BASEURL = 'https://ukw0y1.laf.run'

+ 2 - 2
env/.env.development

@@ -2,5 +2,5 @@
 NODE_ENV = 'development'
 # 是否去除console 和 debugger
 VITE_DELETE_CONSOLE = false
-
-# VITE_SERVER_BASEURL = 'https://ukw0y1.laf.run'
+# 是否开启sourcemap
+VITE_SHOW_SOURCEMAP = true

+ 2 - 2
env/.env.production

@@ -2,5 +2,5 @@
 NODE_ENV = 'development'
 # 是否去除console 和 debugger
 VITE_DELETE_CONSOLE = true
-
-# VITE_SERVER_BASEURL = 'https://xxx.com'
+# 是否开启sourcemap
+VITE_SHOW_SOURCEMAP = false

+ 22 - 22
package.json

@@ -1,7 +1,7 @@
 {
   "name": "unibest",
   "type": "commonjs",
-  "version": "1.5.0",
+  "version": "2.0.0",
   "description": "unibest - 最好的 uniapp 开发模板",
   "author": {
     "name": "codercup",
@@ -22,6 +22,7 @@
     "pnpm": ">=7.30"
   },
   "scripts": {
+    "upgrade": "npx @dcloudio/uvm@latest",
     "dev:app": "uni -p app",
     "dev:app-android": "uni -p app-android",
     "dev:app-ios": "uni -p app-ios",
@@ -78,20 +79,20 @@
     "bin-wrapper": "npm:bin-wrapper-china"
   },
   "dependencies": {
-    "@dcloudio/uni-app": "3.0.0-4000720240327002",
-    "@dcloudio/uni-app-plus": "3.0.0-4000720240327002",
-    "@dcloudio/uni-components": "3.0.0-4000720240327002",
-    "@dcloudio/uni-h5": "3.0.0-4000720240327002",
-    "@dcloudio/uni-mp-alipay": "3.0.0-4000720240327002",
-    "@dcloudio/uni-mp-baidu": "3.0.0-4000720240327002",
-    "@dcloudio/uni-mp-jd": "3.0.0-4000720240327002",
-    "@dcloudio/uni-mp-kuaishou": "3.0.0-4000720240327002",
-    "@dcloudio/uni-mp-lark": "3.0.0-4000720240327002",
-    "@dcloudio/uni-mp-qq": "3.0.0-4000720240327002",
-    "@dcloudio/uni-mp-toutiao": "3.0.0-4000720240327002",
-    "@dcloudio/uni-mp-weixin": "3.0.0-4000720240327002",
-    "@dcloudio/uni-mp-xhs": "3.0.0-4000720240327002",
-    "@dcloudio/uni-quickapp-webview": "3.0.0-4000720240327002",
+    "@dcloudio/uni-app": "3.0.0-4000820240401001",
+    "@dcloudio/uni-app-plus": "3.0.0-4000820240401001",
+    "@dcloudio/uni-components": "3.0.0-4000820240401001",
+    "@dcloudio/uni-h5": "3.0.0-4000820240401001",
+    "@dcloudio/uni-mp-alipay": "3.0.0-4000820240401001",
+    "@dcloudio/uni-mp-baidu": "3.0.0-4000820240401001",
+    "@dcloudio/uni-mp-jd": "3.0.0-4000820240401001",
+    "@dcloudio/uni-mp-kuaishou": "3.0.0-4000820240401001",
+    "@dcloudio/uni-mp-lark": "3.0.0-4000820240401001",
+    "@dcloudio/uni-mp-qq": "3.0.0-4000820240401001",
+    "@dcloudio/uni-mp-toutiao": "3.0.0-4000820240401001",
+    "@dcloudio/uni-mp-weixin": "3.0.0-4000820240401001",
+    "@dcloudio/uni-mp-xhs": "3.0.0-4000820240401001",
+    "@dcloudio/uni-quickapp-webview": "3.0.0-4000820240401001",
     "dayjs": "1.11.10",
     "pinia": "2.0.36",
     "pinia-plugin-persistedstate": "3.2.1",
@@ -103,22 +104,21 @@
     "@commitlint/cli": "^18.4.3",
     "@commitlint/config-conventional": "^18.4.3",
     "@dcloudio/types": "^3.4.8",
-    "@dcloudio/uni-automator": "3.0.0-4000720240327002",
-    "@dcloudio/uni-cli-shared": "3.0.0-4000720240327002",
-    "@dcloudio/uni-stacktracey": "3.0.0-4000720240327002",
-    "@dcloudio/vite-plugin-uni": "3.0.0-4000720240327002",
+    "@dcloudio/uni-automator": "3.0.0-4000820240401001",
+    "@dcloudio/uni-cli-shared": "3.0.0-4000820240401001",
+    "@dcloudio/uni-stacktracey": "3.0.0-4000820240401001",
+    "@dcloudio/vite-plugin-uni": "3.0.0-4000820240401001",
     "@iconify-json/carbon": "^1.1.27",
     "@types/node": "^20.11.5",
     "@types/wechat-miniprogram": "^3.4.7",
     "@typescript-eslint/eslint-plugin": "^6.15.0",
     "@typescript-eslint/parser": "^6.15.0",
-    "@uni-helper/vite-plugin-uni-components": "^0.0.8",
     "@uni-helper/vite-plugin-uni-layouts": "^0.1.7",
     "@uni-helper/vite-plugin-uni-manifest": "^0.2.3",
     "@uni-helper/vite-plugin-uni-pages": "^0.2.15",
     "@uni-helper/vite-plugin-uni-platform": "^0.0.4",
     "@unocss/preset-legacy-compat": "^0.59.1",
-    "@vue/runtime-core": "^3.3.13",
+    "@vue/runtime-core": "^3.4.21",
     "@vue/tsconfig": "^0.1.3",
     "autoprefixer": "^10.4.16",
     "commitlint": "^18.4.3",
@@ -139,9 +139,9 @@
     "stylelint": "^16.0.2",
     "stylelint-config-html": "^1.1.0",
     "stylelint-config-recess-order": "^4.4.0",
+    "stylelint-config-recommended-scss": "^14.0.0",
     "stylelint-config-recommended-vue": "^1.5.0",
     "stylelint-config-standard": "^35.0.0",
-    "stylelint-config-standard-scss": "^12.0.0",
     "stylelint-prettier": "^5.0.0",
     "terser": "^5.26.0",
     "typescript": "^4.9.5",

+ 0 - 10
shell/postinstall.sh

@@ -1,10 +0,0 @@
-# 本文件会在依赖包安装时执行,用以生成 `src/manifest.json`
-# 如果不存在 `src/manifest.json` 会运行报错,提示找不到 `src/manifest.json`
-# 如果中途自己删除了 'src/manifest.json' 文件,记得手动执行本文件,可以右键 `Run Code` 快速执行
-
-if test -f ./src/manifest.json; then
-  echo ./src/manifest.json 存在
-else
-  touch ./src/manifest.json
-  echo "{}" >./src/manifest.json
-fi

+ 0 - 17
shell/rename.sh

@@ -1,17 +0,0 @@
-# pnpm build:app 之后会生成 unpackage/dist/build/app
-# 我要把它改名为 unpackage/dist/build/unibest_app_build
-
-# 只有存在新的 app 文件时,才执行这些操作!!否则会误删!!
-if test -d ./dist/build/app; then
-  echo '存在新打包出来的app'
-
-  cd ./dist/build/
-
-  # 1、删除旧的 rename 后的文件夹
-  if test -d './unibest_app_build'; then
-    rm -rf ./unibest_app_build
-  fi
-
-  # 2、把 app 命名为 unibest_app_build
-  mv ./app ./unibest_app_build
-fi

src/pages-sub/.gitkeep → src/components/.gitkeep


+ 0 - 6
src/components/AppTest.vue

@@ -1,6 +0,0 @@
-<!-- 本文件会自动导入 -->
-<template>
-  <span>
-    <slot />
-  </span>
-</template>

+ 42 - 0
src/hooks/useRequest.ts

@@ -0,0 +1,42 @@
+type IUseRequestOptions<T> = {
+  /** 是否立即执行,如果是则在onLoad执行 */
+  immediate?: boolean
+  /** 初始化数据 */
+  initialData?: T
+}
+
+/**
+ * useRequest是一个定制化的请求钩子,用于处理异步请求和响应。
+ * @param func 一个执行异步请求的函数,返回一个包含响应数据的Promise。
+ * @param options 包含请求选项的对象 {immediate, initialData}。
+ * @param options.immediate 是否立即执行请求,默认为true。
+ * @param options.initialData 初始化数据,默认为undefined。
+ * @returns 返回一个对象{loading, error, data, run},包含请求的加载状态、错误信息、响应数据和手动触发请求的函数。
+ */
+export default function useRequest<T>(
+  func: () => Promise<IResData<T>>,
+  options: IUseRequestOptions<T> = { immediate: true },
+) {
+  const loading = ref(false)
+  const error = ref(false)
+  const data = ref<T>()
+  const run = async () => {
+    loading.value = true
+    func()
+      .then((res) => {
+        data.value = res.data
+        error.value = false
+      })
+      .catch((err) => {
+        error.value = err
+      })
+      .finally(() => {
+        loading.value = false
+      })
+  }
+
+  onLoad(() => {
+    options.immediate && run()
+  })
+  return { loading, error, data, run }
+}

+ 0 - 9
src/i18n.d.ts

@@ -1,9 +0,0 @@
-/* eslint-disable no-unused-vars */
-export {}
-
-declare module 'vue' {
-  interface ComponentCustomProperties {
-    $t: (key: string, opt?: Record<string, any>) => string
-    $tm: (key: string, opt?: Record<string, any>) => [] | { [p: string]: any }
-  }
-}

+ 1 - 0
src/interceptors/index.ts

@@ -1,2 +1,3 @@
 export { routeInterceptor } from './route'
 export { requestInterceptor } from './request'
+export { prototypeInterceptor } from './prototype'

+ 13 - 0
src/interceptors/prototype.ts

@@ -0,0 +1,13 @@
+export const prototypeInterceptor = {
+  install() {
+    // 解决低版本手机不识别 array.at() 导致运行报错的问题
+    if (typeof Array.prototype.at !== 'function') {
+      // eslint-disable-next-line no-extend-native
+      Array.prototype.at = function (index: number) {
+        if (index < 0) return this[this.length + index]
+        if (index >= this.length) return undefined
+        return this[index]
+      }
+    }
+  },
+}

+ 12 - 9
src/interceptors/request.ts

@@ -1,13 +1,16 @@
 /* eslint-disable no-param-reassign */
 import qs from 'qs'
 import { useUserStore } from '@/store'
+import { platform } from '@/utils/platform'
 
 export type CustomRequestOptions = UniApp.RequestOptions & {
   query?: Record<string, any>
+  /** 出错时是否隐藏错误提示 */
+  hideErrorToast?: boolean
 } & IUniUploadFileOptions // 添加uni.uploadFile参数类型
 
-// 请求基地址
-const baseURL = import.meta.env.VITE_SERVER_BASEURL
+// 请求基地址
+const baseUrl = import.meta.env.VITE_SERVER_BASEURL
 
 // 拦截器配置
 const httpInterceptor = {
@@ -22,19 +25,19 @@ const httpInterceptor = {
         options.url += `?${queryStr}`
       }
     }
-
-    // 1. 非 http 开头需拼接地址
+    // 非 http 开头需拼接地址
     if (!options.url.startsWith('http')) {
-      options.url = baseURL + options.url
+      options.url = baseUrl + options.url
+      // TIPS: 如果需要对接多个后端服务,也可以在这里处理,拼接成所需要的地址
     }
-    // 2. 请求超时
+    // 1. 请求超时
     options.timeout = 10000 // 10s
-    // 3. 添加小程序端请求头标识
+    // 2. (可选)添加小程序端请求头标识
     options.header = {
-      platform: 'mp-weixin', // 可选值与 uniapp 定义的平台一致,告诉后台来源
+      platform, // 可选,与 uniapp 定义的平台一致,告诉后台来源
       ...options.header,
     }
-    // 4. 添加 token 请求头标识
+    // 3. 添加 token 请求头标识
     const userStore = useUserStore()
     const { token } = userStore.userInfo as unknown as IUserInfo
     if (token) {

+ 11 - 12
src/interceptors/route.ts

@@ -21,7 +21,7 @@ const isDev = import.meta.env.DEV
 const navigateToInterceptor = {
   // 注意,这里的url是 '/' 开头的,如 '/pages/index/index',跟 'pages.json' 里面的 path 不同
   invoke({ url }: { url: string }) {
-    console.log(url) // /pages/route-interceptor/index?name=feige&age=30
+    // console.log(url) // /pages/route-interceptor/index?name=feige&age=30
     const path = url.split('?')[0]
     let needLoginPages: string[] = []
     // 为了防止开发时出现BUG,这里每次都获取一下。生产环境可以移到函数外,性能更好
@@ -30,18 +30,17 @@ const navigateToInterceptor = {
     } else {
       needLoginPages = _needLoginPages
     }
-    console.log(needLoginPages.includes(path))
-
-    if (needLoginPages.includes(path)) {
-      const isLogin = isLogined()
-      if (isLogin) {
-        return true
-      }
-      const redirectRoute = `${loginRoute}?redirect=${encodeURIComponent(url)}`
-      uni.navigateTo({ url: redirectRoute })
-      return false
+    const isNeedLogin = needLoginPages.includes(path)
+    if (!isNeedLogin) {
+      return true
+    }
+    const hasLogin = isLogined()
+    if (hasLogin) {
+      return true
     }
-    return true
+    const redirectRoute = `${loginRoute}?redirect=${encodeURIComponent(url)}`
+    uni.navigateTo({ url: redirectRoute })
+    return false
   },
 }
 

+ 0 - 7
src/layouts/default.vue

@@ -3,10 +3,3 @@
     <slot />
   </view>
 </template>
-
-<style lang="scss">
-.default-layout {
-  height: 100vh;
-  overflow: auto;
-}
-</style>

+ 1 - 1
src/layouts/demo.vue

@@ -1,5 +1,5 @@
 <template>
-  <view class="text-center p-4">
+  <view class="demo-layout">
     <slot />
   </view>
 </template>

+ 2 - 2
src/main.ts

@@ -1,8 +1,7 @@
 import { createSSRApp } from 'vue'
 import App from './App.vue'
 import store from './store'
-import { routeInterceptor, requestInterceptor } from './interceptors'
-import 'virtual:svg-icons-register'
+import { routeInterceptor, requestInterceptor, prototypeInterceptor } from './interceptors'
 import 'virtual:uno.css'
 import '@/style/index.scss'
 
@@ -11,6 +10,7 @@ export function createApp() {
   app.use(store)
   app.use(routeInterceptor)
   app.use(requestInterceptor)
+  app.use(prototypeInterceptor)
   return {
     app,
   }

+ 2 - 3
src/manifest.json

@@ -1,6 +1,6 @@
 {
-  "name": "unibest",
-  "appid": "H5871D791",
+  "name": "unibest-base",
+  "appid": "H57F2ACE4",
   "description": "",
   "versionName": "1.0.0",
   "versionCode": "100",
@@ -71,7 +71,6 @@
     "enable": false
   },
   "vueVersion": "3",
-  "locale": "zh-Hans",
   "h5": {
     "router": {
       "base": "/"

+ 0 - 19
src/pages-sub/README.md

@@ -1,19 +0,0 @@
-# 分包配置
-
-在 `vite.config.ts` 中进行配置。
-
-```ts
-import { defineConfig } from 'vite'
-import UniPages from '@uni-helper/vite-plugin-uni-pages'
-
-export default defineConfig({
-  plugins: [
-    UniPages({
-      // ... 其他配置
-      subPackages: [
-        'src/pages-sub', // 是个数组,可以配置多个
-      ],
-    }),
-  ],
-})
-```

+ 8 - 0
src/pages.json

@@ -59,6 +59,14 @@
       "style": {
         "navigationBarTitleText": "请求"
       }
+    },
+    {
+      "path": "pages/index/request2",
+      "type": "page",
+      "layout": "demo",
+      "style": {
+        "navigationBarTitleText": "请求"
+      }
     }
   ],
   "subPackages": []

+ 4 - 12
src/pages/index/about.vue

@@ -16,27 +16,19 @@
       鸽友们好,我是
       <text class="text-red-500">菲鸽</text>
     </view>
-    <view class="text-center mt-8">
+    <view class="text-center mt-8 text-#fff">
       <wd-button type="primary" @click="gotoPage('request')">去请求页</wd-button>
+      <wd-button type="primary" @click="gotoPage('request2')" class="ml-2">
+        去请求页2 (请求状态一体化)
+      </wd-button>
     </view>
-
-    <view class="text-center py-4">
-      当前平台是:
-      <text class="text-red-500">{{ PLATFORM.platform }}</text>
-    </view>
-    <view class="text-center desc mt-10">设计稿样式编写:</view>
-    <view class="text-center desc">设计稿是750px,css里面全部写rpx 即可</view>
   </view>
 </template>
 
 <script lang="ts" setup>
-import PLATFORM from '@/utils/platform'
-
 // 获取屏幕边界到安全区域距离
 const { safeAreaInsets } = uni.getSystemInfoSync()
 
-console.log(PLATFORM)
-
 const gotoPage = (page: string) => {
   uni.navigateTo({
     url: `/pages/index/${page}`,

+ 8 - 3
src/pages/index/index.vue

@@ -19,16 +19,21 @@
     <view class="text-center text-2xl mt-2 mb-8">最好用的 uniapp 开发模板</view>
 
     <view class="text-justify max-w-100 m-auto text-4 indent mb-2">{{ description }}</view>
-    <view class="mt-8 text-center">
-      <text class="text-green-400">当前模板分支:base</text>
+    <view class="text-center mt-8">
+      当前平台是:
+      <text class="text-green-500">{{ PLATFORM.platform }}</text>
+    </view>
+    <view class="text-center mt-4">
+      模板分支是:
+      <text class="text-green-500">base</text>
     </view>
   </view>
 </template>
 
 <script lang="ts" setup>
+import PLATFORM from '@/utils/platform'
 // 获取屏幕边界到安全区域距离
 const { safeAreaInsets } = uni.getSystemInfoSync()
-
 const author = ref('菲鸽')
 const description = ref(
   'unibest 是一个集成了多种工具和技术的 uniapp 开发模板,由 uniapp + Vue3 + Ts + Vite4 + UnoCss + UniUI + VSCode 构建,模板具有代码提示、自动格式化、统一配置、代码片段等功能,并内置了许多常用的基本组件和基本功能,让你编写 uniapp 拥有 best 体验。',

+ 17 - 16
src/pages/index/request.vue

@@ -8,35 +8,35 @@
 </route>
 
 <template>
-  <view class="mt-6">
-    <!-- http://localhost:9000/#/pages/index/request -->
-    <button @click="getFoo" class="my-4">测试 GET 请求</button>
-    <view class="text-xl">请求数据如下</view>
-    <view class="text-green h-10">{{ JSON.stringify(data) }}</view>
-    <view class="text-xl">完整数据</view>
-    <view class="text-green h-20">{{ JSON.stringify(originalData) }}</view>
-    <button @click="postFoo" class="my-4">测试 POST 请求</button>
-    <view class="text-xl">请求数据如下</view>
-    <view class="text-green h-10">{{ JSON.stringify(data2) }}</view>
-
-    <button class="my-8" type="warn" @click="reset">一键清空数据</button>
-
+  <view class="p-6 text-center">
     <view class="my-2">使用的是 laf 云后台</view>
     <view class="text-green-400">我的推荐码,可以获得佣金</view>
+
     <!-- #ifdef H5 -->
-    <view class="my-2 text-center">
-      <a class="my-2 text-center" :href="recommendUrl" target="_blank">{{ recommendUrl }}</a>
+    <view class="my-2">
+      <a class="my-2" :href="recommendUrl" target="_blank">{{ recommendUrl }}</a>
     </view>
     <!-- #endif -->
 
     <!-- #ifndef H5 -->
     <view class="my-2 text-left text-sm">{{ recommendUrl }}</view>
     <!-- #endif -->
+
+    <!-- http://localhost:9000/#/pages/index/request -->
+    <button @click="getFoo" class="my-6">1.测试 GET 请求</button>
+    <view class="text-xl">请求数据如下</view>
+    <view class="text-green h-10">{{ JSON.stringify(data) }}</view>
+    <view class="text-xl">完整数据</view>
+    <view class="text-green h-16">{{ JSON.stringify(originalData) }}</view>
+    <button @click="postFoo" class="my-6">2.测试 POST 请求</button>
+    <view class="text-xl">请求数据如下</view>
+    <view class="text-green h-10">{{ JSON.stringify(data2) }}</view>
+    <button class="my-6" type="warn" @click="reset">3.一键清空数据</button>
   </view>
 </template>
 
 <script lang="ts" setup>
-import { getFooAPI, postFooAPI, IFooItem } from '@/service/foo'
+import { getFooAPI, postFooAPI, IFooItem } from '@/service/index/foo'
 
 const recommendUrl = ref('http://laf.run/signup?code=ohaOgIX')
 
@@ -44,6 +44,7 @@ onLoad(() => {
   getFoo()
   postFoo()
 })
+
 const originalData = ref<IResData<IFooItem>>()
 const data = ref<IFooItem>()
 const getFoo = async () => {

+ 30 - 0
src/pages/index/request2.vue

@@ -0,0 +1,30 @@
+<route lang="json5">
+{
+  layout: 'demo',
+  style: {
+    navigationBarTitleText: '请求',
+  },
+}
+</route>
+
+<template>
+  <view class="p-6 text-center">
+    <!-- http://localhost:9000/#/pages/index/request -->
+    <button @click="getFoo" class="my-6">测试 GET 请求</button>
+    <view class="text-xl">请求数据如下</view>
+    <view v-if="loading" class="text-blue h-10">加载中...</view>
+    <view v-else class="text-green h-10">{{ JSON.stringify(data) }}</view>
+    <button class="my-6" type="warn" @click="reset">一键清空数据</button>
+  </view>
+</template>
+
+<script lang="ts" setup>
+import { getFooAPI, IFooItem } from '@/service/index/foo'
+
+const { loading, data, run } = useRequest<IFooItem>(() => getFooAPI('菲鸽'), { immediate: true })
+
+const getFoo = () => run()
+const reset = () => {
+  data.value = undefined
+}
+</script>

src/service/foo.d.ts → src/service/index/foo.d.ts


src/service/foo.ts → src/service/index/foo.ts


+ 0 - 14
src/shime-uni.d.ts

@@ -1,14 +0,0 @@
-export {}
-
-declare module 'vue' {
-  type Hooks = App.AppInstance & Page.PageInstance
-  interface ComponentCustomOptions extends Hooks {
-    $uv?: any
-  }
-}
-
-declare global {
-  interface Uni {
-    $uv?: any
-  }
-}

global.d.ts → src/types/global.d.ts


+ 0 - 2
src/typings.ts

@@ -1,5 +1,3 @@
-/* eslint-disable @typescript-eslint/no-unused-vars */
-/* eslint-disable no-unused-vars */
 // 全局要用的类型放到这里
 
 type IResData<T> = {

+ 5 - 4
src/utils/http.ts

@@ -22,10 +22,11 @@ export const http = <T>(options: CustomRequestOptions) => {
           reject(res)
         } else {
           // 其他错误 -> 根据后端错误信息轻提示
-          uni.showToast({
-            icon: 'none',
-            title: (res.data as IResData<T>).msg || '请求错误',
-          })
+          !options.hideErrorToast &&
+            uni.showToast({
+              icon: 'none',
+              title: (res.data as IResData<T>).msg || '请求错误',
+            })
           reject(res)
         }
       },

+ 2 - 8
src/utils/index.ts

@@ -8,7 +8,7 @@ export const getIsTabbar = () => {
     return false
   }
   const pages = getCurrentPages()
-  const lastPage = getArrElementByIdx(pages, -1)
+  const lastPage = pages.at(-1)
   const currPath = lastPage.route
   return !!pagesJson.tabBar.list.find((e) => e.pagePath === currPath)
 }
@@ -22,7 +22,7 @@ export const currRoute = () => {
   const pages = getCurrentPages()
   console.log('pages:', pages)
 
-  const lastPage = getArrElementByIdx(pages, -1)
+  const lastPage = pages.at(-1)
   const currRoute = (lastPage as any).$page
   // console.log('lastPage.$page:', currRoute)
   // console.log('lastPage.$page.fullpath:', currRoute.fullPath)
@@ -105,9 +105,3 @@ export const getNeedLoginPages = (): string[] => getAllPages('needLogin').map((p
  * 只得到 path 数组
  */
 export const needLoginPages: string[] = getAllPages('needLogin').map((page) => page.path)
-
-export const getArrElementByIdx = (arr: any[], index: number) => {
-  if (index < 0) return arr[arr.length + index]
-  if (index >= arr.length) return undefined
-  return arr[index]
-}

+ 4 - 7
tsconfig.json

@@ -4,7 +4,10 @@
     "skipLibCheck": true,
     "module": "ESNext",
     "moduleResolution": "Node",
+    "resolveJsonModule": true,
+    "noImplicitThis": true,
     "allowSyntheticDefaultImports": true,
+    "allowJs": true,
     "sourceMap": true,
     "baseUrl": ".",
     "paths": {
@@ -12,13 +15,7 @@
     },
     "outDir": "dist",
     "lib": ["esnext", "dom"],
-    "types": [
-      "@dcloudio/types",
-      "@types/wechat-miniprogram",
-      "wot-design-uni/global.d.ts",
-      "./components.d.ts",
-      "./global.d.ts"
-    ]
+    "types": ["@dcloudio/types", "@types/wechat-miniprogram", "wot-design-uni/global.d.ts"]
   },
   "vueCompilerOptions": {
     "target": 3,

+ 2 - 8
uno.config.ts

@@ -8,12 +8,7 @@ import {
   transformerVariantGroup,
 } from 'unocss'
 
-import {
-  presetApplet,
-  presetRemRpx,
-  transformerApplet,
-  transformerAttributify,
-} from 'unocss-applet'
+import { presetApplet, presetRemRpx, transformerAttributify } from 'unocss-applet'
 
 // @see https://unocss.dev/presets/legacy-compat
 import presetLegacyCompat from '@unocss/preset-legacy-compat'
@@ -36,8 +31,8 @@ if (!isH5) {
 }
 export default defineConfig({
   presets: [
-    presetApplet({ enable: !isH5 }),
     ...presets,
+    presetApplet(),
     // 支持图标,需要搭配图标库,eg: @iconify-json/carbon, 使用 `<button class="i-carbon-sun dark:i-carbon-moon" />`
     presetIcons({
       scale: 1.2,
@@ -71,7 +66,6 @@ export default defineConfig({
       prefixedOnly: true,
       prefix: 'fg',
     }),
-    transformerApplet(),
   ],
   rules: [
     [

+ 0 - 43
vite-plugins/imagemin.ts

@@ -1,43 +0,0 @@
-// TIPS: 很多用户无法安装这个插件所以先注释掉了,如果您可以安装成功,那就可以放开这个注释,以及下面的viteImagemin配置
-// 注意,小程序有主包2M的限制,所以一般图片会放到图片服务器(不放本地),那就不需要这个插件
-// 如果是开发h5或者app的,可以自行安装
-import viteImagemin from 'vite-plugin-imagemin'
-
-export default (enabled: boolean) => {
-  if (!enabled) {
-    return undefined
-  }
-  return viteImagemin({
-    gifsicle: {
-      // gif图片压缩
-      optimizationLevel: 3, // 选择1到3之间的优化级别
-      interlaced: false, // 隔行扫描gif进行渐进式渲染
-      // colors: 2 // 将每个输出GIF中不同颜色的数量减少到num或更少。数字必须介于2和256之间。
-    },
-    optipng: {
-      // png
-      optimizationLevel: 7, // 选择0到7之间的优化级别
-    },
-    mozjpeg: {
-      // jpeg
-      quality: 20, // 压缩质量,范围从0(最差)到100(最佳)。
-    },
-    pngquant: {
-      // png
-      quality: [0.8, 0.9], // Min和max是介于0(最差)到1(最佳)之间的数字,类似于JPEG。达到或超过最高质量所需的最少量的颜色。如果转换导致质量低于最低质量,图像将不会被保存。
-      speed: 4, // 压缩速度,1(强力)到11(最快)
-    },
-    svgo: {
-      // svg压缩
-      plugins: [
-        {
-          name: 'removeViewBox',
-        },
-        {
-          name: 'removeEmptyAttrs',
-          active: false,
-        },
-      ],
-    },
-  })
-}

+ 33 - 47
vite.config.ts

@@ -11,24 +11,14 @@ import UniLayouts from '@uni-helper/vite-plugin-uni-layouts'
 import UniPlatform from '@uni-helper/vite-plugin-uni-platform'
 // @see https://github.com/uni-helper/vite-plugin-uni-manifest
 import UniManifest from '@uni-helper/vite-plugin-uni-manifest'
-// @see https://github.com/uni-helper/vite-plugin-uni-components
-import Components from '@uni-helper/vite-plugin-uni-components'
 // @see https://unocss.dev/
 import UnoCSS from 'unocss/vite'
-// import autoprefixer from 'autoprefixer'
 // @see https://github.com/jpkleemans/vite-svg-loader
 import svgLoader from 'vite-svg-loader'
-import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'
-// @see https://github.com/vbenjs/vite-plugin-vue-setup-extend
-import vueSetupExtend from 'vite-plugin-vue-setup-extend'
-// @see https://github.com/vbenjs/vite-plugin-svg-icons
 import AutoImport from 'unplugin-auto-import/vite'
-// import viteCompression from 'vite-plugin-compression'
-import ViteRestart from 'vite-plugin-restart'
+import vueSetupExtend from 'vite-plugin-vue-setup-extend'
 import { visualizer } from 'rollup-plugin-visualizer'
-// import imagemin from './vite-plugins/imagemin'
-
-console.log('process.platform -> ', process.platform)
+import ViteRestart from 'vite-plugin-restart'
 
 // https://vitejs.dev/config/
 export default ({ command, mode }) => {
@@ -40,13 +30,16 @@ export default ({ command, mode }) => {
   // pnpm build:h5 时得到 => build production
   // pnpm dev:mp-weixin 时得到 => build development (注意区别,command为build)
   // pnpm build:mp-weixin 时得到 => build production
+  // pnpm dev:app 时得到 => build development (注意区别,command为build)
+  // pnpm build:app 时得到 => build production
+  // dev 和 build 命令可以分别使用 .env.development 和 .env.production 的环境变量
+
+  const { UNI_PLATFORM } = process.env
+  console.log('UNI_PLATFORM -> ', UNI_PLATFORM) // 得到 mp-weixin, h5, app 等
 
-  // process.cwd(): 获取当前文件的目录跟地址
-  // loadEnv(): 返回当前环境env文件中额外定义的变量
   const env = loadEnv(mode, path.resolve(process.cwd(), 'env'))
-  console.log('env -> ', env)
-  console.log('process.env.UNI_PLATFORM: ', process.env.UNI_PLATFORM) // 得到 mp-weixin, h5, app 等
-  console.log('isH5: ', process.env.UNI_PLATFORM === 'h5') // 得到 mp-weixin, h5, app 等
+  const { VITE_APP_PORT, VITE_SERVER_BASEURL, VITE_DELETE_CONSOLE, VITE_SHOW_SOURCEMAP } = env
+  console.log('环境变量 env -> ', env)
 
   return defineConfig({
     envDir: './env', // 自定义env目录
@@ -58,12 +51,11 @@ export default ({ command, mode }) => {
         // homePage 通过 vue 文件的 route-block 的type="home"来设定
         // pages 目录为 src/pages,分包目录不能配置在pages目录下
         // subPackages: ['src/pages-sub'], // 是个数组,可以配置多个,但是不能为pages里面的目录
+        dts: 'src/types/uni-pages.d.ts',
       }),
       UniLayouts(),
       UniPlatform(),
       UniManifest(),
-      // 自动安装 src/components 里面的组件为全局组件,非全局组件不要放到 src/components
-      Components(),
       // UniXXX 需要在 Uni 之前引入
       Uni(),
       UnoCSS(),
@@ -71,47 +63,38 @@ export default ({ command, mode }) => {
       svgLoader({
         defaultImport: 'url', // or 'raw'
       }),
-      createSvgIconsPlugin({
-        // 指定要缓存的文件夹
-        iconDirs: [path.resolve(process.cwd(), 'src/assets/svg')],
-        // 指定symbolId格式
-        symbolId: 'icon-[dir]-[name]',
-      }),
-      vueSetupExtend(),
       AutoImport({
         imports: ['vue', 'uni-app'],
-        dts: 'src/auto-import.d.ts',
-        // dirs: ['src/hooks'], // 自动导入 hooks
-        eslintrc: { enabled: false },
+        dts: 'src/types/auto-import.d.ts',
+        dirs: ['src/hooks'], // 自动导入 hooks
+        eslintrc: { enabled: true },
         vueTemplate: true, // default false
       }),
 
-      // viteCompression(),
+      vueSetupExtend(),
       ViteRestart({
         // 通过这个插件,在修改vite.config.js文件则不需要重新运行也生效配置
         restart: ['vite.config.js'],
       }),
       // h5环境增加编译时间
-      process.env.UNI_PLATFORM === 'h5' && {
+      UNI_PLATFORM === 'h5' && {
         name: 'html-transform',
         transformIndexHtml(html) {
           return html.replace('%BUILD_DATE%', dayjs().format('YYYY-MM-DD HH:mm:ss'))
         },
       },
-      // 打包分析插件
-      mode === 'production' &&
+      // 打包分析插件,h5 + 生产环境才弹出
+      UNI_PLATFORM === 'h5' &&
+        mode === 'production' &&
         visualizer({
           filename: './node_modules/.cache/visualizer/stats.html',
           open: true,
           gzipSize: true,
           brotliSize: true,
         }),
-      // 这个图片压缩插件比较耗时,希望仅在生产环境使用
-      // TODO: 缓存每次压缩过的图片,已经压缩过的不再压缩
-      // imagemin(mode === 'production'),
     ],
     define: {
-      __UNI_PLATFORM__: JSON.stringify(process.env.UNI_PLATFORM),
+      __UNI_PLATFORM__: JSON.stringify(UNI_PLATFORM),
     },
     css: {
       postcss: {
@@ -133,23 +116,26 @@ export default ({ command, mode }) => {
     server: {
       host: '0.0.0.0',
       hmr: true,
-      port: Number.parseInt(env.VITE_APP_PORT, 10),
+      port: Number.parseInt(VITE_APP_PORT, 10),
+      proxy: {
+        '/api': {
+          target: VITE_SERVER_BASEURL,
+          changeOrigin: true,
+          rewrite: (path) => path.replace(/^\/api/, ''),
+        },
+      },
     },
     build: {
+      // 方便非h5端调试
+      sourcemap: VITE_SHOW_SOURCEMAP === 'true', // 默认是false
+      target: 'es6',
       minify: 'terser',
       terserOptions: {
         compress: {
-          drop_console: env.VITE_DELETE_CONSOLE === 'true',
-          drop_debugger: env.VITE_DELETE_CONSOLE === 'true',
+          drop_console: VITE_DELETE_CONSOLE === 'true',
+          drop_debugger: true,
         },
       },
-      // 解决windows系统对微信小程序自动关闭服务的问题
-      watch:
-        process.platform === 'win32' // 检测是否为 windows 系统
-          ? {
-              exclude: ['node_modules/**', '/__uno.css'],
-            }
-          : null,
     },
   })
 }