前端优化的新思考

2020.06.27

前提

我是喜欢做一些前端优化相关的工作的,最近又做了一些,也踩了一些坑。于是就分享记录一下。

之前遇到的问题

之前遇到的显著问题是由于历史债,或者说为了省事,在做一些webpack相关的流程的时候,采用了在入口处将所有资源都打出去的做法。然后将一些体积比较大的npm包,或者用处比较多的npm包,通过webpack的external方式来分离出去,通过这样的操作,让主入口的index.js文件尽可能地小。

这样的做法有什么优缺点呢?

优点:

只需要一个index.js文件,其他的资源都可以通过external的方式获取。

用户从着陆页跳转到其他的页面的时候,只要是在SPA之下,就无需再请求webpack打包后的其他资源,这样地话,打开这些页面会很快,因为资源早就预先加载过了。

缺点:

由于将整个项目中用到的所有资源都打包到了入口中(除了external的资源),致使有一些页面,尽管并不会被用户访问,也已经直接在打包的文件中了。那必然导致,这个index.js 体积很大,那么如何解决这个问题呢?

举一个形象的例子,当时的做法就是费了很大的力气,我用卡车拉了一车的水果到你家门口,西瓜,苹果,大鸭梨,应有尽有。你想要什么水果,我能够立刻就把你要的水果给到你。但是,我可能只是想要两个苹果,你却要为此浪费那么多汽油。

我的方案,其实是一个通用的方案,也就是React 官方文档推荐的code-splitting 的方式,用到了Suspense 以及Lazy 这两个方法来实现。

其他的,也就是Webpack 4中配置dynamic-imports 的方法了。

这里需要解释的是,其实我早在上家公司的时候,就已经使用这样的方式来进行code spliting。 之所以这次又做了这方面的工作,也是因为当前公司项目的一些技术债。

一个项目,多个项目

我来这家公司之前,对微前端只停留在认知层面,并没有太多了解。后来,来到这家公司,慢慢地发现原来还有我们这样的项目。

产品究竟是什么

产品是SAAS的,面向企业的软件。它的最终目的是希望能够帮助企业在遇到危机或者突发事件的时候,合理地调配,处理一些事情。比如飓风来袭之前,向飓风所在地的员工发送短信,邮件提醒,管理员需要能够快速执行一个预案,这个预案也可以说是一个任务列表,逐个任务去完成,直到所有任务完成,它的工作才算完成,这所有的一切都是这个软件提供的。

然而虽然大体上说是一个软件,但是更具体地来说,应该是多端的服务。

首先是需要一个管理终端,这个终端能够去为所有SAAS用户设置相应的权限,依据它们所购买的产品。这个管理终端,我们可以跟它叫做admin portal.

另外,还需要一个SAAS用户的管理终端,这个终端可以依据你购买的产品,提供相应的服务。这些服务,包括发送消息,包括发布任务等等。这个SAAS用户的管理终端,我们可以跟它叫做manager portal.

其次,还需要一个普通用户终端,这个终端接受来自manager portal的指令,例如下达的任务等。我们可以跟它叫做member portal.

我们现在搞清楚了,这样一个大的SAAS产品,需要多端来进行支持。

如果你还不明白,也可以有个更加通俗易懂的解释。我们普通用户逛的淘宝,其实是淘宝买家版,淘宝的卖家也需要一个终端来管理和维护商品,这就是淘宝卖家版。除此之外,还有一个淘宝的员工才能用的终端,通过它可以看到所有的卖家数据,可以在这个终端上面,设置一些全场优惠券。所以,我们可以看到,一个大的产品,下面相应地会有多端产品。

而即便是一个淘宝买家版,也会根据用户使用设备不同而分成不同版本,比如PC网页版,手机网页版,安卓手机APP版,苹果手机APP版,Ipad版本等等,所以一个产品需要维护的内容实际上是相当多的。

好了,我们现在不谈淘宝了,来继续说我们的SAAS产品。

现在为了说明清楚,而又不泄露一些公司的隐私。我们假设我们做的产品是一个类似于微盟或者有赞这样的一个产品,它可以给一些中小商家提供搭建电商店铺的能力。我们可以暂时给它起一个名字,就叫做微赞 。好了,现在我们继续来分析我们的微赞。

微赞有一个admin portal,它用来管理商户。还有一个manager portal, 它是卖家的平台,方便卖家上下架商品,做一些促销活动,查看最新的销售数据等等。当然,微赞还有一个member portal,它是消费者终端,可能是小程序,也可能是微信网页,还可能是APP,最终都是要让消费者消费的入口。

然而,如果微赞细分开来,又可以分成多个不同的模块。比如优惠券模块,又比如百亿补贴模块,这个时候,我们当然希望我们地微赞更稳定,这里的稳定从以下几个方面来谈:

  1. 各个功能模块,可以单独部署,这样每一个新的功能开发完成,都不会等待其他的模块,而可以直接上线。

  2. 各个功能模块之间应该相互独立,这样能更好地支撑第一点。项目也能足够简洁。

所以,这个时候,我们发现针对第一个问题,我们需要引入微服务的概念,这个时候,对于后端服务来说,每个服务就能够单独部署,上线。相对应的,前端要做好支持,也需要引入微前端的概念,这样的话,才好。

code spliting 又多种方式,在webpack的官方文档中,提到了两种比较推荐的方式。第一种方式,是我们以前就用到的webpack打包方式,其原理说白了,就是把那些external的资源拿出去,把那些common的资源也都拿出去,单独打包,对于这个入口来说,还是只有一个chunk。页面在初始化的时候,就已经把所有的资源全部加载上了,之后,你就用就好了。第二种方式,就是我们现在用的这种方式了。

我做的工作厉害吗?并不厉害,事实上,这个工作只需要按照文档按部就班就可以完成。

但是接下来,还是有一些不一样的东西的。

混合应用

前面说了,我们是想将我们的项目,进行微前端化处理的

这个时候,不光用到了动态加载,也在恰当的时机,用到了loadRemote , 这是我们自己写的一个加载远程模块的机制,通过它,我们可以实现类似node imort, require那样的效果。

之所以这样做的目的,是有一下几点。

第一,前面说了,我们会有多端产品,而这多端产品中,又有大量的业务组件是重复的,比如一个表单组件,这个表单组件并不单单是一个UI组件,也是我们自己定制好的一个业务组件,跟业务绑定的非常紧,随着开发和迭代,这个表单组件,可能每周都会有代码的提交,这个时候,我们希望对这个表单组件进行一个有效的管理。但是受限于基础设施,我们当时还并没有一个私有的npm库来完成这样一个工作,所以我当时就做了一个工作,通过loadRemote的方式,来把这个组件单独build出来,这样的话,这个组件也就能够被另外一端的产品访问了。不过值得一提的是,这个方案乍看起来还很不错,但是遇到了一个经典的问题,那就是跨域。这里可以详细说一说,比如我在manager 端对这个组件进行build,最后生成的域名是manager.test.com 而我想要在member 端引用这个组件,那么就会引起跨域的问题。解决这个问题,也很意外,非常凑巧的是,我们的后端在使用K8S的时候,就将两端的域做了整合。这样的话,如果访问member.test.com/mgr-static/abc ,它实际上会往manager.test.com/static/abc这个地址去解析。也就完美解决了跨域的问题。

第二,我们也发现,虽然用到了动态加载,但是由于有一些npm模块写得并不符合规范,导致出现了在多个chunk中某个npm包多次被打包进去的情况,这个时候,如果我们想要对打包后的chunk文件进行优化,一个方法就是将那些写得并不规范的npm包通过loadRemote的方式,单独打包出去,这样的话,它在最终打包的文件中,只会有一份结果,而不会像刚才我们所说的那样,在多个chunk中都有它的身影了。

事实上,关于这里提到的第一点,随着私有npm库的搭建,也许更加优雅的方式已经出现。关于这里提到的第二点,我也一直在找寻更加优雅的解决办法。

完稿时间: 20200917

2020.06.27

前提

我是喜欢做一些前端优化相关的工作的,最近又做了一些,也踩了一些坑。于是就分享记录一下。

之前遇到的问题

之前遇到的显著问题是由于历史债,或者说为了省事,在做一些webpack相关的流程的时候,采用了在入口处将所有资源都打出去的做法。然后将一些体积比较大的npm包,或者用处比较多的npm包,通过webpack的external方式来分离出去,通过这样的操作,让主入口的index.js文件尽可能地小。

这样的做法有什么优缺点呢?

优点:

只需要一个index.js文件,其他的资源都可以通过external的方式获取。

用户从着陆页跳转到其他的页面的时候,只要是在SPA之下,就无需再请求webpack打包后的其他资源,这样地话,打开这些页面会很快,因为资源早就预先加载过了。

缺点:

由于将整个项目中用到的所有资源都打包到了入口中(除了external的资源),致使有一些页面,尽管并不会被用户访问,也已经直接在打包的文件中了。那必然导致,这个index.js 体积很大,那么如何解决这个问题呢?

举一个形象的例子,当时的做法就是费了很大的力气,我用卡车拉了一车的水果到你家门口,西瓜,苹果,大鸭梨,应有尽有。你想要什么水果,我能够立刻就把你要的水果给到你。但是,我可能只是想要两个苹果,你却要为此浪费那么多汽油。

我的方案,其实是一个通用的方案,也就是React 官方文档推荐的code-splitting 的方式,用到了Suspense 以及Lazy 这两个方法来实现。

其他的,也就是Webpack 4中配置dynamic-imports 的方法了。

这里需要解释的是,其实我早在上家公司的时候,就已经使用这样的方式来进行code spliting。 之所以这次又做了这方面的工作,也是因为当前公司项目的一些技术债。

一个项目,多个项目

我来这家公司之前,对微前端只停留在认知层面,并没有太多了解。后来,来到这家公司,慢慢地发现原来还有我们这样的项目。

产品究竟是什么

产品是SAAS的,面向企业的软件。它的最终目的是希望能够帮助企业在遇到危机或者突发事件的时候,合理地调配,处理一些事情。比如飓风来袭之前,向飓风所在地的员工发送短信,邮件提醒,管理员需要能够快速执行一个预案,这个预案也可以说是一个任务列表,逐个任务去完成,直到所有任务完成,它的工作才算完成,这所有的一切都是这个软件提供的。

然而虽然大体上说是一个软件,但是更具体地来说,应该是多端的服务。

首先是需要一个管理终端,这个终端能够去为所有SAAS用户设置相应的权限,依据它们所购买的产品。这个管理终端,我们可以跟它叫做admin portal.

另外,还需要一个SAAS用户的管理终端,这个终端可以依据你购买的产品,提供相应的服务。这些服务,包括发送消息,包括发布任务等等。这个SAAS用户的管理终端,我们可以跟它叫做manager portal.

其次,还需要一个普通用户终端,这个终端接受来自manager portal的指令,例如下达的任务等。我们可以跟它叫做member portal.

我们现在搞清楚了,这样一个大的SAAS产品,需要多端来进行支持。

如果你还不明白,也可以有个更加通俗易懂的解释。我们普通用户逛的淘宝,其实是淘宝买家版,淘宝的卖家也需要一个终端来管理和维护商品,这就是淘宝卖家版。除此之外,还有一个淘宝的员工才能用的终端,通过它可以看到所有的卖家数据,可以在这个终端上面,设置一些全场优惠券。所以,我们可以看到,一个大的产品,下面相应地会有多端产品。

而即便是一个淘宝买家版,也会根据用户使用设备不同而分成不同版本,比如PC网页版,手机网页版,安卓手机APP版,苹果手机APP版,Ipad版本等等,所以一个产品需要维护的内容实际上是相当多的。

好了,我们现在不谈淘宝了,来继续说我们的SAAS产品。

现在为了说明清楚,而又不泄露一些公司的隐私。我们假设我们做的产品是一个类似于微盟或者有赞这样的一个产品,它可以给一些中小商家提供搭建电商店铺的能力。我们可以暂时给它起一个名字,就叫做微赞 。好了,现在我们继续来分析我们的微赞。

微赞有一个admin portal,它用来管理商户。还有一个manager portal, 它是卖家的平台,方便卖家上下架商品,做一些促销活动,查看最新的销售数据等等。当然,微赞还有一个member portal,它是消费者终端,可能是小程序,也可能是微信网页,还可能是APP,最终都是要让消费者消费的入口。

然而,如果微赞细分开来,又可以分成多个不同的模块。比如优惠券模块,又比如百亿补贴模块,这个时候,我们当然希望我们地微赞更稳定,这里的稳定从以下几个方面来谈:

  1. 各个功能模块,可以单独部署,这样每一个新的功能开发完成,都不会等待其他的模块,而可以直接上线。

  2. 各个功能模块之间应该相互独立,这样能更好地支撑第一点。项目也能足够简洁。

所以,这个时候,我们发现针对第一个问题,我们需要引入微服务的概念,这个时候,对于后端服务来说,每个服务就能够单独部署,上线。相对应的,前端要做好支持,也需要引入微前端的概念,这样的话,才好。

code spliting 又多种方式,在webpack的官方文档中,提到了两种比较推荐的方式。第一种方式,是我们以前就用到的webpack打包方式,其原理说白了,就是把那些external的资源拿出去,把那些common的资源也都拿出去,单独打包,对于这个入口来说,还是只有一个chunk。页面在初始化的时候,就已经把所有的资源全部加载上了,之后,你就用就好了。第二种方式,就是我们现在用的这种方式了。

我做的工作厉害吗?并不厉害,事实上,这个工作只需要按照文档按部就班就可以完成。

但是接下来,还是有一些不一样的东西的。

混合应用

前面说了,我们是想将我们的项目,进行微前端化处理的

这个时候,不光用到了动态加载,也在恰当的时机,用到了loadRemote , 这是我们自己写的一个加载远程模块的机制,通过它,我们可以实现类似node imort, require那样的效果。

之所以这样做的目的,是有一下几点。

第一,前面说了,我们会有多端产品,而这多端产品中,又有大量的业务组件是重复的,比如一个表单组件,这个表单组件并不单单是一个UI组件,也是我们自己定制好的一个业务组件,跟业务绑定的非常紧,随着开发和迭代,这个表单组件,可能每周都会有代码的提交,这个时候,我们希望对这个表单组件进行一个有效的管理。但是受限于基础设施,我们当时还并没有一个私有的npm库来完成这样一个工作,所以我当时就做了一个工作,通过loadRemote的方式,来把这个组件单独build出来,这样的话,这个组件也就能够被另外一端的产品访问了。不过值得一提的是,这个方案乍看起来还很不错,但是遇到了一个经典的问题,那就是跨域。这里可以详细说一说,比如我在manager 端对这个组件进行build,最后生成的域名是manager.test.com 而我想要在member 端引用这个组件,那么就会引起跨域的问题。解决这个问题,也很意外,非常凑巧的是,我们的后端在使用K8S的时候,就将两端的域做了整合。这样的话,如果访问member.test.com/mgr-static/abc ,它实际上会往manager.test.com/static/abc这个地址去解析。也就完美解决了跨域的问题。

第二,我们也发现,虽然用到了动态加载,但是由于有一些npm模块写得并不符合规范,导致出现了在多个chunk中某个npm包多次被打包进去的情况,这个时候,如果我们想要对打包后的chunk文件进行优化,一个方法就是将那些写得并不规范的npm包通过loadRemote的方式,单独打包出去,这样的话,它在最终打包的文件中,只会有一份结果,而不会像刚才我们所说的那样,在多个chunk中都有它的身影了。

事实上,关于这里提到的第一点,随着私有npm库的搭建,也许更加优雅的方式已经出现。关于这里提到的第二点,我也一直在找寻更加优雅的解决办法。

完稿时间: 20200917

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,126评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,254评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,445评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,185评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,178评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,970评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,276评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,927评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,400评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,883评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,997评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,646评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,213评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,204评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,423评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,423评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,722评论 2 345