说好的经验总结,但是真写起来反而不知道写些什么。
就写点学到、见到的东西罢,也不一定是经验之类的。

  1. typescript 函数声明参数的时候定义 props 接口

    这个其实大概是比较普遍常见的用法了,例子如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    interface IfuncAProps {
    a: boolean;
    b: number;
    c: string;
    }

    function funcA(props: IfuncAProps) {
    ...
    }

    这样写的的好处在于扩展方便、也更加清晰。
    尤其是在写 React 函数组件的时候其实有很多父函数组件调用子函数组件的情况,这个时候往往父函数的参数很多其实是子函数需要的,这个时候就可以用父函数的参数接口扩展子函数的参数接口。这样子子函数若要添加新的参数就直接改子函数的接口定义就好了,不需要再往上改相应的父接口。这样说来其实说的是 extend 的好处……
    不过函数参数定义写得短一点总归好看不少。

  2. 异步加载

    异步加载可以减少首屏加载量以及非必需的包的加载,一个最简单的写法大概是如下,是我在我的开源项目写的:

    1
    2
    3
    4
    5
    export async function importOggOpusDecoder() {
    return import(
    /* webpackChunkName: "ogg-opus-decoder" */ "ogg-opus-decoder"
    );
    }

    这样在需要用到这个包的时候调用 importOggOpusDecoder 就可以了,其中 /* webpackChunkName: "ogg-opus-decoder" */ 的作用是给包标记名字,一个作用是 F12 调试的时候可以便捷地看出下载的包是什么,而不是是乱码。
    不过我感觉一些必须用的或者说正常使用肯定会用到的包或函数可能也不一定要动态加载?毕竟如果一定会用到的话直接加载也可以说是预加载吧。

  3. 埋点

    埋点这东西,我之前都没有注意过或者说不知道,但后面发现其实用的是很广泛的。虽然感觉不是必需的,但是感觉如果能收集到很多数据的话最后汇总形成报告肯定也是很有意思的。
    不过遗憾的是我没有太深究到埋点的实现上,目前只知道如果埋点很多的话先收集起来,一段时间后再发送会好一点。

    不过毕竟总是是向后端发送信息,如果有人伪造数据发送埋点怎么办?感觉大概很多网络请求都有类似的问题,应该可以参考一下。
    还有就是收集数据可能会涉及到用户隐私的问题,这个是不是也需要考虑告知用户之类的?虽然不准备收集涉及隐私的东西,但是偷偷收集总感觉被发现的话会出事。

  4. Feature Gates

    Feature Gates 这东西,其实单人的小项目可能还真用不到。这个东西本质就是一个下传一堆 bool 值来控制前端某些功能的开关。
    这个东西往往会和灰度一起使用打组合技,大概就是给某些灰度用户先开某个特性看看有没有 bug,没有再继续扩大。也方便出问题的时候处理,直接把 FG 关掉就可以了。

  5. SCM 版本控制

    这两个词大概是一起的?总之理解下来大概就是对于每一个合并到主分支的提交,都可以创建一个版本号,然后访问的时候就可以根据通过在 url 添加版本号来访问到不同的版本上。
    还有就是设置一个默认版本,不设置版本的时候默认根据这个版本访问。这个其实也涉及到版本发布流程相关的了,而且其实也有很多相关的防范措施防止用户乱访问环境。

    总的来说这个也算是一个类似 FG 的东西,只不过 FG 是以特性为单位,这个则是以时间线或者说 commit 来作为分界,也是可以方便测试以及出问题回退。

  6. 基建,依赖注入

    这个我有点说不清,大概是涉及到微前端方面的东西了,这个应该也是减少依赖减少包体积、提升加载速度的一个方法。
    不过想了想应该就是依赖注入,具体来说就是一个项目声明一个接口,内部要使用一些相关函数的时候就直接调用接口的函数,函数的实现则在其他项目中进行,然后再将这些实现注入给接口里。
    这种感觉也是复用很多的时候会用到,就是一对多或者多对一这样子,这样也算是应该可以裁剪部分用不到的数据?不过似乎还要结合其他一些实现才可以,大概主要是依赖注入的好处吧。

  7. 技术文档

    感觉没什么活了,开始乱写了。
    技术文档这东西主要还是学到了该怎么写,往大了说,要分析需求,写出几个(一个也行)解决方案;小了说,解决方案这部分其实要写得比较详细的,大概是定义了什么接口,使用了什么结构、大概写在哪里都需要大概写出来。属于是那种看完看懂后也基本知道具体写法是怎么样的了,而不是只知道大概是个什么思想。
    这样子确实会导致写技术文档要很多时间来写,而且写了好几个解决方案的话肯定是只能用其中一个的,不过好处也是写完之后写代码其实就不太需要脑子了,直接根据方案上的来就可以了,当然也方便今后自己忘了自己怎么写了的然后翻阅。

  8. 接口实现返回 JSX

    其实就是创建一个接口,然后创建其他很多类来实现这个接口,算是接口的正统应用了。

    但是比较惊讶的是,没想到过实现接口的函数可以返回 JSX。用法也是之前比较没见过,大概就是外面套一个界面的框架,然后内部的一些细节使用实现接口的函数来渲染。
    怎么说呢,虽然是可以想象的、甚至说也是比较正常的,但是就有种意料之外的感觉吧,只能说接口确实用得少。

  9. 文案

    这个用的也是比较少,其他 i18n 方案是不是这样的不太清楚,但感觉这个方案想了想也是比较靠谱的。

    大概就是要用到文案的地方先预先用一个文案 key 占位,然后通过函数获取到文案 key 相应的文案。具体实现不太清楚,但感觉这样子能统一管理文案,应该函数获取的时候直接通过语言和 key 来获取就好了。或者是通过设置的语言直接获取到 key 对应的文案 map,然后函数其实只是通过 key 从 map 取出文案内容?后者应该更正确些,但是感觉可能会需要一定后端了。

  10. 编译剪枝

    这个更是我不常用而且不会用的东西了。
    大概就是设置一些类似于 C/C++ 编译期的宏定义类似的东西,然后在编译的时候就控制程序的 if 之类的分支走向。比如:

    1
    2
    3
    4
    5
    6
    function func() {
    if(__IS_SIMPLE__) {
    return;
    }
    ... // 这里是正常函数逻辑
    }

    注意到 __IS_SIMPLE__ 应该既不是运行时环境也不是什么变量之类的,而是编译时就确定好值了(我感觉)。
    这样的好处我认为一个是可能会节省不走的路径的一些包和库的大小,另一个可能是其实比如上面在 __IS_SIMPLE__ 环境下其实本来下面的逻辑就是无法正常执行的,这样子做只是防止运行到会报错的代码。
    但总归来说,肯定是能减少包体积的。


其实很多也是想不起来了,或者说没注意到、不知道怎么写。大概有点嗯编的感觉?大概吧。
不过话说为什么代码没有上到色,答案是我也不知道,懒得折腾了(