从0到1构建开源 vue-uniapp-template:使用 UniApp + Vue3 + TypeScript 和 VSCoe、CLI 开发跨平台移动端脚手架_uniapp vue3脚手架
🚀 作者主页: 有来技术
🔥 开源项目: youlai-mall ︱vue3-element-admin︱youlai-boot︱vue-uniapp-template
🌺 仓库主页: GitCode︱ Gitee ︱ Github
💖 欢迎点赞 👍 收藏 ⭐评论 📝 如有错误敬请纠正!
开局一张图,先看一下初期登录的效果图,内容和UI正在升级中…
目录
-
- 前言
- 环境准备
-
- 安装 Node
- 安装 VSCode
- 创建项目
-
- 初始化项目
- 配置编译器
- 启动项目
- 代码规范配置
-
- 集成 ESLint
-
- 安装插件
- 配置 ESLint
- 添加 ESLint 脚本
- 测试效果
- 推荐配置
- 集成 Prettier
-
- 安装插件
- 安装依赖
- 配置 Prettier
- 配置忽略文件
- 添加格式化脚本
- 保存自动格式化
- 测试
- 集成 Stylelint
-
- 安装插件
- 安装依赖
- 配置 Stylelint
- 配置忽略文件
- 添加 Stylelint 脚本
- 保存自动修复
- 测试
- Git提交规范配置
-
- 集成 Husky
-
- 安装依赖
- 初始化
- 测试
- 集成 lint-staged
-
- 安装依赖
- 配置 lint-staged
- 添加 Husky 钩子
- 测试
- 集成 Commitlint
-
- 安装依赖
- 配置 Commitlint
- 添加 Husky 钩子
- 测试
- 集成 Commitizen 和 cz-git
-
- 安装依赖
- 配置 cz-git
- 添加 cz-git 脚本
- 测试
- 整合 Sass
- 整合 UnoCSS
-
- 安装插件
- 安装依赖
- 配置 UnoCSS
- 测试
- 添加 TabBar
-
- 添加页面
- 添加图标
- 配置 TabBar
- 测试
- 按需自动导入
-
- 安装依赖
- 配置自动导入
- 配置 ESLint 规则
- 测试
- 环境变量
-
- 配置环境变量
- 智能提示
- 整合 HTTP 请求
-
- 封装请求工具
- 登录接口定义
- 登录页面
- 登录测试
- 整合源码
- 整合 Pinia
-
- 安装依赖
- 全局注册
- 用户信息接口
- 用户状态管理
- 个人中心页面
- 测试效果
- 整合源码
- 反向代理
-
- 环境变量配置
- 请求工具的调整
- Vite 反向代理配置
- 测试与验证
- 整合源码
- 整合 wot-design-uni
-
- 安装依赖
- 配置自动引入组件
- Volar 支持
- 测试组件
- 整合源码
- 项目部署
-
- H5 部署
- 小程序发布
-
- 下载工具
- 获取小程序 AppID
- 配置项目
- 设置微信开发者工具
- 运行项目
- 上传发布
- 查看效果
- 结语
- 附:项目源码
前言
本文将从零开始,详细介绍如何通过 Vite + degit
构建一个基于 Vue3 和 TypeScript 的 UniApp 跨移动端开源脚手架模板。内容会涵盖从环境配置到项目部署的各个重要开发环节,通过详实的步骤讲解,致力于打造高效的开发工具,进而提升项目质量与开发效率。
环境准备
vue-uniapp-template 是一个跨移动端脚手架模板,它结合了 UniApp
、Vue 3
和 TypeScript
这些主流技术栈。其构建借助了 Vite
,你可以使用 degit
直接从官方克隆基于 Vite
和 TypeScript
的模板来搭建此项目。。
安装 Node
Node.js
是运行 JavaScript 代码的环境,也是npm
包管理器的依赖。
打开 Node.js 官方下载页面,根据你的操作系统选择合适的版本进行下载,推荐安装 LTS 版本,这是长期支持版本,适合开发环境,比如这里选择 v20.18.0(LTS)
版本。
下载之后,双击安装包根据提示安装,通过以下命令检查是否成功安装:
node -v
安装 VSCode
VSCode
是一款非常流行的代码编辑器,特别适合前端开发。
访问 Visual Studio Code 官方网站 ,根据你的操作系统下载相应版本的 VSCode
,下载完成后,双击安装程序并按照提示完成安装。
创建项目
初始化项目
按照 uni-app 官方文档 的步骤,通过 vue-cli
创建 uni-app
+ vue
+ typescript
脚手架:
npx degit dcloudio/uni-preset-vue#vite-ts vue-uniapp-template
如果使用命令创建失败,可以通过 Gitee 下载 ZIP 包:vite-ts 分支。
配置编译器
默认生成的 TypeScript
编译器配置文件 tsconfig.json
中继承的 @vue/tsconfig/tsconfig.json
文件不存在。因此,你需要移除此继承配置并添加相应的编译设置。
根据 TypeScript 官方配置文档,调整后的完整配置如下:
{ \"compilerOptions\": { \"module\": \"esnext\", \"moduleResolution\": \"node\", \"target\": \"esnext\", \"allowJs\": true, \"skipLibCheck\": true, \"strict\": true, \"sourceMap\": true, \"baseUrl\": \".\", \"paths\": { \"@/*\": [\"./src/*\"] }, \"lib\": [\"esnext\", \"dom\"], \"types\": [\"@dcloudio/types\"] }, \"include\": [\"src/**/*.ts\", \"src/**/*.d.ts\", \"src/**/*.tsx\", \"src/**/*.vue\"], \"exclude\": [\"node_modules\", \"dist\"]}
\"module\": \"esnext\"
: 指定模块系统为ESNext
,即最新的 ECMAScript 模块系统,支持import.meta
和其他最新的特性。\"moduleResolution\": \"node\"
: 模块解析策略,通常设置为Node
以支持 Node.js 风格的模块解析。\"target\": \"esnext\"
: 将目标 JavaScript 版本设置为ESNext
,编译输出现代浏览器能够支持的最新特性代码。\"allowJs\": true
: 允许 TypeScript 编译器处理.js
文件,混合使用 TypeScript 和 JavaScript 文件。\"skipLibCheck\": true
: 跳过库文件的类型检查,提升编译速度。\"strict\": true
: 启用所有严格类型检查选项。
启动项目
创建完成后,使用 VSCode
打开项目并启动:
# 安装依赖pnpm install# 启动项目pnpm run dev:h5
项目启动后,访问 http://localhost:5173 预览效果:
代码规范配置
为了保证项目代码的规范性和一致性,可以为项目配置 ESLint
、Stylelint
、Prettier
以及 Husky
,从而确保代码质量和开发流程的一致性。
集成 ESLint
ESLint
是一款 JavaScript 和 TypeScript 的代码规范工具,能够帮助开发团队保持代码风格一致并减少常见错误。
ESLint 中文网:https://eslint.nodejs.cn/
安装插件
VSCode 插件市场搜索 ESLint 插件并安装
配置 ESLint
通过以下命令快速生成 ESLint 配置文件:
npx eslint --init
执行该命令后,ESLint 会通过交互式问题的方式,帮助生成配置文件。针对 9.x 版本,默认会生成基于 Flat Config 格式的 eslint.config.mjs
文件,与之前的 .eslintrc
格式有所不同。
默认生成的 eslint.config.mjs
文件如下所示:
在此基础上,可以根据项目的需求进行一些定制化配置,例如添加忽略规则或自定义的特殊规则。
import globals from \"globals\"; // 全局变量配置import pluginJs from \"@eslint/js\"; // JavaScript 的推荐配置import tseslint from \"typescript-eslint\"; // TypeScript 配置import pluginVue from \"eslint-plugin-vue\"; // Vue 配置export default [ {files: [\"**/*.{js,mjs,cjs,ts,vue}\"]}, // 校验的文件类型 {languageOptions: { globals: {...globals.browser , ...globals.node} }}, // 浏览器/Node环境全局变量 pluginJs.configs.recommended, // JavaScript 推荐配置 ...tseslint.configs.recommended, // TypeScript 推荐配置 ...pluginVue.configs[\"flat/essential\"], // Vue 推荐配置 { files: [\"**/*.vue\"], languageOptions: { parserOptions: { parser: tseslint.parser } } }, // 对 .vue 文件使用 TypeScript 解析器 // 添加忽略的文件或目录 { ignores: [ \"/dist\", \"/public\", \"/node_modules\", \"**/*.min.js\", \"**/*.config.mjs\", \"**/*.tsbuildinfo\", \"/src/manifest.json\", ] }, // 自定义规则 { rules: { quotes: [\"error\", \"double\"], // 强制使用双引号 \"quote-props\": [\"error\", \"always\"], // 强制对象的属性名使用引号 semi: [\"error\", \"always\"], // 要求使用分号 indent: [\"error\", 2], // 使用两个空格进行缩进 \"no-multiple-empty-lines\": [\"error\", { max: 1 }], // 不允许多个空行 \"no-trailing-spaces\": \"error\", // 不允许行尾有空格 // TypeScript 规则 \"@typescript-eslint/no-explicit-any\": \"off\", // 禁用 no-explicit-any 规则,允许使用 any 类型 \"@typescript-eslint/explicit-function-return-type\": \"off\", // 不强制要求函数必须明确返回类型 \"@typescript-eslint/no-empty-interface\": \"off\", // 禁用 no-empty-interface 规则,允许空接口声明 \"@typescript-eslint/no-empty-object-type\": \"off\", // 允许空对象类型 // Vue 规则 \"vue/multi-word-component-names\": \"off\", // 关闭多单词组件名称的限制 \"vue/html-indent\": [\"error\", 2], // Vue 模板中的 HTML 缩进使用两个空格 \"vue/no-v-html\": \"off\", // 允许使用 v-html (根据实际项目需要) }, },];
添加 ESLint 脚本
为了方便使用 ESLint,可以在 package.json
中添加 lint
脚本命令:
{ \"scripts\": { \"lint:eslint\": \"eslint --fix ./src\" }}
此脚本会自动修复符合 ESLint 规则的代码问题,并输出检查结果。
测试效果
在 App.vue
文件中声明一个未使用的变量,并运行 pnpm run lint:eslint
,可以看到 ESLint 提示该变量未使用。如下图所示:
推荐配置
安装 Vue 文件解析器 vue-eslint-parser
:
pnpm add -D vue-eslint-parser
针对不同文件配置插件和解析器:
// eslint.config.mjsimport globals from \"globals\";import js from \"@eslint/js\";// ESLint 核心插件import pluginVue from \"eslint-plugin-vue\";import pluginTypeScript from \"@typescript-eslint/eslint-plugin\";// Prettier 插件及配置import configPrettier from \"eslint-config-prettier\";import pluginPrettier from \"eslint-plugin-prettier\";// 解析器import * as parserVue from \"vue-eslint-parser\";import * as parserTypeScript from \"@typescript-eslint/parser\";// 定义 ESLint 配置export default [ // 通用 JavaScript/TypeScript 配置 { ...js.configs.recommended, ignores: [ \"/dist\", \"/public\", \"/node_modules\", \"**/*.min.js\", \"**/*.config.mjs\", \"**/*.tsbuildinfo\", \"/src/manifest.json\", ], languageOptions: { globals: { ...globals.browser, // 浏览器变量 (window, document 等) ...globals.node, // Node.js 变量 (process, require 等) }, }, plugins: { prettier: pluginPrettier, }, rules: { ...configPrettier.rules, ...pluginPrettier.configs.recommended.rules, \"no-debug\": \"off\", // 允许使用 debugger \"prettier/prettier\": [ \"error\", { endOfLine: \"auto\", // 解决换行符冲突 }, ], }, }, // TypeScript 配置 { files: [\"**/*.?([cm])ts\"], languageOptions: { parser: parserTypeScript, parserOptions: { sourceType: \"module\", }, }, plugins: { \"@typescript-eslint\": pluginTypeScript, }, rules: { ...pluginTypeScript.configs.recommended.rules, \"@typescript-eslint/no-explicit-any\": \"off\", // 允许使用 any \"@typescript-eslint/no-empty-function\": \"off\", // 允许空函数 \"@typescript-eslint/no-empty-object-type\": \"off\", // 允许空对象类型 \"@typescript-eslint/consistent-type-imports\": [ \"error\", { disallowTypeAnnotations: false, fixStyle: \"inline-type-imports\" }, ], // 统一类型导入风格 }, }, // TypeScript 声明文件的特殊配置 { files: [\"**/*.d.ts\"], rules: { \"eslint-comments/no-unlimited-disable\": \"off\", // 关闭 eslint 注释相关规则 \"unused-imports/no-unused-vars\": \"off\", // 忽略未使用的导入 }, }, // JavaScript (commonjs) 配置 { files: [\"**/*.?([cm])js\"], rules: { \"@typescript-eslint/no-var-requires\": \"off\", // 允许 require }, }, // Vue 文件配置 { files: [\"**/*.vue\"], languageOptions: { parser: parserVue, parserOptions: { parser: \"@typescript-eslint/parser\", sourceType: \"module\", }, }, plugins: { vue: pluginVue, }, processor: pluginVue.processors[\".vue\"], rules: { ...pluginVue.configs[\"vue3-recommended\"].rules, \"vue/no-v-html\": \"off\", // 允许 v-html \"vue/require-default-prop\": \"off\", // 允许没有默认值的 prop \"vue/multi-word-component-names\": \"off\", // 关闭组件名称多词要求 \"vue/html-self-closing\": [ \"error\", { html: { void: \"always\", normal: \"always\", component: \"always\" }, svg: \"always\", math: \"always\", }, ], // 自闭合标签 }, },];
集成 Prettier
Prettier 是一个代码格式化工具,能够和 ESLint 配合使用,确保代码风格统一。
prettier 中文网:https://prettier.nodejs.cn/
安装插件
VSCode 插件市场搜索 Prettier - Code formatter
插件安装
安装依赖
pnpm install -D prettier eslint-config-prettier eslint-plugin-prettier
-
prettier:主要的 Prettier 格式化库。
-
eslint-plugin-prettier:将 Prettier 的规则作为 ESLint 的规则来运行。
-
eslint-config-prettier:禁用所有与格式相关的 ESLint 规则,以避免和 Prettier 的冲突。
配置 Prettier
项目根目录下新建配置文件 prettier.config.mjs
,添加常用规则:
export default { printWidth: 100, // 每行最多字符数量,超出换行(默认80) tabWidth: 2, // 缩进空格数,默认2个空格 useTabs: false, // 指定缩进方式,空格或tab,默认false,即使用空格 semi: true, // 使用分号 singleQuote: false, // 使用单引号 (true:单引号;false:双引号) trailingComma: \'all\', // 末尾使用逗号};
配置忽略文件
项目根目录新建 .prettierignore
文件指定 Prettier 不需要格式化的文件和文件夹
# .prettierignorenode_modulesdistpublic*.min.js
添加格式化脚本
在 package.json
文件中添加:
{ \"scripts\": { \"format\": \"prettier --write ./src\" }}
保存自动格式化
打开 VSCode 的 File
→ Preferences
→ Settings
,然后选择 Open Settings (JSON)
,添加以下配置
{ \"editor.formatOnSave\": true, // 保存格式化文件 \"editor.defaultFormatter\": \"esbenp.prettier-vscode\" // 指定 prettier 为所有文件默认格式化器}
测试
下图演示了保存时的自动格式化效果,展示了代码中引号和换行的自动调整:
集成 Stylelint
Stylelint 一个强大的 CSS linter(检查器),可帮助您避免错误并强制执行约定。
Stylelint 官网:https://stylelint.io/
安装插件
VSCode 插件搜索 Stylelint
并安装
安装依赖
pnpm install -D postcss postcss-html postcss-scss stylelint stylelint-config-recommended stylelint-config-recommended-scss stylelint-config-recommended-vue stylelint-config-recess-order stylelint-config-html stylelint-prettier
其中选择 stylelint-config-recommended 替代 stylelint-config-standard 的原因在于它不仅提供了灵活性,还更加轻量。stylelint-config-recommended 默认包含的规则较少,避免了 stylelint-config-standard 中可能不需要的规则,这样可以减少配置的复杂度,提高项目的启动速度,同时让开发者能够集中关注对项目真正重要的风格指南。轻量配置有助于简化工作流程,特别是在大型或复杂的项目中。
配置 Stylelint
根目录新建 .stylelintrc.cjs
文件,配置如下:
{ \"extends\": [ \"stylelint-config-recommended\", \"stylelint-config-recommended-scss\", \"stylelint-config-recommended-vue/scss\", \"stylelint-config-html/vue\", \"stylelint-config-recess-order\" ], \"plugins\": [\"stylelint-prettier\"], \"overrides\": [ { \"files\": [\"**/*.{vue,html}\"], \"customSyntax\": \"postcss-html\" }, { \"files\": [\"**/*.{css,scss}\"], \"customSyntax\": \"postcss-scss\" } ], \"rules\": { \"import-notation\": \"string\", \"selector-class-pattern\": null, \"custom-property-pattern\": null, \"keyframes-name-pattern\": null, \"no-descending-specificity\": null, \"no-empty-source\": null, \"selector-pseudo-class-no-unknown\": [ true, { \"ignorePseudoClasses\": [\"global\", \"export\", \"deep\"] } ], \"unit-no-unknown\": [true, { \"ignoreUnits\": [\"rpx\"] }] \"property-no-unknown\": [ true, { \"ignoreProperties\": [] } ], \"at-rule-no-unknown\": [ true, { \"ignoreAtRules\": [\"apply\", \"use\", \"forward\"] } ] }}
配置忽略文件
根目录创建 .stylelintignore 文件,配置忽略文件如下:
*.min.jsdistpublicnode_modules
添加 Stylelint 脚本
package.json 添加 Stylelint 检测指令:
\"scripts\": { \"lint:stylelint\": \"stylelint \\\"**/*.{css,scss,vue,html}\\\" --fix\" }
保存自动修复
项目根目录下.vscode/settings.json
文件添加配置:
{ \"editor.codeActionsOnSave\": { \"source.fixAll.stylelint\": true }, \"stylelint.validate\": [\"css\", \"scss\", \"vue\", \"html\"]}
为了验证把尺寸属性 width 放置在定位属性 position 前面,根据 CSS 书写顺序规范 推断是不符合规范的,在保存时 Stylelint 自动将属性重新排序,达到预期。
测试
执行以下命令进行检测
npm run lint:stylelint
Git提交规范配置
配置 Husky 的 pre-commit
和 commit-msg
钩子,实现代码提交的自动化检查和规范化。
- pre-commit: 使用 Husky + Lint-staged,在提交前进行代码规范检测和格式化。确保项目已配置 ESLint、Prettier 和 Stylelint。
- commit-msg: 结合 Husky、Commitlint、Commitizen 和 cz-git,生成规范化且自定义的 Git commit 信息。
集成 Husky
Husky 是 Git 钩子工具,可以设置在 git 各个阶段(pre-commit
、commit-msg
等)触发。
Husky官网:https://typicode.github.io
安装依赖
pnpm add -D husky
初始化
init
命令简化了项目中的 husky 设置。它会在 .husky/
中创建 pre-commit
脚本,并更新 package.json
中的 prepare
脚本。
pnpm exec husky init
测试
通过 pre-commit
钩子,可以自动运行各种代码检查工具,在提交代码前强制执行代码质量和样式检查。常见的工具包括:
eslint
:用于检查和修复 JavaScript/TypeScript 代码中的问题。stylelint
:用于检测和修复 CSS/SCSS 样式问题。
接下来,集成 lint-staged
和 commitlint
来进一步完善开发体验。
集成 lint-staged
lint-staged
是一个工具,专门用于只对 Git 暂存区的文件运行 lint 或其他任务,确保只检查和修复被修改或新增的代码部分,而不会影响整个代码库。这样可以显著提升效率,尤其是对于大型项目。
安装依赖
使用以下命令安装 lint-staged
:
pnpm add -D lint-staged
配置 lint-staged
在 package.json
中添加 lint-staged
配置,确保在 pre-commit
阶段自动检测暂存的文件:
{ \"name\": \"vue-uniapp-template\", \"version\": \"0.0.0\", \"lint-staged\": { \"*.{js,ts}\": [ \"eslint --fix\", \"prettier --write\" ], \"*.{cjs,json}\": [ \"prettier --write\" ], \"*.{vue,html}\": [ \"eslint --fix\", \"prettier --write\", \"stylelint --fix\" ], \"*.{scss,css}\": [ \"stylelint --fix\", \"prettier --write\" ], \"*.md\": [ \"prettier --write\" ] }}
在 package.json
的 scripts
部分中,添加用于运行 lint-staged
的命令:
\"scripts\": { \"lint:lint-staged\": \"lint-staged\"}
添加 Husky 钩子
在项目根目录的 .husky/pre-commit
中添加以下命令,确保在提交代码前执行 lint-staged
:
pnpm run lint:lint-staged
测试
提交代码时,lint-staged
会自动对暂存的文件运行相应的 lint 任务。
通过这种集成方式,确保代码在提交前经过自动格式化和校验,提高代码质量和一致性。
集成 Commitlint
commitlint
用于检查 Git 提交信息是否符合特定规范(如 Angular 提交规范),从而保证提交信息的一致性。
Commitlint官网:https://commitlint.js.org/
安装依赖
pnpm add -D @commitlint/cli @commitlint/config-conventional
配置 Commitlint
在项目根目录下创建 commitlint.config.cjs
文件,添加以下内容来启用 Angular 规范:
module.exports = { // 继承的规则 extends: [\"@commitlint/config-conventional\"], // 自定义规则 rules: { // 提交类型枚举,git提交type必须是以下类型 @see https://commitlint.js.org/#/reference-rules \"type-enum\": [ 2, \"always\", [ \"feat\", // 新增功能 \"fix\", // 修复缺陷 \"docs\", // 文档变更 \"style\", // 代码格式(不影响功能,例如空格、分号等格式修正) \"refactor\", // 代码重构(不包括 bug 修复、功能新增) \"perf\", // 性能优化 \"test\", // 添加疏漏测试或已有测试改动 \"build\", // 构建流程、外部依赖变更(如升级 npm 包、修改 webpack 配置等) \"ci\", // 修改 CI 配置、脚本 \"revert\", // 回滚 commit \"chore\", // 对构建过程或辅助工具和库的更改(不影响源文件、测试用例) ], ], \"subject-case\": [0], // subject大小写不做校验 },};
添加 Husky 钩子
将 commitlint
与 Husky 集成,在 .husky/commit-msg
文件中添加以下内容,确保提交信息符合规范:
npx --no-install commitlint --edit $1
测试
根据 Angular 的提交规范,提交信息由以下部分组成:
- 类型:表示本次提交的类型,例如
feat
(新功能)、fix
(修复 bug)、docs
(文档更新)。 - 作用域(可选):说明本次提交影响的模块,例如
auth
、ui
。 - 简短描述:简洁明了的提交描述,限定在 50 字符以内。
当你尝试提交不符合规范的提交信息时,提交会被阻止,并显示相关错误提示。如下图所示:
集成 Commitizen 和 cz-git
-
commitizen: 是一个帮助开发者以标准化格式生成提交信息的工具。–Commitizen 官方文档
-
cz-git:
cz-git
是Commitizen
的适配器之一,它基于Commitizen
,提供了更多自定义功能和增强的交互体验。–cz-git 官方文档
安装依赖
pnpm add -D commitizen cz-git
配置 cz-git
在项目中初始化 Commitizen
,并配置使用 cz-git
作为适配器。在 package.json
中添加以下配置:
\"config\": { \"commitizen\": { \"path\": \"node_modules/cz-git\" }}
在commitlint
的配置文件 commitlint.config.cjs
中添加配置,commitlint 配置模板:https://cz-git.qbb.sh/zh/config/
module.exports = { // 继承的规则 extends: [\"@commitlint/config-conventional\"], // 自定义规则 rules: { // ... }, // cz-git 配置 prompt: { messages: { type: \"选择你要提交的类型 :\", scope: \"选择一个提交范围(可选):\", customScope: \"请输入自定义的提交范围 :\", subject: \"填写简短精炼的变更描述 :\\n\", body: \'填写更加详细的变更描述(可选)。使用 \"|\" 换行 :\\n\', breaking: \'列举非兼容性重大的变更(可选)。使用 \"|\" 换行 :\\n\', footerPrefixesSelect: \"选择关联issue前缀(可选):\", customFooterPrefix: \"输入自定义issue前缀 :\", footer: \"列举关联issue (可选) 例如: #31, #I3244 :\\n\", generatingByAI: \"正在通过 AI 生成你的提交简短描述...\", generatedSelectByAI: \"选择一个 AI 生成的简短描述:\", confirmCommit: \"是否提交或修改commit ?\", }, // prettier-ignore types: [ { value: \"feat\", name: \"特性: ✨ 新增功能\", emoji: \":sparkles:\" }, { value: \"fix\", name: \"修复: 🐛 修复缺陷\", emoji: \":bug:\" }, { value: \"docs\", name: \"文档: 📝 文档变更\", emoji: \":memo:\" }, { value: \"style\", name: \"格式: 💄 代码格式(不影响功能,例如空格、分号等格式修正)\", emoji: \":lipstick:\" }, { value: \"refactor\", name: \"重构: ♻️ 代码重构(不包括 bug 修复、功能新增)\", emoji: \":recycle:\" }, { value: \"perf\", name: \"性能: ⚡️ 性能优化\", emoji: \":zap:\" }, { value: \"test\", name: \"测试: ✅ 添加疏漏测试或已有测试改动\", emoji: \":white_check_mark:\"}, { value: \"build\", name: \"构建: 📦️ 构建流程、外部依赖变更(如升级 npm 包、修改 vite 配置等)\", emoji: \":package:\"}, { value: \"ci\", name: \"集成: 🎡 修改 CI 配置、脚本\", emoji: \":ferris_wheel:\"}, { value: \"revert\", name: \"回退: ⏪️ 回滚 commit\",emoji: \":rewind:\"}, { value: \"chore\", name: \"其他: 🔨 对构建过程或辅助工具和库的更改(不影响源文件、测试用例)\", emoji: \":hammer:\"}, ], useEmoji: true, emojiAlign: \"center\", useAI: false, aiNumber: 1, themeColorCode: \"\", scopes: [], allowCustomScopes: true, allowEmptyScopes: true, customScopesAlign: \"bottom\", customScopesAlias: \"custom\", emptyScopesAlias: \"empty\", upperCaseSubject: false, markBreakingChangeMode: false, allowBreakingChanges: [\"feat\", \"fix\"], breaklineNumber: 100, breaklineChar: \"|\", skipQuestions: [], issuePrefixes: [{ value: \"closed\", name: \"closed: ISSUES has been processed\" }], customIssuePrefixAlign: \"top\", emptyIssuePrefixAlias: \"skip\", customIssuePrefixAlias: \"custom\", allowCustomIssuePrefix: true, allowEmptyIssuePrefix: true, confirmColorize: true, maxHeaderLength: Infinity, maxSubjectLength: Infinity, minSubjectLength: 0, scopeOverrides: undefined, defaultBody: \"\", defaultIssues: \"\", defaultScope: \"\", defaultSubject: \"\", },};
添加 cz-git 脚本
在package.json
文件中添加 commit
脚本命令
\"scripts\": { \"commit\": \"git-cz\" }
测试
执行 pnpm run commit
命令后,按照提示输入相关信息,最终生成符合规范的提交信息。
整合 Sass
Sass是帮助开发者编写、管理和维护样式的强大工具,通过 使用。它提供变量、嵌套、混合等功能,提升了样式的可维护性和开发效率,尤其在复杂项目中减少重复代码、提高复用性。
pnpm add -D sass sass-loader
整合 UnoCSS
UnoCSS 是一个高性能、灵活且按需生成的原子化 CSS 引擎。
官方网站:https://unocss.net/
先比较下


安装插件
VSCode
安装 UnoCSS
插件
安装依赖
本次整合基于官网提供的社区预设 unocss-preset-weapp。该预设内置了 transformer
,用于解决小程序的兼容性问题。
进一步参考 unocss-preset-weapp 的 uniapp_vue3 使用与配置指南,使用以下命令安装 UnoCSS 和 unocss-preset-weapp
:
pnpm add -D unocss unocss-preset-weapp
配置 UnoCSS
参考 unocss-preset-weapp 的 uniapp_vue3 使用与配置指南,配置如下:
-
vite.config.ts
在
vite.config.ts
中添加如下配置,整合 UnoCSS 到 UniApp 项目:import { defineConfig } from \'vite\'import uni from \'@dcloudio/vite-plugin-uni\'export default defineConfig(async () => { const UnoCss = await import(\'unocss/vite\').then(i => i.default) return { plugins: [ uni(), // 配置 UnoCSS UnoCss(), ], }})
-
unocss.config.ts
添加unocss.config.ts文件,搭配 unocss vscode 插件,智能提示
import presetWeapp from \"unocss-preset-weapp\";import { extractorAttributify, transformerClass } from \"unocss-preset-weapp/transformer\";const { presetWeappAttributify, transformerAttributify } = extractorAttributify();export default { presets: [ // https://github.com/MellowCo/unocss-preset-weapp presetWeapp(), // attributify autocomplete presetWeappAttributify(), ], shortcuts: [ { \"flex-center\": \"flex justify-center items-center\", \"flex-col\": \"flex flex-col\", }, ], transformers: [ // https://github.com/MellowCo/unocss-preset-weapp/tree/main/src/transformer/transformerAttributify transformerAttributify(), // https://github.com/MellowCo/unocss-preset-weapp/tree/main/src/transformer/transformerClass transformerClass(), ],};
shortcuts
自定义样式组合:可以在 shortcuts
中定义常用的样式组合,以便简化项目中的样式使用和维护,避免冗余和重复的样式。
-
main.ts
import \'uno.css\'
测试
下图展示了在 VSCode 中测试 UnoCSS 时,智能提示和样式设置功能已经正常生效。
此外,在 unocss.config.ts
文件中预设的 shortcuts
组合样式也得到了正确应用。
添加 TabBar
在 APP 开发中,底部导航栏(TabBar)是移动端应用的重要部分,方便用户在不同页面间进行切换。
添加页面
在初始化的模板项目中,src/pages
目录下默认有一个 index/index.vue
页面。为了更好地演示 TabBar
的切换效果,我们在 pages
目录下再新增两个页面:
-
工作台页面(
src/pages/work/index.vue
):<template> <view class=\"flex-center flex-col\"> <view> <text class=\"text-cyan font-bold text-lg\">工作台</text> </view> </view></template>
-
我的页面(
src/pages/my/index.vue
):<template> <view class=\"flex-center flex-col\"> <view> <text class=\"text-blue font-bold text-lg\">我的</text> </view> </view></template>
添加图标
在 src/static
目录下创建一个 tabbar
文件夹,存放从 iconfont 获取的图标。每个图标都需要有未激活和激活两种状态的样式。
配置 TabBar
在 UniApp 项目中,底部导航栏(TabBar)通过配置 pages.json
文件来实现。首先,找到并打开项目根目录下的 src/pages.json
文件。在该文件中,可以为每个页面配置导航栏,同时定义 TabBar。
下面是完整的配置示例,注意 tabBar
中的 pagePath
必须对应 pages
目录下的实际页面路径。
{ \"pages\": [ { \"path\": \"pages/index/index\", \"style\": { \"navigationBarTitleText\": \"首页\" } }, { \"path\": \"pages/work/index\", \"style\": { \"navigationBarTitleText\": \"工作台\" } }, { \"path\": \"pages/mine/index\", \"style\": { \"navigationBarTitleText\": \"我的\" } } ], \"tabBar\": { \"color\": \"#474747\", \"selectedColor\": \"#3B8DFF\", \"backgroundColor\": \"#F8F8F8\", \"list\": [ { \"pagePath\": \"pages/index/index\", \"text\": \"首页\", \"iconPath\": \"static/tabbar/home.png\", \"selectedIconPath\": \"static/tabbar/home-active.png\" }, { \"pagePath\": \"pages/work/index\", \"text\": \"工作台\", \"iconPath\": \"static/tabbar/work.png\", \"selectedIconPath\": \"static/tabbar/work-active.png\" }, { \"pagePath\": \"pages/mine/index\", \"text\": \"我的\", \"iconPath\": \"static/tabbar/mine.png\", \"selectedIconPath\": \"static/tabbar/mine-active.png\" } ] }}
测试
按需自动导入
在传统的 Vue 开发中,我们通常需要在每个页面手动导入 Vue 组合式 API(如 ref
, reactive
, onMounted
等)。随着项目的增大,手动导入会增加代码的冗余度,降低开发体验。
通过对比,来看一下手动导入与按需自动导入的区别:


手动导入: 每个页面都需要显式地引入 ref
, reactive
, onMounted
等组合式 API。
按需自动导入: 配置了自动导入插件后,这些 API 无需显式导入即可直接使用,减少了重复代码,提高了开发效率。
由于当前还未整合按需自动导入插件,所以右图的代码仍然报错,提示未找到 ref
和 reactive
的定义。这展示了按需自动导入的重要性:一旦整合插件,这类错误将被消除,代码更加简洁易维护。
安装依赖
首先使用以下命令安装 unplugin-auto-import
插件:
pnpm add -D unplugin-auto-import
配置自动导入
接着,在 vite.config.ts
中配置 unplugin-auto-import
插件,确保 Vue 和 UniApp 的 API 能够自动按需导入。
// vite.config.tsimport { defineConfig } from \"vite\";import AutoImport from \"unplugin-auto-import/vite\";export default defineConfig(async () => { return { plugins: [ uni(), // 这里是你的 uni-app 插件 AutoImport({ imports: [\"vue\", \"uni-app\"], // 自动导入 Vue 和 UniApp 的 API dts: \"src/types/auto-imports.d.ts\", // 自动生成类型声明文件 eslintrc: { enabled: true, // 生成 ESLint 配置文件 filepath: \'./.eslintrc-auto-import.json\', // ESLint 配置文件路径 }, }), ], };});
配置 ESLint 规则
为了让 ESLint 能识别这些通过 unplugin-auto-import
自动导入的 API,需要在 ESLint 的配置中引入 unplugin-auto-import
生成的 .eslintrc-auto-import.json
文件。
在 ESLint 9.x 版本中,使用 Flat Config 时不再支持 extends
关键字。因此,不能使用以下配置:
// 错误示例export default [ { extends: [\"./.eslintrc-auto-import.json\"], // 这种扩展方式在 Flat Config 中不再支持 },];
取而代之的是直接引入 .eslintrc-auto-import.json
文件内容,通过解析文件的方式将自动导入的全局变量配置整合进 ESLint 配置。
在 eslint.config.mjs
中添加如下配置:
// eslint.config.mjs 正确的配置import { readFileSync } from \"fs\";import { fileURLToPath } from \"url\";import { dirname, resolve } from \"path\";// 动态读取 .eslintrc-auto-import.json 文件内容const autoImportConfig = JSON.parse( readFileSync( resolve(dirname(fileURLToPath(import.meta.url)), \".eslintrc-auto-import.json\"), \"utf-8\", ),);export default [ { // 语言选项配置,定义全局变量 languageOptions: { globals: { // ... ...autoImportConfig.globals, // 自动导入的全局变量 }, }, },];
这样配置后,ESLint 将能够识别通过自动导入的 API,避免例如 \'ref\' is not defined
这样的错误,从而使项目的开发更加顺畅。
测试
通过上述步骤配置后,原先在未手动导入情况下报错的页面,现在可以正常使用 ref
, reactive
等 API,而无需显式导入。
以下是最终的效果:
整合按需自动导入后,你将不再需要在每个页面显式导入 Vue 或 UniApp 的组合式 API,大幅度减少了重复的代码,提升了开发体验。
环境变量
Vite 环境变量主要是为了区分开发、测试、生产等环境的变量
下面的整合过程参考 Vite 环境变量配置官方文档
配置环境变量
项目根目录新建 .env.development
、.env.production
-
开发环境变量配置:.env.development
# 变量必须以 VITE_ 为前缀才能暴露给外部读取# 项目运行的端口号VITE_APP_PORT = 5173# API 基础路径,开发环境下的请求前缀VITE_APP_BASE_API = \'/dev-api\'# API 服务器的 URLVITE_APP_API_URL = https://api.youlai.tech
-
生产环境变量配置:.env.production
# API 基础路径,生产环境下的请求前缀VITE_APP_BASE_API = \'/prod-api\'# API 服务器的 URLVITE_APP_API_URL = https://api.youlai.tech
智能提示
首先,在 src/types/env.d.ts
文件中添加环境变量的类型声明:
// src/types/env.d.tsinterface ImportMetaEnv { /** * 应用端口 */ VITE_APP_PORT: number; /** * API 基础路径 */ VITE_APP_BASE_API: string; /** * API 服务器的 URL */ VITE_APP_API_URL: string;}interface ImportMeta { readonly env: ImportMetaEnv;}
确保 TypeScript 编译器使用的模块系统支持 import.meta
。在 tsconfig.json
文件中,你可以指定 es2020
、es2022
或 esnext
等模块系统。例如:
// tsconfig.json{ \"compilerOptions\": { \"module\": \"esnext\", // 支持 import.meta // ... }}
在任意页面中测试 import.meta
是否能够智能提示环境变量:
console.log(import.meta.env.VITE_APP_PORT);
整合 HTTP 请求
通过一个登录案例演示如何在Uniapp中整合HTTP请求。这里未使用axios和alova请求库的原因在于,Uniapp自身提供了跨平台的uni.request方法,该方法在不同平台(如小程序、App和H5)下表现一致,且无需额外安装第三方库,从而减少了项目的依赖复杂性和体积。
封装请求工具
在 global.d.ts
中定义全局响应数据类型 ResponseData
:
// src/types/global.d.tsdeclare global { /** * 响应数据结构 */ interface ResponseData<T = any> { code: string; // 业务状态码 data: T; // 返回数据 msg: string; // 消息 }}export {};
在 src/utils/request.ts
下创建一个 HTTP 请求工具,用于与 API 服务器进行通信:
// src/utils/request.tsexport default function request<T>(options: UniApp.RequestOptions): Promise<T> { const token = uni.getStorageSync(\"token\"); // 从本地缓存获取 token return new Promise((resolve, reject) => { uni.request({ ...options, // VITE_APP_API_URL 是在 Vite 项目的 .env.development 文件中配置的环境变量,表示 API 的路径 url: `${import.meta.env.VITE_APP_API_URL}${options.url}`, header: { ...options.header, Authorization: token, }, success: (response) => { const resData = response.data as ResponseData<T>; // 业务状态码 00000 表示成功 if (resData.code === \"00000\") { resolve(resData.data); } else { uni.showToast({ title: resData.msg || \"业务处理失败\", icon: \"none\", duration: 2000, }); reject({ message: resData.msg || \"业务处理失败\", code: resData.code, }); } }, fail: (error) => { uni.showToast({ title: \"网络请求失败\", icon: \"none\", duration: 2000, }); reject({ message: \"网络请求失败\", error, }); }, }); });}
注意事项
当首次使用该请求工具类时,可能会出现 \'uni\' is not defined
的 ESLint 错误,如下图所示:
为解决此问题,需要在 ESLint 配置文件中定义 uni
为全局变量:
// eslint.config.mjsexport default [ { // 语言选项配置,定义全局变量 languageOptions: { globals: { // ... ...{ uni: \"readonly\", // uni-app 全局对象 }, }, }, },];
登录接口定义
请求URL: https://api.youlai.tech/api/v1/auth/login
请求参数:
返回响应:
{ \"code\": \"00000\", \"data\": { \"accessToken\": \"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIxxx.xxxxxxx\", \"tokenType\": \"Bearer\" }, \"msg\": \"一切ok\"}
根据上述登录接口信息,创建 AuthAPI
类用于处理登录请求:
import request from \"@/utils/request\";const AuthAPI = { /** * 登录接口 * * @param username 用户名 * @param password 密码 * @returns 返回 token */ login(username: string, password: string): Promise<LoginResult> { return request<LoginResult>({ url: \"/api/v1/auth/login\", method: \"POST\", data: { username, password, }, header: { \"Content-Type\": \"application/x-www-form-urlencoded\", }, }); }, /** * 登出接口 */ logout(): Promise<void> { return request({ url: \"/api/v1/auth/logout\", method: \"DELETE\", }); },};export default AuthAPI;/** 登录响应 */export interface LoginResult { /** 访问token */ accessToken?: string; /** token 类型 */ tokenType?: string;}
登录页面
新建 src/pages/login/index.vue
文件,编写登录页面及逻辑:
<template> <view class=\"flex-col\"> <input v-model=\"username\" placeholder=\"请输入用户名\" /> <input v-model=\"password\" placeholder=\"请输入密码\" type=\"password\" /> <button @click=\"handleLogin\">登录</button> </view></template><script lang=\"ts\" setup>import AuthAPI, { LoginResult } from \'@/api/auth\';const username = ref(\'\');const password = ref(\'\');const router = useRouter();const handleLogin = async () => { try { const response: LoginResult = await AuthAPI.login(username.value, password.value); if (response.accessToken) { uni.setStorageSync(\'token\', response.accessToken); uni.showToast({ title: \'登录成功\', icon: \'success\' }); } else { uni.showToast({ title: \'登录失败\', icon: \'none\' }); } } catch (err) { uni.showToast({ title: \'登录失败\', icon: \'none\' }); }};</script><style scoped></style>
在 pages.json
文件中,声明登录页面的路由:
// src/pages.json{ \"pages\": [ { \"path\": \"pages/login/index\", \"style\": { \"navigationBarTitleText\": \"登录\" } } ]}
登录测试
访问登录页面:http://localhost:5173/#/pages/login/index,输入用户名和密码 (admin
/123456
) 测试登录接口,登录成功后可以看到返回的访问令牌。
整合源码
整合HTTP请求
代码版本:vue-uniapp-template#737f6a3。
整合 Pinia
Pinia 是 Vue 的状态管理库,专为跨组件或页面共享状态设计。
- Pinia 官方文档: https://pinia.vuejs.org/zh/getting-started.html
安装依赖
首先,安装 pinia
依赖:
pnpm add pinia
全局注册
在项目的 src
目录下创建 store
文件夹,并新建 index.ts
文件,初始化并注册 Pinia 实例。
// src/store/index.tsimport type { App } from \"vue\";import { createPinia } from \"pinia\";const store = createPinia();// 注册 Piniaexport function setupStore(app: App<Element>) { app.use(store); // 全局注册 Pinia}
接着,将 store
在项目入口文件 main.ts
中引入,并将其作为全局插件传递给应用:
// src/main.tsimport { createSSRApp } from \"vue\";import App from \"./App.vue\";import { setupStore } from \"@/store\";export function createApp() { const app = createSSRApp(App); // 全局注册 store setupStore(app); return { app, };}
接下来,我们通过 Pinia 管理登录状态和用户信息,并在多个页面共享状态。
用户信息接口
编写一个 API 来获取当前登录用户的信息:
import request from \"@/utils/request\";const USER_BASE_URL = \"/api/v1/users\";const UserAPI = { /** * 获取当前登录用户信息 * * @returns 登录用户昵称、头像信息,包括角色和权限 */ getUserInfo(): Promise<UserInfo> { return request<UserInfo>({ url: `${USER_BASE_URL}/me`, method: \"GET\", }); },};export default UserAPI;/** 登录用户信息 */export interface UserInfo { /** 用户ID */ userId?: number; /** 用户名 */ username?: string; /** 昵称 */ nickname?: string; /** 头像URL */ avatar?: string; /** 角色 */ roles: string[]; /** 权限 */ perms: string[];}
用户状态管理
通过 Pinia 定义 user
模块,管理登录状态、用户信息等。
// src/store/module/user.tsimport { defineStore } from \"pinia\";import AuthAPI from \"@/api/auth\";import UserAPI, { UserInfo } from \"@/api/user\";export const useUserStore = defineStore(\"user\", () => { // 确保 token 是响应式的 const token = ref<string>(uni.getStorageSync(\"token\") || \"\"); const userInfo = ref<UserInfo | null>(null); // 登录 const login = async (username: string, password: string) => { const { tokenType, accessToken } = await AuthAPI.login(username, password); token.value = `${tokenType} ${accessToken}`; // Bearer token uni.setStorageSync(\"token\", token.value); }; // 获取用户信息 const getUserInfo = async () => { const info = await UserAPI.getUserInfo(); userInfo.value = info; }; // 登出 const logout = async () => { await AuthAPI.logout(); userInfo.value = null; token.value = \"\"; // 清空 token uni.removeStorageSync(\"token\"); // 从本地缓存移除 token }; return { token, userInfo, login, logout, getUserInfo, };});
个人中心页面
个人中心页面展示用户的头像和昵称,未登录时引导用户去登录。
<template> <view class=\"flex-center flex-col\"> <text class=\"text-blue font-bold text-lg\">我的</text> <template v-if=\"isLoggedIn\"> <image :src=\"userInfo?.avatar\" class=\"w100 h100 mb-5 rounded-full\" /> <text class=\"text-lg font-bold\">{{ userInfo?.nickname }}</text> <button @click=\"handleLogout\" class=\"mt-5\">退出登录</button> </template> <template v-else> <text>您还未登录,请先登录</text> <button @click=\"goToLoginPage\" class=\"mt-5\">去登录</button> </template> </view></template><script lang=\"ts\" setup>import { useUserStore } from \"@/store/modules/user\";// 使用 piniaconst userStore = useUserStore();const isLoggedIn = computed(() => userStore.token);const userInfo = computed(() => userStore.userInfo);// 跳转到登录页面const goToLoginPage = () => { uni.navigateTo({ url: \"/pages/login/index\" });};// 退出登录处理const handleLogout = async () => { await userStore.logout(); uni.showToast({ title: \"已退出登录\", icon: \"success\" });};</script>
登录页通过 Pinia
实现用户信息的全局状态管理,并在登录成功后跳转到个人中心页面。
<template> <view class=\"flex-col items-center\"> <input v-model=\"username\" placeholder=\"请输入用户名\" /> <input v-model=\"password\" placeholder=\"请输入密码\" type=\"password\" /> <button class=\"mt-5\" @click=\"handleLogin\">登录</button> </view></template><script lang=\"ts\" setup>import { useUserStore } from \"@/store/modules/user\";// 登录表单const username = ref(\"admin\");const password = ref(\"123456\");// 使用 piniaconst userStore = useUserStore();// 登录处理const handleLogin = async () => { await userStore.login(username.value, password.value); if (!!userStore.token) { await userStore.getUserInfo(); // 登录成功后获取用户信息 uni.showToast({ title: \"登录成功\", icon: \"success\" }); uni.navigateBack(); // 登录成功后返回上一页 } else { uni.showToast({ title: \"登录失败\", icon: \"none\" }); }};</script><style scoped>input { width: 80%; padding: 10px; margin-top: 16px; border: 1px solid #ccc;}</style>
测试效果
登录后,个人中心会显示用户的头像和昵称。通过 Pinia 实现了登录状态的共享和跨页面传递。
整合源码
整合Pinia
代码版本:vue-uniapp-template#737f6a3。
反向代理
在开发中,若服务端没有启用 CORS(跨域资源共享),浏览器会基于安全策略拦截跨域请求,导致无法访问接口。为了绕过这个问题,我们可以通过 Vite 的反向代理功能,将开发阶段的请求代理到真实的 API 服务器上,伪装成同源请求。
本节将介绍如何配置 Vite 的反向代理来处理跨域请求。
环境变量配置
我们将通过环境变量来管理项目端口和 API 请求地址,以下是 .env.development
中的相关配置:
# .env.development# 项目运行的端口号VITE_APP_PORT=5173# API 请求的基础路径(开发环境)VITE_APP_BASE_API=/dev-api# 真实 API 服务器的 URLVITE_APP_API_URL=https://api.youlai.tech
请求工具的调整
为了让请求走代理,我们需要在请求工具中将 VITE_APP_API_URL
替换为 VITE_APP_BASE_API
。这样,所有对 API
的请求都会通过代理标识 /dev-api
进行转发。
export default function request<T>(options: UniApp.RequestOptions): Promise<T> { return new Promise((resolve, reject) => { uni.request({ ...options, // 原请求方式: 使用真实 API URL // url: `${import.meta.env.VITE_APP_API_URL}${options.url}`, // 示例: https://api.youlai.tech/login // 修改后:使用代理标识,实际转发到真实 API url: `${import.meta.env.VITE_APP_BASE_API}${options.url}`, // 示例: http://localhost:5173/dev-api/login }); });}
Vite 反向代理配置
接下来,在 vite.config.ts
中添加反向代理配置,将 /dev-api
的请求代理到 VITE_APP_API_URL
,通过 http-proxy
实现请求的转发。
// vite.config.tsimport { defineConfig, UserConfig, ConfigEnv, loadEnv } from \"vite\";export default defineConfig(async ({ mode }: ConfigEnv): Promise<UserConfig> => { const env = loadEnv(mode, process.cwd()); return { server: { host: \"0.0.0.0\", port: +env.VITE_APP_PORT, open: true, // 反向代理配置 proxy: { [env.VITE_APP_BASE_API]: { target: env.VITE_APP_API_URL, // 目标服务器 changeOrigin: true, // 支持跨域 rewrite: (path) => path.replace(new RegExp(\"^\" + env.VITE_APP_BASE_API), \"\"), // 去掉前缀 }, }, }, plugins: [ // 插件配置... ], };});
测试与验证
在配置好反向代理后,浏览器发出的请求将被 Vite 的代理服务器拦截并转发至真实的 API 地址。例如,浏览器请求 http://localhost:5173/dev-api/api/v1/auth/login
时,Vite 会将该请求代理到 https://api.youlai.tech/api/v1/auth/login
。
下图展示了这一过程,浏览器认为请求的 URL 与应用的主机地址一致,因此不会阻止该请求,即便真实请求已通过代理转发到外部服务器。
需要注意,反向代理的目标是伪装请求来源,虽然它绕过了浏览器的同源策略,但有时也会让开发者误以为请求地址错误。实际上,这是由于代理转发过程造成的表面请求地址与真实请求地址的差异。
整合源码
整合反向代理
和环境变量
代码版本:vue-uniapp-template#272d643。
整合 wot-design-uni
wot-design-uni
是基于 Vue 3
和 TypeScript
构建的高质量组件库。组件库遵循 Wot Design
的设计规范,提供 70 多个组件,支持暗黑模式、国际化和自定义主题,旨在为开发者提供一致的 UI 交互,同时提高开发效率。
说明: 本文档整合步骤基于
wot-design-uni
官方文档编写,建议开发者参考 官方文档 进行安装和配置,以确保组件库的正确使用。
安装依赖
根据官方文档,使用 pnpm
安装组件库的依赖:
pnpm add wot-design-uni
配置自动引入组件
在传统的 Vue
项目中,使用组件需要手动安装、引用、注册。而使用 easycom
可以简化这些操作。只要组件路径符合规范,就可以直接在页面中使用,无需手动导入和注册。
在 pages.json
文件中配置 easycom
自动引入:
// pages.json{ \"easycom\": { \"autoscan\": true, \"custom\": { \"^wd-(.*)\": \"wot-design-uni/components/wd-$1/wd-$1.vue\" } }, \"pages\": [ // 这里是项目已有的内容 ]}
关于 easycom
:
easycom
是 uni-app
提供的自动化引入功能,更多细节请参考 easycom 官方文档。
Volar 支持
为了让 Volar
正确识别和提示全局组件,你需要在项目的 tsconfig.json
文件中配置全局组件类型支持:
// tsconfig.json{ \"compilerOptions\": { \"types\": [\"wot-design-uni/global\"] }}
这将确保你在 TypeScript
项目中编写代码时,Volar 能提供完整的类型支持和代码提示。
测试组件
安装和配置完成后,你可以开始使用 wot-design-uni
的组件。在页面中,直接写组件标签即可,无需手动导入和注册:
<template> <view> <wd-button size=\"small\">主要按钮</wd-button> <wd-button type=\"success\" size=\"small\">成功按钮</wd-button> <wd-button type=\"info\" size=\"small\">信息按钮</wd-button> <wd-button type=\"warning\" size=\"small\">警告按钮</wd-button> <wd-button type=\"error\" size=\"small\">危险按钮</wd-button> </view></template>
你将看到如下按钮效果:
整合源码
整合wot-design-uni
代码版本:vue-uniapp-template#a775721。
项目部署
H5 部署
执行 pnpm run build:h5
命令来完成项目的打包:
pnpm run build:h5
打包后生成的静态文件位于 dist/build/h5
目录下。将该目录下的文件复制到服务器的 /usr/share/nginx/html/vue-uniapp-template
目录。
接下来,配置 nginx:
# nginx.confserver { listen 80; server_name localhost; location / { root /usr/share/nginx/html/vue-uniapp-template; index index.html index.htm; } # 反向代理配置 location /prod-api/ { # 将 api.youlai.tech 替换为后端 API 地址,注意保留后面的斜杠 / proxy_pass http://api.youlai.tech/; }}
这样配置完成后,就可以通过 nginx
服务器来访问你的项目了。
小程序发布
下载工具
下载 HBuilder X 编辑器
下载 微信开发者工具
获取小程序 AppID
访问 微信公众平台申请小程序,获取 AppID
。如果已申请,可在 首页
→ 小程序信息
→ 查看详情
查看 AppID
配置项目
使用 HBuilder X 打开项目,修改 manifest.json
文件中的小程序配置,并填写获取的 AppID。
设置微信开发者工具
使用微信扫码登录微信开发者工具,开启服务端口:点击工具栏设置
→安全设置
→安全
→服务端口
,选择打开。
运行项目
在 HBuilder X 中,点击 运行
→运行到小程序模拟器
→微信开发者工具
。
项目编译完成后,微信开发者工具会自动启动并呈现页面。
上传发布
在微信开发者工具中,点击 上传
将应用发布到小程序平台。
查看效果
最后,使用手机打开小程序查看效果:
结语
通过本文的详细讲解,相信你已经掌握了如何从零搭建一个高效的、基于 Vue3 和 TypeScript 的 UniApp 跨移动端解决方案脚手架模板——vue-uniapp-template。无论是代码规范、状态管理、样式配置,还是 Git 提交规范与项目部署,都能帮助你在实际项目中提高开发效率和代码质量。
希望本文能为你的项目开发提供全面的指导与支持,助你快速搭建出一个高效的跨移动端解决方案。Happy 1024 & Happy Coding!
附:项目源码
本篇文章涉及的源码已开源,项目地址:https://gitee.com/youlaiorg/vue-uniapp-template ,项目正在努力建设中,希望有兴趣参与开源的小伙伴们联系我(haoxianrui)。