分类:计算机 / 架构 / oa-codeblock项目架构设计
- oa-codeblock项目架构设计 - JS文件包含
最近在开发一个非常复杂的需求,代码量巨大,为了清晰起见,必须拆分成多个JS文件,然后有序地组合起来。开发框架目前只支持将代码写在单个JS文件script.js中,因此需要修改。 考虑历史代码兼容性和开发周期,我决定采用一种简单的实现方案:文件包含。类似于C语言中的#include,我们在JS文件中做特殊标记,表明要将另一个JS文件的内容包含进来,然后在构建时用指定JS文件的内容替换这个特殊标记,这样就实现了分开编写、组合运行。 文件包含标记:在JS文件中用如下标记表明要包含哪个JS文件: //#include: A/B/C/xxx.js 解析文件包含: 迭代解析:A包含B,B包含C,通过迭代算法可以实现正确的链式包含。算法:循环检查A中是否还有包含标记,有则对第一个包含标记(B)执行替换,此时,如果替换的内容中带进来了新的包含标记(C),则会在下一次循环中被解析。 防止循环包含:迭代解析的过程中,要记住走过的文件有哪些,一旦发现要包含的文件之前已经走过,就说明出现了循环包含,报错。 动态监听:一个脚本文件现在可以拆分为多个文件,这多个文件又随时可能修改、增加、删除,则对于持续构建模式来说,要监听变化的文件范围是动态的。每次构建一个脚本文件时,都要重新计算并监听涉及的文件。 有了文件包含机制,我们就可以获得以下好处: 将单个复杂的任务分解为多个简单的任务,提高了清晰度、可维护性。 可以实现公共代码,免于复制粘贴,提高了代码复用度。 在OA系统的代码块机制中,多个<script src="...">之间的执行顺序是随机的,通过在同一个文件中控制文件包含的顺序,我们就可以严格控制多个脚本间的执行顺序。 文件包含机制也有其缺点: IDE不识别:标记是我们自己定的,IDE并不知道要包含哪个文件、文件间的顺序等信息,也就无法提供文件跳转、准确的代码提示等功能。 作用域不隔离:文件包含本质上是将代码拼在一起,是同一个作用域,并没有实现真正的JS模块化。编写代码时需要对这一点有清晰的认识,如果需要模块化,则必须自己用IIFE等手段实现。 不太容易理解:我开发的这个非常复杂的需求,其他同事在阅读代码时,不太容易跟踪和理解同一作用域、多层包含下的执行过程。 这些缺点,未来可以通过用Webpack实现真正的JS模块化来解决。
- oa-codeblock项目架构设计 - 支持JSX和SCSS
使用代码块开发复杂的功能时,经常需要写React组件和复杂的CSS来实现界面,目前的开发框架只支持原生JS和CSS,因此书写很繁琐,需要修改。 支持编译JSX:在JS业务代码被替换到template.js之前,先用Babel库进行编译(presets为@babel/preset-react)。 支持编译SCSS:如果样式文件的文件名为style.scss,则先用Sass库将SCSS代码编译为CSS代码。style.css则无需编译。 支持JSX和SCSS语法,显著提高了React组件和样式的开发效率。
- oa-codeblock项目架构设计 - 两套环境
我们的OA系统有两套环境:生产环境,开发环境。我们需要先在开发环境上编写代码,测试通过后,再部署到生产环境。同一个功能,在两套环境上的业务逻辑部分完全相同,但是部分配置值会有差异。之前的开发框架实现只支持单个环境,因此需要修改。 环境配置文件:在script.js所在目录中,约定config_prod.js为生产环境的配置文件,config_dev.js为开发环境的配置文件。两种配置文件中通常只定义常量,有哪些常量是完全相同的,只是常量的值不同。如果常量值在环境之间无差异,则直接写在script.js中。 分环境构建并输出:构建时,使用config_prod.js+script.js+style.css构建生产环境版本的脚本文件,并输出到dist/prod/目录下;使用config_dev.js+script.js+style.css构建开发环境版本的脚本文件,并输出到dist/dev/目录下。 代码压缩与格式化:对于生产环境的脚本文件,构建时我们使用uglify-js和clean-css库对JS和CSS代码压缩,提高传输性能;对于开发环境的脚本文件,构建时我们使用prettier库对JS和CSS代码格式化,以便在浏览器中阅读和调试。
- oa-codeblock项目架构设计 - 基本构建
问题 公司使用泛微的Ecology 9作为OA系统,OA提供了代码块功能,能让我们在页面中嵌入自定义的HTML、CSS和JavaScript代码,实现自定义功能。 目前看到同事的开发模式:在后台管理中打开代码块编辑界面,编写代码(主要是JS代码和CSS代码),保存,然后刷新页面查看效果。如果需要修改,就再打开编辑界面,编写,保存,刷新。如此往复。 这种模式显然非常繁琐,除了要编写代码,还要在后台管理中做很多步骤。通常代码要改很多次才能写好,因此这种模式的效率非常低。 我决定做一个开发框架,命名为oa-codeblock项目,简化整个开发流程,提高效率。 思路 代码块中不直接写JS和CSS代码,而是只引用JS脚本文件<script src="...">,CSS代码包含在脚本文件中,也就是说,最终一个脚本文件就对应一块功能,其中同时封装了行为和样式。 开发时,引用的脚本文件在本地,可直接修改其中的代码,然后刷新页面查看效果即可,不必重复保存代码块,也就是说,开发流程被简化为“编写→刷新”2步即可。 部署时,将脚本文件上传到服务器,然后将引用的脚本文件地址改为服务器即可。 实现 基于Node.js来实现开发框架,使用NPM管理依赖。 项目目录结构: package.json:NPM配置文件。 index.js:框架核心代码,执行构建。 template.js:用于构建脚本文件的模板。 src/:源文件目录,存放业务代码。 流程布局/:存放用于流程布局代码块的业务代码。 功能名称/:存放指定功能的业务代码。 script.js:业务代码的JS部分。 style.css:业务代码的CSS部分。 建模布局/:存放用于建模布局代码块的业务代码。 ... 建模查询/:存放用于建模查询代码块的业务代码。 ... dist/:构建输出目录,Git忽略。 脚本文件模板template.js:用于构建脚本文件成品的模板,其中写好了在documentready时才执行JS代码,以及将CSS代码应用到<head>中,并留有占位符,以便将具体的JS和CSS代码替换进来。 框架核心代码index.js: 构建过程:遍历src/目录,如果发现某个目录中有script.js,则说明该目录要构建成一个脚本文件,并输出到dist/目录,src/A/B/C/script.js将输出到dist/A/B/C.js。构建时,从script.js读取JS代码,从style.css读取CSS代码,替换template.js中的占位符,然后输出。 持续构建:支持命令行参数指定一次性构建或持续构建。持续构建时,监听扫描到的script.js和style.css的变化,并在有变化时重新构建对应的脚本文件。这样,“编写”和“刷新”之间就无需手动的“构建”步骤。 实践表明,本开发框架显著提高了开发效率。