前言
在2023年末的这个节点,聊起小程序开发,离不开当前市场占有率最高的两个框架:Taro和Uniapp,那么到底哪个框架更符合当前主流开发,更好,更易用呢?具体的工程该怎么搭建呢?
在回答上诉问题之前,我们先来讲一个故事,并且回答几个问题。
如果太长不看可以直接拉到后面享用模板!
很久很久以前,一个公司要面向用户提供某项业务,得做一个app。开发维护的成本都极其高昂。 后来微信公众号出现,以公众号为流量入口,h5作为业务载体也风靡一时。但是h5毕竟有它的局限性:性能和体验问题使得它始终不能承载太复杂的业务,中小公司还是需要一个app。
后来,由于微信公众号已经承接不了蓬勃发展的需求了,小程序在历史滚滚长河中登场。 它的出现解决了很多掣肘公众号+h5的问题,例如:
- 性能好,提供了相当原生的用户体验,加载快。
- 提供wx-sdk,也就具备获取微信提供的泛能力,例如转发、分享等、支付扫一扫等。
- 依托微信的用户体系和生态。
简单来说就是,微信搞了一个基础,大家在上面做开发可以又吃又拿。在流量池子里玩,别人还给你铲子,那就没什么理由不搞一搞小程序了。
当时几乎每家公司都把自己原来由h5和app承接的业务转移到小程序上,大树底下好乘凉。 但是由于小程序的处于安全和性能考虑的特殊架构,使得一开始在没有小程序框架出现前,小程序的开发体验不是特别好,市面上出现了专门的小程序开发工程师,那这不就是又变相提高了开发成本?
于是Taro、Weapp、Uni-app、Mpvue、Remax等小程序框架出现,但是经过这几年的大浪淘沙,基本就剩下Taro和Uni-app两家了。
一、小程序基础架构
小程序到底是怎么架构的,为啥他的原生开发有如此难用的语法和开发体验?
下图是小程序的架构:
摘一下官方文档:
网页开发渲染线程和脚本线程是互斥的,这也是为什么长时间的脚本运行可能会导致页面失去响应,而在小程序中,二者是分开的,分别运行在不同的线程中。网页开发者可以使用到各种浏览器暴露出来的 DOM API,进行 DOM 选中和操作。而如上文所述,小程序的逻辑层和渲染层是分开的,逻辑层运行在 JSCore 中,并没有一个完整浏览器对象,因而缺少相关的DOM API和BOM API。这一区别导致了前端开发非常熟悉的一些库,例如 jQuery、 Zepto 等,在小程序中是无法运行的。同时 JSCore 的环境同 NodeJS 环境也是不尽相同,所以一些 NPM 的包在小程序中也是无法运行的。
小程序的架构和普通的浏览器渲染不同,传统的浏览器渲染是单线程的,也就是渲染和逻辑的执行是互斥的,这个大家都学过。但是小程序的架构设计是双线程的设计,页面的渲染和js的逻辑执行是分成两个线程来执行的。同时,为了达到原生app类似的良好体验,小程序的页面的渲染是多页面渲染的(多个webview),可以理解为开了多个浏览器来渲染多个页面,可以参考上图。
那么为什么要使用双线程的架构模式呢? 原因主要有以下几点:
- 为了很好的注入WXSDK
- 为了确保安全
WXSDK就是上图和前文所阐述的微信的一些jsApi
的集合,提供了微信的丰富原生能力和一些内部的方法。 那这些sdk在传统浏览器的架构中,得通过网络请求的方式去加载,这非常影响用户体验,甚至会出现白屏的情况。而在微信公众号的解决方案是做了离线缓存,一个公众号有一定容量的缓存大小。这样做是改善了用户体验,但是会造成微信的缓存越来越多,想起微信动辄几十个g的空间占用,是不是更加蛋疼了。 所以为了解决这些问题,小程序的出现必将采取新的架构,也就是在native层中往页面动态注入sdk来实现,也就是one weixin one sdk
,这样是不是很爽。 当前,不只是sdk,还有底层基础库
、Service
等很多服务都是事先放在Native
层中的。
解决SDK的问题,那怎么确保安全呢? 我们知道,js是非常开发和灵活的,与此同时带来的是相对的不安全性。而微信和浏览器端不一样,微信对于安全的要求是要更高一级的,例如操作dom(就存在可能变相获取到用户的敏感数据),网页的跳转等,执行动态脚本等。这些都是不受控的,而微信又希望控制这些过程,以达到安全的目的。于是,就产生了封装一个沙箱来运行js,而不是在webview中运行js的理念。于是在ios采用专门jscore,在安卓上采用x5内核来执行js,也就是逻辑层,就能对js的灵活进行一定的管控。
以上,就是双线程架构的由来,而双线程架构能够使得逻辑的归逻辑,渲染的归渲染,各司其职,安全且原生,看起来是不是十分完美。
但是!
什么都有个但是!
就苦了我们这帮苦哈哈的前端-马上被大厂裁员---或者被ai淘汰---程序员。
小程序的原生开发因此就有了和开发传统webapp不一样的地方,不管是语法还是生态,写起来,真是不太得劲。
直到了英特奈熊-taro 和uni-救世主-app的出现,使得大家能够采用习惯的vue和react语法以及相关的生态来进行小程序的开发。下面我们就就正式展开,如何使用Taro和Uniapp搭建一个规范的前端项目工程。
二、Uniapp篇
我们先来快速搭建一个uniapp的前端工程,该工程采用vue3+vite技术栈,使用uview组件库,使用vscode开发,tyepscript 封装并且使用如下项目规范的工具:
- eslint: 负责校验代码
- prettile: 格式化代码
- stylelint: 校验和格式化样式代码
- commitlint:校验git提交
- lint-staged: 只对当前更改的进行校验
- husky:在提交前做所有的校验
vscode配置
px2rem方案
写一个cli完成这些事情,
cicd, 开发和生产环境的区分和部署 git项目 命名和ui规范 vite配置 npm管理 路由方案 数据存储方案 请求方案 低代码方案 docker和gitlab
1.初始化项目
js
//根据uniapp官方文档,快速创建一个vue3+vite项目,并使用vscode开发
npm install -g @vue/cli
npx degit dcloudio/uni-preset-vue#vite-ts my-vue3-project
2.使用lint工具链来保证代码风格和质量
为什么要确保代码风格的统一?
在多人的项目开发过程中,代码风格的统一非常重要,因为代码不仅是给机器阅读的,同时也是给人阅读的。为了避免不同风格的代码导致的满屏红和难以阅读维护,同时确保代码的质量,需要一定的规范去约束。
如何统一代码风格和质量?
通过如:
eslint
prettier
stylelint
commitlint
tsc
等主流lint的工具的使用。配合husky
lintstaged
vscode插件
来实现自动化的代码规范的检查和格式化,把语法错误,和低质量代码在开发阶段规避掉。人只需要关注开发逻辑本身,这就是lint的工具链的意义。
2.1 Eslint的使用
简介
ESLint 是在 ECMAScript/JavaScript 代码中识别和报告模式匹配的工具,它的目标是保证代码的一致性和避免错误。
说人话就是,搞一个配置文件,里面有不同的规则(rules),eslint通过这个配置文件来来检验代码的规范是否符合要求。现在常见的规则如:Airbnb JavaScript 代码规范、Standard JavaScript 规范、Google JavaScript 规范等等,大部分情况下,直接采用以上开发规范就好了。
开始干!先安装eslitnt!
注意:全文的安装包都带有版本号,如想用最新版本会存在版本不兼容导致校验失败的问题。
js
yarn add eslint@8.55.0 -D
以及安装如下eslint衍生包
- @typescript-eslint/eslint-plugin@latest(为了支持TypeScript)
- @typescript-eslint/parser@lates(为了支持TypeScript)
- eslint-plugin-vue@latest(为了支持Vue语法的解析)
- @vue/eslint-config-typescript(Vue官方提供的在Vue项目中使用 TypeScript 时的代码规范检查)
js
yarn add eslint-plugin-vue@9.19.2 @typescript-eslint/eslint-plugin@6.14.0 @typescript-eslint/parser@6.14.0 @vue/eslint-config-typescript@12.0.0 -D
在vscode中安装插件prettier和eslint
然后在项目的根目录新建一个.eslintrc.js,然后把以下热乎乎的eslint配置粘贴进去。
注意:下面的配置和上面安装的衍生包是对应的,因为extends中用的别人的配置,所以就要有相应的包来支持,不然就会出现配置不生效的问题。如果要自定义配置,请注意这一点。
js
//.eslintrc.js
module.exports = {
root: true, // 表示这是项目的根 ESLint 配置。
env: {
node: true, // 指定环境为 Node.js。
},
//extends 用于继承其他配置的属性。你可以基于已有的配置来构建自己的配置,避免从头开始定义所有的规则。也就是抄别人的成熟模板~
extends: [
"plugin:vue/vue3-essential", // Vue3 的基本配置规则。
"eslint:recommended", // 推荐的 ESLint 配置规则。
"@vue/typescript/recommended", // Vue中 TypeScript 的推荐配置规则。
"@vue/prettier", // 扩展 Prettier 的 ESLint 配置规则。
"@vue/prettier/@typescript-eslint", // 扩展 TypeScript 特定规则的 Prettier ESLint 配置。
],
//parserOptions是解析器选项,对eslint语法解析器的能力进行定制
parserOptions: {
ecmaVersion: 2020, // 指定要使用的 ECMAScript 版本(在这种情况下为 ES2020)。
ecmaFeatures: {
jsx: true, // 启用 JSX 解析。
},
},
//rules-这里就是具体的规则配置拉
rules: {
"prettier/prettier": "error", // 强制执行 Prettier 规则,如果不遵循则生成错误。
"no-console": process.env.NODE_ENV === "production" ? "warn" : "off", // 在开发中允许 console.log,在生产中警告。
"no-debugger": process.env.NODE_ENV === "production" ? "warn" : "off", // 在开发中允许 debugger,在生产中警告。
"@typescript-eslint/no-unused-vars": [
"error",
{
vars: "local", // 强制局部变量使用。
args: "none", // 不允许未使用的函数参数。
varsIgnorePattern: "usePresenter|model|reactive", // 在未使用变量检查中忽略特定变量名。
caughtErrors: "none", // 不允许未使用的捕获的错误。
},
],
"@typescript-eslint/no-explicit-any": 2, // 不允许使用 any 作为类型声明。
eqeqeq: 2, // 强制使用严格相等(=== 和 !==)。
"max-lines": ["error", 800], // 强制文件的最大行数。
complexity: ["error", 20], // 强制函数的最大圈复杂度。
"require-await": "error", // 强制异步函数有 await 表达式。
"vue/multi-word-component-names": "off", // 禁用 Vue 文件中多词组件名称的规则。
"@typescript-eslint/no-empty-function": 1, // 警告空函数。
"no-shadow": "error", // 强制变量名不与其作用域链中的变量名重复。
"@typescript-eslint/ban-types": "off", // 禁用对特定类型的禁令。
"@typescript-eslint/no-non-null-assertion": "off", // 禁用对非空断言的禁令。
"vue/valid-v-model": "off", // 禁用 Vue 文件中 v-model 使用的规则。
},
overrides: [
{
files: [
"**/__tests__/*.{j,t}s?(x)", // 对 __tests__ 目录下的文件进行覆盖。
"**/tests/unit/**/*.spec.{j,t}s?(x)", // 对单元测试文件进行覆盖。
],
env: {
mocha: true, // 指定 Mocha 测试环境。
},
},
],
};
同样在根目录配置一个.eslintignore来忽略检测的文件
js
.eslintignore
*.sh
node_modules
*.md
*.woff
*.ttf
.vscode
.idea
dist
/public
/docs
.husky
.local
/bin
Dockerfile
/types
配置完.eslintrc.js之后,就完事了吗? 搜德麻跌! 这个配置文件中这个prettier是什么意思?
ok,术业有专攻,eslint可以做两件事:
- 代码的规范和质量的检查和提示,例如使用未声明的变量、修改const变量、字符串是否是双引号等
- 按照规范格式化这些不符合要求的代码
prettier在第二件事中,做的比eslint好。因为除了js/ts外,prttier还支持对多种语言进行格式化,如vue、html、css、less、scss、json、jsx等等,是一个比较综合的代码格式化工具,且lint的速度更快。于是,我们一般把格式化这件事情,交给prettier去做。
2.2 prettier和eslintの故事
首先我们安装一下prettier
js
yarn add prettier@2.7.1 -D
在项目根目录下新建.prettierrc.js配置文件,然后再把下面第二份热乎乎的配置粘贴进去,并按照你们的团队规范自定义修改
js
// .prettierrc.js
module.exports = {
printWidth: 80, //一行的字符数,如果超过会进行换行,默认为80
tabWidth: 2, // 一个 tab 代表几个空格数,默认为 2 个
useTabs: false, //是否使用 tab 进行缩进,默认为false,表示用空格进行缩减
singleQuote: false, // 字符串是否使用单引号,默认为 false,使用双引号
semi: true, // 行尾是否使用分号,默认为true
trailingComma: "all", // 是否使用尾逗号
bracketSpacing: true, // 对象大括号直接是否有空格,默认为 true,效果:{ a: 1 }
htmlWhitespaceSensitivity: "ignore",// 在 HTML 中空格的敏感性,"ignore" 表示忽略空格敏感性
endOfLine: "auto" // 换行符的风格,"auto" 表示自动识别当前操作系统的换行符风格
};
接下来我们把prettier和eslint一起打配合,各司其职。
细心的朋友发现了,为啥eslint一套规范,prettier一套规范,到底听谁的?不冲突吗?
所以我们得安装如下两个包,来确保校验的归eslint,格式化的归prettier,不能打架!
- @vue/eslint-config-prettier(用来覆盖eslint本身的规则配置)
- eslint-plugin-prettier(让prettier来接管eslint --fix也就是代码修复格式化的能力)
js
yarn add @vue/eslint-config-prettier@6.0.0 eslint-plugin-prettier@4.2.1 -D
写到这,再回顾之前写的.eslintrc.js的配置中,涉及prettier的部分代表什么意思了。
js
//.eslintrc.js
module.exports = {
...
extends: [
...
"@vue/prettier", // 扩展 Prettier 的 ESLint 配置规则。
"@vue/prettier/@typescript-eslint", // 扩展 TypeScript 特定规则的 Prettier ESLint 配置。
],
//rules-这里就是具体的规则配置拉
rules: {
"prettier/prettier": "error", // 强制执行 Prettier 规则,如果不遵循则生成错误。
...
}
};
我们在package.json中定义一个脚本,然后执行 yarn run lint
就可以通过命令行的方式格式化代码了。
js
{
"scripts": {
...
"lint": "eslint --ext .js,.jsx,.ts,.tsx --fix --quiet ./src", }
}
在开发阶段,我们还可以通过vite插件在开发阶段进行扫描,以命令行的方式展示出代码中的规范问题,并直接定位到源文件。如下图:
先安装插件
js
yarn add vite-plugin-eslint -D
然后再vite.config.js中进行配置
js
import viteEslint from "vite-plugin-eslint"; //1.引入
export default defineConfig({
plugins: [...省略其他插件, viteEslint()], //2.使用
});
这样重新运行项目,开发时就会有上图的提示了。
2.3 样式的规范-stylelint
先来一个官网的说明
Stylelint 是一个强大、先进的 CSS 代码检查器(linter),可以帮助你规避 CSS 代码中的错误并保持一致的编码风格。 Stylelint 的强大源于:
- 拥有超过 100 条内置规则 来检查最新的 CSS 语法和功能
- 支持 插件 以创建你自己的规则
- 自动 修复 大多数代码格式上的问题
- 支持创建或扩展 可共享的配置
- 可定制,让其而符合你的需求
- 经过 15000 多次的单元测试,保证其健壮性
- 被大型公司所采用,例如 Google 和 GitHub
我们建议在使用 Stylelint 的同时使用格式化工具 Prettier。代码检查工具和格式化工具是互相补充的,能够辅助你编写一致且正确的代码。
同样,根据官网所说,stylelint也是一个代码检查工具,专注于样式
的检查,格式化的部分还是交给prettier
来完成。
先安装依赖
- stylelint
- stylelint-prettier(
stylelint插件,用于集成Prettier格式化工具
) - stylelint-config-prettier(
禁用了stylelint中与Prettier冲突的规则
) - stylelint-config-standard(
基于stylelint的预定义配置,包含了一系列的标准化的规则和推荐配置
) - stylelint-config-clean-order(
它提供了一套规则,用于指定CSS属性排序的顺序
)
js
yarn add stylelint@13.2.1 stylelint-prettier@1.1.2 stylelint-config-prettier@8.0.1 stylelint-config-standard@20.0.0 stylelint-config-clean-order@2.0.0 -D
然后再根目录下新建文件.stylelintrc.js
,把以下配置粘贴进去。
这个配置文件指定了 stylelint 的配置选项,具体解释见注释。通过这些配置,stylelint 将遵循 Standard 规范的代码规则,并与 Prettier 格式化工具兼容,同时禁用了一些特定的警告和错误。
js
module.exports = {
processors: [], // 指定要使用的处理器,这里为空数组,表示不使用任何处理器
extends: [
"stylelint-config-standard", // 继承了 stylelint-config-standard 配置,即使用了 Standard 规范的代码规则
"stylelint-prettier/recommended", // 继承了 stylelint-prettier/recommended 配置,即使用了与 Prettier 推荐配置兼容的 stylelint 规则
"stylelint-config-prettier", // 继承了 stylelint-config-prettier 配置,用于确保 stylelint 和 Prettier 规则的一致性
"stylelint-config-clean-order", // 继承了 stylelint-config-clean-order 配置,用于定义 CSS 属性的排序规则
],
rules: {
"prettier/prettier": true, // 启用 prettier/prettier 规则,确保代码与 Prettier 的格式化规则一致
"at-rule-no-unknown": null, // 禁用对未知@规则的警告或错误
"no-empty-source": null, // 禁用对空样式表的警告或错误
"unit-no-unknown": null, // 禁用对未知单位的警告或错误
"no-descending-specificity": null, // 禁用对特异性下降的警告或错误
"selector-pseudo-class-no-unknown": null, // 禁用对未知伪类的警告或错误
"declaration-block-no-duplicate-properties": null, // 禁用对重复属性的警告或错误
"selector-type-no-unknown": null, // 禁用对未知选择器类型的警告或错误
"block-no-empty": null, // 禁用对空块的警告或错误
"font-family-no-missing-generic-family-keyword": null, // 禁用对缺少通用字体系列关键字的警告或错误
"declaration-block-no-shorthand-property-overrides": null, // 禁用对简写属性覆盖的警告或错误
},
};
我们在 package.json
中,增加如下的 scripts
配置:
js
{
"scripts": {
// ...省略其他配置
// stylelint 命令
"lint:style": "stylelint --fix \"src/**/*.{css,scss}\""
}
}
执行yarn run lint:style
即可完成样式代码的规范检查和自动格式化。
在 VSCode 中安装Stylelint
插件,这样能够在开发阶段样式代码问题,见下图。
同样,vite也有stylelint插件支持,可以实现在终端提示样式问题,如下图
安装vite-plugin-stylelint
js
yarn add vite-plugin-stylelint -D //支持vite>=3.0
然后再vite配置文件中配置
js
import viteStylelint from 'vite-plugin-stylelint';
{
plugins: [
// ...其他插件
viteStylelint({
//排除node_modules的文件
exclude: /node_modules/
}),
]
}
到此就可以在开发阶段实现stylint的格式检查和格式化了。
2.4 在vscode保存时自动格式化
在前面的配置已经实现了对规范的检查和格式化,但是格式化的操作只能通过执行命令行来进行,例如:yarn lint。
这样操作十分麻烦,有没有办法让我们每一次保存文件的时候,都自动格式化代码呢?答案是肯定的。 我们做如下的配置。
未完待续:moropo pnpm、路由跳转,生命周期 组件使用,全局变量配置,piana hooks...