深度解读字节跳动Web Infra发起的 Modern.js 开源项⽬

{"type":"doc","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"7⽉,字节跳动 Web Infra 做过⼀次主题为 "},{"type":"text","marks":[{"type":"strong"}],"text":"《迈⼊现代 Web 开发(字节跳动的现代 Web 开发实践)》"},{"type":"text","text":" 的分享,在分享中他们梳理了「传统前端技术栈」的典型组成部分,展示了其中每个部分都存在的瓶颈问题。也介绍了在这些问题的驱动下,业界正在发⽣从「传统 Web 开发范式」到「现代 Web 开发范式」的「范式转移」。在这个分享的最后预告了 Modern.js 开源项⽬。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"10 ⽉ 27-28 ⽇举办的 "},{"type":"text","marks":[{"type":"strong"}],"text":"稀⼟开发者⼤会"},{"type":"text","text":" 上,字节跳动 Web Infra 正式发起 "},{"type":"link","attrs":{"href":"https:\/\/xie.infoq.cn\/article\/33788df9613aef714809f08af","title":"xxx","type":null},"content":[{"type":"text","text":"Modern.js "}]},{"type":"text","text":"开源项⽬。在专场分享《介绍 Modern.js——"},{"type":"link","attrs":{"href":"https:\/\/mp.weixin.qq.com\/s?__biz=MzUxMzcxMzE5Ng==&mid=2247510615&idx=1&sn=3f6d6098e6e1f906e6b0c54247d9aba1&chksm=f9521f14ce259602d4410c3129dd72448881cdf7c2b21bbd9c9da1ec69a973ac38c36004bb00&scene=27#wechat_redirect","title":"xxx","type":null},"content":[{"type":"text","text":"现代 Web ⼯程体系"}]},{"type":"text","text":"》中,⾸先介绍了业界和字节内部的前端开发、 Web 开发在发⽣哪些影响深远的变⾰,从这些变⾰的⻆度,展示了基于 Modern.js 的现代 Web 开发。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"这些变⾰包括:"}]},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"更多「前端开发者」成为「应⽤开发者 \/ 产品开发者」"}]}]}]},{"type":"paragraph","attrs":{"indent":1,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"先讨论了什么根本因素在驱动这种转变,\"Frontend Focused\" 的意义,指出服务器端开发⻔槛不断降低的⻓期趋势、原有基建的缺陷,⽤ Modern.js 演示了「⼀体化、⽆服务器化的全栈开发」、「以客⼾端为中⼼的 Web 开发」"}]},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"从「前后端分离」到「前后端⼀体化」"}]}]}]},{"type":"paragraph","attrs":{"indent":1,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"分析了「前后端分离」产⽣的两种前端项⽬,为什么其中⼀种是「假分离」,另⼀种「不完整」,⽤ Modern.js 演示了「前后端⼀体化」在哪些地⽅带来改变"}]},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Meta Framework 取代传统「前端三剑客」"}]}]}]},{"type":"paragraph","attrs":{"indent":1,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"分析了四代「前端三剑客」,以及每⼀代都被下⼀代的成员「吞并」的规律,结合字节内部的 真实案例,讲解了 Meta Framework 的⻆⾊"}]},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"形成基于「前端技术」的成熟 GUI 软件研发体系"}]}]}]},{"type":"paragraph","attrs":{"indent":1,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"先明确了「前端技术」的定义, 结合 Modern.js 的功能和设计,讨论了如何实现「充分抽象」,才能 解决 DX 和 UX 的⽭盾"}]},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"智能化、平台化、低码化"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"接下来系统介绍了 "},{"type":"text","marks":[{"type":"strong"}],"text":"Modern.js 的六⼤要素"},{"type":"text","text":",包括:"}]},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"普及:现代 Web 开发范式"}]}]}]},{"type":"paragraph","attrs":{"indent":1,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"回顾了这种范式的 9 ⼤主要特征"}]},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"核⼼:现代 Web 应⽤(MWA)"}]}]}]},{"type":"paragraph","attrs":{"indent":1,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"从 Universal App、⼀体化、应⽤架构、Runtime API 这四个⻆度来了解 MWA。"}]},{"type":"paragraph","attrs":{"indent":1,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在应⽤架构部分介绍了 Modern.js 中 Model 的设计和背景"}]},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"内置:前端⼯程最佳实践◦ 列举了⼏个典型的最佳实践,包括 Post-Webpack Era 的新⼯具趋势、Modern.js 的 Unbundled 开发,Modern.js 推荐的「CSS 三剑客」,Modern.js 微前端项⽬跟直接使⽤ Garfish 的微前端项⽬对⽐、模块⼯程⽅案和 Monorepo ⼯程⽅案中的最佳实践。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"包含:Web 开发全流程"}]}]}]},{"type":"paragraph","attrs":{"indent":1,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"演示了 Modern.js 在「编码」环节的微⽣成器功能、在「调试环节」的微前端调试"}]},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"提供:⼯程标准体系"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"⿎励:定制⼯程⽅案"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"末尾介绍了除已经发布的开源项⽬,还有哪些对现代 Web 开发者有帮助的事情在发起和推进中。介绍了 Modern.js 当前⾼优的社区计划。"}]},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"分享实录"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"⼤家好,我是来⾃"},{"type":"text","marks":[{"type":"strong"}],"text":"字节跳动 Web Infra"},{"type":"text","text":" 的宋振伟,在字节跳动,我们部⻔负责打造和发展「Web 技术中台」和「前端研发体系」。"}]},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/40\/40622193d107ab32eecc86cd4d28d9ce.webp","alt":"图片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"今年 7⽉,我们做过⼀次主题是 "},{"type":"text","marks":[{"type":"strong"}],"text":"《字节跳动的现代 Web 开发实践》"},{"type":"text","text":" 的分享,在分享中我们梳理了 「传统前端技术栈」的典型组成部分,展示了其中每个部分都存在的瓶颈问题。"}]},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/ad\/ade4c4b471d7a7ced40be78584520bb0.webp","alt":"图片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"也介绍了在这些问题的驱动下,业界正在发⽣从「传统 Web 开发范式」到「现代 Web 开发范式」的 「范式转移」。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在这个分享的最后也预告了 "},{"type":"text","marks":[{"type":"strong"}],"text":"Modern.js"},{"type":"text","text":" 开源项⽬。"}]},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/2f\/2f410668eb7967cb386814dce2fcab0a.webp","alt":"图片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"昨天上午的主题演讲中,字节跳动正式发布了 "},{"type":"text","marks":[{"type":"strong"}],"text":"Modern.js"},{"type":"text","text":"。今天的专场分享,我想结合字节内部的变⾰和实践,介绍基于 Modern.js 的现代 Web 开发,和所带来的实际效果。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"议程"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"今天的分享可以分成三个部分。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"昨天的主题演讲有说到,整个业界和字节内部的前端开发、Web 开发,都在发⽣着影响深远的变⾰,我们⾸先从这些变⾰的⻆度,看下基于 Modern.js 的现代 Web 开发是什么样⼦,有什么区别。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"然后,我们整体看下 Modern.js 有哪些要素和收益。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"最后再看下除了已经发布的开源项⽬,还有哪些对现代 Web 开发者有帮助的事情在发起和推进中。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我们先来看"},{"type":"text","marks":[{"type":"strong"}],"text":"第⼀部分「现代 Web 开发」"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"⼀、基于 Modern.js 的现代 Web 开发"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"1. 更多「前端开发者」成为「应⽤开发者 \/ 产品开发者」"}]},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/60\/600532d2cee74317f20bfd5e9352ee7b.webp","alt":"图片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"可以从这五个⽅⾯的变⾰,来展示「现代 Web 开发」是什么样⼦。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"这五个变⾰之间是承前启后的关系。⾸先最根本的推动⼒,不是来⾃技术侧,不是前端开发者⼀厢情愿的发展⾃⼰主观的技术偏好,⽽是在互联⽹和 IT ⾏业、市场需求、⽤⼾产品这⼀侧的⼤趋势,需要更多「前端开发者」成为「应⽤开发者」或「产品开发者」,⿎励和倒逼着技术领域,不断产⽣更有利于这种需求的技术形态和基础设施。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"当传统技术范式遇到瓶颈,不再能进⼀步适应需求,就会发⽣「范式转移」,出现从⼀开始就针对这种需求重新设计的、新⼀代的技术范式。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"这种转变推动前端技术领域出现了「从分离到⼀体化」、新⼀代「前端三剑客」的变⾰。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"这种变⾰带来的新⼀代技术标准和基础设施,开始形成完全基于「前端技术」的成熟 GUI 软件研发体系,并且进⼀步朝着平台化、低码化的⽅向发展。"}]},{"type":"heading","attrs":{"align":"center","level":5},"content":[{"type":"text","marks":[{"type":"underline"}],"text":"\"Frontend Focused\" 的意义"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/e1\/e15b91e59755987cd5d74892bfd0bc1b.webp","alt":"图片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我们刚才⼀直在说「前端」,「前端」这个概念似乎⼀直是只有开发者才关⼼的技术细节,但最近⼏年,却变成了商业领域、投资机构也都很关⼼的事情,全球市场上涌现出越来越多的新⼀代云平台和研发⼯具产品,多数都涉及前端研发特有的需求和模式,其中还有很多像 Vercel 这样明确「专注于前端」的产品。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"就像幻灯⽚上这张图,云计算和研发产品最初是从最接近机器的底层开始发展,从虚拟化,到容器编排,到基于容器技术的各种平台化、服务化的研发⼯具形态,这个阶段是后端技术主导的,整个趋势 是越来越向上层发展,越来越接近市场和商业价值最终所在的地⽅——也就是⾯向⽤⼾的产品,因此 必然会发展到前端技术主导的抽象层,让应⽤开发和产品开发能更专注于⽤⼾需求,⽽越来越不需要关⼼服务器端的复杂性和专业技术细节。"}]},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/04\/04f8dcf51254bc02e575a113b5a40022.webp","alt":"图片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"所以市场需求会趋向于推动应⽤开发⽅式往「专注于前端」的⽅向的发展,专注于前端就是专注于用户,⽽专注于⽤⼾是多数企业、产品的根本利益所在。"}]},{"type":"heading","attrs":{"align":"center","level":5},"content":[{"type":"text","marks":[{"type":"underline"}],"text":"最⼤的开发者群体"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/fa\/fae5429a5359a525fbc0c7114df71eff.webp","alt":"图片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"另⼀⽅⾯,从进⼊移动互联⽹时代开始就不断⼤幅增加的应⽤开发需求,现在不但没减弱,反⽽还在加强,⽐如幻灯⽚上 IDC 的预测,要满⾜这么庞⼤的应⽤开发需求,传统开发⽅式和⼈才储备是很不够的,需要让尽可能多的开发者能独⽴、完整的开发这些应⽤,⽽前端技术栈的开发者,正是最⼤的开发者群体和技术社区。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"所以在用户、产品、市场这⼀侧,⼀直有趋势和压⼒,需要更多「前端开发者」成为「应⽤开发者」 或「产品开发者」,⿎励和倒逼着技术领域,不断产⽣更有利于这种需求的技术形态和基础设施。"}]},{"type":"heading","attrs":{"align":"center","level":5},"content":[{"type":"text","marks":[{"type":"underline"}],"text":"服务器端开发⻔槛不断降低"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/59\/597362cda7d9c96eec5219cf7258dcbb.webp","alt":"图片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在这种客观趋势的推动下,基于 Web 技术的应⽤开发中,服务器端的占⽐和⻔槛⼀直在不断下降, 国内⼤⼚的中台建设,提供了⼤量不跟特定客⼾端捆绑、专注于数据需求和底层业务逻辑的 API,让 产品开发更聚焦在上层的客⼾端业务逻辑。还有 BaaS 和基于云函数的后端云 Serverless,也进⼀步降低服务器端的⻔槛,让前端开发者能更独⽴的、端到端的完成产品开发。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"但要进⼀步降低⻔槛,提⾼效率,这些基础设施的⼀个缺陷就暴露出来,就是他们都把应⽤依赖的 API,放在应⽤项⽬之外维护,跟前端研发是割裂的。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"还有⼀个缺陷是它们不解决 API 之外的服务器端需求,⽐如路由、SSR 等。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"有⼀个字节内部的典型例⼦,前端开发者在⾃⼰实现的 SSR 项⽬中,始终⽤ HTTP ⽅式请求外⽹域 名的 API 来获取数据,导致 SSR 频繁超时,HTML 响应慢严重影响⽤⼾体验。可以给前端开发者做培训,让他们具备⾜够的服务器端开发思维和知识,知道要在 SSR 环节切换成内⽹的请求⽅式,还要考虑缓存机制等,但更根本的解决⽅法是屏蔽这种服务器端问题和实现细节,⾃动处理这些问题。"}]},{"type":"heading","attrs":{"align":"center","level":5},"content":[{"type":"text","marks":[{"type":"underline"}],"text":"⼀体化、⽆服务器化的全栈开发"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/1e\/1e037cca4a0ad5305998b52bf383b3a5.webp","alt":"图片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"因此服务器端⻔槛不断降低的趋势,⾃然会发展到「⼀体化、⽆服务器化的做全栈开发」的阶段,让前端开发者直接开发 「接近纯前端的项⽬」⽽不是 「Node.js 框架项⽬」,感觉就像没有服务器⼀样。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"幻灯⽚上是这次分享中第⼀个 Modern.js 的 demo, 左侧是⼀个 Modern.js 应⽤项⽬的完整⽬录结构,src\/ ⽬录下的应⽤主体,可以像调⽤普通函数⽂件⼀样访问 api\/ ⽬录下的 BFF 函数,不需要了解网络细节,Modern.js 会⾃动基于 BFF 函数的路径、参数等⾃动⽣成 REST API,在 CSR 过程中⾃动请求。"}]},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/fa\/fa5a49fa7b273106dc7bf223e4a6a226.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"接下来我们在 package.json 的 modernConfig 配置⾥启⽤ SSR、「差异分发」和「⾃动 Polyfill」,可以看到这些功能不要增加代码逻辑,只需要静态开关配置。"}]},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/34\/34df14d1609db4d61be89b558c51d8af.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"构建后,幻灯⽚左侧可以看到产物⾥的 HTML 和 JS 都有 es6 和 es5 两个版本,⽤⼾访问时应⽤的时候,Modern.js 的 Web Server 会根据浏览器 UA 选择分发 es6 版本还是 es5 版本,也就是「差异化分发」。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"右边上⾯的图是现代浏览器的访问结果,不会返回任何 polyfill 代码, 下⾯的图是低版本浏览器的访问结果, Web Server 会⾃动提供这个 UA 需要的 polyfill 代码。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"可以看到 Modern.js 不但⽀持⼀体化的开发 BFF,也满⾜ BFF 之外的服务器端需求,尽可能⾃动利⽤⾃带的 web server 去做性能优化和提供产品级的兼容性,同时开发体验仍然是⽆服务器化的。"}]},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/e9\/e9482ee4e3562d6858b81a39d65dd9d4.webp","alt":"图片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"之前我们启⽤了 SSR, 左侧图上⾼亮的 HTML ⽚段,已经包含了通过 BFF 请求到的数据,会根据应⽤运⾏的⽅式⾃动选择最⾼效的请求⽅式。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"这种⾃动优化不会阻碍开发者对技术细节的掌控,右边这张图展示了 BFF 函数也会⽣成标准的 REST API,可以⼿动调⽤。"}]},{"type":"heading","attrs":{"align":"center","level":5},"content":[{"type":"text","marks":[{"type":"underline"}],"text":"以客⼾端为中⼼的 Web 开发"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/9d\/9db8a7487817ca54164213016aa952fa.webp","alt":"图片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"这种⼀体化、⽆服务器化的全栈开发进⼀步发展,⾃然会得到⼀种客⼾端为中⼼的 Web 开发⽅式。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"⽐如在传统 Web 开发中,要实现常⻅的权限识别和重定向,除了前端⻚⾯的逻辑,还需要在服务器端的路由中,添加实现跳转的业务逻辑。⽐如图上,在访问 home ⻚⾯的时候根据 cookie 的值决定 要不要重定向到登陆⻚⾯。"}]},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/d0\/d04738e7d3a59fc7088c443c0fc4745c.webp","alt":"图片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"同样的需求,在以客⼾端为中⼼的 Web 开发⽅式中,可以⼀体化的在客⼾端代码⾥实现,⽐如前⾯已经启⽤ SSR 的 Modern.js 项⽬,只需要添加 Redirect 组件,就可以实现和刚才完全相同的权限识别和重定向效果,访问⻚⾯时会根据 cookie 决定要不要返回 302 状态码。整个实现过程是客⼾端思维的。"}]},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/0c\/0cc493376fb440ccf3218535eb32f627.webp","alt":"图片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"以客⼾端为中⼼,不代表不能掌控服务器端,不能直接写服务器端业务逻辑。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果已经习惯 Node.js 框架的开发⽅式,可以 server ⽬录的钩⼦⽂件⾥,对框架⾃带的 Web Server 添加⾃定义逻辑,⽐如⾃由添加中间件,可以在这个局部,⽤⾃⼰熟悉的传统 Web 开发⽅式实现权限识别和重定向。"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"2. 从「前后端分离」到「前后端⼀体化」"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Web 项⽬的技术栈也在转变,相当于是先发展出「前后端分离」,然后⼜⽤新⽅式回归了 「前后端⼀体化」。"}]},{"type":"heading","attrs":{"align":"center","level":5},"content":[{"type":"text","marks":[{"type":"underline"}],"text":"「前后端分离」"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/fe\/fee12f45cdd725fa12456fbcdf3d6eb5.webp","alt":"图片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"以前的 Web 开发就像图上这个 Ruby on Rails 项⽬,粉⾊的前端代码,「寄居」在 "},{"type":"text","marks":[{"type":"strong"}],"text":"绿⾊的"},{"type":"text","text":" 后端 Web 框架项⽬中的,前端和后端会互相⼲扰互相拖累,做⼯程建设也⽐较⿇烦。"}]},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/69\/6968937d4f8ebdcde67ac676772aeac8.webp","alt":"图片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"之后 Web 开发普遍转变到「前后端分离」的模式,分离后的前端项⽬和后端项⽬,都倾向特定的类型。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"后端项⽬不倾向包含 Web 的功能,⽽这时的前端项⽬可以归纳为两种类型。"}]},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/bf\/bfd469d6110960ed01a5394da108bd22.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"MERN 这种项⽬类型相当于⼜回到了分离前的状态,整个项⽬是基于 Node.js 框架的,前端被嵌在⾥ ⾯。这种结果其实反映出「前后端分离」实现的更多是分⼯上的分离,⽽不是技术架构上的分离,在技术架构上仍然没有摆脱以服务器端框架为中⼼的 Web 开发。"}]},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/a1\/a1d7af80b611febc6beb3977b6337a3a.webp","alt":"图片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"从 MERN 项⽬的结构可以看到,它不但是假分离,⽽且也不算⼀体化,React 代表的前端部分和 Node.js 框架代表的后端部分,在项⽬⾥是泾渭分明的,没有真正融合到⼀起去。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"使⽤ Node.js 框架的项⽬,多数属于这个类型。"}]},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/88\/88518c5a942fb5650d72e6884f38da6e.webp","alt":"图片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"「前后端分离」模式中另⼀种前端项⽬类型,我们称作「⽼⼀代 JAMstack」,这种类型没有假分离问题,就是纯粹的前端项⽬。可以实现 SPA 和 MPA,也能基于编译⼯具实现 SSG(静态⽹站⽣成)。靠静态托管来运⾏,⿎励在 CSR 中调⽤ API 满⾜动态的应⽤需求。"}]},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/93\/93683ec42d3f4908483174310772cf8c.webp","alt":"图片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"「⽼⼀代 JAMstack」最⼤的问题是,虽然分离成了独⽴的项⽬,却不⾜以承担完整的应⽤开发,只能产出静态⽂件,依靠外部的 Web 服务器去运⾏,⽆法实现 SSR,三⼤组成部分⾥的 API,也需要 在项⽬之外,⽤云函数、独⽴后端项⽬等⽅式来实现,不能跟着项⽬⼀起迭代。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"⽤ CRA 或直接⽤ webpack 搭建的项⽬,多数属于这个类型。"}]},{"type":"heading","attrs":{"align":"center","level":5},"content":[{"type":"text","marks":[{"type":"underline"}],"text":"「前后端⼀体化」"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/5a\/5a1eadfc5490d4e600300d880b1b25da.webp","alt":"图片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在前⾯说的需要更多「前端开发者」成为「应⽤开发者」的背景下,新⼀代的 JAMstack 项⽬⽤「客⼾端为中⼼」的「前后端⼀体化」⽅式,解决了上⾯说的问题。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"新⼀代 JAMstack 的三⼤组成部分虽然没变,对应的内容却有很⼤变化,JS 部分更加函数化和组件化、以 JS 为中⼼,HTML 可以完全不在项⽬中出现,⾃动⽣成。BFF API 变成项⽬⾃包含。和之前简单的静态托管相⽐,基于前端 Serverless 平台可以实现 SSR、SPR 等动态能⼒,即使是静态⻚⾯,也可以获得很多好处,⽐如前⾯展示的 「差异化分发」。"}]},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/1d\/1ddb2ac9ab97663615e0890690959b81.webp","alt":"图片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"图上是⽤ Modern.js 的 demo 来展示新⼀代 JAMstack 项⽬。在开发中只需要聚焦在 JS 代码上,不 论是 SPA 还是 MPA,HTML 都是⾃动⽣成的。不论是 SSR 渲染的代码,还是 API 逻辑,构建之后按照规范输出到 dist 下的不同⽬录,构建产物规范是 Serverless 友好的,⽀持把 Web、SSR、BFF 等 拆分成不同服务器。"}]},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/56\/566a17da30207af5851e9178beb7fe55.webp","alt":"图片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"前⾯提到 Modern.js 倾向于 JS 为中⼼、⾃动⽣成 HTML。但不阻碍开发者⾃⼰掌控 HTML。图上是 Modern.js 渲染 HTML 的默认模板。"}]},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/cd\/cd76939101e24dbf98c73888b7423d04.webp","alt":"图片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"⼀体化 BFF 的调⽤,在前⾯的例⼦演示过,这⾥可以看到 BFF 函数的⽂件路径是有约定的,可以实 现任意设计的 REST API。"}]},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/0f\/0f2b3e01d789e6ca8532958dda4e1ec8.webp","alt":"图片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"构建产物会针对 BFF、Web、SSR 分别⽣成独⽴可运⾏的 Server,这是对前端 Serverless 平台更友好的,Serverless 平台可以⾃主选择让 BFF、Web、SSR ⽤不同⽅式在独⽴进程中运⾏,不会互相⼲扰。⽐如在 SSR 环节遇到 app 代码的的内存泄露导致 SSR 超时,Web Server 不受影响,可以⾃动降级到 CSR 模式,返回静态的 HTML 给⽤⼾作为兜底,⽤⼾的 HTML 请求始终不会超时或挂掉。"}]},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/9b\/9b1abad2099c22d7e0b150e6b9aac1e2.webp","alt":"图片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"对于 SSR,同样可以前后端⼀体化的开发,图⾥⾼亮的 useLoader 函数中的代码,同时适⽤于 SSR 和 CSR,如果这个 Loader 在 SSR 中已经预加载,CSR 就会⾃动跳过,否则会执⾏。"}]},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/64\/64c15cc5df8566df3c4483469e51f4e8.webp","alt":"图片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"SPR 相当于有缓存机制的 SSR,在 Modern.js ⾥也可以⼀体化的开发,只要使⽤这个预渲染组件。"}]},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/5a\/5a647984ff415cb0029f0cde9785b546.webp","alt":"图片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"SSG 实际上就是在编译时运⾏的 SSR,在 Modern.js ⾥只要配置 SSG 路由,就会⾃动启⽤这种编译逻辑,给路由⽣成静态 HTML。CSR、SSR、SSG 都是⽤同⼀份代码。"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"3. 新⼀代「前端三剑客」和 Meta Framework"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"除了在技术栈层⾯向「前后端⼀体化」转变,在⼯程层⾯,传统的「前端三剑客」也在转变成元框架这种新的⼯程基建。"}]},{"type":"heading","attrs":{"align":"center","level":5},"content":[{"type":"text","marks":[{"type":"underline"}],"text":"传统「前端三剑客」"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/9e\/9e5b9f16afc148e9bdf5bf50fbeb2b7d.webp","alt":"图片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"先来回顾下传统的「前端三剑客」,第 1 代和第 2 代如图上所示,也被⼤家熟知。⽽第 3 代「前端 三剑客」由视图框架、Node.js 命令⾏、Node.js 框架三个⽅向组成。"}]},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/ac\/acce2eb03192e8d3f74684a7f55d7679.webp","alt":"图片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"其中 Node.js 命令⾏代表了⼯程化,其中最典型的是像 Webpack 这样的打包⼯具,以及 Babel、 PostCSS 这样的编译⼯具。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"视图框架和 Node.js 框架很好理解,就是之前讨论的 MERN 项⽬中的前端和后端部分。"}]},{"type":"heading","attrs":{"align":"center","level":5},"content":[{"type":"text","marks":[{"type":"underline"}],"text":"第 4 代「前端三剑客」"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/77\/77a85cb2b5f5ad8e6ab71549a2c93737.webp","alt":"图片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"随着现代 Web 开发范式的发展,第 4 代「前端三剑客」的轮廓已经越来越明显,由元框架、前端 PaaS、低代码三个⽅向组成。其中低代码⽅向在昨天晚上稀⼟⼤会的低码专场已经介绍过,⽽ Modern.js 就属于元框架这个⽅向。"}]},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/6a\/6aecce87eb95763fc9565b6be9abfbff.webp","alt":"图片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"从这张图可以清楚的看到,每⼀代前端三剑客中,都有⼀个⽅向,把上⼀代前端三剑客完整包含在⾃⼰⾥⾯,变成不需要太关⼼的底层,让⾃⼰取代他们成为前端开发的新地基。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"第 3 代中的视图框架,就扮演这样的⻆⾊,把第⼆代的 HTML、CSS、JS 封装在⾃⼰⾥⾯,⽽第 4 代中的元框架,⼜对视图框架、Node.js 框架、Node.js 命令⾏做了整合和抽象,成为前端开发和⼯程建设性起点,元框架扮演了过去 Webpack、React 扮演的⻆⾊。"}]},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/1b\/1bb9cef94e87cc45e67a48d5b4f7ed7f.webp","alt":"图片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"这张 JS 框架的 S 曲线图,也能体现这种转变。在左边这个时期,发展的前沿、开发的起点,都是 React、Vue、Svelte 这样的视图框架,新的视图框架项⽬也层出不穷。现在已进⼊右边这个时期, 前沿收敛到基于 React 发展更上层的元框架。"}]},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/57\/57b76044cbcce095d220e7723ad52a1b.webp","alt":"图片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Modern.js 作为现代 Web ⼯程体系,是由元框架组成的,提供三⼤⼯程类型,⿎励开发者基于⼯程类型建设⾃⼰的业务⼯程⽅案。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"以字节内部的「⽕⼭引擎⼦应⽤⼯程⽅案」为例,初始化的⽬录结构没有什么变化,只在配置中默认加载了⾃⼰的框架插件,插件中通过 server 提供的 hook 修改渲染后的 HTML ,在原来的 HTML 上套了层壳,也就是右下⻆截图中⽕⼭引擎统⼀的顶栏和左侧导航栏。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"这样建设出来的⼯程⽅案,既能满⾜垂直场景的需求或⾃⼰的偏好,⼜能保持跟三⼤⼯程类型的兼容,⾃动获得 Modern.js 的能⼒和收益"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"4. 基于「前端技术」的成熟 GUI 软件研发体系"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在「前端开发者」成为「应⽤开发者」的⼤背景下,技术栈、⼯程基建的发展,开始形成基于「前端技术」的成熟 GUI 软件研发体系。"}]},{"type":"heading","attrs":{"align":"center","level":5},"content":[{"type":"text","marks":[{"type":"underline"}],"text":"什么是「前端技术」"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/97\/97d6744707c6f0f8353b03f762a5bb3e.webp","alt":"图片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"先明确⼀下我们⼀直说的前端技术,不是指做 UI 的技术,⽽是由 Web 原⽣语⾔、Web Runtime、 Web 技术⽣态组成的技术栈,不是只在浏览器⾥才有前端技术,⽽是有 Web Runtime、有 Web 语⾔的地⽅,就有前端技术。"}]},{"type":"heading","attrs":{"align":"center","level":5},"content":[{"type":"text","marks":[{"type":"underline"}],"text":"DX 和 UX 同样重要"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/ff\/ff431d6be0c5d84c3cd4387398f7b8ec.webp","alt":"图片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"传统前端开发不是成熟的软件研发体系,缺乏⾜够的抽象和基建,导致 DX 和 UX 始终存在⽭盾,此消彼涨。以往的产品开发中,习惯更重视 UX,这有两⽅⾯的原因,⼀来是因为产品是由产品主导,因此更重视 UX,不会过多关注开发者体验,再就是缺乏⾜够的抽象和基建,导致 DX 和 UX 之间必须牺牲⼀个。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在新⼀代更成熟的研发体系的⽀持下,已经可以实现 DX 和 UX 的同时最⼤化了,也从「更重视 UX」 转变为「DX 优先」的⽅式。"}]},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/5c\/5c90479e7b87c426a76053025390e204.webp","alt":"图片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"要实现 DX 和 UX 的同时最⼤化,需要充分的抽象。⽐如前⾯提到的 Modern.js 的这个例⼦,项⽬⾥只有三个⽂件,就具备全⾯的能⼒,包括⾃动 Polyfill、差异化分发、SSR 等,既具备产品级的 UX,有保持了 DX 的简单、开箱即⽤等。"}]},{"type":"heading","attrs":{"align":"center","level":5},"content":[{"type":"text","marks":[{"type":"underline"}],"text":"充分抽象"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/d3\/d3f7a24e39c4a29f41caf9f8922fc406.webp","alt":"图片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"要实现充分抽象,需要让项⽬从基于「库、⼯具」发展成基于「框架」,这两者的区别在图上表现的 ⽐较好。蓝底⽩边部分是项⽬开发者⾃⼰写的代码。左边是传统前端项⽬,由开发者⼿写整个应⽤, 把库和⼯具当做积⽊来组装,填补项⽬⾥的空⽩。⽽右边是 Modern.js 项⽬,整个应⽤是框架本⾝,开发者⼿写的代码,是按照框架的要求填充到框架预留的位置上。"}]},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/a1\/a11eeaaa96c832fcdc161bca3e4fd8f1.webp","alt":"图片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"要实现充分抽象,也需要在尽可能多的环节实现最⼤化的抽象,图上体现了 Modern.js 除了像常规 的框架⼀样,在运⾏时和编译时做抽象,也会在 IDE 编写代码的环节,和部署产物的环节,引⼊最⼤化的抽象。"}]},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/2d\/2d986645d6b6109df055ca4fd1278780.webp","alt":"图片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"要实现充分抽象,也需要解决前端模板的问题,Modern.js 把各种研发场景、项⽬类型,收敛和标准 化成了始终固定的三个⼯程类型,其中「应⽤」⼯程⽅案,也就是 MWA,⽀持所有需要部署和运⾏的项⽬,「模块」⼯程⽅案⽀持所有需要实现代码复⽤的项⽬。"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"5. 智能化、平台化、低码化"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Modern.js 代表的现代 Web 开发,也在继续朝着智能化、平台化、低码化的⽅向发展。"}]},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/e5\/e5721f9edab76ca4aa35bf152aedecc6.webp","alt":"图片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"智能化⽅⾯,当前可⽤的功能,是⽤ Modern.js 的初始化⼯具创建的项⽬,会开箱即⽤的在 VSCode ⾥做好配置,启⽤⼏千条规则组成的 ESLint 全量规则集,加上按最佳实践内置在 ESLint ⾥的 Prettier,期望尽可能多⾃动修正问题,⽽不是仅仅提示问题。也追求尽可能多的让 IDE 负责⽣成真正的源码,让开发者⼿写的代码变成跟 IDE 沟通的语⾔。"}]},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/5e\/5e55e32441eb59a8751352ac7959dbce.webp","alt":"图片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在平台化⽅⾯,Modern.js 的⽬标之⼀就是形成「⼯程标准」,让各种前端 PaaS 平台可以围绕标准实现⾼级能⼒,⽐如图上粉⾊部分列出的产品级 Web Server、差异化分发、SSR 兜底、ESR、微前 端等,都需要结合代码层⾯的⼯程标准。"}]},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/24\/24818f38648a9ef23ea32b12c83dfaf2.webp","alt":"图片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"除了部署运⾏环节⽅⾯的平台,有了⼯程标准之后,研发环节也可以引⼊更多低码提效。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"⽬前我们内部使⽤的研发平台,可以直接在图形界⾯上简单操作完成项⽬的创建、开发、部署。图上右侧可以看到图形界⾯上展示了当前项⽬的的状态: ⼊⼝数量、项⽬配置等,蓝⾊框内添加应⽤的⼊⼝,⼀键从 「单⼊⼝」 转变为 「多⼊⼝」 。右侧在 Web IDE 中也能看到 src ⽬录结构下的变化。"}]},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/9a\/9a5c745061634ea2dccbde1d43db37b8.webp","alt":"图片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"低码化有两个⽅向,⼀个是刚才说的跟研发⼯具结合,另⼀个就是研发从某些⼯作中解脱出来的低码搭建,昨天的低代码专题中有介绍。"}]},{"type":"heading","attrs":{"align":"center","level":5},"content":[{"type":"text","marks":[{"type":"underline"}],"text":"总结"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/75\/7529d83aea44c4b73fa20294e711b0d6.webp","alt":"图片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"到⽬前为⽌,我们从这些变⾰的⻆度,展⽰了很多 Modern.js 的 demo 和效果。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"⼆、Modern.js 的六⼤要素"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"接下来我们系统的看⼀下 Modern.js 是什么,Modern.js 提供了什么。"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"1. 普及:现代 Web 开发范式"}]},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/c8\/c85df9859485bd459b8560e1a510dfce.webp","alt":"图片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"可以⽤这六⼤要素来说明 Modern.js 。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"⾸先这个项⽬是希望能推动现代 Web 开发范式的普及,发展完整的现代 Web ⼯程体系,突破应⽤开发效率的瓶颈。"}]},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/1d\/1d3f98e9762cd4d2bd0d300ee473b7fe.webp","alt":"图片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"前⾯讨论「现代 Web 开发」的时候,已经展示过这种范式的 9 ⼤主要特征。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"其中 Serverless 范式、平台化、低码化这三个特征,在当前版本的 Modern.js ⾥还没什么体现,需要后续会跟⼀些平台配合提供。"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"2. 核⼼:现代 Web 应⽤(MWA)"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"继续看第⼆个要素。Modern.js 三⼤⼯程类型中最核⼼的就是 「现代 Web 应⽤」,简称 MWA,或 直接叫「应⽤」。"}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"从 Universal JS 到 Universal App"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"前⾯提到过,「应⽤」⼯程⽅案⽀持所有需要部署和运⾏的项⽬,把这些项⽬收敛成⽤同⼀套框架、 同⼀套约定、同⼀套模板、同⼀套架构、⼀套 API 来开发。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"反过来,我们也可以从 Universal App、⼀体化、应⽤架构、Runtime API 这四个⻆度来了解 MWA。"}]},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/b9\/b94281e787d774194a78cc4967d31370.webp","alt":"图片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Universal JS 指同⼀份 JS 代码,既能在浏览器端运⾏,也能在服务器端运⾏,Universal App 是它 的进⼀步发展,同⼀份 App 代码可以在不同环节运⾏,也可以⽤不同的模式来运⾏。"}]},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/1c\/1c7a2ffd8ea438dcc8aa7485f301cf70.webp","alt":"图片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"⾸先是常⻅的 MPA 和 SPA 的需求,本质上是「服务器端路由」和「客⼾端路由」的需求。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在 Modern.js ⾥它们可以随意组合。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我们之前的例⼦都是单⼊⼝应⽤,只需要把 App.tsx 组件、pages ⽬录这样的⼊⼝标识放到 src 的⼦ ⽬录⾥,就能变成多⼊⼝的 MPA,会⽤⼊⼝名⾃动⽣成服务器端路由,⽐如图上的 admin-app 和 landing-page 两个⼊⼝。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"这两个⼊⼝也分别都是 SPA,根据⼊⼝标识不同,⼀个使⽤基于组件的客⼾端路由,⼀个使⽤基于⽂件系统的客⼾端路由。"}]},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/3e\/3e24bb6e1c9b5d2a6c03684d37630d09.webp","alt":"图片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"然后是⽀持「动静⼀体」。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"前⾯展示过⼀个静态的、CSR 的项⽬如何直接开启 SSR、SPR、SSG 功能。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Modern.js 也⽀持 CSR 和 SSR\/SSG 混⽤,⽐如图上右侧红⾊⾼亮部分会在服务端渲染到 html 中, 蓝⾊区域的⽇期时间,在 CSR 阶段动态展示在⻚⾯上。也就是整体 SSR + 局部 CSR。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"整体 CSR + 局部 SSR 的能⼒后续会加⼊。"}]},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/5b\/5b0f4e4ce2e645cbd848bf6e27756c75.webp","alt":"图片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在 BFF ⽀持⽅⾯,Modern.js 中还提供了类型友好的⽅式,可以通过 Type Schema 实现运⾏时⾃动 校验接⼝的参数和返回值。⽐如右下⻆请求时,参数 text 类型为 number 时,response 中会⾃动提示相应的错误。"}]},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/db\/db54fb44b71bcf75d078c4122c8046cd.webp","alt":"图片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"最后 Modern.js 还⽀持不同类型的应⽤开发,上图就是之前例⼦中介绍 Web 开发模式。"}]},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/b6\/b664b19e5ed67ae0ed1a8d427ec79168.webp","alt":"图片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"最后是不同的运⾏模式。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"微前端在 Modern.js 中是原⽣⽀持的,底层解决⽅案是 Web Infra 之前开源的 Garfish 微前端解决⽅案。⼀个 MWA 可以随时变成微前端主应⽤,在配置中指定⼦应⽤列表的加载地址,Modern.js 就会 ⾃动在 Web Server 中预加载⼦应⽤数据,注⼊到运⾏时,在 Runtime API 的帮助下,可以像普通 React 组件⼀样使⽤⼦应⽤。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"MWA 也可以分别作为独⽴的 Web 和微前端⼦应⽤的运⾏和部署。"}]},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/22\/2272a97e618ee5dc6a714a2ed9354025.webp","alt":"图片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"MWA 在启用 Electron 支持之后,能作为桌⾯应⽤来运⾏,项目里会新增 electron ⽬录用于写主进程相关代码。除了开箱即⽤的 Electron 构建等能力,也提供运⾏时 API ⽀持 Electron 的常⻅需求和最佳实践,进⼀步提升开发效率。"}]},{"type":"heading","attrs":{"align":"center","level":5},"content":[{"type":"text","marks":[{"type":"underline"}],"text":"前后端⼀体化"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"第⼆个看待 MWA 的⻆度是 「前后端⼀体化」。"}]},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/69\/69f8659bc1ea90cdf80c426f74007af6.webp","alt":"图片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"之前的例⼦只展示了⽤ BFF 函数,api\/ ⽬录下每个⽂件就是 BFF 路由,当服务器端逻辑更重的时候,可以增加 Node.js 框架元素,⽬前⽀持了 4 种不同的框架,还可以⾃⼰开发 Modern.js 插件⽀持更多框架。"}]},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/82\/82950e9b9f2c040edfe9ab6be8c76a87.webp","alt":"图片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"前⾯提到过,以客⼾端为中⼼,不代表不能掌控服务器端,不能直接写服务器端业务逻辑。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"⽐如前⾯提到的⽕⼭引擎⼯程⽅案的例⼦,除了⽤框架插件,也可以在项⽬⾥创建 server ⽬录和钩 ⼦⽂件,添加修改 HTML 渲染结果的逻辑。在框架插件⾥和直接在项⽬下定制 Server,能⼒是对等的。"}]},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/ac\/ac2c10c92557a543dcf8f1c79109c247.webp","alt":"图片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在只有 src ⽬录,或有 api ⽬录的情况下,MWA 类似 JAMstack 项⽬。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果增加了 server 等钩⼦⽂件的情况下,MWA 像传统 Node.js App ⼀样能直接写服务器端业务逻 辑,使⽤ Node.js 框架插件、中间件等。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果删掉 src ⽬录,MWA 就是⼀个纯 REST API 的项⽬。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我们把这三种模式之间的随意迁移,称作「三位⼀体」。"}]},{"type":"heading","attrs":{"align":"center","level":5},"content":[{"type":"text","marks":[{"type":"underline"}],"text":"应⽤架构"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"接下来看下应⽤架构⻆度。"}]},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/1b\/1beb5d61fc800090be51fcbfd749faf0.webp","alt":"图片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"传统 Web 开发中的应⽤架构,等同于服务器端应⽤架构,前端部分的架构要么缺失,要么需要项开发者⾃⼰摸索、搭建,缺乏 API ⽀持和⼀致的抽象,难以跨项⽬复⽤业务逻辑。"}]},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/cc\/cc76800eebad81dfb6fd9d9d148bb245.webp","alt":"图片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"MWA 提供的开箱即⽤的、客⼾端为中⼼的应⽤架构。类似图上那样,可以⽤标准化的 Runtime API,轻易实现 React 开发中⽋缺的 Model 层和 Controller 层。Model 作为封装 UI ⽆关业务逻辑的积⽊,跟 UI 组件⼀样可以复⽤和组装。"}]},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/0b\/0bc1e923d1e05644ea8f7c7ec435dfa5.webp","alt":"图片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"之前 Web Infra 举办的 React 核⼼开发者在线访谈⾥,Redux 作者 Dan 提到,状态管理最重要的是理解状态的类型,根据需要处理的状态是什么种类,来选择对应的⽅案。"}]},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/fb\/fbfe9a245e84db53a79e9ea380338b4d.webp","alt":"图片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"常⻅的状态管理⽅案,都有适合的状态类型和场景,很多时候需要混合使⽤,⽽不是⼀把锤⼦锤所有钉⼦,要么所有状态都放到全局应⽤状态⾥,要么所有状态都在局部状态⾥。"}]},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/d8\/d8db4d50321048d77165144f7d62b286.webp","alt":"图片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"很多开发者不⽤ Redux,是因为 Redux 本⾝只能算底层 API,需要手动创建和维护store,业务逻辑被reducer,action等分散在不同的地方,提高了维护成本。其实 Redux 社区⼀直有解决⽅案,比如 Ducks Modular 设计模式会把业务逻辑聚集在⼀起,Redux官方支持的主流库RTK也为解决这样的问题而生。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Modern.js 的 Model 基于 Redux 进⼀步提⾼抽象程度,保留了 Redux 在不可变数据、数据流等⽅⾯ 的收益,对整个 Redux ⽣态兼容,让使⽤和不使⽤ Redux 的开发者都能受益。⽀持多种状态类型,也⽀持不同的 Model 写法。"}]},{"type":"heading","attrs":{"align":"center","level":5},"content":[{"type":"text","marks":[{"type":"underline"}],"text":"Runtime API 标准库"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"最后看下 MWA 的 Runtime API 标准库。"}]},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/88\/8884b47b79e788c393b5240d31332e00.webp","alt":"图片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"这套 API 相当于对「应⽤」层级的基础 API,不⽌能在 MWA ⾥使⽤,在 Modern.js 的模块⼯程⽅案⾥,同样可以使⽤这些 API,开发可复⽤的业务组件,⽀持独⽴调试和测试。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"图上最上⾯蓝⾊⽅块是业务开发中常⽤的 api,⽐如 useLoader,useModel 等 API。中间橙⾊部分 就是前⾯提到定制 server 需要⽤到的 API, 最底下就是我们的插件 API,可以扩展框架、定制⼯程⽅案。右侧也提供了⼀些⼯具函数 API, ⽐如⽤于代码分割的 loadable API。最右边 测试相关的⼯具 API 保证了 runtime 不论在应⽤、模块还是 API 服务中 都可以进⾏单元测试和集成测试。"}]},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/9f\/9fd628ffa4c1faf2469cf4b0ec497946.webp","alt":"图片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"当应⽤中的组件需要拆分成独⽴的模块复⽤时,使⽤的 Runtime API 怎么办,还能继续调试、测试嘛,答案是肯定的,这套 API 相当于「应⽤」领域的 API 标准库,不⽌能在 MWA ⾥使⽤,在 Modern.js 的模块⼯程⽅案⾥,同样可以使⽤这些 API,开发可复⽤的业务组件,⽀持独⽴调试和测试。上图右侧是模块⼯程的⽬录结构。左侧 TableList 组件中使⽤了 useLoader API,调试时只需要 提供对应的 story ⽂件,模块⼯程⽅案⽀持我们在 storybook 调试⽤到了 Runtime API 的组件。测试⽤例也是⼀样⽀持。"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"3. 内置:前端⼯程最佳实践"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"对于第三个要素,简单列举⼏个 Modernjs 内置的前端⼯程最佳实践。"}]},{"type":"heading","attrs":{"align":"center","level":5},"content":[{"type":"text","marks":[{"type":"underline"}],"text":"Post-Webpack Era"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/2c\/2c402493ace03c79a5c2706c3aa8a6c0.webp","alt":"图片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"传统前端⼯程建设都是基于 Webpack 的配置封装, Webpack 不论是配置还是速度的问题,⼤家应该都有⽐较深的感受, 但是从去年开始业界涌现很多新的⼯具,完全不涉及 webpack,⽐如 snowpack、 vite、wmr、等等,有⼈把它称为 JS 第三纪元。"}]},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/ff\/ff42cad9a7c5b05c1d6eb0538a5698e5.webp","alt":"图片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"从第三纪元开始, esbuild 、swc 这种编译打包⼯具使⽤⾮ JS 的系统编程语⾔开发,显著提⾼构建速度。编译时间的缩减也意味着不打包,按需编译的 ESM 场景可以实现, Snowpack、Vite 这样的⼯具就是在 esbuild 的基础上实现的开发者体验优先的不打包开发调试模式。在 Modern.js 中不打包的模式⽬前已经被⽤于公共库的构建、业务项⽬的开发调试等真实场景。"}]},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/1d\/1dcce366545cacb0a685bdc59bc4c3b4.webp","alt":"图片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Modern.js 中也内置类似 Snowpack、Vite 的不打包开发调试模式,左侧启⽤该功能之后,运⾏效果就像图上右侧那样,开发服务器在秒级启动。"}]},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/7b\/7b052c41af56232971827739b57c6431.webp","alt":"图片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"为什么可以做到速度这么快?主要是因为业务代码只有在请求时使⽤ esbuild 按需编译,第三⽅依赖⾃动从 Goofy PDN 加载已经预编译好的产物。"}]},{"type":"heading","attrs":{"align":"center","level":5},"content":[{"type":"text","marks":[{"type":"underline"}],"text":"CSS 最佳实践"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/fa\/faea89bd781250cb0785532fb12552a8.webp","alt":"图片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在 CSS 开发⽅⾯,Modern.js 默认推荐图上「CSS 三剑客」搭配使⽤,有需要也可以开启 LESS\/SASS 等预处理器和 CSS Modules ⽀持。"}]},{"type":"heading","attrs":{"align":"center","level":5},"content":[{"type":"text","marks":[{"type":"underline"}],"text":"默认零配置、样板⽂件最⼩化"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/48\/483a41f0d221a85167458660475705d7.webp","alt":"图片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"和以前把功能作为样板⽂件塞到项⽬⾥相⽐, 现代 Web 开发范式下的最佳实践要求默认零配置的,同时样板⽂件尽可能简洁最⼩化。之前我们也通过例⼦看到 Modern.js 项⽬⼿动创建⾮常简单,只需要应⽤根组件和 package.json。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"跟直接使⽤ Garfish 开发微前端⼦应⽤的项⽬做对⽐,上图可以看到直接使⽤ garfish 的项⽬,需要⼿动运⾏ Garfish 框架、处理公⽤模块、路由等逻辑。除了运⾏时,还需要编译环节⾃定义⼀⼤堆配置。直接使⽤还是有⼀定的成本。"}]},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/21\/21c402ae313dd1c250aeaa1870db2f61.webp","alt":"图片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在 Modern.js 中使⽤微前端,之前的例⼦已经说过,只需要在 web 应⽤的基础上启⽤微前端功能, 提供⼦应⽤列表即可,每个⼦应⽤加载后就是组件、路由可以⾃⼰灵活组织。"}]},{"type":"heading","attrs":{"align":"center","level":5},"content":[{"type":"text","marks":[{"type":"underline"}],"text":"构建产物规范"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/56\/564fe5436b7b50dcf1dbcf8b546a7ab6.webp","alt":"图片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Modern.js 的模块⼯程⽅案,会并⾏编译出多种符合社区主流规范的构建产物。模块的编译也是不打包的,更容易引⼊速度更快的⼯具⽐如 esbuild、swc 等。"}]},{"type":"heading","attrs":{"align":"center","level":5},"content":[{"type":"text","marks":[{"type":"underline"}],"text":"Monorepo ⼯程⽅案"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/43\/43737d9a0ad22fe9e378fe7532da883a.webp","alt":"图片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"应⽤和库如果分散在不同项⽬开发的话,通过 link 调试也⽐较⿇烦,业界的主流⽅案就是 monorepo, Modern.js 本⾝就是基于 pnpm monorepo 开发的,同时也将这部分最佳实践收敛到 monorepo ⼯程⽅案。初始化的 monorepo 默认使⽤pnpm,左侧是他的⽬录结构,apps 对应的是 MWA 应⽤ 、features\/packages 对应是可复⽤的模块。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"右侧内部模块指的是不会发布到 npm、仅在当前仓库下复⽤的库。它本⾝不需要构建,同仓库下的应⽤直接使⽤它的源码即可。monorepo 我们也提供了 new 命令,可以选择创建应⽤或者模块。"}]},{"type":"heading","attrs":{"align":"center","level":5},"content":[{"type":"text","marks":[{"type":"underline"}],"text":"更多"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/64\/644c26681e684df0db82eb16d64c3fb9.webp","alt":"图片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"除了上⾯提到的⼀些最佳实践,Modernjs 还提供了单元测试、集成测试、Visual Testing 等、ESlint 全量规则集等最佳实践。这⾥不⼀⼀展开介绍。可以在⽂档上了解和使⽤。"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"4. 包含:Web 开发全流程"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Modernjs 不仅是上⾯介绍过的 运⾏、构建、调试等⽅⾯,本⾝包含了 Web 开发全流程。"}]},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/33\/334d6fda179701a69d493de05f1e351b.webp","alt":"图片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在编码环节,也可以通过微⽣成器启⽤某个功能或者添加⼊⼝,从 SPA 到 MPA, 和前⾯提到的通过研发平台「低码提效」类似,还可以像图上那样在项⽬⽬录下执⾏ new 命令选择要启⽤的功能。这个命令会⾃动重构我们的代码。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"通过微⽣成器按需⾃动启⽤的⽅式,可以放⼼的将⼀些功能作为插件提供,也可以控制 Modern.js 初始化项⽬的体积。"}]},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/a3\/a38d3a208ea3fc7f2447939c6082f446.webp","alt":"图片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在微前端⼦应⽤开发时,通常情况下主应⽤已经部署上线了,这时候开发⼦应⽤就需要结合线上的主 应⽤⼀起调试,之前的⽅式通常是通过全局代理⼦应⽤ js 到本地,⽐较⿇烦。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Modern.js 中只需要主应⽤像右下⻆那样启⽤ DEBUG 模式,之后打开主应⽤线上链接,在 header 中设置需要开发的⼦应⽤信息,server 会⾃动替换注⼊到 html 中的⼦应⽤列表数据。这样也就可以让线上主应⽤加载本地⼦应⽤。"}]},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/fa\/fa9538aa50f2170f9eb58ff25188bc4b.webp","alt":"图片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在运⾏环节,传统的 Web 开发模式,通常是没有提供⽣产环境运⾏项⽬的⽅式,MWA 项⽬本⾝⾃ 带产品级的 Server,⾃⼰就能产品级的运⾏⾃⼰,⽐如图上的⾃动 Polyfill 服务。之前也提过,结 合 serverless 平台,可以⾃动做⼀些优化。也可以在本地运⾏模拟⽣产环境的效果。"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"5. 提供:⼯程标准体系"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Modern.js 不只是⼀个现代 Web 应⽤开发框架,⽽提供了整套现代 Web ⼯程体系。"}]},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/8b\/8b20477c3d207aee6d86cdb5c8da4e59.webp","alt":"图片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"前⾯已经介绍过,我们将前端开发中涉及的场景收敛到 3 种,就是图上应⽤、模块和 monorepo。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"不仅解决了业务模板数量爆炸的问题。融合后的⼯程类型,⽐如 MWA 不是多个场景简单叠加,导致 ⼯程变的⼤⽽全,通过抽象可以做到很轻量,也能更容易交付⼀些之前不好实现的功能。"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"6. ⿎励:定制⼯程⽅案"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Modern.js ⿎励业务结合⾃⾝场景定制垂直的⼯程⽅案。"}]},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/15\/1570826d1f8dd5bb5f554ac36b10f3b7.webp","alt":"图片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"就像前⾯提到的⽕⼭引擎例⼦⼀样,封装插件、微⽣成器、定制出⾃⼰的业务⼯程⽅案。"}]},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/8e\/8ee7fac86d6d8eacb8472df252d8aea7.webp","alt":"图片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"关于 Modern.js 六⼤要素的更多解释和例⼦,可以在官⽹上看到。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"三、Modern.js 社区和现代 Web 研发体系"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"最后我们⼀起看下除了已经发布的开源项⽬,还有哪些对现代 Web 开发者有帮助的事情在发起和推进中。"}]},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/c9\/c90333e9b6060dc4ad6d91ac4cab504a.webp","alt":"图片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Modern.js 开源项⽬现在是刚起步的状态,昨天上线的官⽹,以及最新发的 1.0 版,都是公测状态, 还需要更多意⻅、测试和实践,希望⼤家多参与社区建设。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Modern.js 的起点是字节内部的现代 Web ⼯程体系项⽬,现在⼤部分代码已经完全转到 Github 上开发,⼯作流还在建设中。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"双⽉计划、每周计划、缺陷管理等,也都会全⾯转到 Github 上公开推进。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"当前版本还没有包含 Roadmap 上⼀些重要功能,希望尽量以每周发版的节奏,把这些功能补上。"}]},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/19\/198239775bf6082dfecdb99785b7bd88.webp","alt":"图片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"昨天的分享介绍了 「现代 Web 研发体系」中的其他部分,这些部分⼏乎也都算的上是 Modern.js 的 重要功能,后续会陆续对外开放,欢迎⼤家关注。"}]},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/fc\/fcd2b8a9a5704266a42451d013008290.webp","alt":"图片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"最后,屏幕上右下⻆⼆维码是 Modern.js 官⽹的地址,可以在官⽹上通过快速上⼿和实战教程了解 更多 Modernjs 的细节使⽤部分。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"谢谢⼤家。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"官⽹:"},{"type":"link","attrs":{"href":"https:\/\/modernjs.dev\/","title":"xxx","type":null},"content":[{"type":"text","text":"https:\/\/modernjs.dev\/"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Github:"},{"type":"link","attrs":{"href":"https:\/\/github.com\/modern-js-dev\/modern.js","title":"xxx","type":null},"content":[{"type":"text","text":"https:\/\/github.com\/modern-js-dev\/modern.js"}]}]}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章