7

第八期:前端九条启发分享

image.png

一、 设置git commit的校验 (husky:^5版本之前配置与这里不一样)

     在一般情况下, 我们每次执行git commit -m'提交信息'的时候, 会触发针对commit信息的校验以及代码风格的校验, 如果没通过校验会导致commit失败, 那么这些校验是如何加入到项目中的那?

     大部分时候添加针对commit的校验我们会使用husky这个包, 让我们来安装一下它:

yarn add husky -D

     在packgae.json中添加下面内容, 这里是初始化.husky/目录并指定该目录为git hooks所在的目录, 所谓的git hooks可以理解为git的钩子函数, 比如git add执行之前, git commit之后等等生命周期的钩子函数, 而git hooks所在目录就是用来定义git各个生命周期需要执行的各种函数。

{
  "scripts": {
    "prepare": "husky install"
  }
}
第一步: 添加代码校验

     接下来我们在命令行执行:

yarn prepare
npx husky add .husky/pre-commit "npm run lint"

     上述第二条命令定义了pre-commit这个生命周期执行npm run lint 这句命令。

     在packgae.json中定义lint命令是使用eslint检测src文件夹里的文件, 当然啦检测什么文件都可以。

  "scripts": {
    "lint": "eslint src"
  },
第二步: 添加提交信息校验

     校验commit信息我们最简便的方式就是依赖commitlint这个包。

yarn add @commitlint/config-conventional @commitlint/cli -D

     在根目录里新建commitlint.config.js并写入下面内容:

module.exports = { 
  extends: ["@commitlint/config-conventional"] 
};

     添加校验commit的hook:

npx husky add .husky/commit-msg 'npx --no-install commitlint --edit "$1"'

     上面命令的意思是创建一个commit-msg hook的文件, 里面的内容是npx --no-install commitlint --edit "$1"

     commitlint命令来检测$1这个参数的值是否合法, 而$1就是我们的git commit -m ${1}

校验的标准

     请查阅规范文档

这里我只列出最常用的几个:

规范使用方式
docsgit commit -m"docs: 更新xxx文档"
featgit commit -m"feat: 新增xxx模块"
fixgit commit -m"fix: 修复了上线的xxxxbug"
stylegit commit -m"style: 更新用户信息弹框的样式"
testgit commit -m"test: 修改添加用户按钮的测试用例"
与你项目里配置不一样?

     有的同学可能发现了, 我这里的写法可能与你项目里的写法不一致, 你的项目可能是如下的写法:

{
  "husky": {
    "hooks": {
      "pre-commit": "npm run test",
      "commit-msg": "commitlint -e $HUSKY_GIT_PARAMS"
    }
  }
}

     上述写法是husky^6版本之前的写法, 现在husky已经更新到了7版本, 所以未来创建新项目可能不会再用这种写法配置了。

git的hook

git官网描述hooks

image.png

二、 ///这种注释的使用

     我们在react项目代码里会看到下面这种注释, 那么这种奇怪的注释是干么的那?

/// <reference types="react-scripts" />

     原来这种/// <reference types="包" />的写法主要用在.d.ts文件里面, 作用是引入其他的.d.ts文件, 比如我需要用到一个xxx.d.ts文件, 但是这个并没有放在node_modules/@types里面, 所以并不会被系统默认导入。

image.png

image.png

image.png

image.png

ts官网给出的解释

三、 推荐一款react引导插件 guide

插件地址

image.png

image.png

     一般网站第一次访问的时候都会有个引导操作, 使用guide就可以轻松实现, 让我们一步步来配置:

yarn add byte-guide

     这个插件的使用方法的中心思想是, 我们以数组的形式传入一套配置, 找个配置里面有要被挂载的目标dom, 以及显示的文案等信息, 然后每次点击下一步就可以依次执行数组内的对象:

import Guide from "byte-guide";

export default function Home() {
  const SEARCH = {
    hotspot: true,
    title: "搜索组件",
    selector: "#search",
    placement: "top-left",
    content: <div>这个搜索组件很厉害</div>,
    offset: { x: 20 },
  };
  const TOTAL = {
    title: "列表总数",
    parent: "#search",
    selector: "#total",
    placement: "right",
    content: "这里是列表总数。",
  };

  return (
    <div className={"org"}>
      <div id={"search"}>目标1</div>
      <div id={"total"}>目标2</div>
      <Guide
        lang="en"
        localKey="uni-key"
        className="my-guide"
        steps={[SEARCH, TOTAL]}
        onClose={() => {
          console.log("点击关闭");
        }}
        afterStepChange={(nextIndex, nextStep) => {
          console.log("点击下一步");
        }}
      />
    </div>
  );
}
主要属性的说明
  1. localKey: 我们引导组件的显示一般是只有用户第一次登录才显示, 或者是当用户点击了引导的结束按钮就永远不显示了, guide将是否需要展示引导组件的值储存在Local Storage中, 所以这里定义了储存的key名。
  2. placement定义了弹出框所在的位置, 比如顶端的元素我们会选择使用bottom之类的属性。
  3. offset 虽然设置了placement但是难免位置不尽人意, 所以可以使用这个属性对引导框进行位置的再调。
注意事项

     组件内置了简单的国际化, 也就是当我们不指定文案的时候, 他自己会根据传入的语言英语中文日语进行文案的改变。

     这个插件有bug, 如果两个元素处于父元素的内部滚动状态时, 会出现定位偏差非常多的问题, 所以如果你的引导项目涉及内部滚动的元素则不建议使用这个插件。

四、 eslint 7 版本之后可以注释

     发现团队项目中难免会出现一些/* eslint-disable*/ 这种注释, 每次看到会尝试将其删除, 但是可能会引起一系列的连锁翻译, 这种情况下如果我们使用的是eslint^7版本及以上, 则可以添加注释, 说明为什么这里必须使用/* eslint-disable*/

// eslint-disable-next-line a-rule -- 这里的错误无法修复!

     上面的写法更加友好, 因为毕竟这种禁止eslint检测的方式不推荐大家使用, 如果必须要使用也需要在初期就标明原因。

五、 统一一个index文件导出的利与弊

     比如我们有很多的工具方法放在同一个文件夹下,a.js文件导出a1, a2等方法 我们常常使用一个index.js文件进行统一的导出, 项目里会有很多如下的写法:

export * from './a';

export * from './b';

export * from './c';

export * from './d';

     这种写法虽然看起来计较"优雅"但是有不少弊端存在, 这里我们就列举一下:

1: 导出名字可能重复

     这是个小问题因为会有ts报错提示, 起因是index.js文件里面没有写出具体的方法名, 所以需要每次修改留意一下index文件是否报错。

2: 代码寻径麻烦

     这点也就是对操作最不友好的一点, 比如我们在某个页面上有一个外界导入的方法, 我们mac电脑的话点击`c
ommand + 鼠标左键就可以查到这个方法的出处, 但是往往只是寻径到了index.js`, 这里也没有具体的方法名称呈现, 所以需要再次进到各个文件里面查询。

3: 改变导出没有提示

     当我们修改一个导出时没有提示, 比如删掉一个导出方法, 修改一个导出方法的名称, 此时并不会在文件本身以及index.js文件种报错, 报错的地方是具体使用到这个方法的文件, 这就可能会忽略到, 因为不启动项目直接git push也是可以检验通过的。

4: ts类型二次推导

     有时候会出现你命名导出了一个方法函数, 但是eslint报错说没有导出该成员, 但是当我们进入到这个方法的文件夹里后, eslint的报错就消失了, 这种不好的体验都与这种写法有关。

六、svgr库转换svg图片, filter:drop-shadow

     xxx.svg这些文件是不好控制的, 我们想动态的传入很多配置可能需要借助svgr这个库将svg图片转换成react组件的形式, 通过下面的命令可以在命令行生成代码数据:

npx @svgr/cli --icon  图片的地址.svg

image.png

     在命令行里生成肯定是不能工程化的, 其实各种脚手架已经内置了这个svgr库, 所以我们其实如下方式就可以使用组件模式的svg图片啦。

import { ReactComponent as Logo } from "./logo.svg";

// ....

<Logo width={"30px"} style={{ filter: "drop-shadow(red 20px 0)" }} />  

     filter: "drop-shadow(red 20px 0)"这句可以使svg变成红色,关于它的细节我会单拿一篇文章去讲。

七、 yarn resolutions 管理被多项目依赖的包

     项目中会引用很多的npm包, 比如我们项目里面依赖了A包, A包自身又依赖 ^3.1.5版本的B包, 我们项目本身yarn add B已经安装了^3.0.5版本的B包, 此时B包其实是可以通用的, 完全没必要引用两个版本。

     并且如果打包的话由于我们两处依赖的不同版本的B包导致打包后体积的增大, 所以yarn提供了resolutions这个配置项, 我们可以如下配置(package.json):

  "resolutions": {
    "B": "^3.1.5"
  }
举一个实际的例子
我们创建一个新项目
npx create-react-app 项目名称

进入到项目中

yarn list --depth=1

列出项目的依赖, 并且只打印一级依赖即可, 我们就以workbox-build为例:
image.png

我们在外层package.json进行配置:

  "resolutions": {
    "fs-extra": "^4.0.2"
  }

此时执行yarn命令, 并且在此yarn list --depth=1打印:

image.png

上面的依赖关系已经变化了, 不是仅仅在workbox-build包的下面了。

八、 pnpm 代替 yarn lean做包的管理

     我们经常使用yarn + lean这种方式管理子项目, 但是传输中pnpm更适合做这个工作, 那么为什么说pnpm更适合那?

     yarn管理node_modules的机制会导致, A包依赖的B包, 那么B包的文件位置会处于与A包同级, 这就导致开发者虽然没有执行yarn add B但是项目中也可以引入import B from 'B', 这就为开发埋下拉隐患。

     pnpm采用的方式是, 将包统一管理, 单个项目的node_modules文件里面储存的类似软连接, 这样就不会出现重复安装某个依赖的情况了, 并且也没必要将B 与 A放在同一层级了, 也就不存在莫名其妙的引入B包的情况

     当我们有很多子项目并且依赖越来越复杂的时候, pnpm的优势就显示出来了。

九、 微前端的子应用, 如何单独启动

     微前端应用里面都会有几个子项目, 这些子项目往往会依赖一个主项目(壳工程), 主项目负责分发一些重复使用的资源, 比如react react-router等等公用的依赖, 并且也会出现主项目里的一些自定义的utils工具方法传递给子项目

     由于存在众多需要主项目分发的资源那么就对子项目单独的运行制造了困难, 我们每次都要启动至少主项目+子项目, 并且想要看到完整工程还需要启动其余的所有子项目, 但我们有什么办法只启动子项目自身那?

     我这里的做法是利用请求的代理, 因为大部分微前端框架的原理是每个子项目都是一个js文件, 主应用启动后按需加载子项目的js入口文件, 那么我们就可以访问线上测试环境的地址, 然后找到线上测试环境的主应用访问子应用的url, 然后将这个url代理其指向本地启动的子项目的地址即可。

     这样做的好处就是可以让子项目完全处于一个线上环境的主应用的上下文里, 并且不用启动其余子项目, 要注意子项目的css文件也要代理过来。

end

     这次就是这样, 希望与你一起进步。


lulu_up
5.7k 声望6.9k 粉丝

自信自律, 终身学习, 创业者