UniApp + Vue3 + TS 工程化实战笔记

一、为什么要用 CLI 而不是 HBuilderX?

维度 HBuilderX CLI + Vscode
TS 类型推导 ❌ 经常报红 ✅ 丝滑
依赖管理 内置、黑盒 可见、可锁版本
工程化扩展 受限 随便玩 Vite 插件
团队协作 需要统一 IDE 任意编辑器

⚠️ 用 HBuilderX 创建后再拖到 Vscode,90% 会遭遇「找不到模块」爆红,CLI 模板一步到位。

二、极速创建项目

bash 复制代码
# 官方 vite-ts 模板(已集成 vue3.4 + ts5)
npx degit dcloudio/uni-preset-vue#vite-ts my-vue3-project
cd my-vue3-project
​
# 推荐用 yarn,npm 偶尔出现 peer 冲突
yarn
# 如果 ts 报错,先把 @vue/tsconfig 锁 0.4.0,再 yarn

三、Vscode 必备插件清单

插件 作用 必装
Vue - Official Vue3 语法高亮
uni-create-view 右键一键生成页面
uni-helper 代码片段 & 提示
uni-highlight .uvue 高亮
uniapp 小程序扩展 微信/阿里 API 提示

⚠️ Vue - Official ≥2.x 会对小程序自定义组件误报,关闭「Vue › Validation: Template」或回退到 1.8 即可。

四、封装「零依赖」HTTP 请求层

特点:

  • 自动携带 token & platform
  • 401 自动清缓存 & 跳转登录页
  • 后端字段容错(error / message / data
  • 返回 Promise,直接 await
typescript 复制代码
// src/utils/http.ts
export const http = <T>(options: UniApp.RequestOptions) =>
  new Promise<Data<T>>((resolve, reject) => {
    uni.request({
      ...options,
      url: options.url.startsWith('http') ? options.url : baseURL + options.url,
      header: {
        platform: 'miniapp',
        Authorization: uni.getStorageSync('token') || '',
        ...options.header,
      },
      success: ({ statusCode, data }) => {
        if (statusCode >= 200 && statusCode < 300) return resolve(data as Data<T>);
        if (statusCode === 401) {
          uni.clearStorage();
          uni.navigateTo({ url: '/pages/login/login' });
        }
        uni.showToast({
          icon: 'none',
          title: (data as any)?.error || (data as any)?.message || '请求异常',
        });
        reject(data);
      },
      fail: () => {
        uni.showToast({ icon: 'none', title: '网络开小差~' });
        reject(new Error('network error'));
      },
    });
  });

使用示例:

typescript 复制代码
import { http } from '@/utils/http';
​
type Banner = { id: number; img: string };
const getBanner = () => http<Banner[]>({ url: '/home/banner' });

五、微信小程序热更新方案

很多开发者只会在 onLaunchgetUpdateManager,但以下场景依旧漏掉:

  • 用户 24h 内未冷启动
  • 开发版/体验版需要强制更新

封装 useWxUpdate,支持「间隔控制 + 强制弹窗 + 生命周期回调」。

javascript 复制代码
// src/utils/update.ts
export function useWxUpdate(config?: UpdateConfig) {
  const merge = { ...DEFAULT_CONFIG, ...config };
  const shouldCheck = () => {
    const last = uni.getStorageSync('last_update_check');
    return !last || Date.now() - last > (merge.checkInterval || 86400) * 1000;
  };
  const checkUpdate = () => {
    // #ifdef MP-WEIXIN
    const mgr = wx.getUpdateManager();
    mgr.onCheckForUpdate(({ hasUpdate }) => {
      uni.setStorageSync('last_update_check', Date.now());
      merge.onAfterCheck?.(hasUpdate);
    });
    mgr.onUpdateReady(() => {
      wx.showModal({
        title: '更新提示',
        content: merge.customReadyContent!,
        showCancel: !merge.forceUpdate,
        success: (res) => res.confirm && mgr.applyUpdate(),
      });
    });
    // #endif
  };
  return { checkUpdate, shouldCheck };
}

App.vue 调用:

scss 复制代码
onLaunch(() => {
  // #ifdef MP-WEIXIN
  const { checkUpdate, shouldCheck } = useWxUpdate({ forceUpdate: false });
  if (shouldCheck()) checkUpdate();
  // #endif
});

六、Pinia 持久化存储(小程序适配)

安装:

csharp 复制代码
yarn add pinia pinia-plugin-persistedstate

main.ts 注入:

javascript 复制代码
import { createSSRApp } from 'vue';
import { createPinia } from 'pinia';
import persistedstate from 'pinia-plugin-persistedstate';
import App from './App.vue';
​
export function createApp() {
  const app = createSSRApp(App);
  const pinia = createPinia().use(persistedstate);
  return { app, pinia };
}

Store 示例:

typescript 复制代码
// src/stores/user.ts
export const useUserStore = defineStore(
  'user',
  () => {
    const token = ref('');
    const setToken = (t: string) => (token.value = t);
    return { token, setToken };
  },
  {
    persist: {
      key: 'user',
      storage: {
        getItem: (key) => uni.getStorageSync(key),
        setItem: (key, value) => uni.setStorageSync(key, value),
        removeItem: (key) => uni.removeStorageSync(key),
      },
    },
  }
);

七、Scss 废弃 API 警告消除

vite.config.ts 追加:

php 复制代码
export default defineConfig({
  css: {
    preprocessorOptions: {
      scss: {
        api: 'modern-compiler',
        silenceDeprecations: ['legacy-js-api'],
      },
    },
  },
});

八、UI 组件库怎么选?

优点 缺点
@dcloudio/uni-ui 官方维护、零样式污染、easycom 自动引入 样式朴素
uview-plus 组件丰富、主题色生成器 文档不稳定、广告多、issue 响应慢

⚠️ 无论选哪个,一定 看 npm 是否有源;很多插件市场包只提供 HBuilderX 安装,CI 无法自动构建。

九、常见踩坑 Top3

  1. 锁版本 @dcloudio/* 全部锁死,升级 Vue 到 3.5 也不会带来新特性,反而破坏编译器。
  2. easycom 不生效pages.json 丢到 src/ 下,重新 dev
  3. **小程序插件提示「未添加依赖」**在 manifest.json →「小程序插件配置」手动声明插件 ID。

十、一键运行

bash 复制代码
# 微信小程序
yarn dev:mp-weixin
​
# H5
yarn dev:h5
​
# App
yarn dev:app

十一、总结

CLI + Vscode 是真香,但模板只是起点。把「请求-更新-存储-UI」四条链路封装完,后续业务直接撸页面即可。文中所有代码已在 Gitee 开源

👉 项目地址:gitee.com/sk20020228/...

相关推荐
用户059540174465 小时前
LLM对话记忆测试踩坑实录:手工回归30分钟,自动化后2分钟发现3个隐藏Bug
前端·css
Ashley的成长之路6 小时前
前端性能优化实战手册·第2篇:资源加载策略全解
前端·性能优化·资源加载·http/3·性能优化实战·资源加载优化
浅水壁虎6 小时前
vue基础(第二章 )
前端·javascript·vue.js
界面开发小八哥6 小时前
界面控件DevExtreme v26.1新版亮点——支持Angular 22
前端·javascript·angular.js·devexpress·ui开发·devextreme
Getflare6 小时前
前端 + UI 设计 + AI:这不是三个工种,是一个新三角能力模型(附自检清单)
前端·人工智能·ui
oil欧哟6 小时前
我做了一个 Vibe Coding 术语学习站:VibeHub
前端·ai·agent·独立开发·vibe coding
审小匠OpenCPAi7 小时前
银行流水核查怎么自动化?单边匹配、双向勾稽与图聚类异常检测的工程对比
java·前端·人工智能·python·审计
Revolution617 小时前
一个公共表格组件,是怎么一步步失控的
前端·前端工程化
腻害兔8 小时前
【若依项目-产品经理视角】RuoYi-Vue-Pro 源码拆解:CRM 客户关系模块深度解析——从线索到回款,一套完整的 B2B 销售闭环是怎么搭的?
java·前端·javascript·vue.js·产品经理·ai编程