├── CNAME ├── _config.yml ├── images ├── cls-slot.png ├── cls-step-2.png ├── ms-align.png └── clean-frontend.png ├── LICENSE ├── .gitignore ├── README.md └── README_en.md /CNAME: -------------------------------------------------------------------------------- 1 | componentless.com 2 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-cayman -------------------------------------------------------------------------------- /images/cls-slot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phodal/componentless/HEAD/images/cls-slot.png -------------------------------------------------------------------------------- /images/cls-step-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phodal/componentless/HEAD/images/cls-step-2.png -------------------------------------------------------------------------------- /images/ms-align.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phodal/componentless/HEAD/images/ms-align.png -------------------------------------------------------------------------------- /images/clean-frontend.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phodal/componentless/HEAD/images/clean-frontend.png -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Fengda Huang 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Diagnostic reports (https://nodejs.org/api/report.html) 10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | *.lcov 24 | 25 | # nyc test coverage 26 | .nyc_output 27 | 28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 29 | .grunt 30 | 31 | # Bower dependency directory (https://bower.io/) 32 | bower_components 33 | 34 | # node-waf configuration 35 | .lock-wscript 36 | 37 | # Compiled binary addons (https://nodejs.org/api/addons.html) 38 | build/Release 39 | 40 | # Dependency directories 41 | node_modules/ 42 | jspm_packages/ 43 | 44 | # TypeScript v1 declaration files 45 | typings/ 46 | 47 | # TypeScript cache 48 | *.tsbuildinfo 49 | 50 | # Optional npm cache directory 51 | .npm 52 | 53 | # Optional eslint cache 54 | .eslintcache 55 | 56 | # Microbundle cache 57 | .rpt2_cache/ 58 | .rts2_cache_cjs/ 59 | .rts2_cache_es/ 60 | .rts2_cache_umd/ 61 | 62 | # Optional REPL history 63 | .node_repl_history 64 | 65 | # Output of 'npm pack' 66 | *.tgz 67 | 68 | # Yarn Integrity file 69 | .yarn-integrity 70 | 71 | # dotenv environment variables file 72 | .env 73 | .env.test 74 | 75 | # parcel-bundler cache (https://parceljs.org/) 76 | .cache 77 | 78 | # Next.js build output 79 | .next 80 | 81 | # Nuxt.js build / generate output 82 | .nuxt 83 | dist 84 | 85 | # Gatsby files 86 | .cache/ 87 | # Comment in the public line in if your project uses Gatsby and *not* Next.js 88 | # https://nextjs.org/blog/next-9-1#public-directory-support 89 | # public 90 | 91 | # vuepress build output 92 | .vuepress/dist 93 | 94 | # Serverless directories 95 | .serverless/ 96 | 97 | # FuseBox cache 98 | .fusebox/ 99 | 100 | # DynamoDB Local files 101 | .dynamodb/ 102 | 103 | # TernJS port file 104 | .tern-port 105 | .DS_Store 106 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Componentless Architecture:无组件架构 2 | 3 | English version: [README_en.md](README_en.md) 4 | 5 | > 无组件(Componentless)架构是一种架构模式,它是指大量依赖于**三方组件**(运行时依赖的组件而非编译时依赖的组件,即编译即服务)或暂存容器中运行的自定义代码的前端应用。应用的三方组件如同三方 API 服务一样,可各自独立发布、独立部署,应用无需重新编译、构建和部署。 6 | 7 | 从无组件定义的英文名称 Componentless,你就可以知道它所要对标的是类 Serverless 一样的后端架构模式上。所以,在定义上和 Serverless 架构的定义颇为相似。这就是为什么,我们定义为无组件架构的原因,你可以不需要编写任何的组件,只需要编写逻辑代码或者 DSL 来实现它们的组合。甚至于,我们可以只提供一个 DSL + 通用的 URL,由浏览器根据 DSL 完成应用的全自动构建和运行。 8 | 9 | 看一个简单的示例,便是 Quake 的 Transflow 设计:`from('todo','blog').to();`,让组件标准化,数据标准化,自然而然地我们就不需要考虑任何组件的设计。 10 | 11 | ## 前端与后端架构的演进 12 | 13 | 先前,经常和别人交流起领域驱动设计(DDD)在前端的应用,也是颇为有意思的。作为 “九又四分之三” / 10 个 DDD 方面的砖家,过去,我一直觉得领域驱动设计并不适合于前端,[整洁前端架构](https://github.com/phodal/clean-frontend) 才是人们所需要的,但是设计 + 上手难度略大。在今年里,又双叕对多个后端应用使用了 DDD 的设计和规划,又有了新的体会(虽然依旧不行)。前端可以有类似于 DDD 的方式,只是方式完全和后端不一样。后端以模型和函数作为两种风格不同编程风格的基础,前端则是以**组件** + **事件**作为编程风格的基础。组件是可消灭的,事件则由是设计事件流来编排。 14 | 15 | ![Clean Frontend](images/clean-frontend.png) 16 | 17 | 所以,你并不直接将后端 DDD 的思想,直接套用在前端应用上,除非你应用的逻辑主要是在前端。 18 | 19 | ### 微服务与微前端 20 | 21 | 对于现今的大多数系统来说,它们依旧维续在一种:「**后端微服务,前端“大泥球”** 」的状态。后端的微服务已经按照「康威定律」拆为一个个的微服务(当然了,不合理地拆分微服务是另外的一个问题),而前端还处在一个大泥球的状态。所以,微前端便作为**其中的一种**(并非唯一)技术来解决组织架构对齐,并实现快速发布上线的架构模式。它可以将单体大应用拆分为多个较小的自治应用,但它们依旧聚合为一。可以用于解决迁移遗留系统、统一用户体验、帮助多团队协作等。 22 | 23 | 在进行后端系统迁移时,我们使用 DDD(领域驱动设计)的方式寻找合理地微服务架构设计依据,微服务成为我们改造遗留系统的方式。我们从一个模块、一个功能开始,逐步地替换旧的单体应用,直至整个系统完成替换。这个替换模式对于前端应用来说,它也是颇为类似的。 24 | 25 | 所以,在进行了微前端的改造后,架构上对齐了,人员上对齐了,皆大欢喜。 26 | 27 | ![Team Align](images/ms-align.png) 28 | 29 | 再往前呢,我们应该如何继续演进系统? 30 | 31 | ### Serverless 与 ComponentLess 32 | 33 | 2017 年,在学习了 DDD 与 Serverless 之后,开源了《[Serverless 应用开发指南](https://serverless.ink/)》() 之后,我一直在思考在前端领域如何应用使用类似于 Serverless 的思想?于是,就有了关于跨框架组件库的想法:《[前端下半场:构建跨框架的 UI 库](https://www.phodal.com/blog/build-cross-framework-ui-library/)》,只是国内这些写组件库的公司,并没有这种大胆的想法,太可惜了 —— 只会版本号 + 1,别人做什么跟着做什么?还有一条有意思的故事线,在经历了无代码编程的火热之后,我重新思考了一下前端和后端的未来:《[前后端一体化:前后端分离将死?](https://www.phodal.com/blog/kill-frontend-backend/)》。 34 | 35 | > 起先,我以为无代码编程是一个 ComponentLess 方向,但是一研究发现并不是。无代码编程倾向于可视化编程,而 ComponentLess 倾向于使用 DSL 编程。就这一点来说,我便偏向于使用 Web Components + WAM 技术来构建新的前端架构。 36 | 37 | 直到我最近在开源知识管理工具 [Quake](https://github.com/phodal/quake) ()重新应用了这个思想之后,发现了特别有意思,我便想着写一篇文章来介绍相关的理念 —— 毕竟,市场上已经接受了 Serverless 的观念,接受了微前端的观念。那么,剩下的问题就变得非常的简单了。 38 | 39 | ## 无组件架构 40 | 41 | 继续回到开头上的定义: 42 | 43 | > 无组件(Componentless)架构是一种架构模式,它是指大量依赖于**三方组件**(运行时依赖的组件而非编译时依赖的组件,即编译即服务)或暂存容器中运行的自定义代码的前端应用。应用的三方组件如同三方 API 服务一样,可各自独立发布、独立部署,应用无需重新编译、构建和部署。 44 | 45 | 简单来说,无组件所要做的事情就是将组件变成一种**运行时服务**,而非**过去的编译时依赖**。当所有的组件都变成一种真正的基础设施时,我们就不再需要这些组件,进而从应用开发侧让组件消失,达成了应用无需组件的状态。如此一来,它也变成了一个低代码(LowCode)式的系统,配合简单的代码生成,可以达到无码的状态(NoCode)。 46 | 47 | 从形式上来说,使用微前端相关的技术可以提供无组件架构所需要的一系列基础技术。其中,最为简单的方式是使用:Web Components 。那么,先让我们来看一个基于 Web Components 的 Componentless 架构示例。 48 | 49 | ### 示例:如何迈向 Componentless 架构? 50 | 51 | 从过程来说,可以分为三步: 52 | 53 | 1. 使用 Web Component 分解应用 54 | 2. 拆分更多的组件以消灭组件 55 | 3. 构建生成式低代码模式 56 | 57 | 剩下的部分就是填空式的编程了。 58 | 59 | **1. 使用 Web Component 分解应用** 60 | 61 | 先来看个示例,比如我们的前端部分有 A、B 两个微应用,颗粒度已经非常小的,但是依旧是**应用级别**的应用。应用 B 使用了 Web Components 技术构建,并且在微应用 B 里引入了两个三方的 Web Components 组件。常规的前端应用里,如果我们更新了这两个组件,对应的应用需要重新编译,再发布上线。 62 | ![Slot](images/cls-slot.png)而在现在,在 Custom Element + Shadow DOM 的加持下,我们只需要更新指向组件库的 `script` 标签的链接,或者缓存即可。 63 | 64 | **2. 拆分更多的组件以消灭组件** 65 | 66 | 接着,让我们进一步地优化,去除应用 A 和 应用 B 的所有内部组件,将这些组件外置,按功能模块构建成一个个的组件集。这些组件集,我们可以按功能团队划分,或者划到所为的前端中台,又或者是前端垃圾回收站。 67 | ![WC ComponentLes](images/cls-step-2.png) 68 | 这些并不重要,现在我们的应用里的「**组件**」已经非常之少了 —— 我们还剩下一些对于这些组件编排的组件 + 一些额外的业务逻辑。 69 | 70 | **3. 构建生成式低代码模式** 71 | 72 | 现在,再回顾一下 Serverless (AWS Lambda,它们没给广告费)中编写的“hello, world”函数: 73 | 74 | ```javascript 75 | module.exports.hello = (event, context, callback) => { 76 | callback(null, "hello, world"); 77 | }; 78 | ``` 79 | 80 | 在使用 Serverless Framework 这样的框架时,我们只需要在这个函数上,填写我们的业务逻辑即可,即**填空式编程**。对于前端来说,这个过程也是类似的,我们的数据有了,我们的目标组件有了,只需要一个有限性**代码生成**的功能。即,我们只需要生成一个有待完善的空函数即可,如 Quake 中的 Transflow:`from('todo','blog').to()`,生成的函数和逻辑(部分代码示例): 81 | 82 | ```javascript 83 | const tl_temp_1 = async (context, commands) => { 84 | const el = document.createElement('quake-calendar'); 85 | ... 86 | return el; 87 | } 88 | ``` 89 | 90 | 在这时,只需要确保路由与函数不被修改,那么剩下的部分就是对于数据处理的填空了。 91 | 92 | ### 迁移方式 93 | 94 | 除了上述的直接分解的方式,还有其它的渐进式迁移方式。 95 | 96 | 迁移方式 2:新嵌老 97 | 98 | 1. 使用新的技术和框架创建应用的架子。 99 | 2. 提取 Web Component 套入旧的组件,转变化公共能力。 100 | 3. 在新的应用中嵌入旧的轮子。 101 | 102 | 迁移方式 3:老嵌新 103 | 104 | 1. 构建新的 Web Component 组件。配合 monorepo 管理 105 | 2. 嵌入组件到现有应用中。 106 | 3. 完善无组件架构机制。 107 | 4. 构建低代码编排模式。 108 | 109 | ### 无组件架构理念 110 | 111 | 从当前个人的理解,它的核心理念是: **组件即「服务」**。即让组件像服务一样,可以自由部署,自由更新。在组件更新后,应用也从某种意义上达到了应用的更新。 112 | 113 | 除此,还有诸如于: 114 | 115 | 1. 自动化环境隔离。圣诞节马上就到了 116 | 2. 生成式低代码。真正意义的前端胶水 117 | 118 | 更多的内容,还有待探索。 119 | 120 | ### 无组件架构问题 121 | 122 | 除了上述的诸多优点,它还有一系列的缺点需要解决: 123 | 124 | * 浏览器兼容性。Web Component 的兼容性问题 125 | * 测试难度。自由的架构往往意味着测试上的成本,在这一点也与微服务、Serverless 类似,将需要由更多的端到端测试才能保障项目的质量。 126 | * 组件模块化的划分依据。当我们构建出一个个的组件集之后,就需要寻找一种方式来合理规划。 127 | * Monorepo 管理方式。repo 越多,管理上就会越复杂。需要引入 nx、pnpm 这样的工具进行管理。 128 | * 更新策略。即应用与组件集的更新策略应保持不一致。 129 | * …… 130 | 131 | ### 优势场景:结合低代码 132 | 133 | 从某种意义上来说,无组件架构是可一种广义低代码的实现模式。因为更独立的组件模式,它构建出来的低代码系统就更有意思: 134 | 135 | 1. 配置即运行时。类似于 Oracle DB 的面向过程式,实现快速上线新特性。 136 | 2. 代码生成的填空式编程。如上所面的例子所述,可以生成基本的函数代码,随后开发人员补充代码逻辑即可。 137 | 3. 基于流编排的低代码。同样适用于传统的低代码架构模式。 138 | 4. DSL 式低代码。如 Quake 中基于 DSL 来构建的。 139 | 140 | 只是呢,从模式上来说,也相差不了太多。 141 | 142 | ## 无组件模式 143 | 144 | 上面的都没啥意思,在我们采纳了 Web Component 作为无组件架构的实施技术之后,在架构上将会有更多的施展空间。Web Component 已经是一个非常好的、类似于 Docker 的容器,可以玩各种 fancy 的容器化模式。我们在 Quake 尝试了一些模式,它带来了一系列的挑战,却也非常有意思。 145 | 146 | ### 适配器:兼容现有的组件。 147 | 148 | 基于 WC 自带的特性,封装现有的主流框架 Angular、React、Vue 等的组件,就可以快速提供这样的能力,诸如于我们在 Quake 中提供的 `QuakeTimeline` 和 `QuakeCalendar` 等都是通过这种方式,将 React 组件封装为 Web Component 组件: 149 | 150 | ```javascript 151 | class ReactElement extends HTMLElement { 152 | ... 153 | } 154 | customElements.define('quake-calendar', ReactElement); 155 | ``` 156 | 157 | 由于,对外暴露的是 WC 组件,就无所谓于使用的是何种前端框架。 158 | 159 | ### 大使模式 160 | 161 | 在云原生模式里,大使模式(Ambassador)可以创建代表消费者服务或应用程序,发送网络请求的帮助服务。同样的事件,也可以通过组件来封装, 162 | 163 | ```javascript 164 | const fetchEl = document.createElement('fetch-api'); 165 | fetchEl.setAttribute("url", "/action/suggest); 166 | fetchEl.addEventListener("fetchSuccess", (res: any) => { 167 | let response = res.detail; 168 | loading.onDidDismiss().then(() => {}); 169 | callback(response); 170 | }) 171 | ``` 172 | 173 | 不过,我这么写就只是为了好玩,创建一个 Loading 组件,在 Loading 里插入 `` 组件发起 HTTP 请求,请求成功后,把 DOM 销毁。 174 | 175 | 这样一来,我只需要替换这个请求组件,就可以替换所有的请求 API。 176 | 177 | ### 无限 “套娃” 模式 178 | 179 | 常规的模式下,我们在 A 组件里调用了 B 组件,那么理论上,我们就不需要在 B 组件里调用 A 组件,会形成循环的引用,但是在 Web Components 中它成了一种功能。 180 | 181 | 如我们在 Quake 的 markdown 渲染引擎里 `` 里,按条件渲染了嵌入页面的 ``,而 `` 嵌入的页面也是 markdown 的,所以需要一个 ``,所以可以无限 “套娃”,直到浏览器的当前页面挂了。 182 | 183 | 从使用方式上来说,A、B 两个组件并不存在这样的相互调用的关系。 184 | 185 | PS:其实这是一个 bug,后来我觉得这是一个 featurs。 186 | 187 | ### Sidecar 模式 188 | 189 | 在云原生模式果,挎斗模式是指将应用程序的组件部署到单独的进程或容器中以提供隔离和封装。这一点来说,对于 Web Components 也是非常简单的。 190 | 191 | ### 边缘计算模式 192 | 193 | 利用 Edge Computing,在边缘侧如 CDN,动态生成数据。 194 | 195 | ### 边缘缓存模式 196 | 197 | 结合 Edge Computing 动态计算请求: 198 | 199 | - 边缘服务:请求静态 HTML 并返回,同时请求中心 SSR 服务,获取动态内容并返回 200 | - SSR 服务:去除静态 HTML,把动态部分返回给边缘服务 201 | 202 | 203 | ### 其它模式 204 | 205 | 依旧很多,有空可以慢慢玩。 206 | 207 | ## 总结 208 | 209 | 跳出框架来思考问题,便会发现各种非常有意思的事情。 210 | -------------------------------------------------------------------------------- /README_en.md: -------------------------------------------------------------------------------- 1 | # Componentless: a architecture pattern for low-code age. 2 | 3 | PS: This is a very fun front-end architecture model that can create unlimited fun. I wrote this article mainly because it is fun, and **there is nothing new**. 4 | 5 | When I create [Quake](https://github.com/phodal/quake/) which is a meta-framework for knowledge management, with meta-data and quake component, you can combine any data to any component, like story in calendar with Transflow DSL `from('story').to(`, story is build from meta-data: 6 | 7 | ![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jciwm6pnxp0o1zc53k9u.png) 8 | 9 | 10 | I found `componentless` is the pattern of Quake's low-code design principle, I decide to abstract the patterns of it. I call it Componentless: 11 | 12 | > Componentless architecture is an architectural pattern, it refers to a large number of rely on third-party components (runtime dependent components rather than compile-time dependent components, that is compilation as a service) or temporary storage of custom code running in the container Frontend application. The three-party components of the application, like the three-party API service, can be independently released and deployed independently, and the application does not need to be recompiled, built, and deployed. 13 | 14 | From the name Componentless, you can know that its target is the serverless-like back-end architecture pattern. Therefore, the definition is quite similar to that of the Serverless architecture. That's why, we define it as a componentless architecture. You don't need to write any components, you only need to write logic code or DSL to achieve their combination. Moreover, we can only provide a DSL + universal URL, and the browser will complete the automatic construction and operation of the application according to the DSL. 15 | 16 | Quake online demo: [https://quake-demo.inherd.org/](https://quake-demo.inherd.org/), try typing `from('stroy').to()`, the `` can be any `quake-component` (like ``, we only have two components in 2021.12.21) or any `ionic` component. 17 | 18 | Quake source code: [https://github.com/phodal/quake/](https://github.com/phodal/quake/) 19 | 20 | ## Evolution of front-end and back-end architecture 21 | 22 | Previously, it was quite interesting to often communicate with others about the application of domain-driven design (DDD) in the front-end. As a “nine and three-quarters”/10 DDD bricks, in the past, I always felt that domain-driven design is not suitable for the front-end. Clean front-end architecture is what people need, but design + getting started is slightly more difficult. 23 | 24 | In this year, I have used DDD design and planning for multiple back-end applications, and I have a new experience (although it still doesn't work). The front-end can have a DDD-like approach, but the approach is completely different from the back-end. The back-end uses model and function as the basis of two different programming styles, and the front-end uses components + events as the basis of the programming style. Components are destructible, and events are orchestrated by designing event streams. 25 | 26 | ![Clean Frontend](https://github.com/phodal/componentless/raw/master/images/clean-frontend.png) 27 | 28 | Therefore, you don't directly apply the idea of back-end DDD to front-end applications, unless the logic of your application is focus on the front-end. 29 | 30 | ### Microservices and micro frontends 31 | 32 | For most of today's systems, they still remain in a state of "back-end microservices, front-end "big mudball"." The back-end microservices have been disassembled into individual microservices according to "Conway's Law" (of course, unreasonably splitting the microservices is another problem), while the front-end is still in a state of a big mud ball. Therefore, the micro-frontend is used as one of the (not the only) technologies to solve the organizational structure alignment and implement the architectural model of rapid release and online. It can split a single large application into multiple smaller autonomous applications, but they are still aggregated into one. It can be used to solve the migration of legacy systems, unify user experience, help multi-team collaboration, etc. 33 | 34 | When migrating back-end systems, we use DDD (Domain Driven Design) to find a reasonable basis for the design of microservice architecture. Microservices have become a way for us to transform the legacy system. We start with one module and one function, and gradually replace the old single application until the entire system is replaced. This replacement mode is quite similar for front-end applications. 35 | 36 | Therefore, after the transformation of the micro front end, the structure is aligned, and the personnel is aligned. Everyone is happy. 37 | 38 | ![MS Align](https://github.com/phodal/componentless/raw/master/images/ms-align.png) 39 | 40 | Going forward, how should we continue to evolve the system? 41 | 42 | ### Serverless and ComponentLess 43 | 44 | 45 | In 2017, after learning about DDD and Serverless, and create the "Serverless Application Development Guide" (https://serverless.ink/), I have been thinking about how to apply Serverless-like ideas in the front-end? So, there was an idea about the cross-frame component library: "The second half of the front-end: building a cross-frame UI library", but these domestic companies that write component libraries do not have such a bold idea, it is a pity-only the version number + 1, what others do follow? There is also an interesting story line. After experiencing the enthusiasm of low-code programming, I rethinked the future of front-end and back-end: "[Front-end and back-end integration: Will the front-end and back-end separation die?](https://www.phodal.com/blog/kill-frontend-backend/)". 46 | 47 | At first, I thought no-code programming was a ComponentLess direction, but a research found that it was not. Nocode programming tends to visualize programming, while Componentless tends to use DSL programming. At this point, I prefer to use Web Components + WASM technology to build a new front-end architecture. 48 | 49 | Until I recently reapplied this idea in the open source knowledge management tool [Quake](https://github.com/phodal/quake), I found it particularly interesting, so I wanted to write an article to introduce the related idea-after all , The market has accepted the Serverless concept and the micro front end concept. Then, the remaining questions become very simple. 50 | 51 | ## Componentless architecture 52 | 53 | Continue back to the definition at the beginning: 54 | 55 | > Componentless architecture is an architectural pattern, it refers to a large number of rely on third-party components (runtime dependent components rather than compile-time dependent components, that is, compilation as a service) or temporary storage of custom code running in the container Front-end application. The three-party components of the application, like the three-party API service, can be independently released and deployed independently, and the application does not need to be recompiled, built, and deployed. 56 | 57 | Simply, what a componentless thing needs to do is to turn the component into a **runtime service** instead of a compile-time dependency in the past. When all the components become a kind of infrastructure, we no longer need these components, and then let the components disappear from the application development side, and achieve a state where the application does not require components. In this way, it has also become a LowCode type system, with simple code generation, it can reach the state of NoCode. 58 | 59 | From a formal point of view, the use of micro-front-end related technologies can provide a series of basic technologies required by a componentless architecture. Among them, the simplest way is to use: Web Components. So, let us first look at an example of a Componentless architecture based on Web Components. 60 | 61 | ### Example: How to move towards a Componentless architecture? 62 | 63 | In terms of the process, it can be divided into three steps: 64 | 65 | 1. Decompose the application using Web Component 66 | 2. Split more components to eliminate components 67 | 3. Build a generative low-code model 68 | 69 | The remaining part is fill-in-the-blank programming. 70 | 71 | #### 1. Use Web Component to decompose the application 72 | 73 | Let's look at an example first. For example, our front-end part has two micro-applications, A and B. The granularity is already very small, but it is still an application-level application. Application B is built using Web Components technology, and two tripartite Web Components components are introduced into micro-application B. In a conventional front-end application, if we update these two components, the corresponding application needs to be recompiled and released again. 74 | 75 | ![CLS Slot](https://github.com/phodal/componentless/raw/master/images/cls-slot.png) 76 | 77 | For now, with the support of Custom Element + Shadow DOM, we only need to update the link to the script tag of the component library, or the cache. 78 | 79 | #### 2. Split more components to eliminate components 80 | 81 | Next, let us further optimize, remove all the internal components of application A and application B, externally build these components into a set of components according to functional modules. These component sets can be divided by functional teams. 82 | 83 | ![Step 2](https://github.com/phodal/componentless/raw/master/images/cls-step-2.png) 84 | 85 | These are not important. Now there are very few "components" in our application-we still have some components for orchestrating these components + some additional business logic. 86 | 87 | #### 3. Build a generative low-code model 88 | 89 | Now, let’s review the "hello, world" function written in Serverless (AWS Lambda, they don’t pay for advertising): 90 | 91 | ```javascript 92 | module.exports.hello = (event, context, callback) => { 93 | callback(null, "hello, world"); 94 | }; 95 | ``` 96 | 97 | When using a framework like Serverless Framework, we only need to fill in our business logic on this function, that is, fill-in-the-blank programming. For the front end, the process is similar. We have data and our target components. Only a limited code generation function is needed. That is, we only need to generate an empty function to be improved, such as Transflow in Quake: `from('todo','blog').to()`, the generated function and logic (part of the code example ): 98 | 99 | ```javascript 100 | const tl_temp_1 = async (context, commands) => { 101 | const el = document.createElement('quake-calendar'); 102 | ... 103 | return el; 104 | } 105 | ``` 106 | 107 | At this time, you only need to ensure that the routing and functions are not modified, and the remaining part is to fill in the blanks for data processing. 108 | 109 | ### Migration to Componentless 110 | 111 | In addition to the above-mentioned direct decomposition method, there are other gradual migration methods. 112 | 113 | Migration method 2: new embedded in old 114 | 115 | 1. Use new technologies and frameworks to create application shelves. 116 | 2. Extract the Web Component and insert it into the old component, and then change the public capabilities. 117 | 3. Embed old wheels in new applications. 118 | 119 | Migration method 3: old embedded in new 120 | 121 | 1. Build a new Web Component component. Cooperate with monorepo management 122 | 2. Embed components into existing applications. 123 | 3. Improve the componentless architecture mechanism. 124 | 4. Build a low-code orchestration model. 125 | 126 | ### Componentless architecture concept 127 | 128 | From the current personal understanding, its core concept is: **Components are "services."** That is, components can be deployed and updated freely, just like services. After the component is updated, the application has also reached the update of the application in a sense. 129 | 130 | In addition, there are such as: 131 | 132 | 1. Automated environment isolation. Christmas is coming soon 133 | 2. Generate low code. The real front end glue 134 | 135 | More content remains to be explored. 136 | 137 | ### Componentless architecture issues 138 | 139 | In addition to the many advantages mentioned above, it also has a series of shortcomings to be solved: 140 | 141 | 1. Browser compatibility. Web Component2 compatibility issues 142 | 2. Test difficulty. Free architecture often means the cost of testing, which is similar to microservices and serverless at this point. More end-to-end testing will be required to ensure the quality of the project. 143 | 3. The division basis of component modularization. When we build a set of components, we need to find a way to plan rationally. 144 | 4. Monorepo management. The more repo, the more complicated the management. Need to introduce tools such as nx and pnpm for management. 145 | 5. Upgrade strategy. That is, the upgrade strategy of the application and the component set should remain inconsistent. 146 | ... 147 | 148 | ### Advantage scenario: combined with lowcode 149 | 150 | In a sense, componentless architecture is a generalized low-code implementation mode. Because of the more independent component model, the low-code system it builds is more interesting: 151 | 152 | 1. Configuration is runtime. It is similar to the process-oriented style of Oracle DB, and realizes new features quickly on the line. 153 | 2. Fill-in-the-blank programming for code generation. As mentioned in the above example, basic function codes can be generated, and then developers can add code logic. 154 | 3. Low code based on stream orchestration. The same applies to the traditional low-code architecture model. 155 | 4. DSL style low code. Such as Quake based on DSL to build. 156 | 157 | It's just that, in terms of mode, there is not much difference. 158 | 159 | ## Componentless patterns 160 | 161 | None of the above is interesting. After we adopt Web Component as the implementation technology of componentless architecture, there will be more room for architectural display. Web Components is already a very good container similar to Docker, which can play various fancy containerization modes. We tried some patterns at Quake, which brought a series of challenges, but it was also very interesting. 162 | 163 | ### Adapter: Compatible with existing components. 164 | 165 | Based on the features of WC, encapsulating the components of the existing mainstream frameworks such as Angular, React, Vue, etc., can quickly provide such capabilities. For example, the QuakeTimeline and QuakeCalendar we provide in Quake are all in this way. React components are packaged as Web Components: 166 | 167 | ```javascript 168 | class ReactElement extends HTMLElement { 169 | ... 170 | } 171 | customElements.define('quake-calendar', ReactElement); 172 | ``` 173 | 174 | Since the WC components are exposed to the outside, it doesn't matter what front-end framework is used. 175 | 176 | ### Ambassador pattern 177 | 178 | In the cloud-native model, the Ambassador model can create services or applications on behalf of consumers and send help services for network requests. The same event can also be encapsulated by components, 179 | 180 | ```javascript 181 | const fetchEl = document.createElement('fetch-api'); 182 | fetchEl.setAttribute("url", "/action/suggest); 183 | fetchEl.addEventListener("fetchSuccess", (res: any) => { 184 | let response = res.detail; 185 | loading.onDidDismiss().then(() => {}); 186 | callback(response); 187 | }) 188 | ``` 189 | 190 | However, I wrote this just for fun. I created a Loading component and inserted the `` component in Loading to initiate an HTTP request. After the request was successful, the DOM was destroyed. 191 | 192 | In this way, I only need to replace this request component to replace all request APIs. 193 | 194 | ### Infinite nesting "Dolls" patten 195 | 196 | In the normal pattenrn, we call the B component in the A component, then in theory, we don't need to call the A component in the B component, it will form a circular reference, but it becomes a function in Web Components. 197 | 198 | For example, in Quake's markdown rendering engine ``, the `` embedded in the page is rendered conditionally, and the embedded page of the is also markdown, so we need a , So you can "mock doll" infinitely, until the current page of the browser is hung up. 199 | 200 | In terms of usage, the two components A and B do not have such a mutual calling relationship. 201 | 202 | PS: Actually this is a bug. Later I thought it was a features. 203 | 204 | ### Sidecar pattern 205 | 206 | In the cloud-native patterns, the sidecar model refers to the deployment of application components into separate processes or containers to provide isolation and encapsulation. In this regard, it is also very simple for Web Components. 207 | 208 | ### Other parterns 209 | 210 | There are still many, you can play slowly when you have time. 211 | 212 | ## Summarize 213 | 214 | Think outside the frame and think about the problem, and you will find all kinds of very interesting things. 215 | 216 | 217 | --------------------------------------------------------------------------------