
vue3和vite双向加持,uni-app性能再次提升
uni-app
对vue3 & Vite
的升级,是一个渐进式过程:
- 2020年9月:小程序平台支持 vue3 开发,小程序平台编译器依然使用webpack;
- 2021年5月:H5平台支持 vue3 开发,H5平台编译器升级为 Vite;
- 2021年8月:App平台支持 vue3 开发,App平台编译器升级为 Vite;
- 2021年11月:小程序平台编译器升级为 Vite;
至此,uni-app
在全平台支持了 Vite
编译及Vue 3.x
运行。
so,这场持续一年之久的大版本升级,究竟给uni-app
项目带来了哪些提升?
是时候总结(秀)一波了。
新版 uni-app 框架主要做了三大改进:
- 重写框架内核:基于
vue3 + ts
重写内置组件和API,实现更彻底、更高效的tree-shaking
; - 新增支持 Vite 构建工具,在H5平台实现秒开预览;
- 新增支持 Vue3.x,实现更灵活的开发方式,及更高的运行性能;
基于这三大改进,uni-app项目获得了多快好省四大收益:
- 更多的语法支持,支持组合式API,业务聚焦,开发效率更高;
- 更快的编译速度,H5平台十倍加速,小程序、App加速30%以上;
- 更好的运行性能,用户端响应更快,体验更好;
- 更小的代码体积,瘦身30%以上,更省体积、更省流量
更多的语法支持
新版uni-app
支持Vue 3.x框架,支持组合式API,可实现更聚焦的业务开发。
Vue 3.x的一些新增特性,uni-app
也已经完全支持,如:
- 支持
<script setup>
- 支持
<style scoped>
、<style module>
、State-Driven Dynamic CSS(v-bind)
- 支持
jsx
、tsx
(h5,app 平台支持,小程序不支持)
另外,在小程序平台,新版uni-app
也扩展了更多的语法,如:
- 更完善的模板语法支持(如
class
、style
支持函数、变量等,不再局限数组、对象类型) - 更完整的
props
支持(如传递函数) - 更完善的
slot
支持(如作用域插槽)
更快的编译速度
开发者日常工作中,最无聊的就是等待编译构建。
某乎上还有一个”程序员在等待编译的时候都做什么?“的讨论帖,可见编译时间对开发者而言,是一个多么尴尬无聊的碎片时间。
uni-app
本次升级vue3 & Vite
后,在编译时间上有多少改进?带给开发者多少福利?我们安排真实测试,以数据说话。
测试环境说明:
硬件:RedmiBook 14 二代
处理器:Intel(R) Core(TM) i7-1065G7 CPU @ 1.30GHz
内存:16.0 GB
操作系统:Windows 11 专业版 64 位操作系统
关于编译速度,我们做了两个维度的对比:
- 纵向对比:挑选
uni-app
常用项目模板,在H5、小程序、App平台,分别测试vue 2.6
和vue 3.x
的编译时间 - 横向对比:使用业内优秀的其它跨端框架,创建默认项目模板,记录其编译时间,和
uni-app
的vue 3.x
版本进行对比
uni-app 历史版本纵向对比
我们选择uni-app默认模板
、uni-starter
、hello-uniapp
三个项目模板,分别测试vue 2.6
和vue 3.x
的编译时间。
uni-app项目编译时间的采集方式:
vue 2.6
版本编译时间 = webpack 的 stats.endTime - stats.startTimevue 3.x
版本编译时间 = 构建工具入口处记录 global.vite_start_time = performance.now(),构建工具编译完成时:performance.now() - global.vite_start_time
H5平台
对uni-app
的三个项目模板分别运行到H5平台,进行多次编译测试,并求其均值后,获得如下数据:
由此,我们可以观察到:
- 在
vue 2.6
环境下,随着项目复杂度的提升,H5首页预览所需编译时间会直线增加;这是因为在vue 2.6
版本下,虽然仅预览首页,但依然会使用webpack
编译整个项目资源;故项目越复杂,编译时间越长; - 在
vue 3.x
环境下,H5首页预览的编译时间跟项目复杂度也有关系,但增幅不大;这是因为在vue 3.x
版本下,使用Vite
进行构建,预览首页时仅编译首页及首页所依赖资源,不会编译其它页面资源。
通过图表对比,我们可以直观得出结论:vue 3.x
环境下的首页编译时间,平均不到vue 2.6
环境下的十分之一。
换言之,vue 3.x
版本下的首页编译速度,相比vue 2.6
版本,有十倍效率提升。
这个十倍效率提升,主要得益于新版采用Vite
作为构建工具,由此带来了两大好处:
- 使用原生 ESM 文件,无需打包,实现极速的服务启动;
- 预览(运行)使用
esbuild
作为打包工具,相比vue 2.6
环境下的webpack
,构建速度快 10-100 倍(这不是我们夸大,详见esbuild)
本着这个十倍效率提升,小伙伴们还不赶紧上手试试?
小程序平台
对uni-app
的三个模板项目运行到小程序平台,多次编译测试,并求其均值后,获得如下数据:
从上图对比数据来看,我们可以得出结论:小程序平台,vue 3.x
版本下的运行编译,相比vue 2.6
版本,编译性能至少提升30%;且项目越复杂,编译性能提升越明显,可以达到40% ~ 50%。
App平台
对uni-app
的三个项目模板继续运行到App平台,多次编译测试,并求其均值后,获得如下数据:
从上图对比数据来看,我们可以得出结论:App平台,vue 3.x
版本下的运行编译,相比vue 2.6
版本,编译性能提升将近50%。
虽没有H5平台的十倍效率提升那么刺激,但将近50%的速度提升,经常开发小程序/App的小伙伴,还不心动?
业内优秀框架横向对比
除了采用不同版本的uni-app
进行纵向对比外,我们还使用业内优秀的跨端框架Taro
,创建空的项目模板,进行横向对比测试。
具体测试方案:
- 安装
Taro
的最新cli,本文测试时使用的版本为"@Tarojs/Taro": "3.3.16" - 使用
Taro init
命令,分别选择react
、vue
、vue3
框架,创建三个默认项目模板,三个项目名称分别为taro3-react
、taro3-vue
、taro3-vue3
,如下图:
- 使用
npm run dev:h5
,运行到H5平台进行预览,记录每次预览编译时间,重复执行,求其均值
关于Taro
编译时间的计算方案:
- 开发一个
Taro
扩展插件,插件规范参考Taro官网 - 插件功能 - 在
ctx.onBuildStart
中记录开始编译时间 - 在
ctx.onBuildFinish
中记录编译结束时间 - 两者的时间差,即为编译过程消耗时间
然后使用uni-app
的cli
命令行,创建基于vue3.x
的空项目模板,项目命名为uni-app-vue3
。
我们使用各自框架的命令行,将如上创建的5个项目分别编译到H5平台和小程序平台,多次测试,并求其均值。
同框架版本在H5平台上的编译时间,结果如下:
从图中可以看出,uni-app
的vue3
版本,在H5平台上的首页编译预览性能是遥遥领先的。这个遥遥有多远呢?这么讲吧,你都编译20次了,友商第一次还没完呢。
继续编译到小程序平台,多次测试,求其均值,结果如下:
从图中可以看出,uni-app
的vue3
版本,在小程序平台上的编译性能也是遥遥领先的,这个遥遥也不近。
更好的运行速度
开发环节编译快了,那面向最终用户的软件,运行性能怎么样?
我们进入性能测试章节。
测试方案:
- 开发内容:开发一个仿微博小程序首页的复杂长列表,支持下拉刷新、上拉翻页、点赞。
- 界面如下:
- 测试机型:小米 Mi 10 pro、MIUI 12.5 (21.11.3 开发版) 、微信版本 8.0.16
- 准备工作:每次开始测试前,杀掉各App进程、清空内存,保证测试机环境基本一致;每次从本地读取静态数据,屏蔽网络差异。
- 评测点:长列表中的某个组件,比如点赞组件,点击时是否能及时的修改未赞和已赞状态?
测试计时方式:
- 选中某微博,点击“点赞”按钮,实现点赞状态状态切换(已赞高亮、未赞灰色),
- 点赞按钮 onclick函数开头开始计时,setData回调函数开头结束计时;
在小米手机上进行多次测试,求其平均值,结果如下:
记录条数 | 200 | 400 | 600 | 800 | 1000 |
---|---|---|---|---|---|
vue2 | 30ms | 43ms | 56ms | 72ms | 90ms |
vue3 | 8ms | 9ms | 9ms | 8ms | 9ms |
从表格中可以看出:
- 随着页面记录的增加,
vue 2.6
版本的uni-app
项目,点赞组件响应时间快速增加,响应越来越慢; - 基于
vue 3.x
的uni-app
项目,点赞组件的响应时间跟页面条数无关,一直保持极高的响应灵敏度,性能体验远高于vue 2.6
版本。
从这个常见的长列表组件响应实验来看,vue 3.x
的性能体验要远高于vue 2.6
版本。
更小的代码体积
项目发行后的代码体积,是一个很重要的考量指标:
- H5平台:更小的代码体积,可以帮助开发者节省服务端带宽及CDN流量,可实现更快的资源加载及页面渲染;
- 小程序平台:更小的代码体积,可加速小程序包的下载(甚至可能免了分包加载的繁琐),帮助用户更快进入小程序业务界面;
- App平台:更小的代码体积,可实现更快的App启动,帮助用户更快进入App首页
为了测试vue 3.x
新版升级后,代码体积的变化,我们同样做了两个维度的测试:
- 纵向对比:选择
uni-app
常用项目模板,在H5、小程序、App平台,分别测试vue 2.6
和vue 3.x
的编译包大小 - 横向对比:使用业内优秀的其它跨端框架,创建默认项目模板,记录其编译后的包体积大小,和
uni-app
版本进行对比
Tips:
- 开发阶段重在编译速度,对应
npm run dev
操作 - 发行阶段重在编译包大小,对应
npm run build
操作
uni-app 不同版本纵向对比
我们复用之前创建的uni-app默认模板
、uni-starter
、hello-uniapp
三个项目模板,分别测试vue 2.6
和vue 3.x
的编译包体积。
uni-app
项目编译包体积的采集方式:编译到对应平台后,记录编译后文件夹的大小。
H5平台
H5平台编译后代码体积记录如下:
从统计结果来看,uni-app
的vue3.x
版本,在H5平台上的编译包体积至少瘦身30%以上。
H5平台的瘦身优化,主要得益于uni-app
框架的底层全面重构,实现了更彻底的摇树优化。
小程序平台
小程序平台编译后代码体积记录如下:
从统计结果来看,uni-app
的vue3.x
版本,在小程序平台上也有大幅瘦身。
App平台
App平台编译后代码体积记录如下:
从统计结果来看,uni-app
的vue3.x
版本,在App平台上根据项目不同,会有不同幅度的瘦身。
从理论上来讲,项目中的页面模板越复杂,App平台的瘦身效果越明显。
业内优秀框架横向对比
关于编译后的代码体积,我们也和业内优秀的跨端框架Taro
进行了对比,复用前面章节创建的三个Taro
项目,分别编译到H5平台和小程序平台,计算其编译后的源码文件夹大小。
从图中可以看出,uni-app
的vue3版本,在H5平台上编译包体积是最小的,只有友商的十分之一左右。
我们继续测试,不同版本框架发行到微信小程序平台,记录其编译包大小:
从图中可以看出,uni-app
的vue3版本,在小程序平台上编译包体积也是最小的。
Tips:细心的开发者会发现,所有框架版本编译到小程序上的代码包体积都远小于其在H5平台上的包体积,这是因为小程序由平台厂商提供内置组件及接口实现,而H5平台则需跨端框架自己实现内置组件及接口,故H5平台的代码包普遍要大一些。
总结
综上,我们以数字说话,阐述了vue3版本uni-app
开发的诸多好处,再回顾一遍:
- 更多的语法
- 更快的编译
- 更好的运行
- 更少的代码
你还不赶紧升级新版uni-app
来试试吗?
对文本测试过程及结果有疑问的同学,欢迎到github上提交issue,欢迎指正。
uni-app
对vue3 & Vite
的升级,是一个渐进式过程:
- 2020年9月:小程序平台支持 vue3 开发,小程序平台编译器依然使用webpack;
- 2021年5月:H5平台支持 vue3 开发,H5平台编译器升级为 Vite;
- 2021年8月:App平台支持 vue3 开发,App平台编译器升级为 Vite;
- 2021年11月:小程序平台编译器升级为 Vite;
至此,uni-app
在全平台支持了 Vite
编译及Vue 3.x
运行。
so,这场持续一年之久的大版本升级,究竟给uni-app
项目带来了哪些提升?
是时候总结(秀)一波了。
新版 uni-app 框架主要做了三大改进:
- 重写框架内核:基于
vue3 + ts
重写内置组件和API,实现更彻底、更高效的tree-shaking
; - 新增支持 Vite 构建工具,在H5平台实现秒开预览;
- 新增支持 Vue3.x,实现更灵活的开发方式,及更高的运行性能;
基于这三大改进,uni-app项目获得了多快好省四大收益:
- 更多的语法支持,支持组合式API,业务聚焦,开发效率更高;
- 更快的编译速度,H5平台十倍加速,小程序、App加速30%以上;
- 更好的运行性能,用户端响应更快,体验更好;
- 更小的代码体积,瘦身30%以上,更省体积、更省流量
更多的语法支持
新版uni-app
支持Vue 3.x框架,支持组合式API,可实现更聚焦的业务开发。
Vue 3.x的一些新增特性,uni-app
也已经完全支持,如:
- 支持
<script setup>
- 支持
<style scoped>
、<style module>
、State-Driven Dynamic CSS(v-bind)
- 支持
jsx
、tsx
(h5,app 平台支持,小程序不支持)
另外,在小程序平台,新版uni-app
也扩展了更多的语法,如:
- 更完善的模板语法支持(如
class
、style
支持函数、变量等,不再局限数组、对象类型) - 更完整的
props
支持(如传递函数) - 更完善的
slot
支持(如作用域插槽)
更快的编译速度
开发者日常工作中,最无聊的就是等待编译构建。
某乎上还有一个”程序员在等待编译的时候都做什么?“的讨论帖,可见编译时间对开发者而言,是一个多么尴尬无聊的碎片时间。
uni-app
本次升级vue3 & Vite
后,在编译时间上有多少改进?带给开发者多少福利?我们安排真实测试,以数据说话。
测试环境说明:
硬件:RedmiBook 14 二代
处理器:Intel(R) Core(TM) i7-1065G7 CPU @ 1.30GHz
内存:16.0 GB
操作系统:Windows 11 专业版 64 位操作系统
关于编译速度,我们做了两个维度的对比:
- 纵向对比:挑选
uni-app
常用项目模板,在H5、小程序、App平台,分别测试vue 2.6
和vue 3.x
的编译时间 - 横向对比:使用业内优秀的其它跨端框架,创建默认项目模板,记录其编译时间,和
uni-app
的vue 3.x
版本进行对比
uni-app 历史版本纵向对比
我们选择uni-app默认模板
、uni-starter
、hello-uniapp
三个项目模板,分别测试vue 2.6
和vue 3.x
的编译时间。
uni-app项目编译时间的采集方式:
vue 2.6
版本编译时间 = webpack 的 stats.endTime - stats.startTimevue 3.x
版本编译时间 = 构建工具入口处记录 global.vite_start_time = performance.now(),构建工具编译完成时:performance.now() - global.vite_start_time
H5平台
对uni-app
的三个项目模板分别运行到H5平台,进行多次编译测试,并求其均值后,获得如下数据:
由此,我们可以观察到:
- 在
vue 2.6
环境下,随着项目复杂度的提升,H5首页预览所需编译时间会直线增加;这是因为在vue 2.6
版本下,虽然仅预览首页,但依然会使用webpack
编译整个项目资源;故项目越复杂,编译时间越长; - 在
vue 3.x
环境下,H5首页预览的编译时间跟项目复杂度也有关系,但增幅不大;这是因为在vue 3.x
版本下,使用Vite
进行构建,预览首页时仅编译首页及首页所依赖资源,不会编译其它页面资源。
通过图表对比,我们可以直观得出结论:vue 3.x
环境下的首页编译时间,平均不到vue 2.6
环境下的十分之一。
换言之,vue 3.x
版本下的首页编译速度,相比vue 2.6
版本,有十倍效率提升。
这个十倍效率提升,主要得益于新版采用Vite
作为构建工具,由此带来了两大好处:
- 使用原生 ESM 文件,无需打包,实现极速的服务启动;
- 预览(运行)使用
esbuild
作为打包工具,相比vue 2.6
环境下的webpack
,构建速度快 10-100 倍(这不是我们夸大,详见esbuild)
本着这个十倍效率提升,小伙伴们还不赶紧上手试试?
小程序平台
对uni-app
的三个模板项目运行到小程序平台,多次编译测试,并求其均值后,获得如下数据:
从上图对比数据来看,我们可以得出结论:小程序平台,vue 3.x
版本下的运行编译,相比vue 2.6
版本,编译性能至少提升30%;且项目越复杂,编译性能提升越明显,可以达到40% ~ 50%。
App平台
对uni-app
的三个项目模板继续运行到App平台,多次编译测试,并求其均值后,获得如下数据:
从上图对比数据来看,我们可以得出结论:App平台,vue 3.x
版本下的运行编译,相比vue 2.6
版本,编译性能提升将近50%。
虽没有H5平台的十倍效率提升那么刺激,但将近50%的速度提升,经常开发小程序/App的小伙伴,还不心动?
业内优秀框架横向对比
除了采用不同版本的uni-app
进行纵向对比外,我们还使用业内优秀的跨端框架Taro
,创建空的项目模板,进行横向对比测试。
具体测试方案:
- 安装
Taro
的最新cli,本文测试时使用的版本为"@Tarojs/Taro": "3.3.16" - 使用
Taro init
命令,分别选择react
、vue
、vue3
框架,创建三个默认项目模板,三个项目名称分别为taro3-react
、taro3-vue
、taro3-vue3
,如下图:
- 使用
npm run dev:h5
,运行到H5平台进行预览,记录每次预览编译时间,重复执行,求其均值
关于Taro
编译时间的计算方案:
- 开发一个
Taro
扩展插件,插件规范参考Taro官网 - 插件功能 - 在
ctx.onBuildStart
中记录开始编译时间 - 在
ctx.onBuildFinish
中记录编译结束时间 - 两者的时间差,即为编译过程消耗时间
然后使用uni-app
的cli
命令行,创建基于vue3.x
的空项目模板,项目命名为uni-app-vue3
。
我们使用各自框架的命令行,将如上创建的5个项目分别编译到H5平台和小程序平台,多次测试,并求其均值。
同框架版本在H5平台上的编译时间,结果如下:
从图中可以看出,uni-app
的vue3
版本,在H5平台上的首页编译预览性能是遥遥领先的。这个遥遥有多远呢?这么讲吧,你都编译20次了,友商第一次还没完呢。
继续编译到小程序平台,多次测试,求其均值,结果如下:
从图中可以看出,uni-app
的vue3
版本,在小程序平台上的编译性能也是遥遥领先的,这个遥遥也不近。
更好的运行速度
开发环节编译快了,那面向最终用户的软件,运行性能怎么样?
我们进入性能测试章节。
测试方案:
- 开发内容:开发一个仿微博小程序首页的复杂长列表,支持下拉刷新、上拉翻页、点赞。
- 界面如下:
- 测试机型:小米 Mi 10 pro、MIUI 12.5 (21.11.3 开发版) 、微信版本 8.0.16
- 准备工作:每次开始测试前,杀掉各App进程、清空内存,保证测试机环境基本一致;每次从本地读取静态数据,屏蔽网络差异。
- 评测点:长列表中的某个组件,比如点赞组件,点击时是否能及时的修改未赞和已赞状态?
测试计时方式:
- 选中某微博,点击“点赞”按钮,实现点赞状态状态切换(已赞高亮、未赞灰色),
- 点赞按钮 onclick函数开头开始计时,setData回调函数开头结束计时;
在小米手机上进行多次测试,求其平均值,结果如下:
记录条数 | 200 | 400 | 600 | 800 | 1000 |
---|---|---|---|---|---|
vue2 | 30ms | 43ms | 56ms | 72ms | 90ms |
vue3 | 8ms | 9ms | 9ms | 8ms | 9ms |
从表格中可以看出:
- 随着页面记录的增加,
vue 2.6
版本的uni-app
项目,点赞组件响应时间快速增加,响应越来越慢; - 基于
vue 3.x
的uni-app
项目,点赞组件的响应时间跟页面条数无关,一直保持极高的响应灵敏度,性能体验远高于vue 2.6
版本。
从这个常见的长列表组件响应实验来看,vue 3.x
的性能体验要远高于vue 2.6
版本。
更小的代码体积
项目发行后的代码体积,是一个很重要的考量指标:
- H5平台:更小的代码体积,可以帮助开发者节省服务端带宽及CDN流量,可实现更快的资源加载及页面渲染;
- 小程序平台:更小的代码体积,可加速小程序包的下载(甚至可能免了分包加载的繁琐),帮助用户更快进入小程序业务界面;
- App平台:更小的代码体积,可实现更快的App启动,帮助用户更快进入App首页
为了测试vue 3.x
新版升级后,代码体积的变化,我们同样做了两个维度的测试:
- 纵向对比:选择
uni-app
常用项目模板,在H5、小程序、App平台,分别测试vue 2.6
和vue 3.x
的编译包大小 - 横向对比:使用业内优秀的其它跨端框架,创建默认项目模板,记录其编译后的包体积大小,和
uni-app
版本进行对比
Tips:
- 开发阶段重在编译速度,对应
npm run dev
操作 - 发行阶段重在编译包大小,对应
npm run build
操作
uni-app 不同版本纵向对比
我们复用之前创建的uni-app默认模板
、uni-starter
、hello-uniapp
三个项目模板,分别测试vue 2.6
和vue 3.x
的编译包体积。
uni-app
项目编译包体积的采集方式:编译到对应平台后,记录编译后文件夹的大小。
H5平台
H5平台编译后代码体积记录如下:
从统计结果来看,uni-app
的vue3.x
版本,在H5平台上的编译包体积至少瘦身30%以上。
H5平台的瘦身优化,主要得益于uni-app
框架的底层全面重构,实现了更彻底的摇树优化。
小程序平台
小程序平台编译后代码体积记录如下:
从统计结果来看,uni-app
的vue3.x
版本,在小程序平台上也有大幅瘦身。
App平台
App平台编译后代码体积记录如下:
从统计结果来看,uni-app
的vue3.x
版本,在App平台上根据项目不同,会有不同幅度的瘦身。
从理论上来讲,项目中的页面模板越复杂,App平台的瘦身效果越明显。
业内优秀框架横向对比
关于编译后的代码体积,我们也和业内优秀的跨端框架Taro
进行了对比,复用前面章节创建的三个Taro
项目,分别编译到H5平台和小程序平台,计算其编译后的源码文件夹大小。
从图中可以看出,uni-app
的vue3版本,在H5平台上编译包体积是最小的,只有友商的十分之一左右。
我们继续测试,不同版本框架发行到微信小程序平台,记录其编译包大小:
从图中可以看出,uni-app
的vue3版本,在小程序平台上编译包体积也是最小的。
Tips:细心的开发者会发现,所有框架版本编译到小程序上的代码包体积都远小于其在H5平台上的包体积,这是因为小程序由平台厂商提供内置组件及接口实现,而H5平台则需跨端框架自己实现内置组件及接口,故H5平台的代码包普遍要大一些。
总结
综上,我们以数字说话,阐述了vue3版本uni-app
开发的诸多好处,再回顾一遍:
- 更多的语法
- 更快的编译
- 更好的运行
- 更少的代码
你还不赶紧升级新版uni-app
来试试吗?
对文本测试过程及结果有疑问的同学,欢迎到github上提交issue,欢迎指正。
收起阅读 »
uni-app 清爽型商城app开源代码,支持小程序,h5,Android,ios
https://github.com/gooking/uni-app--mini-mall
[码云镜像:] https://gitee.com/javazj/uni-app--mini-mall
直接贴 GitHub 和 码云的下载地址吧,上面有演示二维码可以扫码体验,做的还是挺不错的
https://github.com/gooking/uni-app--mini-mall
[码云镜像:] https://gitee.com/javazj/uni-app--mini-mall
直接贴 GitHub 和 码云的下载地址吧,上面有演示二维码可以扫码体验,做的还是挺不错的
收起阅读 »
APP开发为什么选择uni-app,目前主流的APP开发方式总结和对比
Native App
使用原生语言开发的应用;
性能和体验都是最好,但开发和发布成本最高;
常用的开发技术:Swift,OC, Java
Web App
移动端的网站,常被称为H5应用,即运行在移动端浏览器的网站应用,一般泛指SPA模式开发的网站,与MPA对应,代表:微信公众号里的H5应用(微信公众号的H5又可以调用Native API,也可以认为是Hybrid App);
开发和发布成本最低,但性能最差;
常用的开发技术:VueJS、ReactJS等;
Hybrid App
混合模式移动应用,介于WebApp、Native App两者之间的App开发技术;
原理:JS写逻辑且可以通过JSBridge调用Native的API,用HTML+CSS编写界面,并由webview渲染界面;
渲染方式:webview渲染;
JSBridge统一封装了IOS和Android的API,因此Hybrid App具有跨平台效果;
JS逻辑的执行由webview内置的JS引擎决定,调用Native API是通过JSBridge来实现;
开发和发布成本介于Native App 和 WebApp之间。
热更新:支持
常用开发技术:PhoneGap、ApiCloud、MUI、Wex5、AppCan等;
React Native App
RN是Facebook开发并开源的一款UI框架,以解决Hybrid存在的缺陷与不足;
原理:JS写逻辑且运行在JS引擎中,底层自动把JS代码解析成对应平台(ios、安卓)的原生API,调用Native的API绘制原生UI,即原生渲染界面,这是与Hybird App最大的不同,因此性能好于Hybrid App。
渲染方式:原生渲染;
JS引擎为:ios为JSCore,andorid为v8,最新版rn开始在andorid上搞自己的js引擎Hermes
界面:由JSX语言写界面
布局:Flexbox;
基于的开发技术:ReactJS
热更新:支持;
思想:learn once, write anywhere; 注:不敢说write once,因为RN要针对ios和安卓各写一套代码;
Weex App
与React Native App类似,由阿里开发并开源一款UI框架;
原理:跟RN类似;
渲染方式:原生渲染
跟RN最大不同:Weex写一套代码即可运行在IOS和安卓中,RN要写两套代码,IOS一套,安卓一套;
JS引擎为:ios为JSCore,andorid为v8
界面:由Vue编写界面;
布局:Flexbox;
基于的开发技术:VueJS;
热更新:支持;
思想:write once, run anywhere;
注:
- 微信小程序类似于RN/Weex开发方式,也分为逻辑层和视图层;
- 微信小程序的页面属于混合渲染,什么是混合渲染?看后文总结;
Flutter APP
由Google开发并开源的一套UI框架,使用dart语言;逻辑和界面使用Flutter Engine;
Flutter使用Engine来绘制Widget(Flutter的显示单元),即Widget渲染界面,Dart代码都是通过AOT(Ahead Of Time)编译为平台的原生代码,所以Flutter可以直接与平台通信,不需要JS引擎的桥接。
Widget是不可变的,仅支持一帧,并且在每一帧上不会直接更新,要更新而必须使用Widget的状态。无状态和有状态widget的核心特性是相同的,每一帧他们都会重新构建,有一个State对象,它可以跨帧存储状态数据并恢复它。
渲染方式:Widget渲染界面
性能:Flutter APP是除了Native APP以外性能最好的;
热更新:不支持;
Uni-App
DCloud公司开发的一款基于vue.js的跨端的框架;
渲染方式:混合渲染、weex原生渲染、webview渲染。小程序和app-vue页面属于混合渲染,app-nvue页面全部是weex原生渲染。H5全部为webview渲染;
uni-app里的App端原生插件,这类插件使用IOS或者Android原生语言编写,封装成插件,供其他开发者使用js来调用;
原生插件分为原生组件component和原生模块module;
原生组件component只能在App-nvue页面中使用;
uni-app插件市场的大部分原生插件大部分属于原生模块module;
uni-app开发app性能足够好,用官方原话说是:点击跳转原文
> 当然,uni-app的app引擎并没有吊炸天。App平台,所有跨平台工具都还比不过原生,这是客观事实。只是,如果uni-app不能满足你的需求,你没有必要去用其他跨平台工具,直接上原生吧。
笔者认为使用uni-app开发最大的好处就是省成本和不错的生态:
- 成本,包括学习成本、开发成本,时间成本,招人成本等;
- 生态,包括开发者数量,社区活跃度,文档是否齐全等;
总结
目前主流的3大渲染引擎有:webview、React Native/weex、Flutter,复杂程度依次降低、渲染性能依次上升
混合渲染:主体为webview渲染,部分元素为原生渲染,比如导航栏、tabbar、video、map使用了原生控件
例如:微信小程序,uniapp发布的app-vue页面都属于混合渲染;
混合渲染虽然提升了性能,但也带来了其他问题,点击查看
Flutter的逻辑层和视图层统一,运行在同一套dart虚拟机下。
rn和weex使用原生渲染,性能高于webview,但是同为原生渲染,rn和weex怎么会慢于flutter呢?其实并不是原生渲染慢,而是js和原生通信慢
rn和weex分为js引擎和原生渲染层两个运行环境,当js引擎联网获取数据后,通知原生视图层更新界面时,有一个跨环境的通信折损。同样,但用户在屏幕上操作原生视图层时,要给js引擎发送通知,也会产生通信折损。
这个通信折损,普遍存在于所有逻辑和视图分离的框架中,各家小程序因为也使用这个架构,所以也存在这个问题。
因为flutter只有一个dart引擎,所有没有来回通信参数的性能问题,所以性能比rn和weex跟高;
这个通信的折损特别表现在跟手势的js响应操作绘制帧动画,或者说js连续操作界面元素方面。场景如:界面可拖动的浮动球、可拖动的滑块等。
为了解决通信的折损,RN搞了lottie的动画库,weex搞了BindingX,微信小程序搞了wxs,百度小程序搞了Filter,阿里小程序搞了SJS,uniapp若使用weex渲染时使用BindingX,使用app-vue时使用renderjs或wxs,renderjs和wxs是一种运行在视图层的js,不和逻辑层通信。
Native App
使用原生语言开发的应用;
性能和体验都是最好,但开发和发布成本最高;
常用的开发技术:Swift,OC, Java
Web App
移动端的网站,常被称为H5应用,即运行在移动端浏览器的网站应用,一般泛指SPA模式开发的网站,与MPA对应,代表:微信公众号里的H5应用(微信公众号的H5又可以调用Native API,也可以认为是Hybrid App);
开发和发布成本最低,但性能最差;
常用的开发技术:VueJS、ReactJS等;
Hybrid App
混合模式移动应用,介于WebApp、Native App两者之间的App开发技术;
原理:JS写逻辑且可以通过JSBridge调用Native的API,用HTML+CSS编写界面,并由webview渲染界面;
渲染方式:webview渲染;
JSBridge统一封装了IOS和Android的API,因此Hybrid App具有跨平台效果;
JS逻辑的执行由webview内置的JS引擎决定,调用Native API是通过JSBridge来实现;
开发和发布成本介于Native App 和 WebApp之间。
热更新:支持
常用开发技术:PhoneGap、ApiCloud、MUI、Wex5、AppCan等;
React Native App
RN是Facebook开发并开源的一款UI框架,以解决Hybrid存在的缺陷与不足;
原理:JS写逻辑且运行在JS引擎中,底层自动把JS代码解析成对应平台(ios、安卓)的原生API,调用Native的API绘制原生UI,即原生渲染界面,这是与Hybird App最大的不同,因此性能好于Hybrid App。
渲染方式:原生渲染;
JS引擎为:ios为JSCore,andorid为v8,最新版rn开始在andorid上搞自己的js引擎Hermes
界面:由JSX语言写界面
布局:Flexbox;
基于的开发技术:ReactJS
热更新:支持;
思想:learn once, write anywhere; 注:不敢说write once,因为RN要针对ios和安卓各写一套代码;
Weex App
与React Native App类似,由阿里开发并开源一款UI框架;
原理:跟RN类似;
渲染方式:原生渲染
跟RN最大不同:Weex写一套代码即可运行在IOS和安卓中,RN要写两套代码,IOS一套,安卓一套;
JS引擎为:ios为JSCore,andorid为v8
界面:由Vue编写界面;
布局:Flexbox;
基于的开发技术:VueJS;
热更新:支持;
思想:write once, run anywhere;
注:
- 微信小程序类似于RN/Weex开发方式,也分为逻辑层和视图层;
- 微信小程序的页面属于混合渲染,什么是混合渲染?看后文总结;
Flutter APP
由Google开发并开源的一套UI框架,使用dart语言;逻辑和界面使用Flutter Engine;
Flutter使用Engine来绘制Widget(Flutter的显示单元),即Widget渲染界面,Dart代码都是通过AOT(Ahead Of Time)编译为平台的原生代码,所以Flutter可以直接与平台通信,不需要JS引擎的桥接。
Widget是不可变的,仅支持一帧,并且在每一帧上不会直接更新,要更新而必须使用Widget的状态。无状态和有状态widget的核心特性是相同的,每一帧他们都会重新构建,有一个State对象,它可以跨帧存储状态数据并恢复它。
渲染方式:Widget渲染界面
性能:Flutter APP是除了Native APP以外性能最好的;
热更新:不支持;
Uni-App
DCloud公司开发的一款基于vue.js的跨端的框架;
渲染方式:混合渲染、weex原生渲染、webview渲染。小程序和app-vue页面属于混合渲染,app-nvue页面全部是weex原生渲染。H5全部为webview渲染;
uni-app里的App端原生插件,这类插件使用IOS或者Android原生语言编写,封装成插件,供其他开发者使用js来调用;
原生插件分为原生组件component和原生模块module;
原生组件component只能在App-nvue页面中使用;
uni-app插件市场的大部分原生插件大部分属于原生模块module;
uni-app开发app性能足够好,用官方原话说是:点击跳转原文
> 当然,uni-app的app引擎并没有吊炸天。App平台,所有跨平台工具都还比不过原生,这是客观事实。只是,如果uni-app不能满足你的需求,你没有必要去用其他跨平台工具,直接上原生吧。
笔者认为使用uni-app开发最大的好处就是省成本和不错的生态:
- 成本,包括学习成本、开发成本,时间成本,招人成本等;
- 生态,包括开发者数量,社区活跃度,文档是否齐全等;
总结
目前主流的3大渲染引擎有:webview、React Native/weex、Flutter,复杂程度依次降低、渲染性能依次上升
混合渲染:主体为webview渲染,部分元素为原生渲染,比如导航栏、tabbar、video、map使用了原生控件
例如:微信小程序,uniapp发布的app-vue页面都属于混合渲染;
混合渲染虽然提升了性能,但也带来了其他问题,点击查看
Flutter的逻辑层和视图层统一,运行在同一套dart虚拟机下。
rn和weex使用原生渲染,性能高于webview,但是同为原生渲染,rn和weex怎么会慢于flutter呢?其实并不是原生渲染慢,而是js和原生通信慢
rn和weex分为js引擎和原生渲染层两个运行环境,当js引擎联网获取数据后,通知原生视图层更新界面时,有一个跨环境的通信折损。同样,但用户在屏幕上操作原生视图层时,要给js引擎发送通知,也会产生通信折损。
这个通信折损,普遍存在于所有逻辑和视图分离的框架中,各家小程序因为也使用这个架构,所以也存在这个问题。
因为flutter只有一个dart引擎,所有没有来回通信参数的性能问题,所以性能比rn和weex跟高;
这个通信的折损特别表现在跟手势的js响应操作绘制帧动画,或者说js连续操作界面元素方面。场景如:界面可拖动的浮动球、可拖动的滑块等。
为了解决通信的折损,RN搞了lottie的动画库,weex搞了BindingX,微信小程序搞了wxs,百度小程序搞了Filter,阿里小程序搞了SJS,uniapp若使用weex渲染时使用BindingX,使用app-vue时使用renderjs或wxs,renderjs和wxs是一种运行在视图层的js,不和逻辑层通信。

如何在VUE中播放RTSP监控视频,且延迟小于300毫秒?
近期研究在VUE中播放RTSP实时视频,客户要求延迟低于300毫秒,并且要求支持多路同时播放,支持H.265格式视频,比较了下目前市场上常见的几种方案,以供大家参考!
一、海康威视官方WEB解决方案:
海康威视官方提供了两种WEB解决方案,即无插件方案和有插件方案。

1.无插件方案,实际采用的是服务器转码推流的方式,因为需要转码两次,导致延迟比较高,多路播放或者播放高清视频容易卡顿或者花屏,无法满足客户需求。
2.有插件版方案,虽然延迟比较低,但要求浏览器需要支持NPAPI插件,所以只能运行在IE和低版本Chrome等浏览器,IE明年就彻底不能用了,低版本的浏览器漏洞也比较多,商用还是有很大风险,只能忍痛放弃!
二、低版本浏览器VLC播放方案:
2015年之前Chrome等浏览器还未取消对NPAPI插件支持的时主流方案,继续使用低版本Chrome浏览器,通过VLC原生播放器直接播放,也不需要服务器支持,延迟非常低,终端也可以使用硬件的加速能力,多路播放也毫无压力。
缺点也非常明显:无法使用最新的浏览器和操作系统,不适合商用。如果能解决高版本的Chrome、Firefox、Edge等浏览器使用,此方案无疑是最佳选择!
三、猿大师VLC播放程序方案:
猿大师的VLC播放程序是基于猿大师中间件提供的内嵌网页播放的专利技术,底层调用VLC客户端的ActiveX控件可实现在Chrome等高版本浏览器中内嵌播放海康威视、大华等摄像头的RTSP视频流,可以以做到低延迟(300毫秒),支持多路同时播放,支持H.264和H.265格式,支持2K、4K等高清视频,兼容主流浏览器的老版本和最新版本,不用担心浏览器升级导致不能用的问题。
猿大师官网:http://www.yuanmaster.com
1.猿大师与大华官方网页延迟对比:https://www.bilibili.com/video/BV1ff4y1j7qg/
2.猿大师VLC播放程序与海康威视官方网页延迟对比:https://www.bilibili.com/video/BV1mr4y127oX/
3.猿大师VLC播放程序VUE测试页面效果演示:https://www.bilibili.com/video/BV1Y34y197Z3
近期研究在VUE中播放RTSP实时视频,客户要求延迟低于300毫秒,并且要求支持多路同时播放,支持H.265格式视频,比较了下目前市场上常见的几种方案,以供大家参考!
一、海康威视官方WEB解决方案:
海康威视官方提供了两种WEB解决方案,即无插件方案和有插件方案。
1.无插件方案,实际采用的是服务器转码推流的方式,因为需要转码两次,导致延迟比较高,多路播放或者播放高清视频容易卡顿或者花屏,无法满足客户需求。
2.有插件版方案,虽然延迟比较低,但要求浏览器需要支持NPAPI插件,所以只能运行在IE和低版本Chrome等浏览器,IE明年就彻底不能用了,低版本的浏览器漏洞也比较多,商用还是有很大风险,只能忍痛放弃!
二、低版本浏览器VLC播放方案:
2015年之前Chrome等浏览器还未取消对NPAPI插件支持的时主流方案,继续使用低版本Chrome浏览器,通过VLC原生播放器直接播放,也不需要服务器支持,延迟非常低,终端也可以使用硬件的加速能力,多路播放也毫无压力。
缺点也非常明显:无法使用最新的浏览器和操作系统,不适合商用。如果能解决高版本的Chrome、Firefox、Edge等浏览器使用,此方案无疑是最佳选择!
三、猿大师VLC播放程序方案:
猿大师的VLC播放程序是基于猿大师中间件提供的内嵌网页播放的专利技术,底层调用VLC客户端的ActiveX控件可实现在Chrome等高版本浏览器中内嵌播放海康威视、大华等摄像头的RTSP视频流,可以以做到低延迟(300毫秒),支持多路同时播放,支持H.264和H.265格式,支持2K、4K等高清视频,兼容主流浏览器的老版本和最新版本,不用担心浏览器升级导致不能用的问题。
猿大师官网:http://www.yuanmaster.com
1.猿大师与大华官方网页延迟对比:https://www.bilibili.com/video/BV1ff4y1j7qg/
2.猿大师VLC播放程序与海康威视官方网页延迟对比:https://www.bilibili.com/video/BV1mr4y127oX/
3.猿大师VLC播放程序VUE测试页面效果演示:https://www.bilibili.com/video/BV1Y34y197Z3

苹果内购项目怎样获取货币符号
let codes=[];
codes.push({country:'USD',code:'$ '})
codes.push({country:'AED',code:'AED'})
codes.push({country:'EGP',code:'EGP'})
codes.push({country:'EUR',code:'€ '})
codes.push({country:'AUD',code:'$ '})
codes.push({country:'PKR',code:'Rs '})
codes.push({country:'BRL',code:'R$ '})
codes.push({country:'BGN',code:'лв '})
codes.push({country:'PLN',code:'zł '})
codes.push({country:'DKK',code:'kr '})
codes.push({country:'RUB',code:'₽ '})
codes.push({country:'PHP',code:'₱ '})
codes.push({country:'COP',code:'$ '})
codes.push({country:'KZT',code:'₸ '})
codes.push({country:'KRW',code:'₩ '})
codes.push({country:'CAD',code:'$ '})
codes.push({country:'CZK',code:'Kč '})
codes.push({country:'QAR',code:'QAR'})
codes.push({country:'HRK',code:'kn '})
codes.push({country:'RON',code:'lei'})
codes.push({country:'MYR',code:'RM '})
codes.push({country:'PEN',code:'S/''})
codes.push({country:'MXN',code:'$ '})
codes.push({country:'ZAR',code:'R '})
codes.push({country:'NGN',code:'₦ '})
codes.push({country:'NOK',code:'kr '})
codes.push({country:'JPY',code:'¥ '})
codes.push({country:'SEK',code:'kr '})
codes.push({country:'CHF',code:'CHF'})
codes.push({country:'SAR',code:'SR '})
codes.push({country:'TWD',code:'NT '})
codes.push({country:'THB',code:'฿ '})
codes.push({country:'TZS',code:'TZS'})
codes.push({country:'TRY',code:'₺ '})
codes.push({country:'HKD',code:'HK$'})
codes.push({country:'SGD',code:'S$ '})
codes.push({country:'NZD',code:'$ '})
codes.push({country:'HUF',code:'Ft '})
codes.push({country:'ILS',code:'₪ })'
codes.push({country:'INR',code:'₹ '})
codes.push({country:'IDR',code:'Rp '})
codes.push({country:'GBP',code:'£ '})
codes.push({country:'VND',code:' đ '})
codes.push({country:'CLP',code:' $ '})
codes.push({country:'CNY',code:'¥ '})
大神们有没有更好的方式。原生的有,但是uniapp不知道怎样调用,获取各国的货币符号
let codes=[];
codes.push({country:'USD',code:'$ '})
codes.push({country:'AED',code:'AED'})
codes.push({country:'EGP',code:'EGP'})
codes.push({country:'EUR',code:'€ '})
codes.push({country:'AUD',code:'$ '})
codes.push({country:'PKR',code:'Rs '})
codes.push({country:'BRL',code:'R$ '})
codes.push({country:'BGN',code:'лв '})
codes.push({country:'PLN',code:'zł '})
codes.push({country:'DKK',code:'kr '})
codes.push({country:'RUB',code:'₽ '})
codes.push({country:'PHP',code:'₱ '})
codes.push({country:'COP',code:'$ '})
codes.push({country:'KZT',code:'₸ '})
codes.push({country:'KRW',code:'₩ '})
codes.push({country:'CAD',code:'$ '})
codes.push({country:'CZK',code:'Kč '})
codes.push({country:'QAR',code:'QAR'})
codes.push({country:'HRK',code:'kn '})
codes.push({country:'RON',code:'lei'})
codes.push({country:'MYR',code:'RM '})
codes.push({country:'PEN',code:'S/''})
codes.push({country:'MXN',code:'$ '})
codes.push({country:'ZAR',code:'R '})
codes.push({country:'NGN',code:'₦ '})
codes.push({country:'NOK',code:'kr '})
codes.push({country:'JPY',code:'¥ '})
codes.push({country:'SEK',code:'kr '})
codes.push({country:'CHF',code:'CHF'})
codes.push({country:'SAR',code:'SR '})
codes.push({country:'TWD',code:'NT '})
codes.push({country:'THB',code:'฿ '})
codes.push({country:'TZS',code:'TZS'})
codes.push({country:'TRY',code:'₺ '})
codes.push({country:'HKD',code:'HK$'})
codes.push({country:'SGD',code:'S$ '})
codes.push({country:'NZD',code:'$ '})
codes.push({country:'HUF',code:'Ft '})
codes.push({country:'ILS',code:'₪ })'
codes.push({country:'INR',code:'₹ '})
codes.push({country:'IDR',code:'Rp '})
codes.push({country:'GBP',code:'£ '})
codes.push({country:'VND',code:' đ '})
codes.push({country:'CLP',code:' $ '})
codes.push({country:'CNY',code:'¥ '})
大神们有没有更好的方式。原生的有,但是uniapp不知道怎样调用,获取各国的货币符号
收起阅读 »
uniapp使用微信小程序分包异步化能力临时方案
背景
参考问题:uniapp开发微信小程序如何使用分包异步化特性,目前(2022/02/07)uniapp中的pages.json配置不支持分包异步化的特性(按照微信官方文档配置,构建后并不会在app.json文件生成对应的配置,猜测是因为分包异步化中的pages为空,构建代码过滤了,有空查看构建源码确认一下)。
这里应该由uniapp官方支持一下这个功能,目前项目需要,先用下面的临时方案
解决方案
思路:在uniapp构建完成后,添加自己的构建脚本,做以下的事情
- 读取pages.json
- 判断pages.json中是否有配置分包异步化
- 把分包异步化相关配置写入app.json
- 寻找用到分包组件的地方(小程序的页面 or 组件json配置文件),注入组件占位(不注入的话小程序会报错导致分包内组件无法使用)
构建脚本源码
/* eslint-disable @typescript-eslint/no-require-imports */
const fs = require('fs');
const path = require('path');
console.log('开始处理异步化分包...');
// 读取pages.json
const pagesConfig = (() => {
const configPath = path.resolve(__dirname, '../../../pages.json'); // @NOTE 这里要根据脚本执行的路径改一下
const pages = fs.readFileSync(configPath, 'utf8');
// @NOTE 移除注释
let pagesJson = pages.replace(/\/\*.*\*\//g, '');
pagesJson = pagesJson.replace(/\/\/.*/g, '');
return JSON.parse(pagesJson);
})();
// 读取page.json中的异步分包(没有配置pages)
const asyncPackages = (pagesConfig.subPackages || []).filter(package => !package.pages || package.pages.length === 0);
// console.log(pagesConfig, asyncPackages);
// 写入app.json
const distPath = path.resolve(__dirname, '../../../../dist/build/mp-weixin'); // @NOTE 这里要根据脚本执行的路径改一下
const appJsonPath = path.resolve(distPath, 'app.json');
const appJson = JSON.parse(fs.readFileSync(appJsonPath, 'utf8'));
if (!appJson.subPackages) {
appJson.subPackages = [];
}
asyncPackages.forEach((package) => {
const hasInject = appJson.subPackages.find(pack => pack.root === package.root);
if (hasInject) {
return;
}
appJson.subPackages.push({
root: package.root,
pages: [],
});
});
fs.writeFileSync(appJsonPath, JSON.stringify(appJson));
// 寻找用到分包组件的地方,注入组件占位(不注入的话小程序会报错导致分包内组件无法使用)
const ignorePaths = [];
ignorePaths.push(appJsonPath); // 过滤app.json
asyncPackages.forEach((package) => {
ignorePaths.push(path.join(distPath, package.root)); // 过滤分包的内容
});
const injectPlaceholder = (filepath) => {
// 判断是否用到了分包的组件
const jsonConfig = require(filepath);
if (!jsonConfig.usingComponents) {
return;
}
const subPackageComponents = [];
// @TODO 可以考虑使用map来加快查找速度
Object.keys(jsonConfig.usingComponents).forEach((componentName) => {
const componentPath = jsonConfig.usingComponents[componentName];
const targetSubPackage = asyncPackages.find(package => componentPath.startsWith(`/${package.root}`));
if (targetSubPackage) {
// 防止重复添加
// eslint-disable-next-line @typescript-eslint/prefer-optional-chain
if (jsonConfig.componentPlaceholder && jsonConfig.componentPlaceholder[componentName]) {
return;
}
subPackageComponents.push(componentName);
}
});
if (subPackageComponents.length === 0) {
return;
}
console.log('开始处理: ', filepath);
if (!jsonConfig.componentPlaceholder) {
jsonConfig.componentPlaceholder = {};
}
subPackageComponents.forEach((name) => {
jsonConfig.componentPlaceholder[name] = 'view'; // 占位符全用view组件
});
fs.writeFileSync(filepath, JSON.stringify(jsonConfig));
console.log('处理完成: ', filepath);
};
findJSON(distPath, ignorePaths, injectPlaceholder);
console.log('异步化分包处理完成');
function findJSON(folder, ignorePaths, cb) {
fs.readdirSync(folder).forEach((filename) => {
const filepath = path.join(folder, filename);
const isIgnore = ignorePaths.some(ignorePath => filepath.startsWith(ignorePath));
if (isIgnore) {
return;
}
const stat = fs.statSync(filepath);
if (filename.endsWith('.json')) {
cb(filepath);
return;
}
if (stat.isDirectory()) {
findJSON(filepath, ignorePaths, cb);
}
});
}
最后
目前用这个方式解决了分包异步化中使用分包内的组件问题,至于分包内的js使用,大家可以验证一下,我暂时没有这个场景,所以没有验证。
上面的代码编写没有review,但测试过单个分包配置的场景,项目使用的时候请谨慎。
最后还是希望官方大佬支持一下分包异步化这个特性。
背景
参考问题:uniapp开发微信小程序如何使用分包异步化特性,目前(2022/02/07)uniapp中的pages.json配置不支持分包异步化的特性(按照微信官方文档配置,构建后并不会在app.json文件生成对应的配置,猜测是因为分包异步化中的pages为空,构建代码过滤了,有空查看构建源码确认一下)。
这里应该由uniapp官方支持一下这个功能,目前项目需要,先用下面的临时方案
解决方案
思路:在uniapp构建完成后,添加自己的构建脚本,做以下的事情
- 读取pages.json
- 判断pages.json中是否有配置分包异步化
- 把分包异步化相关配置写入app.json
- 寻找用到分包组件的地方(小程序的页面 or 组件json配置文件),注入组件占位(不注入的话小程序会报错导致分包内组件无法使用)
构建脚本源码
/* eslint-disable @typescript-eslint/no-require-imports */
const fs = require('fs');
const path = require('path');
console.log('开始处理异步化分包...');
// 读取pages.json
const pagesConfig = (() => {
const configPath = path.resolve(__dirname, '../../../pages.json'); // @NOTE 这里要根据脚本执行的路径改一下
const pages = fs.readFileSync(configPath, 'utf8');
// @NOTE 移除注释
let pagesJson = pages.replace(/\/\*.*\*\//g, '');
pagesJson = pagesJson.replace(/\/\/.*/g, '');
return JSON.parse(pagesJson);
})();
// 读取page.json中的异步分包(没有配置pages)
const asyncPackages = (pagesConfig.subPackages || []).filter(package => !package.pages || package.pages.length === 0);
// console.log(pagesConfig, asyncPackages);
// 写入app.json
const distPath = path.resolve(__dirname, '../../../../dist/build/mp-weixin'); // @NOTE 这里要根据脚本执行的路径改一下
const appJsonPath = path.resolve(distPath, 'app.json');
const appJson = JSON.parse(fs.readFileSync(appJsonPath, 'utf8'));
if (!appJson.subPackages) {
appJson.subPackages = [];
}
asyncPackages.forEach((package) => {
const hasInject = appJson.subPackages.find(pack => pack.root === package.root);
if (hasInject) {
return;
}
appJson.subPackages.push({
root: package.root,
pages: [],
});
});
fs.writeFileSync(appJsonPath, JSON.stringify(appJson));
// 寻找用到分包组件的地方,注入组件占位(不注入的话小程序会报错导致分包内组件无法使用)
const ignorePaths = [];
ignorePaths.push(appJsonPath); // 过滤app.json
asyncPackages.forEach((package) => {
ignorePaths.push(path.join(distPath, package.root)); // 过滤分包的内容
});
const injectPlaceholder = (filepath) => {
// 判断是否用到了分包的组件
const jsonConfig = require(filepath);
if (!jsonConfig.usingComponents) {
return;
}
const subPackageComponents = [];
// @TODO 可以考虑使用map来加快查找速度
Object.keys(jsonConfig.usingComponents).forEach((componentName) => {
const componentPath = jsonConfig.usingComponents[componentName];
const targetSubPackage = asyncPackages.find(package => componentPath.startsWith(`/${package.root}`));
if (targetSubPackage) {
// 防止重复添加
// eslint-disable-next-line @typescript-eslint/prefer-optional-chain
if (jsonConfig.componentPlaceholder && jsonConfig.componentPlaceholder[componentName]) {
return;
}
subPackageComponents.push(componentName);
}
});
if (subPackageComponents.length === 0) {
return;
}
console.log('开始处理: ', filepath);
if (!jsonConfig.componentPlaceholder) {
jsonConfig.componentPlaceholder = {};
}
subPackageComponents.forEach((name) => {
jsonConfig.componentPlaceholder[name] = 'view'; // 占位符全用view组件
});
fs.writeFileSync(filepath, JSON.stringify(jsonConfig));
console.log('处理完成: ', filepath);
};
findJSON(distPath, ignorePaths, injectPlaceholder);
console.log('异步化分包处理完成');
function findJSON(folder, ignorePaths, cb) {
fs.readdirSync(folder).forEach((filename) => {
const filepath = path.join(folder, filename);
const isIgnore = ignorePaths.some(ignorePath => filepath.startsWith(ignorePath));
if (isIgnore) {
return;
}
const stat = fs.statSync(filepath);
if (filename.endsWith('.json')) {
cb(filepath);
return;
}
if (stat.isDirectory()) {
findJSON(filepath, ignorePaths, cb);
}
});
}
最后
目前用这个方式解决了分包异步化中使用分包内的组件问题,至于分包内的js使用,大家可以验证一下,我暂时没有这个场景,所以没有验证。
上面的代码编写没有review,但测试过单个分包配置的场景,项目使用的时候请谨慎。
最后还是希望官方大佬支持一下分包异步化这个特性。
收起阅读 »
让小程序开发进入 `tailwind jit` 时代!
让小程序开发进入 tailwind jit
时代!
把
tailwindcss JIT
思想带入小程序开发吧!
笔者几个月前写了一个 tailwindcss-miniprogram-preset 预设,可是这个预设方案,可操作性非常的小,也不能兼容 tailwindcss v2/v3
的 Just in time
引擎,同时在写法上也有一定的变体。
于是笔者又设计了一个方案,并最终实现了 weapp-tailwindcss-webpack-plugin
。相比原先 preset
or postcss
方案,这个方案有很多的优势:
- 为
jit
设计,兼容v2/v3
2个版本的jit
引擎 - 开发者不需要额外记忆任何的写法变体,带来原汁原味的
tailwindcss
开发体验 - 兼容基于
webpack v4/v5
的小程序多端开发框架,简单易用
那么接下来就来展示一个基于 uni-app
的 demo 来快速体验这个方案吧。
最佳实践
前置准备: vscode
,vscode-tailwindcss
,nodejs lts
,微信开发者工具
1.通过vue-cli命令行创建工程
此部分内容见 uni-app快速上手
2.安装 npm 包
由于目前 uni-app
内置的 webpack
版本为 4
, postcss
版本为 7
我们需要安装 tailwindcss
的 postcss7-compat
版本:
yarn add -D weapp-tailwindcss-webpack-plugin postcss-rem-to-responsive-pixel tailwindcss@npm:@tailwindcss/postcss7-compat postcss@^7 autoprefixer@^9
postcss-rem-to-responsive-pixel 是一个由笔者撰写的 postcss 插件,支持
rem
->rpx
,同时支持postcss7
和postcss8
,配置见此
3. 初始化 tailwind.config.js
和 postcss.config.js
只需要在初始化的文件内加入一些配置:
// tailwind.config.js 基础配置,无需任何preset
// https://github.com/sonofmagic/weapp-tailwindcss-webpack-plugin/blob/main/demo/uni-app/tailwind.config.js
/** @type {import('@types/tailwindcss/tailwind-config').TailwindConfig} */
module.exports = {
mode: 'jit',
purge: {
content: ['./src/**/*.{vue,js,ts,jsx,tsx,wxml}']
},
corePlugins: {
preflight: false
}
}
// postcss.config.js 参考示例
// https://github.com/sonofmagic/weapp-tailwindcss-webpack-plugin/blob/main/demo/uni-app/postcss.config.js
const path = require('path')
module.exports = {
parser: require('postcss-comment'),
plugins: [
require('postcss-import')({
resolve(id, basedir, importOptions) {
if (id.startsWith('~@/')) {
return path.resolve(process.env.UNI_INPUT_DIR, id.substr(3))
} else if (id.startsWith('@/')) {
return path.resolve(process.env.UNI_INPUT_DIR, id.substr(2))
} else if (id.startsWith('/') && !id.startsWith('//')) {
return path.resolve(process.env.UNI_INPUT_DIR, id.substr(1))
}
return id
}
}),
require('autoprefixer')({
remove: process.env.UNI_PLATFORM !== 'h5'
}),
// #region 添加的部分开始
// tailwindcss for postcss7
require('tailwindcss')({ config: './tailwind.config.js' }),
// rem 转 rpx
require('postcss-rem-to-responsive-pixel/postcss7')({
rootValue: 32,
propList: ['*'],
transformUnit: 'rpx'
}),
// #endregion 添加的部分结束
require('@dcloudio/vue-cli-plugin-uni/packages/postcss')
]
}
4. 设置环境变量
添加 .env
设置 TAILWIND_MODE
# https://github.com/sonofmagic/weapp-tailwindcss-webpack-plugin/blob/main/demo/uni-app/.env
# jit 模式 HMR
TAILWIND_MODE=watch
这是为了兼容 tailwindcss v2
的 HMR 方案,如果你是用的是 tailwindcss v3
就不需要了。
5. 在 src/App.vue
中引用:
<script lang="ts">
import Vue from 'vue'
export default Vue.extend({
//...
})
</script>
<style lang="scss">
/*每个页面公共css */
// scss 需要安装 yarn add -D sass sass-loader@^10
// 小程序需要 'base' 来注入变量,但不需要 html preflight
// @tailwind base;
// @tailwind utilities;
@import 'tailwindcss/base';
@import 'tailwindcss/utilities';
</style>
6. 在根目录下添加 vue.config.js
// vue.config.js
const { UniAppWeappTailwindcssWebpackPluginV4 } = require('weapp-tailwindcss-webpack-plugin')
/**
* @type {import('@vue/cli-service').ProjectOptions}
*/
const config = {
//....
configureWebpack: {
plugins: [new UniAppWeappTailwindcssWebpackPluginV4()]
}
//....
}
module.exports = config
现在,您就可以在 uni-app
中使用 jit
的大部分特性了!
jit example
vue / wxml
<view :class="[flag?'bg-red-900':'bg-[#fafa00]']">bg-[#fafa00]</view>
<view :class="{'bg-[#098765]':flag===true}">bg-[#098765]</view>
<view class="p-[20px] -mt-2 mb-[-20px] ">p-[20px] -mt-2 mb-[-20px] margin的jit 不能这么写 -m-[20px]</view>
<view class="space-y-[1.6rem]">
<view class="w-[300rpx] text-black text-opacity-[0.19]">w-[300rpx] text-black text-opacity-[0.19]</view>
<view class="min-w-[300rpx] max-h-[100px] text-[20px] leading-[0.9]">min-w-[300rpx] max-h-[100px] text-[20px] leading-[0.9]</view>
<view class="max-w-[300rpx] min-h-[100px] text-[#dddddd]">max-w-[300rpx] min-h-[100px] text-[#dddddd]</view>
<view class="flex items-center justify-center h-[100px] w-[100px] rounded-[40px] bg-[#123456] bg-opacity-[0.54] text-[#ffffff]">Hello</view>
<view class="border-[10px] border-[#098765] border-solid border-opacity-[0.44]">border-[10px] border-[#098765] border-solid border-opacity-[0.44]</view>
<view class="grid grid-cols-3 divide-x-[10px] divide-[#010101] divide-solid">
<view>1</view>
<view>2</view>
<view>3</view>
</view>
</view>
or @apply
<template><view class="hello">world</view></template>
<style lang="scss">
.hello {
@apply flex items-center justify-center h-[100px] w-[100px] rounded-[40px] bg-[#123456] bg-opacity-[0.54] text-[#ffffff] #{!important};
}
</style>
了解更多
上述只是一个简单的 hello world
,想要了解更多,可以到 Github,欢迎 star
/fork
。
Bugs & Issues
如果在使用过程中遇到 Bugs 或者提出问题,欢迎提交到此处,笔者会尽快复现并修改
让小程序开发进入 tailwind jit
时代!
把
tailwindcss JIT
思想带入小程序开发吧!
笔者几个月前写了一个 tailwindcss-miniprogram-preset 预设,可是这个预设方案,可操作性非常的小,也不能兼容 tailwindcss v2/v3
的 Just in time
引擎,同时在写法上也有一定的变体。
于是笔者又设计了一个方案,并最终实现了 weapp-tailwindcss-webpack-plugin
。相比原先 preset
or postcss
方案,这个方案有很多的优势:
- 为
jit
设计,兼容v2/v3
2个版本的jit
引擎 - 开发者不需要额外记忆任何的写法变体,带来原汁原味的
tailwindcss
开发体验 - 兼容基于
webpack v4/v5
的小程序多端开发框架,简单易用
那么接下来就来展示一个基于 uni-app
的 demo 来快速体验这个方案吧。
最佳实践
前置准备: vscode
,vscode-tailwindcss
,nodejs lts
,微信开发者工具
1.通过vue-cli命令行创建工程
此部分内容见 uni-app快速上手
2.安装 npm 包
由于目前 uni-app
内置的 webpack
版本为 4
, postcss
版本为 7
我们需要安装 tailwindcss
的 postcss7-compat
版本:
yarn add -D weapp-tailwindcss-webpack-plugin postcss-rem-to-responsive-pixel tailwindcss@npm:@tailwindcss/postcss7-compat postcss@^7 autoprefixer@^9
postcss-rem-to-responsive-pixel 是一个由笔者撰写的 postcss 插件,支持
rem
->rpx
,同时支持postcss7
和postcss8
,配置见此
3. 初始化 tailwind.config.js
和 postcss.config.js
只需要在初始化的文件内加入一些配置:
// tailwind.config.js 基础配置,无需任何preset
// https://github.com/sonofmagic/weapp-tailwindcss-webpack-plugin/blob/main/demo/uni-app/tailwind.config.js
/** @type {import('@types/tailwindcss/tailwind-config').TailwindConfig} */
module.exports = {
mode: 'jit',
purge: {
content: ['./src/**/*.{vue,js,ts,jsx,tsx,wxml}']
},
corePlugins: {
preflight: false
}
}
// postcss.config.js 参考示例
// https://github.com/sonofmagic/weapp-tailwindcss-webpack-plugin/blob/main/demo/uni-app/postcss.config.js
const path = require('path')
module.exports = {
parser: require('postcss-comment'),
plugins: [
require('postcss-import')({
resolve(id, basedir, importOptions) {
if (id.startsWith('~@/')) {
return path.resolve(process.env.UNI_INPUT_DIR, id.substr(3))
} else if (id.startsWith('@/')) {
return path.resolve(process.env.UNI_INPUT_DIR, id.substr(2))
} else if (id.startsWith('/') && !id.startsWith('//')) {
return path.resolve(process.env.UNI_INPUT_DIR, id.substr(1))
}
return id
}
}),
require('autoprefixer')({
remove: process.env.UNI_PLATFORM !== 'h5'
}),
// #region 添加的部分开始
// tailwindcss for postcss7
require('tailwindcss')({ config: './tailwind.config.js' }),
// rem 转 rpx
require('postcss-rem-to-responsive-pixel/postcss7')({
rootValue: 32,
propList: ['*'],
transformUnit: 'rpx'
}),
// #endregion 添加的部分结束
require('@dcloudio/vue-cli-plugin-uni/packages/postcss')
]
}
4. 设置环境变量
添加 .env
设置 TAILWIND_MODE
# https://github.com/sonofmagic/weapp-tailwindcss-webpack-plugin/blob/main/demo/uni-app/.env
# jit 模式 HMR
TAILWIND_MODE=watch
这是为了兼容 tailwindcss v2
的 HMR 方案,如果你是用的是 tailwindcss v3
就不需要了。
5. 在 src/App.vue
中引用:
<script lang="ts">
import Vue from 'vue'
export default Vue.extend({
//...
})
</script>
<style lang="scss">
/*每个页面公共css */
// scss 需要安装 yarn add -D sass sass-loader@^10
// 小程序需要 'base' 来注入变量,但不需要 html preflight
// @tailwind base;
// @tailwind utilities;
@import 'tailwindcss/base';
@import 'tailwindcss/utilities';
</style>
6. 在根目录下添加 vue.config.js
// vue.config.js
const { UniAppWeappTailwindcssWebpackPluginV4 } = require('weapp-tailwindcss-webpack-plugin')
/**
* @type {import('@vue/cli-service').ProjectOptions}
*/
const config = {
//....
configureWebpack: {
plugins: [new UniAppWeappTailwindcssWebpackPluginV4()]
}
//....
}
module.exports = config
现在,您就可以在 uni-app
中使用 jit
的大部分特性了!
jit example
vue / wxml
<view :class="[flag?'bg-red-900':'bg-[#fafa00]']">bg-[#fafa00]</view>
<view :class="{'bg-[#098765]':flag===true}">bg-[#098765]</view>
<view class="p-[20px] -mt-2 mb-[-20px] ">p-[20px] -mt-2 mb-[-20px] margin的jit 不能这么写 -m-[20px]</view>
<view class="space-y-[1.6rem]">
<view class="w-[300rpx] text-black text-opacity-[0.19]">w-[300rpx] text-black text-opacity-[0.19]</view>
<view class="min-w-[300rpx] max-h-[100px] text-[20px] leading-[0.9]">min-w-[300rpx] max-h-[100px] text-[20px] leading-[0.9]</view>
<view class="max-w-[300rpx] min-h-[100px] text-[#dddddd]">max-w-[300rpx] min-h-[100px] text-[#dddddd]</view>
<view class="flex items-center justify-center h-[100px] w-[100px] rounded-[40px] bg-[#123456] bg-opacity-[0.54] text-[#ffffff]">Hello</view>
<view class="border-[10px] border-[#098765] border-solid border-opacity-[0.44]">border-[10px] border-[#098765] border-solid border-opacity-[0.44]</view>
<view class="grid grid-cols-3 divide-x-[10px] divide-[#010101] divide-solid">
<view>1</view>
<view>2</view>
<view>3</view>
</view>
</view>
or @apply
<template><view class="hello">world</view></template>
<style lang="scss">
.hello {
@apply flex items-center justify-center h-[100px] w-[100px] rounded-[40px] bg-[#123456] bg-opacity-[0.54] text-[#ffffff] #{!important};
}
</style>
了解更多
上述只是一个简单的 hello world
,想要了解更多,可以到 Github,欢迎 star
/fork
。
Bugs & Issues
如果在使用过程中遇到 Bugs 或者提出问题,欢迎提交到此处,笔者会尽快复现并修改
收起阅读 »
IDE may already started at port xxxx, trying to connect
-
1关闭微信开发者工具,然后检查APPID换成自己的APPID
-
2先关闭再打开自己的端口号(微信开发者工具——>设置——>安全设置——>安全(服务端口号))
-
3在HBuilder X的项目>unpackage>dist>dev>project.config.json文件里面添加下面代码,保存运行即可。
"miniprogramRoot": "./unpackage/dist/dev/mp-weixin", -
我是这样子通过的 ,可以留言联系我
-
1关闭微信开发者工具,然后检查APPID换成自己的APPID
-
2先关闭再打开自己的端口号(微信开发者工具——>设置——>安全设置——>安全(服务端口号))
-
3在HBuilder X的项目>unpackage>dist>dev>project.config.json文件里面添加下面代码,保存运行即可。
"miniprogramRoot": "./unpackage/dist/dev/mp-weixin", -
我是这样子通过的 ,可以留言联系我

使用uni-app开发微信小程序,若从vue2迁移到vue3,有几个地方需要修改
使用uni-app开发微信小程序,若从vue2迁移到vue3,有几个地方需要修改。
- 事先声明:以下仅代表我个人观点,所有问题均来自本人亲身经历。
- 开发工具:HBuilder X 3.3.10.20220124
1、创建应用的方式要改。main.js内容如下所示:
import store from '@/store'
import { createSSRApp } from 'vue'
export function createApp () {
// 创建应用
const app = createSSRApp(App)
// 使用app.component方法绑定全局组件
// 使用app.config.globalProperties属性绑定全局方法
// 使用store
app.use(store)
// 导出应用
return { app }
}
2、全局组件的注册,需要修改。需要注册到app上。以前是直接注册到Vue上。示例如下所示:
import BaseCopyright from '@/components/BaseCopyright'
app.component('BaseCopyright', BaseCopyright)
- 上面的BaseCopyright组件会生效。
- 注:亲测发现,在uni-app中,组件需要写成单文件组件,如果写成template的形式则组件不生效。
- 下面的GlobalComponentName组件不会生效。
app.component('GlobalComponentName', { template: `<view>GlobalComponentName</view>` })
3、创建store的方式要改且vuex需要使用"vuex": "^4.0.0-0"
版本。store.js内容如下所示:
import { createStore } from 'vuex'
export default createStore({
state: {},
mutations: {},
actions: {},
modules: {}
})
- 注:选择vue版本为2时,在uni-app中,不能在模板里直接使用store,需要使用computed中转一下。此时开发者工具appData中展示的数据是给人看的(展示完整的键名)。
- 注:选择vue版本为3时,在uni-app中,能在模板里直接使用store。此时开发者工具appData中展示的数据不是给人看的(展示a、b、c、d、e等被简化后的键)。
4、scss问题 - 和dart-sass
版本以及vite
打包工具多少有点关系。
- 路径需要拼全,index不能省,后缀也不能缺,否则会报错。
- 选择vue版本为2时,可以这么用:
~@/scss/config
。 - 选择vue版本为3时,必须这么用:
~@/scss/config/index.scss
。
- 选择vue版本为2时,可以这么用:
- 不能直接使用
/
进行除法,需要使用math.div
。
5、js问题 - 和打包工具换成vite
以及选择vue版本为3
多少有点关系。
- 不能使用
module.exports = {}
进行导出。需要使用export default {}
进行导出。- 第三方组件中亦如此,
mp-html
组件中的module.exports
需要更换为export default
。
- 第三方组件中亦如此,
- api响应的数据发生了变更,以前返回一个数组,第一个值是出错信息,第二个值是响应结果。现在直接返回响应结果,而错误信息需要用catch捕获。
- 这个有点坑,需要改的地方有点多。
- 选择vue版本为2时,在uni-app中,可以直接使用
Vue.prototype.$sleep
进行方法的绑定。- vue3需要使用
app.config.globalProperties.$sleep
进行方法的绑定。
- vue3需要使用
- 类似
:visible.sync
的用法,需要统一更换为,类似v-model:visible
的用法。
6、第三方组件mp-html无法正常使用,需要做如下改动:
- PR:https://github.com/jin-yufeng/mp-html/pull/398
- 1、
parse.js
中module.exports = Parser
更改为export default Parser
。 - 2、
mp-html.vue
中const Parser = require('./parser')
更改为import Parser from './parser'
。 - 3、
node.vue
中wxs
相关的代码转移到js
中。node.vue
中handler.use
别忘了更换为转移后的方法。
使用uni-app开发微信小程序,若从vue2迁移到vue3,有几个地方需要修改。
- 事先声明:以下仅代表我个人观点,所有问题均来自本人亲身经历。
- 开发工具:HBuilder X 3.3.10.20220124
1、创建应用的方式要改。main.js内容如下所示:
import store from '@/store'
import { createSSRApp } from 'vue'
export function createApp () {
// 创建应用
const app = createSSRApp(App)
// 使用app.component方法绑定全局组件
// 使用app.config.globalProperties属性绑定全局方法
// 使用store
app.use(store)
// 导出应用
return { app }
}
2、全局组件的注册,需要修改。需要注册到app上。以前是直接注册到Vue上。示例如下所示:
import BaseCopyright from '@/components/BaseCopyright'
app.component('BaseCopyright', BaseCopyright)
- 上面的BaseCopyright组件会生效。
- 注:亲测发现,在uni-app中,组件需要写成单文件组件,如果写成template的形式则组件不生效。
- 下面的GlobalComponentName组件不会生效。
app.component('GlobalComponentName', { template: `<view>GlobalComponentName</view>` })
3、创建store的方式要改且vuex需要使用"vuex": "^4.0.0-0"
版本。store.js内容如下所示:
import { createStore } from 'vuex'
export default createStore({
state: {},
mutations: {},
actions: {},
modules: {}
})
- 注:选择vue版本为2时,在uni-app中,不能在模板里直接使用store,需要使用computed中转一下。此时开发者工具appData中展示的数据是给人看的(展示完整的键名)。
- 注:选择vue版本为3时,在uni-app中,能在模板里直接使用store。此时开发者工具appData中展示的数据不是给人看的(展示a、b、c、d、e等被简化后的键)。
4、scss问题 - 和dart-sass
版本以及vite
打包工具多少有点关系。
- 路径需要拼全,index不能省,后缀也不能缺,否则会报错。
- 选择vue版本为2时,可以这么用:
~@/scss/config
。 - 选择vue版本为3时,必须这么用:
~@/scss/config/index.scss
。
- 选择vue版本为2时,可以这么用:
- 不能直接使用
/
进行除法,需要使用math.div
。
5、js问题 - 和打包工具换成vite
以及选择vue版本为3
多少有点关系。
- 不能使用
module.exports = {}
进行导出。需要使用export default {}
进行导出。- 第三方组件中亦如此,
mp-html
组件中的module.exports
需要更换为export default
。
- 第三方组件中亦如此,
- api响应的数据发生了变更,以前返回一个数组,第一个值是出错信息,第二个值是响应结果。现在直接返回响应结果,而错误信息需要用catch捕获。
- 这个有点坑,需要改的地方有点多。
- 选择vue版本为2时,在uni-app中,可以直接使用
Vue.prototype.$sleep
进行方法的绑定。- vue3需要使用
app.config.globalProperties.$sleep
进行方法的绑定。
- vue3需要使用
- 类似
:visible.sync
的用法,需要统一更换为,类似v-model:visible
的用法。
6、第三方组件mp-html无法正常使用,需要做如下改动:
- PR:https://github.com/jin-yufeng/mp-html/pull/398
- 1、
parse.js
中module.exports = Parser
更改为export default Parser
。 - 2、
mp-html.vue
中const Parser = require('./parser')
更改为import Parser from './parser'
。 - 3、
node.vue
中wxs
相关的代码转移到js
中。node.vue
中handler.use
别忘了更换为转移后的方法。

vue3下使用schema2code生成的 uni-file-picker 不兼容问题
"avatar": {
"bsonType": "file",
"fileMediaType": "image",
"description": "缩略图地址",
"label": "封面大图",
"title": "封面大图",
"trim": "both",
}
vue3下
<uni-file-picker v-if="item.avatar && item.avatar.fileType == 'image'
** " :value="item.avatar" **:file-mediatype="item.avatar && item.avatar.fileType" return-type="object"
:imageStyles="imageStyles" readonly></uni-file-picker>
<uni-link v-else :href="item.avatar && item.avatar.url" :text="item.avatar && item.avatar.url"></uni-link>
改为
:modelValue="item.avatar"
或者 在schema下做兼容
"componentForEdit": {
"props": {
":modelValue": "item.avatar" //兼容v3
}
},
"componentForShow": {
"props": {
":modelValue": "item.avatar" //兼容v3
}
}
"avatar": {
"bsonType": "file",
"fileMediaType": "image",
"description": "缩略图地址",
"label": "封面大图",
"title": "封面大图",
"trim": "both",
}
vue3下
<uni-file-picker v-if="item.avatar && item.avatar.fileType == 'image'
** " :value="item.avatar" **:file-mediatype="item.avatar && item.avatar.fileType" return-type="object"
:imageStyles="imageStyles" readonly></uni-file-picker>
<uni-link v-else :href="item.avatar && item.avatar.url" :text="item.avatar && item.avatar.url"></uni-link>
改为
:modelValue="item.avatar"
或者 在schema下做兼容
"componentForEdit": {
"props": {
":modelValue": "item.avatar" //兼容v3
}
},
"componentForShow": {
"props": {
":modelValue": "item.avatar" //兼容v3
}
}
收起阅读 »

iOS8 hash路由模式下页面循环reload解决方案
问题描述
h5页面在设置路由模式为hash时,iOS8设备打开页面会反复刷新。
详情请参考:issue - H5 hash路由模式下,iOS8页面加载无限reload
问题定位
- 在uniapp h5相关源码中搜索reload方法的调用,打log,确认到具体代码
- 查看源码发现是用了vue-router来稍加改造
- 提出问题:为什么别的机器不会反复刷新
- 了解popstate事件触发的逻辑:某些版本的浏览器内核会在页面加载完成后触发一次popstate事件,参考MDN文档
- 确认是页面加载完成后自动触发popstate,导致uniapp误处理触发页面reload
hack解决
解决思路:hack reload方法,识别该次异常的reload(load,popstate,reload短时间内连续触发),忽略该次reload。
相关代码:直接写入html文件即可,目前项目内就是这样解决
<script>
// @NOTE 处理uniapp路由bug,load,popstate,reload短时间内依次触发时,忽略这次reload
var reloadHackRecord = {};
window.addEventListener('load', function(e) {
reloadHackRecord.load = new Date().getTime();
});
var onPopState = function() {
reloadHackRecord.popstate = new Date().getTime();
window.removeEventListener('popstate', onPopState);
}
window.addEventListener('popstate', onPopState);
var oldReload = window.location.reload;
window.location.reload = function() {
var load = reloadHackRecord.load;
var popstate = reloadHackRecord.popstate;
var reload = new Date().getTime();
var margin = 100; // 经验值
if (load && popstate && reload && reload > popstate && popstate > load && reload - popstate < margin && popstate - load < margin) {
window.location.reload = oldReload;
// @TODO 可以上报看看有多少量
return;
}
}
</script>
更多信息
今天升级到最新版本,新建模板项目来验证,依然存在问题
路由模式使用history没有该问题
问题描述
h5页面在设置路由模式为hash时,iOS8设备打开页面会反复刷新。
详情请参考:issue - H5 hash路由模式下,iOS8页面加载无限reload
问题定位
- 在uniapp h5相关源码中搜索reload方法的调用,打log,确认到具体代码
- 查看源码发现是用了vue-router来稍加改造
- 提出问题:为什么别的机器不会反复刷新
- 了解popstate事件触发的逻辑:某些版本的浏览器内核会在页面加载完成后触发一次popstate事件,参考MDN文档
- 确认是页面加载完成后自动触发popstate,导致uniapp误处理触发页面reload
hack解决
解决思路:hack reload方法,识别该次异常的reload(load,popstate,reload短时间内连续触发),忽略该次reload。
相关代码:直接写入html文件即可,目前项目内就是这样解决
<script>
// @NOTE 处理uniapp路由bug,load,popstate,reload短时间内依次触发时,忽略这次reload
var reloadHackRecord = {};
window.addEventListener('load', function(e) {
reloadHackRecord.load = new Date().getTime();
});
var onPopState = function() {
reloadHackRecord.popstate = new Date().getTime();
window.removeEventListener('popstate', onPopState);
}
window.addEventListener('popstate', onPopState);
var oldReload = window.location.reload;
window.location.reload = function() {
var load = reloadHackRecord.load;
var popstate = reloadHackRecord.popstate;
var reload = new Date().getTime();
var margin = 100; // 经验值
if (load && popstate && reload && reload > popstate && popstate > load && reload - popstate < margin && popstate - load < margin) {
window.location.reload = oldReload;
// @TODO 可以上报看看有多少量
return;
}
}
</script>
更多信息
今天升级到最新版本,新建模板项目来验证,依然存在问题
路由模式使用history没有该问题
收起阅读 »