1

奇妙的“慧星”之旅

 2 years ago
source link: https://jelly.jd.com/article/6140ab90353de70190902a84
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
JELLY | 奇妙的“慧星”之旅
奇妙的“慧星”之旅
上传日期:2021.10.14
星元二零二一年,宇宙和平,诸星稳定。一时间,年轻人纷纷背起行囊,外出求学历练。历史上有名的第一次宇宙求学潮由此拉开了序幕......

这一日,少年奇妙来到了彗采星球,这是被人们称为“彗星”的承载宇宙最强智慧的发达星球。奇妙站在星球入口,眼前无数尊高大的学者雕像让他激动得热泪盈眶。

11d36b920f7b79f2.png

“这位少年,且随我来。”一位老者迎面走来,他身材矮小,胡子花白,头发却乌黑油亮,明显是染过了的。

“我们星球的人出生就是黑头发,白胡子,一生都不会有变化。”老者对少年说到。

“你能窥探我的内心!”奇妙吓了一跳。往日里听闻彗星居民智商极高,擅攀科技高峰,没想到竟然已经具备了窥探心意的能力。

老者和蔼地笑了笑,“我已知你来意,想学本领,当有考验。只要你通过考验,我便可以教你。”

奇妙一听,立刻双膝跪地:“愿闻其详!”

老者点点头,摆手示意他起身,“我们慧采星球,有六大部落,分别是 PC 分部 、APP 分部、H5 分部、小程序分部、签约平台分部和协同采购分部。这几个部落各持所长,为宇宙做着贡献。你且把手放到这颗水晶球上,让彗星之神来决定将由哪一个部落的长老作为你的考核人。

11d36b920f7b79f2.png

奇妙听得痴迷,呆住半天没动,还是那水晶球发出的强光刺痛了眼才让他回过神来。他将手轻轻地放到水晶球上,随后身体猛地一震,眼前云雾弥漫不能视物,朦胧中头脑里仿佛被塞进了无数记忆,而这些记忆正是慧采 PC 部落过去的故事:

星元二零一五年,慧采 PC 部落推出了一款 B 端平台产品,这个平台为企业用户提供差异化、可快速对接的企业专属综合集采解决方案,为用户提供定制化的优质服务。在 C 长老的用心带领下,部落人民勤勤恳恳地建设着这个面向全宇宙的平台。不久之后,慧采 PC 就凭借着自身的诸多优势,发展了越来越多的用户,影响力日益增大。

11d36b920f7b79f2.png

然而,随着人们审美的提升,慧采 PC 的视觉风格逐渐变得落后,繁杂的交互更是难以满足用户追求极致体验的心情。

“必须要变!” 随着 C 长老的一声令下,慧采 PC 部落的劳动者们快速集结,新版本慧采 PC 的开发工作紧锣密鼓地开展了起来。

长老的考验(项目开发)

奇妙醒过来时,已是翌日中午。彗采星球没有黑夜,人们也无需休息,但是为了让昏迷过去的奇妙睡觉,人们还是用木板和树叶临时搭了一张床。

大侠:“你好,我叫大侠,来自地球。”

奇妙听到有人说话,立刻从床上坐起来,却顿觉头痛难忍。

大侠:“你受到慧采之神力量的冲击,身体难免承受不住,不过不必担心,工作起来就不会觉得头疼了。”

奇妙抬头看了看大侠,这是他在异国他乡遇到的第一个地球人。大侠挑了挑眉毛说到:“长老的意思,之后我们俩会一起合作,完成新版慧采 PC 的开发,完成了这个,我们也就通过第一重考验了。”

奇妙从床上跳了下来,“开干!”

强大的 Legao 组件库

大侠给奇妙分配的第一个任务是给订单中心的确认收货按钮加一个弹层,并建议使用宇宙开源的 Legao 组件库快速搞定。

11d36b920f7b79f2.png

奇妙还是第一次听说 Legao 组件库,赶紧去了解了一下:原来 Legao 是一套 PC 端的 UI 基础组件库,精选 60+ 的高质量组件,能够覆盖 90% 的业务场景,可以满足绝大部分网站需求。而慧采 PC 正是应用 Legao 组件库搭建起来的。

11d36b920f7b79f2.png

Legao 组件库的上手十分简单,奇妙按照 文档 的指引,没几分钟就学会了使用,简单几行代码就搞定了这个弹层的开发:

      <lg-dialog
        :type="dialogType"
        :title="dialogTitle"
        :visible.sync="showDialog"
        :content="dialogContent"
       >
        <div slot="footer">
          <div class="lg-dialog-footer">
              <div class="dialog-footer-btns">
                  <button type="button" @click="showDialog=false">
                    <span class="lg-btn-text">知道了</span>
                  </button>
               </div>
           </div>
         </div>
      </lg-dialog>

接下来的开发中,奇妙还发现,很多地方都可以使用 Legao 组件库快速完成。像分页功能:

    <lg-pagination
        :page-sizes="pageSizes"
        :total="total"
        :small="false"
        :curr-page="currPage"
        :size-on="false"
        :total-on="true"
        :css-style="cssStyle"
        :page-count="pageCount"
        :jump-on="info.jump_on"
        @jump-page="jumpPage"
    >
    </lg-pagination>

组件拥有良好的 API 设计,除每页展示数量、总页数、当前页数等常见属性外,也有点击页码回调函数的对外暴露,只要我们按照要求传入参数,一个底部分页栏瞬间就呈现出来了。

11d36b920f7b79f2.png

不知不觉已到中午,奇妙感觉肚子有些饿了,便去找大侠。随后,二人来到了一家名为“地球餐厅”的餐馆,老板们用各种语言招呼着客人。

大侠习惯性地走到一个摊位前,“Two hamburgers , please”。奇妙心存感激,没想到大侠竟然知道自己喜欢吃汉堡,难不成他已经学会了慧采星球窥探人心意的本领!

大侠:“我中午就吃这两个汉堡,你看看你想吃啥,去买一份儿吧。”

奇妙:“......”

有趣的传参机制

饭后,奇妙接到了新的任务,要完成一次跨越多个层级的组件间传参。奇妙略加思索,常用的传参方式有:

  • $emit / $on
  • attrs / listeners
  • v-model
  • $refs / $root / $parent / $children
  • project / inject

想实现跨层级的组件间传参,优先应当考虑 vuex ,可是在慧采 PC 的项目中,奇妙却并没有发现太多这种技术的使用痕迹。“难道还有其他方式么?”奇妙仔细阅读代码,发现了真相,原来是用了这样一种方法:

在总入口文件内实例化一个 Vue ,代码如下:

vue.prototype.$public = new Vue()

这样,我们就拥有了一个新的 Vue 全局实例, $public 有着 Vue 一切公共属性和方法,包括数据的劫持和监听。我们使用 $emit 和 $on 进行数据传递,代码就可以这样写:

this.$public.$emit('ask','发送');

在遥远的另一个组件里,我们可以进行监听,并接收发送过来的参数:

created(){
  this.$public.$on('ask',(msg)=>{
     console.log(msg) // 发送
  }
}

如此一来,我们便可以不使用 vuex 就实现了无视组件层级的事件监听与参数传递。

奇妙趁热打铁,既然了解了这种传参方式,不妨在项目中试一试:

11d36b920f7b79f2.png

有这样一部分逻辑需要开发:Parent A 组件中有需要动态改变的数据,该数据可以在子组件 Child B 及 孙组件 Grandson A 中触发变化;与此同时,Parent B 中的数据展示同样会被 Child B 中的触发变化所影响。这种情况下,this.$public.$emitthis.$public.$on 的便利性便得到了充分展现:

Parent A :

changeDataA (res) {
  // 在 Parent A 中接收参数,进而变化数据
}

this.$public.$on("change_data",(res) => {
    changeData(res);
});

Child B :

changeDataFromChildB (param) {
    this.$public.$emit("change_data", param);
}

changeDataFromChildB(param);  // 在 Child B 中触发数据变化

Grandson A :

changeDataFromGrandsonA (p) {
    this.$public.$emit("change_data", p);
}

changeDataFromGrandsonA(p);  // 在 Grandson A 中触发数据变化

Parent B :

changeDataB (res) {
  // 在 Parent B 中接收参数,进而变化数据
}

this.$public.$on("change_data",(res) => {
    changeDataB(res);
});

奇妙迅速写完了上面的代码,在感受到这种传参方式带来的便利性的同时,却也多了一份担心,这种方法固然方便,但是较为随意的发布/订阅模式,会让组件之间的联系越来越混乱,一定要慎重使用才好,并且组件的监听不应该是一直存在的,应该主动释放才更合理:

Parent A/Parent B:

destroyed() {
    this.$bus.$off('change_data');
}

长老的进阶考验(项目优化)

时间过得很快,奇妙在慧采星球已经一月有余。就在昨天,新版的 订单中心 发布上线了,全宇宙的用户又一次目睹了新版慧采的风采。

11d36b920f7b79f2.png

正在大侠和奇妙兴高采烈的时候,C 长老走了进来,“做的不错,接下来开始你们第二阶段的考验,慧采 PC 项目运行的时日已久,存在着大大小小的问题,你们二人要尝试去发现它们,解决它们,让项目开发能够更顺畅。”

二人听罢,心中都已勘破长老的用意。这段时间的开发,奇妙的确发现一些亟需优化的点。

打包速度问题

项目的打包速度存在较大问题,每次打包要 10 分钟以上,实在是太慢了。如果遇到问题要重新打包,或者碰到紧急的上线,在这漫长的 10 分钟里,开发者简直就像身置地狱一般煎熬。

11d36b920f7b79f2.png

为了解决这个硬伤,奇妙开始定位问题,和大侠商量后决定用二分法来找到是在哪个分支开始打包变慢的,经过反复的尝试后,终于将问题锁定到了一次大规模的 css 文件引入上。

let data = `@import './theme/${params}-theme.scss'`;
fs.writeFile(path.resolve(__dirname, "./../asset/css/theme.scss"), data, () => {})

由于 theme.scss 文件在多个文件中被引入,导致 data 也被多次引入,但 ${params}-theme.scss 这类文件体积较大,且只需要在个别文件中使用,如此大费周章的引入是不合理的,正确的方法应该是按需引入,在需要它的文件中予以引入即可。

修改后,打包的速度终于降下来了,从原来的 10 几分钟降到了 1 分钟,大大节省了项目的打包时间和热更新时间。

Before:

11d36b920f7b79f2.png

After:

11d36b920f7b79f2.png

大侠呆呆看着这 1 分钟的打包速度:“我滴个亲娘嘞,这要早点把这个问题解决,咱们早就学成回家了!”

打包失败问题

在开发过程中,奇妙发现每次 build 或者 upload 的时候,第一次都是不成功的,会报出来很多 TS 语法检查的错误,这个问题在之前打包需要 10 分钟的时候会有更严重的影响,因为报错通常是在最后发生的,开发者苦苦等了 10 分钟后,控制台却抛出了一片红色的错误提示,这片红色会带给人无尽的绝望。

11d36b920f7b79f2.png

在优化了打包速度后,这个问题的影响强度得以降低,每次就算是报错,也只不过是多等了一分钟。但是这个问题终究要解决,一旦解决了,便可以令打包效率直接提升一倍。

在之前的开发中,奇妙较少接触 TS 开发的项目,不过今天既然遇到了,就要仔细研究一番,为什么要使用 TS:

要理解 TS ,首先要了解一下静态语言和动态语言:

11d36b920f7b79f2.png

JS 是动态语言,即弱类型语言,很多人会误认为 TS 是强类型语言。但是要明确一点,TS 是有类型的可以编译到纯 JS 的 JS 超集,这是它最大的亮点。 TS 不是「强类型」,是能够执行类型检查的「弱类型」,通俗点说 TS 弥补了 JS 作为一门动态弱类型脚本语言的缺点,类型检查功能既能够帮助开发者及时发现代码中的错误,又保留了 JS 的灵活。TS 相较于 JS 有以下优点:

(1)编译阶段即可发现类型不匹配的错误: IDE 下可以做到智能提示,智能感知 bug ,不用等到运行时才能发现错误,提高代码的开发效率。

(2)类型就是最好的注释: 静态类型对阅读代码是友好的,对于编译器来说,类型定义可以让编译器揪出隐藏的 bug 。

(3)提高重构的效率: 当接口返回的字段发生变化,需要全局搜索后逐一修改。在 TS 中,只需把数据对应的 Interface 做更改,再重新编译一次即可。

看到这里,奇妙明白了元老开发者们使用 TS 的良苦用心,不过由于项目庞大,开发者众多,项目中存在着越来越多的不规范写法,其中类型不规范的问题占据多数,开发者习惯赋予变量 any 类型来暂时逃避 TS 的类型检查,但是这样做便失去了使用 TS 的意义,不利于项目的长期建设与维护。

除此之外,有的开发者不指定变量的类型,在开发中,按照写 JS 的习惯随意赋予变量不同类型的值,这也就导致了在编译检查的时候产生了大量报错。

奇妙暂时关闭了 TS 检查,在有报错的文件顶部加上一行代码,即可以让本文件跳过检查:

// @ts-nocheck

报错消失了,打包的效率瞬间提升了一倍。但是这种做法无异于掩耳盗铃,根本问题依然存在。“看来要抽时间整体搞一搞这里了。”奇妙思忖到。

晨来暮往,倏忽间隆冬已至。这一日清晨,C 长老来到了奇妙的房间:“年轻人,这段时间的考验你已经通过。如今,我们的慧采 PC 新版本被更多的用户使用着,也收获了无数星球给予的好评,虽然它还不够完美,但是慧采星球的子民们会不断完善它的,你且回家探望,择日再来完成你接下来的考验吧。”

奇妙连连点头,离家时日已多,确实思乡心切。少年背起行囊,回想起自己这段开发奋斗的时光,嘴角扬起了微笑。

未完待续...


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK