Explorar o código

初始化设计文档

Michael Wang %!s(int64=3) %!d(string=hai) anos
pai
achega
d4bc4534d0
Modificáronse 1 ficheiros con 879 adicións e 0 borrados
  1. 879 0
      arch-design.md

+ 879 - 0
arch-design.md

@@ -0,0 +1,879 @@
+# 总:架构的结构
+
+1. [架构的定义和范围](#scope-%E6%9E%B6%E6%9E%84%E7%9A%84%E5%AE%9A%E4%B9%89%E5%92%8C%E8%8C%83%E5%9B%B4)
+1. [技术栈](#tech-stack-%E6%8A%80%E6%9C%AF%E6%A0%88)
+1. [数据结构](#data-structure-%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84)
+1. [服务的接口](#service-%E6%9C%8D%E5%8A%A1%E7%9A%84%E6%8E%A5%E5%8F%A3)
+1. [状态管理设计及数据流设计](#state-and-data-flow-%E7%8A%B6%E6%80%81%E7%AE%A1%E7%90%86%E8%AE%BE%E8%AE%A1%E5%8F%8A%E6%95%B0%E6%8D%AE%E6%B5%81%E8%AE%BE%E8%AE%A1)
+1. [目录结构](#folder-structure-%E7%9B%AE%E5%BD%95%E7%BB%93%E6%9E%84)
+1. [核心工具接口](#core-utils-interface-%E6%A0%B8%E5%BF%83%E5%B7%A5%E5%85%B7%E6%8E%A5%E5%8F%A3)
+1. 开发规范(api/component/container/css)
+1. [前端 URL 规划](#page-urls-%E5%89%8D%E7%AB%AF-url-%E8%A7%84%E5%88%92)
+1. [路由、页面划分、子组件、常量](#router-%E8%B7%AF%E7%94%B1%E9%A1%B5%E9%9D%A2%E5%88%92%E5%88%86%E5%B8%B8%E9%87%8F)
+1. [环境变量设计](#environment-variables-%E7%8E%AF%E5%A2%83%E5%8F%98%E9%87%8F%E8%AE%BE%E8%AE%A1)
+1. [constants 设计](#constants-constants-%E8%AE%BE%E8%AE%A1)
+1. [开发环境设计](#dev-settings-%E5%BC%80%E5%8F%91%E7%8E%AF%E5%A2%83%E8%AE%BE%E8%AE%A1)
+1. [API 处理设计](#api-status-code-api-%E5%A4%84%E7%90%86%E8%AE%BE%E8%AE%A1)
+1. [network request: 网络请求设计](#network-request-%E7%BD%91%E7%BB%9C%E8%AF%B7%E6%B1%82%E8%AE%BE%E8%AE%A1)
+1. [消息提示处理设计](#notice-handle-%E6%B6%88%E6%81%AF%E6%8F%90%E7%A4%BA%E5%A4%84%E7%90%86%E8%A7%84%E8%8C%83)
+1. [错误处理设计](#error-handle-%E9%94%99%E8%AF%AF%E5%A4%84%E7%90%86%E8%AE%BE%E8%AE%A1)
+1. [样式管理设计](#styles-design-%E6%A0%B7%E5%BC%8F%E7%AE%A1%E7%90%86%E8%AE%BE%E8%AE%A1)
+1. 行为统计设计(百度统计)
+1. [日志设计(本地加密日志与线上日志)](#logging-%E6%97%A5%E5%BF%97%E8%AE%BE%E8%AE%A1%E6%9C%AC%E5%9C%B0%E5%8A%A0%E5%AF%86%E6%97%A5%E5%BF%97%E4%B8%8E%E7%BA%BF%E4%B8%8A%E6%97%A5%E5%BF%97)
+1. 故障诊断设计
+1. 弹出层设计
+1. 组件复用设计
+1. 定时器设计
+1. 人脸识别工具设计 (新加)
+1. [缓存和 PWA 设计](#cache-and-pwa-%E7%BC%93%E5%AD%98%E7%9A%84%E8%AE%BE%E8%AE%A1)
+1. [JS 代码混淆设计](#js-obfuscation-js-%E6%B7%B7%E6%B7%86%E8%AE%BE%E8%AE%A1)
+1. Electron / browser 检测与开发运行设计
+1. Electron 打包设计
+1. websocket 设计
+1. 摄像头处理设计
+1. 时间同步设计
+1. [Layout 设计](#layout-%E8%AE%BE%E8%AE%A1)
+1. 限流设计
+1. 编辑器设计
+1. 防作弊设计
+1. [局部技术难点](#tech-challenges-%E5%B1%80%E9%83%A8%E6%8A%80%E6%9C%AF%E9%9A%BE%E7%82%B9)
+1. [技术特性验证](#tech-verify-%E6%8A%80%E6%9C%AF%E7%89%B9%E6%80%A7%E9%AA%8C%E8%AF%81)
+1. [升级策略](#upgrade-strategy-%E5%8D%87%E7%BA%A7%E7%AD%96%E7%95%A5)
+1. [选做功能](#optional-feature-%E9%80%89%E5%81%9A%E5%8A%9F%E8%83%BD)
+1. [Others](#others)
+
+## Scope: 架构的定义和范围
+
+设计是为了将困难解决在设计阶段,同时为预估工期提高准确度。
+
+适合有点复杂度,追求高质量的项目。
+
+设计目标:
+
+1. 混淆。(可以增强,但是 2 周以后被破解了呢?)动态更新防破解,组合式的手段。
+2. 可维护性。变高。
+3. 遗留问题,得到处理。
+4. 体验优化。提升速度,消灭页面瑕疵。
+5. 扩展性增强。
+
+为保证设计不快速过时,设计文档仅记录不太变动的核心数据结构和流程,部分重要细节。
+某些部分记录下来,也仅仅是为了帮助初次开发,后期如果过时了,可以写明已过时不再维护了。
+
+组件设计;仅为辅助设计的脚手架,后续不维护?
+开发环境设计(基础设施、文件目录、readme):不是设计的核心内容,确实将设计实现的重要入口
+
+## Tech stack: 技术栈
+
+预计采用的技术栈和工具链如下
+
+1. Vue 3.2
+1. and-design-vue 3.x or naiveUI
+1. pinia 2
+1. vue router 4.x
+1. typescript 4.5
+1. eslint 8
+1. prettier 2
+1. vite 2.x
+1. javascript-obfuscator 2
+
+## Data structure: 数据结构
+
+```ts
+// 详见:student-client.d.ts
+type Store = {
+  /** 当前用户 */
+  user: {
+    id: number;
+    /** 身份证号 */
+    identityNumber: string;
+    /** 学号 */
+    studentCodeList: string[];
+    // ...
+  }
+  // ...
+};
+
+/** 得到当前客户端版本 1.9.* */
+type GetCurrentClientVersion = () => string;
+type IsSupportedClientVersion = () => boolean;
+```
+
+## Service: 服务的接口
+
+写明层级的目标,设计层级的协调功能(接口)。
+
+tools layer: 工具类,可以脱离项目的函数  
+api layer: 通信类,处理和服务端数据的交互  
+service layer: 核心服务类,处理项目的生命周期  
+data binding layer: 提供给 UI 展示的类  
+user event handler layer: 提供处理用户触发事件的类
+
+## State and data flow: 状态管理设计及数据流设计
+
+单向数据流与复式记账法的比较。
+
+数据的处理原则要遵循以下原则:
+
+1. 集中统一
+1. 命名清晰
+1. 类型与内容一致
+1. 不包含重复数据
+1. 上层清理数据,比如网络获取 JSON,里面的数据类型不对,要清理以后交给下层
+
+组件的分类(适合复杂业务):
+
+1. container component: fetch data
+1. presentational component: display data
+
+### 以下待整理
+
+不涉及到 store 的状态,直接通过 api 请求,当做 component state 来使用。
+好处:减少状态共享。
+
+当一个状态被创建出,要明确它的 owner/scope/lifecycle,以及可能的值。
+当一个状态被使用时,要明确它可能的值,做好防御性编程。
+
+vue component wrapper. wrapper 里面放权限之类的异步获取数据。comp 里面放业务逻辑和同步的 props。
+或者用 vue router 的 before guard
+
+疑问:究竟是在 action 里面还是 container 里面请求数据?依据是什么?
+
+store actions -> state/storage -> page
+state: page refresh? => sessionStorage (退出登录后要清除部分字段)
+
+错误要直达页面元素呢?-> action return data
+好处:页面清爽;数据集中处理
+数据的共享与过期
+
+page 上的数据满足以下几点:
+1、对数据仅仅做展示
+2、数据输入来源为
+URL(path & query)
+上个页面传递过来的数据(为保证刷新可用,最好通过 URL 做简单的数据传递)
+本地存储的数据(一般不是和页面主动关联,是通过 URL 或其他事件导致要取本地存储)
+组件生命周期
+用户输入
+原生事件(网络)
+
+## Folder structure: 目录结构
+
+文件名/文件夹 组织模块用
+
+强联系的文件放在一起
+文件名有区分度,不要过分依赖文件路径名。否则会出现很多像是 index.js 这样的文件。
+文件影响范围:不超出文件夹最好,image 或 package private
+
+```sh
+.
+├── README.md
+├── index.html
+├── package.json
+├── postcss.config.js
+├── prebuild.mjs
+├── prettier.config.js
+├── public
+│   └── favicon.ico
+├── src
+│   ├── App.vue
+│   ├── api
+│   │   ├── loginPage.ts # api 请求
+│   ├── assets
+│   │   └── logo.png
+│   ├── components # 页面其中的组件,可能复用
+│   │   ├── PageError404.vue
+│   │   ├── QmButton.vue
+│   │   ├── QmDialog.vue
+│   ├── constants
+│   │   └── constants.ts # 项目中的常量。url, name, code,
+│   ├── devLogin.ts # 开发模式下自动登录
+│   ├── devLoginParams.ts
+│   ├── env.d.ts
+│   ├── features
+│   │   ├── Login
+│   │   │   ├── Login.vue
+│   │   │   ├── images
+│   │   │   │   └── bg.png
+│   │   │   └── use
+│   │   │   └── \*.ts # 抽象页面的业务逻辑
+│   ├── filters
+│   │   └── index.ts
+│   ├── main.ts
+│   ├── plugins
+│   │   ├── axiosApp.ts
+│   │   ├── axiosIndex.ts
+│   │   ├── axiosNoAuth.ts
+│   │   ├── axiosNotice.ts
+│   │   └── eventBus.ts
+│   ├── router
+│   │   └── index.ts
+│   ├── setups
+│   │   └── useTimers.ts
+│   ├── store
+│   │   └── store.ts
+│   ├── styles
+│   │   ├── cssvar.css
+│   │   ├── global.css
+│   │   ├── nprogress.css
+│   │   └── tailwind.css
+│   ├── types
+│   │   ├── 3rd.d.ts
+│   │   ├── global.d.ts
+│   │   ├── index.ts
+│   │   └── student-client.d.ts
+│   └── utils
+│   ├── renderJSON.ts
+│   ├── ua.ts
+│   └── utils.ts
+├── tailwind.config.js
+├── tsconfig.json
+└── vite.config.ts
+```
+
+## Environment Variables: 环境变量设计
+
+PORTABLE_EXECUTABLE_FILE:electron 添加,运行时获取可执行文件的路径
+
+VUE_APP_SKIP_CHECK_NATIVE:允许本地通过 web 来访问学生端服务
+
+VUE_APP_CORE_HOST_URL:本地开发时,后台服务器的地址
+
+VUE_APP_SLS_STORE_NAME:阿里云日志服务地址
+
+VUE_APP_CONFIG_FILE_SEVER_URL=https://ecs-static.qmth.com.cn
+
+VUE_APP_GIT_REPO_VERSION=TO_BE_OVERRIDED # 显示版本号
+
+## Constants: constants 设计
+
+```ts
+export const REMOTE_APPS = [
+  ["qq", "QQ"],
+  ["teamviewer", "TeamViewer"],
+  ["lookmypc", "LookMyPC"],
+  ["xt", "协通"],
+  ["winaw32", "Symantec PCAnywhere"],
+  ["pcaquickconnect", "Symantec PCAnywhere"],
+  ["sessioncontroller", "Symantec PCAnywhere"],
+  [/sunloginclient/gi, "向日葵"],
+  [/sunloginremote/gi, "向日葵"],
+  [/选择免安装运行,截图识别/gi, "向日葵"],
+  ["wemeetapp", "腾讯会议"],
+  ["wechat", "微信"],
+] as const;
+```
+
+## API status code: API 处理设计
+
+api 的 statusCode:
+
+1. 200:正常
+1. 401:无权限
+1. 403:无权限
+1. 503:后台限流,要求重试
+
+api 请求是否显示错误:
+
+noErrorMessage: boolean (某些情况下希望网络请求静默处理)
+
+当 statusCode 为非正常时,优先显示 desc 字段,如果没有,则显示“未定义异常:......”
+
+“websocket 重连失败” => "服务器连接失败(websocket)"
+
+## network request: 网络请求设计
+
+网络请求可以限流、重试、取消。
+
+### 给进行中的网络请求覆盖全局的遮罩层
+
+网络请求可设置遮罩层,防止请求过程中用户的误操作、重复操作等等。有 mask,拒绝键盘事件。
+
+```
+globalMaskCount === 0 ====> no mask
+log: inc/dec globalMaskCount, reason
+```
+
+loading / error 状态不进 store
+
+但是可以通过请求的状态机来处理?
+
+### network reactive design(待细化)
+
+const { data, isLoading, isFinished, error } = useAxios('/api/posts')
+好处/难处:
+
+1. v-loading="isLoading"
+2. data 模板中直接用?因为有 loading 开关
+3. 请求有依赖?不好搞?
+4. 错误处理不好搞?
+5. 重复请求?
+
+network loading state from api
+and reactive?
+
+get reactive network result?
+
+form inputs / confirm / throttle? / error => network params => res/loading => display result
+多个 loading 状态转换?
+
+## Error handle: 错误处理设计
+
+错误的边界是用户,无论怎么处理,错误的不可避免的,一定要通知到用户,或不给用户错误的结果(先成功后失败)。
+
+错误分为两种,一种是给用户看的错误,一种是给程序排错或恢复的错误。  
+错误应该抛出 Error 对象,不能 throw 字符串等类型。
+
+### 用户查看类错误
+
+1. 错误以弹窗形式提醒用户。
+1. 错误信息应有识别度,方便用户反馈。
+1. 错误应隐藏敏感的技术信息,比如使用的技术种类。
+1. 重试时应该不报错,默默重试,但要记日志。
+
+### 程序排错类错误包括:
+
+1. JS 错误,需预警,保证及时处理
+1. 网络错误,记日志
+1. 环境错误,提示用户,记日志
+1. 兜底的错误记录
+
+### 网络的错误处理:
+
+1. 补充后台的错误码。如果后台没有统一的,则只能模糊处理。
+2. 未知错误(待讨论):a、显示错误的详细信息 b、错误监控 c、不显示详细信息(不能定位错误)
+
+### 潜在错误位置
+
+1. 在 vue 组件中,某些方法可能会在 vue 组件被销毁后执行。
+1. 错误内部处理被特殊压制?定制错误处理,axios config ?
+1. 发生错误后,流程逻辑是否正常。
+
+### Promise 的错误处理实践
+
+1. 将长串的流程拆解成多个 promise,利用 promise 来处理错误嵌套?
+1. 将 promise 嵌套超过两层的抽象出来变成 async 函数
+1. early return ?? 抽到流程的第一层;throw 不被处理从底层抛到高层;中间层一般不处理底层的错误,而且可能自己 throw guardError;
+1. 错误内部处理?顶层不知道用户友好的错误 => 如果追求这个体验,那么有大量的消息在中间层传递。大部分软件是不追求这个的。
+
+### reference
+
+1. [JavaScript 错误处理完全指南](https://mp.weixin.qq.com/s/I9ZrCsoNo7jrOHj8a9UW1A)
+
+## Logging: 日志设计(本地加密日志与线上日志)
+
+同时记录到本地日志,以及网络日志,网络日志部分可以做监控提醒。
+
+本地日志要采用加密算法,同时在系统处于登录界面时,将本地日志上传。
+
+日志的主要内容为:
+
+1. 可识别用户
+1. 环境信息(硬件、网络、OS、process)
+1. 核心流程的操作
+1. 错误信息
+
+### 日志分等级记录
+
+1. debug,收集个别考生的全日志信息?如何设置它?(ctrl 5 秒内连按 5 次,启动 debug 日志级别)
+1. log,全流程日志。
+1. warn,疑似错误信息。(low network speed)
+1. error,错误信息。(硬件错误,文件不存在)
+
+logger => (destination: baidu / console / file / aliyun) (type: error / warning / operation) (easy / format / single / conf)
+
+### 打印日志的注意事项
+
+1. 打印一个 JS error 对象? ===> new Error('err').stack (IE10+)
+2. Promise 的异常通过 Promise.reason 来获取
+
+## Page URLs: 前端 URL 规划
+
+[前端 URL 规划](https://doc.qmth.com.cn/pages/viewpage.action?pageId=23330835)
+
+1. https://ccnu.exam-cloud.cn/oe-web/index.html
+1. https://ccnu.exam-cloud.cn/oe-web/{js, css, img, fonts, service-worker.js}/\*
+1. https://ccnu.exam-cloud.cn/admin/index.html
+1. https://ccnu.exam-cloud.cn/admin/{js, css, img, fonts, service-worker.js}/\*
+1. https://ccnu.exam-cloud.cn/photo-upload/index.html
+1. https://ccnu.exam-cloud.cn/photo-upload/{js, css, img, fonts, service-worker.js}/\*
+1. https://ccnu.exam-cloud.cn/oe-wap/index.html
+1. https://ccnu.exam-cloud.cn/oe-wap/{js, css, img, fonts, service-worker.js}/\*
+1. https://ccnu.exam-cloud.cn/api/*
+
+## Router: 路由、页面划分、常量
+
+学生端是属于严格受控的页面跳转,既考虑刷新,也考虑缓存。  
+要禁用链接的拖动或通过按 Ctrl 点击链接多开窗口。
+
+### 页面划分
+
+1. Login
+1. MainLayout
+1. OnlineExamContainer
+1. ....
+1. ModifyPassword
+1. ExamingHome
+1. ExamEnd
+
+## Core utils interface: 核心工具接口
+
+clientVersion.ts 管理可用客户端版本。  
+api: getCurrentClientVersion isSupportedClientVersion
+
+updateManager.ts 应用(非客户端)是否应该更新了  
+api: isNewWebAppAvailable isNewBackendAvailable getNewBackendDesc
+
+native.ts 管理原生及系统命令,详细说明 path 和相对 path  
+api: isElectron execCmd readFile getRemoteApps getVirtualCams
+
+runtimeMonitor.ts 检测当前运行的环境是否合法  
+检测是否打开了控制台;检测是否使用了高版本的 chrome(feature 检测)
+检测 onResize;截屏
+
+todolist:
+
+1. md5 文件校验工具方法
+1. auth 认证
+1. 工具类的测试
+
+### Layout 设计
+
+仅有一个 MainLayout 供复用,在 router 里面设置 layout。
+
+- MainLayout:
+- SideBar
+- Header
+  - MainContent
+  - MainContent 不包含统一的 margin,但为了方便,提供全局的 class 来设置 MainContent 的 margin.
+
+## Styles design: 样式管理设计
+
+全局的样式包含以下功能:
+
+1. reset style
+2. 引入组件库的 style(看能否按需引入)
+3. 全局的字体
+4. 全局的 css variables(颜色、字体大小)
+5. 全局的 class。title-text。primary-text。secondary-text。comment-text。
+
+组件内部的样式应采用 scoped,将样式限制在组件内起作用。
+
+## Notice handle: 消息提示处理设计
+
+提示的种类:成功、警告、失败、进度
+
+提示不能过于频繁,要对重复的消息提示做限流处理。
+
+部分流程性质的消息提示,可直接更新内容,延长显示时间。比如“正在上传文件”,“上传成功”。
+
+## Cache and PWA: 缓存的设计
+
+检查各个服务器资源的缓存设置:
+
+1. 后台服务器的 HTML/JS/CSS/image
+2. 阿里云上的 studentClient.json / backgroundImage.
+
+service worker cache html/js/css/image 保证首页快速可用。
+保证在运行过程中,可以更新到最新版本的 js。
+
+缓存分为应用层和网络层。
+应用层的缓存主要是将 store 缓存在 sessionStorage。
+
+都要注意缓存失效的问题,比如用户点击退出回到登录界面,通过权限获取的缓存就应该失效。
+
+PWA 最主要的功能是 cache
+cache 要判断:
+
+1. 对于更新不敏感的资源体验最好
+2. 注意缓存失效的策略
+3. 名字作为缓存的名称
+4. 页面 html 作为缓存的入口,这里是不确定的,但它包含的资源可以通过名称来跟随 html 是否缓存
+5. 网络请求的缓存。post 的不应该缓存。get 可以缓存,刷新并且网络是通畅的情况,请求新的网络请求来了,那么可以替换。
+6. 手动清缓存。做一个按钮,让用户手动点击,unregister service worker。
+
+service worker ; image cache; audio cache/prefetch
+
+## dev settings: 开发环境设计
+
+再使用了 vite 来作为开发服务器后,还有几个可以提升开发效率的功能需要研究。
+
+http/ws proxy  
+开发模式下:  
+设置一个服务器 ip 地址,即满足所有的 https/wss 转发。  
+设置学校域名  
+设置是否为测试环境。最好能 preval,减少代码信息泄露。参考 preval.marco / ts-transformer-preval
+
+## JS obfuscation: JS 混淆设计
+
+### tools
+
+1. rollup.js
+1. js-obfuscator
+
+### 消极影响:
+
+查错会很困难,会变慢。
+
+Todolist:
+
+// sessionStorage design
+// store 防破解?仅保存 user, QECSConfig 信息
+
+## tech challenges: 局部技术难点
+
+技术难题:
+
+1. iframe 的摄像头等数据共享和通信
+1. 学生作答编辑器
+1. 音频播放器
+1. 摄像头各种错误捕捉和提示
+1. webpack / babel 提前执行 js,减少代码长度。确认开发环境不检测 native 的代码。
+1. websocket as a library
+1. network with / without auth
+1. performance
+1. event design: 作为解耦核心流程的手段,用来反调试
+
+## Tech verify: 技术特性验证
+
+- [x] Electron 1.7.16 支持 Proxy / CSS var 等。
+- [ ] naive ui 核心组件在 Electron 的适配
+- [ ] 开考、交卷接口由于接口超时被重复调用,会发生什么?
+- [ ] query 的最佳实践?
+
+1. 如果有不需要链接被分享、收藏、日志或被直接跳转进来,prefer state。typed state?
+1. 传确定的简单数据。类型转换怎么做?
+
+- [ ] select 初始值类型的研究
+- form 字段 null/undefined 的最佳实践
+
+query params: 1. select,未选择,默认为 undefined? 默认为 undefined,则可不传递到后台. clearable => undefined 2. input,未填写,默认为 undefined,查询不传递。如果后台有需要,可以通过 watch 将‘’转 undefined 3. 在 axios paramsSerializer 中处理 query parameter,
+
+https://github.com/axios/axios/issues/1139
+https://www.npmjs.com/package/qs
+paramsSerializer QS defaults: null => '' ; undefined => omit ; change arrayFormat 'comma'
+
+## Upgrade strategy: 升级策略
+
+如果不改接口,仅增加接口,可以分学校升级。
+但此次是为了代码混淆和接口加密而升级的,如果存在多个版本,容易被对比。
+建议充分测试后,全量升级。
+
+## Optional feature: 选做功能
+
+1. electron crash 日志捕获及上传
+1. 不适用的宿主环境日志
+
+## 待整理
+
+======测试规范=====
+工具类充分测试
+服务类模拟测试
+前端单元测试:dom 是否如期变化,api 是否发出
+
+script 抽出来 business logic code? 不好抽取,因为大部分和 UI 相关。将 UI 相关的类抽取成不依赖 UI 的属性集合比如 ImageLike.
+
+======测试规范 end=====
+
+======校验规范=====
+校验字段的 UI 显示
+必须校验
+校验消息提示
+Form rules validator
+校验的问题在于:代码太多,重复太多,干扰正常逻辑
+======校验规范 end=====
+
+======Mock 的研究======
+api mock? 1. 基于 api 规范。 2. 随机生成数据。
+
+easy mock 线上版。
+easy mock 线下版。可以迁移。
+基本满足了需求。
+
+mock 的优缺点?
+缺点: 1. 内网更新比较麻烦 2. 有转换成本
+
+======Mock 的研究 end======
+
+## Others
+
+======设计的遗留问题和感悟=====
+
+前端架构的责任: 1. 架构是方向性的。提出目标和方向,无论底层技术和框架如何发展,目标和方向都不会变,甚至能更好的利用到变化。 2. 架构是管理变化的。当可能的变化点来临,架构能够处理。 3. 架构是划分权力和责任的。即不同的人员负责不同的模块和层级,互相有大致明确的依赖和边界。 4. 架构是负责增长的。 5. 架构是深刻理解了底层技术和业务需求,搭建出的架构既稳固又灵活。
+_. 方向性:易使用、易维护、高性能、高兼容、易调试、日志完善、安全性、文档、code review。。。前端工程化
+_. 日志完善
+_. 作用域可控
+_. 接口规范
+_. 数据类型 => IDE 编程
+_. 测试
+
+设计一个项目时:
+
+1. 先垂直切分,分为几层
+
+架构:关注生命周期,切割生命周期,关注模块,关注模块间的通信
+工具:将常用操作收敛在一起
+业务:具体细节
+
+几种设计方式:
+
+1. obj.method 耦合,同步
+2. postEvent & obj 松耦合,异步,但程序更抽象,必须把模块设计好
+3. store & emit 共享数据,模块耦合程度更低
+
+看得远,才能做设计。
+如何看得远?经验,想象力,推理能力。
+
+几种程序的架构方式:
+
+1. app start/register module
+2. plugin callback
+3. component nest
+
+前端架构:减少重复劳动。库、组件库、流程制定、高难度工具。
+
+先开发逻辑?还是同时开发样式?
+先设计通用组件?还是后面提取?
+
+程序设计能力和过程是估工期的重要因素。
+
+架构与收纳:
+方便获取(就近)
+方便记忆(分类摆放)
+容易还原(将获取模式固定,避免系统状态杂乱)
+流程抽象
+
+设计程序时: 1. 分解流程(操作人的责任范围即为一个流程) 2. 制定接口(接口即为双方开发、调试时查找问题的边界) 3. 保留日志(接收的输入,返回的输出) 4. 错误处理
+
+看源代码: 1. 模块关系 2. 模块加载 3. 模块初始化 4. 模块动态关系
+
+架构:
+
+1. 架构的核心工作是写出核心生命周期。由核心模块去实现核心生命周期。每个核心模块又有自己的生命周期。
+1. 如何分出模块?模块划分的标准:包含一段核心流程。可以独立更新。保持接口服务的稳定性。复用是附加好处。
+1. 如何一眼看出两个模块之间的关系。交互的数据量大小。
+
+框架的目的: 1. 整体可控,整体流程和接口 2. 给模块保证接口,内部可发挥,可 hack,不影响整体的质量
+
+结构良好的程序: 1. 总组件控制流程 2. 子组件控制细节 3. 总组件和子组件通过接口来沟通
+结构不好的程序: 1. 总组件只是个入口 2. 细节和跳转逻辑都在每一个子组件中
+
+有没有可能总组件无法控制流程?
+如果父子、子子组件耦合过高,那么很难梳理出清晰的总流程。
+
+MVC 分层与组织的树状图?
+组织结构
+CEO 下面总监。总监下面经理。经理下面员工。
+总监层?
+每一个层级的职责。目标、进度、指挥、协调。
+
+编程时脑袋里应该存放什么信息(超越本能,练习专业能力):
+
+1. 流程逻辑
+2. 当前打开的文件,之前打开的文件
+3. 预期结果是什么
+
+究竟是前端编织业务,还是后台自行沟通?
+
+组件:
+
+1. 组件本身的 scope,作为一个对象,需要注册。
+2. 组件的本身包含:模板、样式、逻辑。模板是内部的,也可以接受输入。由于 CSS 的特性,会受全局 CSS 的影响。JS 是内部的,接受外部传入的 props。
+3. 模板接受外部的为 slot。
+4. CSS 接受外部的 style 和 class。都是只接受当前层?其他改变样式的通过 props 传入。
+5. JS 通过外部传入。包括事件回调。接口包括变量和事件。
+6. 组件封装,主要是在业务层作用。以实现业务为主,根据业务特点来确定通用性,但不追求复用。
+7. 组件复用主要是框架层。
+8. 组件间通信。props 和 event。props 的耦合性更强,耦合并非坏处,逻辑上该紧耦合就紧耦合。
+9. vuex。全局状态的分发。状态的更新方法和传递。
+
+从需求推导框架的设计,最后到项目的架构:
+用户需求: 1. 更快的响应 2. 更细致的体验 3. 更好的使用机器的特性,如下 4. 屏幕大小的适配 5. GPS,摄像头,通知 6. 由于数据的物理距离的亲密性,在设备内计算是必须的
+环境变化: 1. 硬件更强,CPU 运算更快 2. 网络更好,带宽,延时都有进步 3. 需要考虑电池 4. 移动端的屏幕 5. 浏览器 API 更强大 6. 前端开发工具链更发达
+通用框架的需求: 1. 降低前端开发的复杂性,如下 2. 渲染 => 将数据变成 HTML。模板。DOM 性能 3. 将渲染的流程优化。
+a. 即模板不变,只是根据数据动态改变 HTML,和传递用户的输入。
+b. 将逻辑集中到数据操作。因为数据逻辑更加易于测试和推导。
+c. 如何监控数据?deep? native value? Array value? 4. 组件式开发。例子:UI 库,ant-design。可定制的部分?样式、行为。
+a. 如何支持组件?核心问题。查看 Vue 的源码。
+b. 从模板来的组件树。编译原理?? 5. 数据的流转。store,single source of truth. 数据的共享和隔离。不可变数据? 6. router。适合 web 的一种将应用模块化的方式。用来组织程序,分包,并给用户在程序中定位的能力。
+
+原理:假如自己来写一个前端框架应该怎么写?
+如何组织一个应用程序?分层。模块化。将应用程序模块化。
+
+项目开始编码前问几个问题: 1. 有几个 module? 2. 是否需要划分 module?划分 module 的原则是,项目足够大,需要划分 module 来降低复杂度。未来有可能划分吗? 3. 划分模块后,store/routes 和 modules 放在一起
+
+view 的具体划分
+components 纯视图组件,可共用。比如 view libs,iview 之类的。
+views 和 routes 相关的组件。带状态,最起码和 URL 相关。
+组件划分的需求(终极目标降低复杂度): 1. 可被复用。如果很通用,非业务组件,就追求这一点。业务组件很难被复用。 2. 业务组件的目标。利于维护,需求来自于业务划分。
+利于维护可细化为: 1. 分离相互可以独立的功能,每一个模块可以独立完成一个功能,即因为有了这个模块存在,项目的复杂度降低了。(树形划分功能,并将功能之间的关系连接) 2. 接口清晰。即功能之间的关系最小化。
+
+数据类型:
+全局公用一份,比如 user,privilege
+衍生数据,通过 computed 来拿?getter
+数据逻辑:
+不同 module 的数据不共享,由各自的 module 去维护更新。如果 module 之间的数据不一致,可以设置全局标志位,或由页面刷新来保证一致性。
+Modal 的数据有包含它的组件(Main)提供,Main 提供数据处理完的回调。
+在 Modal 里完成对数据的校验和提交。
+增加和修改的功能抽离为一个组件:所属的代码较多,和主功能牵扯较少。
+组件与 store 数据之间的关系: 1. 尽可能减少使用 store 数据。优先使用 props 传递,这样组件更加独立。 2. 数据集中使用 3. 尽量少修改数据 4. 做好事件回调,将组件内发生的事情传递出去。
+
+设计的原则(主要从人的大脑理解能力出发):
+
+1. 顺序。一个系统切分为多个流程。流程又切分为子流程。流程主要是顺序执行的,较少判断跳转和循环,杜绝随意的流程间的连接。
+2. 集中。具有相同性质的事务,应该集中处理。
+
+设计一个系统就好像给一个团队分工,系统分工不必关心具体人的能力和性格,但是需要知道底层工具组件的能力。
+甚至一个系统最终是给不同的人使用的,那么这些角色的操作流程、效率、配合和权限也要考虑在系统中。
+
+系统的演化:
+
+1. 混为一团。
+2. 识别出主要模块,模块间连接没有规范,物理上还在一起。
+3. 模块间通信规范,物理上没分离。
+4. 模块物理分离。
+
+https://www.infoq.cn/article/AJ0S3IDEHyusNms0bTf1
+深度解读当代前端架构演进与趋势
+MVC: 将 view 和 model 分开,这两个都是比较复杂的部分,且可以独立变化,并且各自的细粒度组件可以复用。controller 是粘合剂。
+经典 MVC 时代,视图没有标准(图形操作系统还没有诞生),视图的输入输出比较底层,比如接收键盘输入,这个时候 controller 就做了大量非本质性工作。
+controller update model.
+controller update view.
+event & reference 都被使用了。
+
+Application Model: 某些状态是属于 view 的,但又不能放 view 里面,因为会影响 view 的通用性,同时这些状态又是 model 派生出来的,但理论上 model 与 view 是无关的,所以 model 来维护这些状态很奇怪。
+比如超过某个数字,把 label 变成红色。
+这时就创造出 AM 这个概念了。AM 来维护 view 的状态。
+
+以上 MVC,
+
+现代个人操作系统大大简化了输入输出,PC OS 一开始就为个人设计,所以 GUI 是重中之重,view 的功能强大了,却同时简化了,大部分 controller 要做的底层部分被简化掉了,变成了 view 内置的逻辑。
+
+MVVM: data-binding
+Model 在哪里?
+view 是 template & style?
+
+MVVM => 重点在于 VM 是 data binding view,data 改变则 view 自动改变
+
+MVVM => data(model) -> transform(view model) -> view
+MVP
+MVC (UI no auto update)
+
+前端的变化:业务流程优化!以往 web 前端弱小的时候,流程是在服务端控制的多页面(业务窗口)完成的,现在前端强大了,虽然可能还是多页面,但已经是由前端控制的流程。
+即由多业务窗口多次提交,变成统一业务窗口了。
+
+改变开发的思维模式:
+首先设想页面要展现什么数据(暂时不考虑组件)
+假设数据已得到(并且要设计数据模型)
+数据会如何变化
+
+总是在第一次采用最直觉的写法完成任务,之后再优化性能和体验
+比如对于易过期的数据,总是获取而不考虑缓存
+
+关于 null 的思考
+boolean select with null? and filter null?
+component:
+state: null; // default
+api pass state null/false/true?
+api:
+if pass null to api 是可以考虑的
+search is null? search 时 null 的话,不传。
+edit 时,null 必须要传到后台 (将 enabled 修改为 null)
+component prop forSearch? no
+search { enabled} 当传递到 api 时,去掉 null
+
+前端开发的几大主题:
+
+1. 校验
+2. 异常处理
+3. 数据流
+4. 安全
+5. 图形化
+6. 数据模型
+
+一个应用如果只考虑正确情况,那它的架构和状态应该是怎么样?
+此为一个简化版本,应用的是第一性原理。
+然后考虑一个应用如果考虑网络请求,网络错误,日志,性能,动画,复用,错误提示,校验?
+
+======设计的遗留问题和感悟=====
+
+======脚手架设计======
+Vue 框架 avue 评估
+
+混用 avue?
+theme?
+样式覆盖
+网络调用
+vuex
+avue 的 vue 使用的是过时版本,它的长期发展不明确,还是自己维护组件比较靠谱。
+q-crud: 增删改查
+q-table:
+q-page:
+脚手架快速启动:
+login page
+4xx/500 page
+router
+store
+权限/角色
+
+只使用 avue 的 表单+表格+新增,分页,网络请求,错误处理
+
+脚手架初始化公共功能
+前端公共模块
+提炼公共接口标准
+提炼公共设计模式
+
+vue 权限管理: 加入脚手架
+scrollbar; visible/hide/width restore
+compatibility
+document.title
+i18n
+
+CRUD: paging, save page state? 最低要求,一个丰富的 sample 页面,增删改查分页上传。最高要求:配置化(自动生成 route, page,被集成,但不进 git);或者通用页面,接收参数。
+
+======componet 设计=====
+一个设计良好的组件:
+
+1. 能简单的完成基本任务。
+2. API 符合直觉。名称。
+3. 不影响外部状态(样式)。
+4. 错误要抛出,出错至少要对开发友好。
+5. 清晰完整的使用文档。
+6. 可平滑升级。
+7. 如果是组件库,那么组件要有相似性,api、样式。
+8. 样式 scoped 很难被外部覆盖,所以最好基于 class 的。
+
+component 的接口:
+
+1. 外部传进的 props,包含数据和 callback
+2. component globals, $store, $http, window
+3. 内部状态?只是影响组件内部逻辑是最好的。
+4. 内部状态由网络获取的部分?与整体的 store 没有关系。
+5. 直接发起请求影响服务器?可能影响 store 的数据一致性,那么应该有 store 去统一操作。
+6. mapstate from store. component 的依赖是个多重来源的,并不由 parent component 完全控制。
+7. 与 graphql 的关系
+
+根据项目的大小划分 component 的责任:
+责任列表:
+
+1. 显示数据
+2. 监听用户操作
+3. 获取数据
+4. 处理数据
+
+中小项目可以将以上合在一起。大型项目中的 component 会很大很复杂。
+需要将 component 的功能简化,变成只 render。
+但 component 需要有办法声明数据依赖,并将对数据的影响传递出去。
+
+container component: fetch data
+presentational component: display data
+
+controlled component: 由上层获取数据,数据有变化,也通过 onchange 事件通知上层去处理,或者上层传递 props 函数去处理。
+
+container component 的子组件层级里面再包含 container component 也是允许的,只要子组件是自己管理它获取的状态就可以。
+
+css 共享和隔离? global css, component css
+
+component 的职责:有无网络请求?有。
+
+======componet 设计 end=====
+
+======脚手架设计 end======