助手函数url不生成https_告别生成后不管的脚手架

32f1af88e861fad940b6b1194c939c91.png
脚手架有一个梦想:陪项目走到仓库归档。

随着开发生产活动的进行,我们有了越来越多的大小项目。这些项目大体上有相似的结构、配置,但是过去除了一些细节较多的通用配置(如 tsconfig 文件,eslint 规则等)我们没有维护一个专门的项目模板仓库,究其原因估计主要有两点:

  • 项目配置相似,但是根据项目大小、运行环境,目录结构还是有区别。搞一个项目模板不一定有新建项目时复制粘贴来得快捷。
  • 项目模板随时间始终会有一些大大小小的变化,意味着每次想要新建项目时,项目模板几乎总会是不够新的。

久而久之,根据项目创建的时间和维护的频率,我们甚至能在各个仓库的最新版本找到各个时期的项目结构和配置。

这里鸣谢 yarn.lock(有的同学可能需要鸣谢 package-lock.json),让我们基本上可以在两年后突然需要维护某个小项目时没有大的障碍。

但强迫症表示,他只要最新的!所以很久以前我就萌生了一个想法,搞一套“活”的项目模板工具:一个命令,就可以把已有项目内,与模板相关的内容全部更新,同时不破坏后续的修改。

这套工具就是 magicspace。

更新思路

magicspace 的思路其实很简单:提供一套可配置的模板项目生成机制,并把每次更新生成的版本作为一个新的 commit 提交到模板分支,再将模板分支合并到项目分支,按需解决冲突并完成合并,模板更新就完成了。至于冲突解决,那是 Git 和使用者的事情,magicspace 就不管了。

fc578e118b7ad83a06123793a4976ee1.png
蓝色是项目分支,粉色是模板分支,可以注意到最初两个分支并无关联

不过在实现上,所谓的模板分支并非始终存在,而是“隐藏”在了项目分支之中。magicspace 会识别 commit message 为 (magicspace-*) 的 commit,并在处理过程中从其中最近的一个切出分支。模板分支上的提交是 magicspace 自动完成的,修改合并分支时自动生成的 commit message 并不会影响 magicspace 的后续使用。

最初的方案没有使用 Git,核心是结构化的值,提供了一系列内置的合并选项(merge、override 等)让使用者组合相关内容。当时的实现要求使用者不能修改多数由模板维护的文件,而需要辗转修改相关模板配置后重新生成。实现的时候就觉得很蛋疼,实际使用起来也确实很蛋疼。于是当时 magicspace 就吃灰了两年。

模板编写

吸取了之前的一些经验,新的文件生成机制就做得非常轻量,一些常用的操作也仅仅是作为工具函数抽了出来,没有加入核心设计。

magicspace 模板中,每一个最终生成的文件对应一个 composable file 对象,模板可以继承,并通过提供相同路径的 composable 对象来编排文件内容。这个过程类似一个管道,原始内容通过多个 composable 加工,变成最后的文件。

以 JSON 文件举例,假定 composable module 文件名为 package.json.js,默认对应的 composable file 输出路径则为 package.json。如果当前模板继承的模板已经有相同的文件,那么我们可以通过以下代码为这个 JSON 文件添加一个名为 build 的脚本:

module.exports = {
  type: 'json',
  compose(data) {
    data.scripts = {
      ...data.scripts,
      build: 'tsc --build .',
    };
  },
};

一个更实际的例子:

https://github.com/makeflow/mufan-code-boilerplates/blob/master/typescript/src/composables/package.json.ts​github.com

如上方链接的例子,composable module 可以生成多个文件,也可以导出一个函数根据用户或模板配置的参数(boilerplate.json)动态生成文件内容。

@magicspace/core 包中,提供了 textjsoncopyhandlebars 等简单封装的函数用于构建 composable 对象;@magicspace/utils 包中则提供了另一些工具函数,用于,比如:

  • extendObjectProperties 在特定的键前后扩展属性,如 {after: '*build*'} 在包含 build 的键后扩展属性。
  • extendPackageScript 在脚本特定的命令前后增加命令(字符串修改)。

模板使用

以我们自用的模板为例:

yarn global add magicspace makeflow/mufan-code-boilerplates

其中 makeflow/mufan-code-boilerplates 是从 GitHub 仓库安装,包名实际为 @mufan/code-boilerplates

创建项目及配置文件

mkdir my-project
cd my-project

magicspace create @mufan/code-boilerplates/typescript

2e8783f6c4735b8dc6d1ea9fe9adaf9b.png

选择模板配置用例创建 .magicspace/boilerplate.json,比如选择上方的“library”我们会得到如下模板配置文件:

{
  "extends": "@mufan/code-boilerplates/typescript",
  "options": {
    "name": "awesome-library",
    "license": "MIT",
    "author": "Awesome Author",
    "tsProjects": [
      {
        "name": "library"
      },
      {
        "name": "test"
      }
    ]
  }
}

其中 extends 是一个字符串或数组,即要继承、使用的模板,解析规则和 Node.js require 类似。可用参数可以参考该模板的相关声明:

https://github.com/makeflow/mufan-code-boilerplates/tree/master/typescript​github.com

根据需要修改后初始化 Git 仓库并进行一次提交。

项目初始化

magicspace init

7a706fbee85369bfdce75423900b3a67.png

根据需要修改文件完成合并。

项目更新

由于 magicspace 模板是动态生成的,那么在如下几种情况可以对项目相关部分进行更新:

  1. 模板更新
  2. 模板配置更新(使用者的 .magicspace/boilerplate.json
  3. 模板中动态请求的内容更新(比如我们自用模板中的包版本号)
magicspace update

4338ad2dbce39a3dfb1a078e5f9bebc7.png

同样也是更新后根据需要修改文件、解决冲突,并完成分支合并。如果想要中止更新,只需要执行 git merge --abort 即可。

关于冲突解决

由于模板分支本身和项目分支是平行的,受限于 magicspace 选择的分支合并的方案和 Git 的相关能力,很多时候更新都会产生需要手动解决的冲突:

0703181baf68072f4d852ca3e4aa44b5.png
如果项目中模板生成的内容前后有修改,每一次相关生成内容有改变合并都需要解决冲突

但即便如此,我认为带来的好处依然是显著的,最坏的情况至少把有变化的内容通过冲突的形式展现出来,方便使用者取用。

复用现有模板

magicspace 提供了 postgenerate 的生命周期钩子,因此即便不使用它提供的 composable 机制,也可以直接利用这个生命周期钩子实现现有模板复用。

作为例子我增加了一个 @magicspace/boilerplate-url 模板, 利用这个钩子下载指定 URL 的模板:

{
  "extends": "@magicspace/boilerplate-url",
  "options": {
    "url": "https://github.com/react-boilerplate/react-boilerplate/archive/master.zip",
    "strip": 1
  }
}

postgenerate 中我们可以直接使用模板包依赖中的命令,因此如果需要,我们完全可以将一些现有脚手架和 magicspace 组合使用。


Makeflow(makeflow.com)让团队经验可以像文档一样详细地记录在流程中,指导和验证工作实践。每一次经验的迭代都可以通过任务的执行自然“推送”到整个团队,消除工作流程从想法到实践、从实践到改进之间的多种障碍。大到产品迭代管理,小到监控报警处置:记录、实践、再记录,把每一次进步写入团队基因——延续、变化、可复制。

相关阅读

vilicvane:通用 TypeScript 项目结构与实践经验​zhuanlan.zhihu.com
8fbd46d1aba1eb92f2a4257a3cdc0562.png
匿名小葫芦:使用Rust实现一个简单的文件系统​zhuanlan.zhihu.com
b01ec70e18eb98a65b0de7ba0437f2f9.png
温柏甫:网页上用 Rust 渲染十万个待办事项有多快?​zhuanlan.zhihu.com
437a8ef1c0e1c78e6a333b6ceeb20bd4.png
vilicvane:一窥 Draft.js 受控渲染机制​zhuanlan.zhihu.com
73477fb2f913c6eef5aff3c91cdd8e4b.png
vilicvane:VS Code 远程开发和代码评审实践​zhuanlan.zhihu.com
b90546d59d994ced28e4f6681bbe4507.png
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值