关于架构:如何结合整洁架构和MVP模式提升前端开发体验三-项目工程化配置规范篇

5次阅读

共计 4068 个字符,预计需要花费 11 分钟才能阅读完成。

工程化配置

还是开发体验的问题,跟开发体验无关的我的项目配置无非就是应用 eslint、prettier、stylelint 对立代码格调。

formatting and lint

eslint、prettier、stylelint 怎么配这里就不说了,网上文章太多了。想说的是 eslint rule 'prettier/prettier': 'error' 肯定要开启,以及 stylelint rule 'prettier/prettier': true 也肯定要开启。

尽管配置了 eslint、prettier、stylelint,然而可能你队友的编辑器并没有装相应的插件,格式化用的也不是 prettier,而后他批改一行代码顺便把整个文件格式化了一遍。所以还得配置 husky + lint-staged,提交代码的时候按标准格式化回去,不符合规范的代码不容许提交。

如果公司的电脑配置还行的话,能够开发阶段就做相应的 lint,把谬误抛出来,中断编译。webpack 能够应用 eslint-loader,stylelint-webpack-plugin;vite 能够应用 vite-plugin-eslint,vite-plugin-stylelint;vue-cli 配置几个参数就能够开启,具体看文档。

ts-check

什么是 ts-check?举个例子,有一个后端接口的某个字段名称变了,由 user_name 改为了 userName,如果没有配置开发阶段进行 ts-check 并把谬误抛出来,那么只能全局查找调用接口的中央去批改,如果改漏了,那就喜提一个 BUG。

ts-check 能够开发阶段就做,也能够提交代码的时候做。开发阶段 webpack 装置 fork-ts-checker-webpack-plugin,vite 也是找相应的插件(临时没找到用的比拟多的)。提交代码的时候,联合 husky 做一次全量的 check (比拟耗时),react 我的项目执行 tsc –noEmit –skipLibCheck,vue 我的项目执行 vue-tsc –noEmit –skipLibCheck

ts-check 能好用的前提是你的我的项目是 TS 写的,接口返回值有具体的类型定义,而不是 any。

代码标准

次要讲讲 model,service,presenter,view 这几层的代码标准,之前的文章也有简略提到过,这里做个演绎。

model

import {reactive, ref} from "vue";
import {IFetchUserListResult} from "./api";

export const useModel = () => {const userList = reactive<{ value: IFetchUserListResult["result"]["rows"] }>({value: [],
  });
 
  return {userList,};
};

export type Model = ReturnType<typeof useModel>;
  1. 每一个字段都要申明类型,不要因为字段多就用 Object[k: string]: string | number | booleanRecord<string, string> 之类的来偷懒。
  2. 能够蕴含一些简略逻辑的办法,比方重置 state。
  3. vue 中字段申明能够移到 useModel 里面,达到状态共享的作用,在 useModel 中 return 进来应用。

service

  1. react 技术栈,presenter 层调用的时候应用单例办法,防止每次 re-render 都生成新的实例。
  2. service 要尽量放弃“整洁”,不要间接调用特定环境,端的 API,尽量遵循  依赖倒置准则 。比方 fetch,WebSocket,cookie,localStorage 等 web 端原生 API 以及 APP 端 JSbridge,不倡议间接调用,而是形象,封装成独自的库或者工具函数,保障是可替换,容易 mock 的。Taro,uni-app 等框架的 API 也不要间接调用,能够放到 presenter 层。组件库提供的命令式调用的组件,也不要应用。
  3. service 办法的入参要正当,不要为了适配组件库而申明不合理的参数,比方某个组件返回 string[] 类型的数据,理论只须要数组第一个元素,参数申明为 string 类型即可。2 个以上参数改为应用对象。
  4. 业务不简单能够省略 service 层。

service 保障足够的“整洁”,model 和 service 是能够间接进行单元测试的,不须要去关怀是 web 环境还是小程序环境。

import {Model} from './model';

export default class Service {
  private static _indstance: Service | null = null;

  private model: Model;

  static single(model: Model) {if (!Service._indstance) {Service._indstance = new Service(model);
    }
    return Service._indstance;
  }

  constructor(model: Model) {this.model = model;}
}

presenter

import {message, Modal} from 'antd';
import {useModel} from './model';
import Service from './service';

const usePresenter = () => {const model = useModel();
  const service = Service.single(model);

  const handlePageChange = (page: number, pageSize: number) => {service.changePage(page, pageSize);
  };

  return {
    model,
    handlePageChange,
  };
};

export default usePresenter;
  1. 解决 view 事件的办法以 handle 或 on 结尾。
  2. 不要呈现过多的逻辑。
  3. 生成 jsx 片段的办法以 render 结尾,比方 renderXXX。
  4. 不论是 react 还是 vue 不要解构 model,间接 model.xxxx 的形式应用。

view

  1. 组件 props 写残缺类型。
  2. jsx 不要呈现嵌套的三元运算。
  3. 尽量所有的逻辑都放到 presenter 中。
  4. 不要解构 presenter 以及 model,以 presenter.xxx,model.xxxx 形式调用。

store

  1. 不要在外层去应用内层的 store。

接口申请办法

  1. 封装的接口申请办法反对泛型
import axios, {AxiosRequestConfig} from "axios";
import {message} from "ant-design-vue";

const instance = axios.create({timeout: 30 * 1000,});

// 申请拦挡
instance.interceptors.request.use((config) => {return config;},
  (error) => {return Promise.reject(error);
  },
);

// 响应拦挡
instance.interceptors.response.use((res) => {return Promise.resolve(res.data);
  },
  (error) => {message.error(error.message || "网络异样");
    return Promise.reject(error);
  },
);

type Request = <T = unknown>(config: AxiosRequestConfig) => Promise<T>;

export const request = instance.request as Request;
  1. 具体接口的申请办法,入参及返回值都要申明类型,参数量最多两个,body 数据命名为 data,非 body 数据命名为 params,都是对象类型。
  2. 参数类型及返回值类型都申明放在一起,不须要用独自的文件夹去放,感觉代码太多不难看能够用 region 正文块折叠起来(vscode 反对)。
  3. 接口申请办法以 fetch,del,submit,post 等单词结尾。
  4. 倡议接口申请办法间接放在组件同级目录里,建一个 api.ts 的文件。很多人都习惯把接口申请对立放到一个 servcies 的文件夹里,然而复用的接口又有几个呢,保护代码的时候在编辑器上跨一大段距离来回切换文件夹真的是很蹩脚的开发体验。
// #region 编辑用户
export interface IEditUserResult {
  code: number;
  msg: string;
  result: boolean;
}

export interface IEditUserParams {id: number;}

export interface IEditUserData {
  name: string;
  age: number;
  mobile: string;
  address?: string;
  tags?: string[];}

/**
 * 编辑用户
 * http://yapi.smart-xwork.cn/project/129987/interface/api/1796964
 * @author 划水摸鱼糊屎工程师
 *
 * @param {IEditUserParams} params
 * @param {IEditUserData} data
 * @returns
 */
export function editUser(params: IEditUserParams, data: IEditUserData) {return request<IEditUserResult>(`${env.API_HOST}/api/user/edit`, {
    method: 'POST',
    data,
    params,
  });
}

// #endregion

下面代码是工具生成的,下篇说说晋升开发效率及体验的工具。

正文完
 0