【硬件SDK项目】uniapp框架设计与业务开发
APP以/src/main.ts为入口h5以/index.html为入口。
框架设计
官方框架设计
平台入口
APP以/src/main.ts为入口
h5以/index.html为入口
index.html
安全区域概念

viewport-fit概念

viewport-fit=cover 内容可以延伸到安全区域


既然viewport-fit=cover内容可以延伸到安全区域内,那么它就需要通过css设置安全区域范围避开遮挡。
css概念env和constant
// index.html
<script>
var coverSupport =
'CSS' in window &&
typeof CSS.supports === 'function' &&
(CSS.supports('top: env(a)') || CSS.supports('top: constant(a)'));
document.write(
'<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' +
(coverSupport ? ', viewport-fit=cover' : '') +
'" />'
);
</script>
看到如果设置viewport-fit=cover,需要浏览器支持env和constant

支持:返回像素值(如 44px、34px)
不支持:返回 0px

适应viewport-fit=cover的css配置
// uno.config.ts
...
rules: [
// 提供一个类 它能够将调整内边距使内容不会在安全区域内
[
'p-safe',
{
padding:
'env(safe-area-inset-top) env(safe-area-inset-right) env(safe-area-inset-bottom) env(safe-area-inset-left)'
}
]
]
<!-- 全方向安全区域内边距 -->
<div class="p-safe">内容</div>
其他例子:

框架运行
编译依赖(这些代码会被编译进最终产物)
import { defineConfig } from "vite";
import uni from "@dcloudio/vite-plugin-uni";
export default defineConfig({
plugins: [uni()],
});
vite只用到了@dcloudio/vite-plugin-uni插件。这个插件在不同平台的环境里编译会根据scripts里的配置动态引入依赖:
// package.json 用-p指定依赖
// build命令同理
"dev:app": "uni -p app",
"dev:app-android": "uni -p app-android",
"dev:app-ios": "uni -p app-ios",
"dev:app-harmony": "uni -p app-harmony",
"dev:custom": "uni -p",
"dev:h5": "uni",
"dev:h5:ssr": "uni --ssr",
"dev:mp-alipay": "uni -p mp-alipay",
"dev:mp-baidu": "uni -p mp-baidu",
"dev:mp-jd": "uni -p mp-jd",
"dev:mp-kuaishou": "uni -p mp-kuaishou",
"dev:mp-lark": "uni -p mp-lark",
"dev:mp-qq": "uni -p mp-qq",
"dev:mp-toutiao": "uni -p mp-toutiao",
"dev:mp-weixin": "uni -p mp-weixin",
"dev:mp-xhs": "uni -p mp-xhs",
"dev:quickapp-webview": "uni -p quickapp-webview",
"dev:quickapp-webview-huawei": "uni -p quickapp-webview-huawei",
"dev:quickapp-webview-union": "uni -p quickapp-webview-union",
pnpm dev:h5 # 只加载 @dcloudio/uni-h5
pnpm dev:mp-weixin # 只加载 @dcloudio/uni-mp-weixin
pnpm dev:app # 只加载 @dcloudio/uni-app-plus

这些依赖包裹着对应不同环境平台的处理逻辑:


为什么需要这么多依赖?
平台差异巨大:每个平台的原生 API、组件、渲染机制都不同
按需加载:避免打包时包含所有平台的代码,减小包体积
统一开发体验:开发者只需要写一套代码,框架负责转换
性能优化:每个平台都有针对性的优化
开发依赖
@dcloudio/types
用途: 为uni-app提供完整的TypeScript类型支持,包括API、组件、生命周期等类型定义
@vue/tsconfig
作用: 提供Vue 3项目的标准TypeScript配置,包括编译选项和路径映射
// tsconfig.json
{
// 继承标准ts配置
"extends": "@vue/tsconfig/tsconfig.json",
"compilerOptions": {
"sourceMap": true,
"baseUrl": ".", // 模块解析基准目录
"paths": {
"@/*": ["./src/*"]
},
"lib": ["esnext", "dom"], // 可用的内置类型库 使ts能够识别这些api
"types": ["@dcloudio/types"] // 仅加载 uni-app 类型定义,不加载其他 @types/* 包
},
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"]
}

@dcloudio/vite-plugin-uni
将uni-app框架集成到Vite构建系统中,处理多端编译和资源转换
@dcloudio/uni-cli-shared
构建时:源码 → Vite 插件(@dcloudio/vite-plugin-uni) → 通用基建(@dcloudio/uni-cli-shared) → 平台实现(@dcloudio/uni-h5 或 @dcloudio/uni-mp-) → 目标产物

平台实现层虽然在处理不同环境下的转换逻辑各不相同,但是其底层的处理逻辑是一致的(比如条件编译处理等),这些可以看作是基础能力,被封装在@dcloudio/uni-cli-shared
@dcloudio/uni-stacktracey

vue-tsc

src/shime-uni.d.ts
怎么生效的?
// tsconfig.json
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"]
作用:是一个 TypeScript 声明文件,用于在 uni-app 中扩展 Vue 组件的类型,让组件能使用 uni-app 的生命周期钩子

注意,App和Page都是uniapp的生命周期。只是把它们两者糅合在一起再加到vue的生命周期里

问题一:
declare module "vue"不会覆盖原先vue模块的定义吗?



问题二:这些全局命名都在哪里被定义?

答案是@dcloudio/types(不包括vue的任何内容)和@vue/runtime-core



问题三:@vue/runtime-core的ts定义是在什么时候被加载的?


以下三种情况会去找@vue/runtime-core的ts定义

我的框架设计
package.json
dependencies
"dependencies": {
"@dcloudio/uni-app": "3.0.0-alpha-4010520240507001",
"@dcloudio/uni-app-plus": "3.0.0-alpha-4010520240507001",
"@dcloudio/uni-components": "3.0.0-alpha-4010520240507001",
"@dcloudio/uni-h5": "3.0.0-alpha-4010520240507001",
"@dcloudio/uni-mp-weixin": "3.0.0-alpha-4010520240507001",
"dayjs": "1.11.10", // 工具函数
"pinia": "2.0.36", //状态管理器
"pinia-plugin-persistedstate": "3.2.1", // 见下文
"qs": "6.5.3", // 格式化url请求,作用请见下文的http封装
"vue": "3.4.21",
"wot-design-uni": "^1.2.26", // ui库,不用它
},
pinia-plugin-persistedstate
是一个 Pinia 状态持久化插件,用于将 Pinia store 的数据自动保存到本地存储中,页面刷新或应用重启后数据不会丢失。
// 初始化pinia
import { createPinia } from 'pinia';
const pinia = createPinia();
import { createApp } from 'vue';
import App from './App.vue';
const app = createApp(App);
app.use(pinia)
开启持久化功能:
...
const pinia = createPinia();
import { createPersistedState } from 'pinia-plugin-persistedstate';
pinia.use(
createPersistedState({
storage: {
getItem: uni.getStorageSync, // uni提供的从本地缓存中同步获取指定 key 对应的内容
setItem: uni.setStorageSync // uni提供的从本地缓存中同步存储指定 key 对应的内容
}
})
);
...
某个状态仓库启用持久化:

devDependencies
只讲新增部分
{
...,
"@commitlint/cli": "^18.6.1", // 见提交规范章节
"@commitlint/config-conventional": "^18.6.3", // 见提交规范章节
"@esbuild/darwin-arm64": "0.20.2", // 下文
"@esbuild/darwin-x64": "0.20.2", // 下文
"@iconify-json/carbon": "^1.1.35", // uno库配置需要使用
"@rollup/rollup-darwin-x64": "^4.18.0", // 与@esbuild同理
"@types/node": "^20.14.2", // node类型定义包
"@typescript-eslint/eslint-plugin": "^6.21.0", // 见eslint配置
"@typescript-eslint/parser": "^6.21.0", // 见eslint配置
"@uni-helper/vite-plugin-uni-manifest": "^0.2.6",// 见unihelper
"@uni-helper/vite-plugin-uni-pages": "0.2.20",// 见unihelper
"@uni-helper/vite-plugin-uni-platform": "^0.0.4",// 见unihelper
"@vue/runtime-core": "^3.4.29",
"commitlint": "^18.6.1",
"eslint": "^8.57.0",
"eslint-config-prettier": "^9.1.0", // 见eslint配置
"eslint-config-standard": "^17.1.0", // 见eslint配置
"eslint-import-resolver-typescript": "^3.6.1", // 见eslint配置
"eslint-plugin-import": "^2.29.1", // 见eslint配置
"eslint-plugin-prettier": "^5.1.3", // 见eslint配置
"eslint-plugin-vue": "^9.26.0", // 见eslint配置
"husky": "^8.0.3",
"lint-staged": "^15.2.7",
"postcss": "^8.4.38", // 见postcss
"postcss-html": "^1.7.0", // 见postcss
"postcss-scss": "^4.0.9", // 见postcss
"rollup-plugin-visualizer": "^5.12.0", //打包分析工具,见下文
"sass": "^1.77.5",
"stylelint": "^16.6.1", // 见stylelint
"stylelint-config-html": "^1.1.0", // 见stylelint
"stylelint-config-recess-order": "^4.6.0", // 见stylelint
"stylelint-config-recommended": "^14.0.0", // 见stylelint
"stylelint-config-recommended-scss": "^14.0.0", // 见stylelint
"stylelint-config-recommended-vue": "^1.5.0", // 见stylelint
"stylelint-prettier": "^5.0.0", // 见stylelint
"terser": "^5.31.1", // 代码压缩
"typescript": "^4.9.5",
"unocss": "^0.58.9", // 见uno
"unocss-applet": "^0.7.8", // 见uno
"vite-plugin-restart": "^0.4.0", // 见下方
"vue-tsc": "^1.8.27"
}
@esbuild/xxx


@esbuild/darwin-arm64 -> M1/M2 Mac
@esbuild/darwin-x64 -> Intel Mac
显式声明,但在vite配置或者整个项目里不会被引用,Vite在编译时自然会去找它们。它们不影响window、linux等其他环境的工作,只是统一了在可能出现问题的平台环境下指定依赖的版本。
@unihelper

@uni-helper/vite-plugin-uni-pages 页面管理
自动根据配置文件和vue文件里的路由生成src/pages.json。不再需要手动书写了。
启用:
// vite.config.ts
import UniPages from '@uni-helper/vite-plugin-uni-pages'
import Uni from '@dcloudio/vite-plugin-uni'
export default ({ command, mode }) => {
plugins: [
UniPages(
exclude: ['**/components/**/**.*'], //这些目录下的文件导出的路由排除在外
routeBlockLang: 'json5', //指定 Vue 文件中 <route> 块使用的语言格式 可以是json或json5
dts: 'src/types/uni-pages.d.ts', // 自动生成页面声明文件,影响uni跳转路由传参
)
// UniXXX 需要在 Uni 之前引入
Uni(),
]
}
routeBlockLang:

vue里的lang其实可以不用写,因为vite已经配置了json5格式解析。vue里的lang其实只是为了IDE语法高亮。
// 首页
<route lang="json5" type="home">
{
style: { navigationBarTitleText: '首页', navigationStyle: 'custom' }
}
</route>
// 页面
<route lang="json5" type="page">
{
style: { navigationBarTitleText: '横屏功率谱', navigationStyle: 'custom' }
}
</route>
src/types/uni-pages.d.ts
当我们声明一个页面时,uniPage插件就会自动生成一份d.ts文件保存到src/types里。

这个types会被ts识别到并更新Uni里的四个关于路由的api的传参声明:

pages.config.ts请见下文专门讲解
@uni-helper/vite-plugin-uni-platform (平台判断)
plugins: [
UniPlatform(),
Uni(),
...
]
挂载插件后,可以:

注意,只能在node环境下通过UniPlatform获取环境变量。想在项目里用只能注入为全局变量


@uni-helper/vite-plugin-uni-manifest (清单配置)
使用 TypeScript 配置 manifest.json,提供类型提示和校验
plugins: [
UniManifest(),
Uni(),
...
]

/manifest.config.ts见下文
rollup-plugin-visualizer
打包分析工具,可视化查看项目打包后各个文件的大小占比。

// vite.config.ts
import { visualizer } from 'rollup-plugin-visualizer'
export default ({ command, mode }) => {
...,
return defineConfig({
plugins: [
Uni(),
UNI_PLATFORM === 'h5' && mode === 'production' &&
visualizer({
filename: './node_modules/.cache/visualizer/stats.html', // 报告保存位置
open: true, // ← 构建完成后自动打开浏览器
gzipSize: true, // ← 显示 gzip 压缩后的大小
brotliSize: true, // ← 显示 brotli 压缩后的大小
}),
]
})
}



vite-plugin-restart
用于监听配置文件的变化,自动重启 Vite 开发服务器。
plugins: [
Uni(),
ViteRestart({
// 通过这个插件,在修改vite.config.js文件则不需要重新运行也生效配置
restart: ['vite.config.js'],
}),
]


scripts
"preinstall": "npx only-allow pnpm",
在install前限制用户只能用pnpm安装包依赖
"uvm": "npx @dcloudio/uvm@latest",
"uvm-rm": "node ./scripts/postupgrade.js",
"postuvm": "echo upgrade uni-app success!",
uni-app 版本管理(Version Manager)简称U-VM
npx @dcloudio/uvm@latest =>将uni-app 框架及相关依赖升级到最新版本

也就是因为升级会自动安装不必要的依赖。所以有了uvm-rm命令。使用脚本清除依赖
// node环境 postupgrade.js
// eslint-disable-next-line @typescript-eslint/no-var-requires
const { exec } = require('child_process')
// 定义要执行的命令
const dependencies = [
'@dcloudio/uni-app-harmony',
// TODO: 如果需要某个平台的小程序,请手动删除或注释掉
'@dcloudio/uni-mp-alipay',
'@dcloudio/uni-mp-baidu',
'@dcloudio/uni-mp-jd',
'@dcloudio/uni-mp-kuaishou',
'@dcloudio/uni-mp-lark',
'@dcloudio/uni-mp-qq',
'@dcloudio/uni-mp-toutiao',
'@dcloudio/uni-mp-xhs',
'@dcloudio/uni-quickapp-webview',
// i18n模板要注释掉下面的
'vue-i18n',
]
// 使用exec执行命令
exec(`pnpm un ${dependencies.join(' ')}`, (error, stdout, stderr) => {
if (error) {
// 如果有错误,打印错误信息
console.error(`执行出错: ${error}`)
return
}
// 打印正常输出
console.log(`stdout: ${stdout}`)
// 如果有错误输出,也打印出来
console.error(`stderr: ${stderr}`)
})
resolutions

bin-wrapper是个常用插件,虽然项目未用到,但是方便后续用户扩展,预留了这行配置。
manifest.config.ts
node环境下读取的配置文件。
只要在vite.config.ts里配置了plugins(UniManifest()),就会自动读取根目录下的manifest.config.ts
// 如果需要js
UniManifest({
input: 'manifest.config.js' // 显式指定 JS 配置文件
})
更多推荐



所有评论(0)