新闻详情

新闻详情

首页 / 资讯中心 / 详情

Leiningen 自定义模板编写指南:从 `lein new template` 生成脚手架到 Clojars 发布

发布时间:2026/9/29 20:25:25来源:尧图网络
Leiningen 自定义模板编写指南:从 `lein new template` 生成脚手架到 Clojars 发布
构建工具CLI【免费下载链接】leiningenMoved to Codeberg; this is a temporary convenience mirror项目地址https://gitcode.com/gh_mirrors/le/leiningen点击查看免费下载Leiningen 内置的lein new任务自带app、plugin、default等模板但当你的库library需要一定初始化配置时最好的做法是为用户提供一份专属模板。本文以官方文档 doc/TEMPLATES.md 为骨架结合leiningen.new.templates等核心源码完整讲解自定义模板的创建、目录结构、Mustache 渲染机制、本地测试、发布到 Clojars 的完整流程以及新旧两种模板命名规范的区别。读完本文你将能独立开发并发布一个可被lein new按需拉取的第三方模板。何时需要自定义模板假设你编写了一个广受欢迎的库比如发布在 Clojars 上的us.technomancy/liquid-cool。如果使用该库需要一些额外配置或者你想给用户提供如何最佳地创建一个使用 liquid-cool 的项目的指引就可以为它提供一份模板——正如lein已经为app、plugin、default等提供了内置模板一样。模板本质上是一组项目脚手架文件用户执行lein new 模板名 项目名后Leiningen 会按照模板的约定生成一个可运行的、预置了该库依赖与目录结构的全新项目。创建模板项目lein new template创建模板本身也使用lein new任务只是套用了一个名为template的元模板meta-template。在官方文档的例子中模板名取自你的库名也可以使用其他名字但需注意 Clojars 对 group-id 的归属验证政策——无法验证所有权的 group-id 不能新建lein new template us.technomancy/liquid-cool --to-dir liquid-cool-template其中--to-dir指定生成目录与项目名不同lein new默认以项目名作为目录名。生成出的模板项目结构如下liquid-cool-template/ ├── CHANGELOG.md ├── LICENSE ├── project.clj ├── README.md ├── resources │ └── leiningen │ └── new │ └── liquid_cool │ └── foo.clj └── src └── leiningen └── new └── liquid_cool.clj注意这会产生一个全新的、独立的项目liquid-cool-template其 group-id 为us.technomancyartifact-id 为lein-template.liquid-cool前缀lein-template.是模板 artifact 的固定约定详见下文命名规范一节。这一生成过程由 src/leiningen/new/template.clj 中的template函数实现它先调用(t/renderer template)创建渲染器然后把template-name、artifact-id、group-prefix、sanitized、year、date等键放入 data再通过-files依次生成README.md、project.clj、.gitignore、.hgignore、src/leiningen/new/{{sanitized}}.clj、resources/leiningen/new/{{sanitized}}/foo.clj、LICENSE、CHANGELOG.md等文件。其中src/leiningen/new/{{sanitized}}.clj就是新模板的入口源码{{sanitized}}会被渲染为下划线形式的模板名例如liquid_cool。生成的模板入口文件内容对应仓库中的 resources/leiningen/new/template/temp.clj如下(ns leiningen.new.{{artifact-id}} (:require [leiningen.new.templates :as tmpl] [leiningen.core.main :as main])) (def render (tmpl/renderer {{sanitized}})) (defn {{artifact-id}} FIXME: write documentation [name] (let [data {:name name :sanitized (tmpl/name-to-path name)}] (main/info Generating fresh lein new {{name}} project.) (tmpl/-files data [src/{{placeholder}}/foo.clj (render foo.clj data)])))而模板自身的project.clj见 resources/leiningen/new/template/project.clj使用了lein-template.前缀的 artifact-id并声明:eval-in-leiningen true——模板代码需要在 Leiningen 进程内执行(defproject {{group-prefix}}lein-template.{{artifact-id}} 0.1.0-SNAPSHOT :description FIXME: write description :url http://example.com/FIXME :license {:name EPL-2.0 OR GPL-2.0-or-later WITH Classpath-exception-2.0 :url https://www.eclipse.org/legal/epl-2.0/} :eval-in-leiningen true)从源码结构看template函数还会在模板名不带 group-id 时发出警告Clojars 新安全政策要求模板名必须携带 group-id否则可以生成该模板但可能无法发布到 Clojars。模板的目录结构与-files约定模板提供给用户的所有文件都放在resources/leiningen/new/liquid_cool目录下模板生成器初始只放了一个foo.clj。你可以删除foo.clj连同入口文件中对应的那一行然后往resources/leiningen/new/liquid_cool中填充你希望出现在新项目里的任意文件。关键约定每添加一个文件都必须同步在liquid_cool.clj的-files调用中增加对应的条目。-files是leiningen.new.templates提供的一个迷你 DSL其完整实现位于 src/leiningen/new/templates.clj规则如下向量[路径 内容]第一个元素是文件路径第二个元素是写入的内容字符串目录名表示创建一个空目录所有路径都会被当作 Mustache 模板用 data 渲染没有占位符的路径不受影响父目录自动创建可选第三项:executable true会把生成文件标记为可执行测试 test/leiningen/test/new/templates.clj 中有对应验证。以内置的app模板src/leiningen/new/app.clj为例它在 data 中准备了:raw-name、:name、:namespace、:nested-dirs、:year、:date等键然后一次性生成project.clj、README.md、doc/intro.md、.gitignore、.hgignore、src/{{nested-dirs}}.clj、test/{{nested-dirs}}_test.clj、LICENSE、CHANGELOG.md以及空目录resources。可以看到src/{{nested-dirs}}.clj这样的路径本身也是模板——nested-dirs由name-to-path计算得到例如foo-bar.baz→foo_bar/baz路径占位符与内容占位符统一被渲染这就是-files对路径也执行render-text的原因见template-path私有函数。为了方便编写模板leiningen.new.templates还提供了以下工具函数均有对应单元测试函数作用示例project-name从可能带 group 限定的名字中取出项目名us.technomancy/liquid-cool→liquid-coolsanitize-ns把项目名转成命名空间形式foo_bar→foo-barmulti-segment给命名空间补充core段已含.则不变foo→foo.corename-to-path把完整 artifact 名转成目录结构foo-bar.baz→foo_bar/bazgroup-name从名字中提取 groupmygroup/myproj→mygroupsanitize连字符转下划线liquid-cool→liquid_coolyear/date当前年份 / ISO8601 日期用于版权声明等—另外fix-line-separators会把模板资源中的\n统一转换为当前系统的换行符如需强制 Unix 换行例如确保生成文件在 Windows 下也使用\n可以设置环境变量LEIN_NEW_UNIX_NEWLINES。renderer从 classpath 上固定约定位置leiningen/new/模板名/读取资源资源缺失时会以Template resource leiningen/new/模板名/文件 not found.终止执行。若模板需要复制图片等二进制资源可使用raw-resourcer直接以输入流返回原始字节不做渲染。测试你的模板开发模板期间只要处于模板项目目录内Leiningen 就能识别它可以直接在本目录测试。例如在liquid-cool-template目录下执行$ lein new us.technomancy/liquid-cool myproject这会创建一个名为myproject的目录内容由你的模板构建。如果想在系统上的其他任意目录测试且尚未把模板发布到 Clojars先执行$ lein install把模板安装到本地 Maven 仓库即加入本机 classpath之后就能从任何目录运行lein new us.technomancy/liquid-cool myproject了。从源码看src/leiningen/new.cljlein new对模板的解析分为两步先尝试直接require本地 classpath 上的leiningen.new.模板名命名空间若未找到抛出FileNotFoundException则通过resolve-remote-template把模板当作依赖解析并动态加入 classpath再require。因此第三方模板不需要事先安装lein new会自动按需拉取。模板渲染系统Stencil 与 Mustache默认生成的模板使用 [stencil][] 作为模板引擎它实现了语言无关的 [Mustache][] 模板系统本仓库在 src/leiningen/new/templates.clj 中直接把stencil/render-string暴露为render-text让模板作者不必额外引入 stencil 依赖。Mustache 的全部标签类型可查阅官方手册这里只介绍最常用的形式。假设我们要加入一个以输入的项目名为主标题的标准 Markdown 说明文件需要做两件事确保输入的项目名存在于 data 中某个键对应的值里在模板文件中用双花括号包裹该键来查找它{{X}}。由于 data 中已经包含:name name因此在模板文件中写{{name}}即可取到输入的项目名。把以下内容保存到resources/leiningen/new/liquid_cool/README.md# {{name}} This is our readme!然后在liquid_cool.clj的-files data行下方加入一行[README.md (render README.md data)]此时执行lein new us.technomancy/liquid-cool liquid-cool-app新生成的项目中就会出现README.md其标题为liquid-cool-app。渲染时renderer会在 classpath 的leiningen/new/liquid_cool/目录下查找README.md读取后用 data 渲染见 src/leiningen/new/templates.clj。除了:name你可以随意向 data 中增加自定义键例如模板名、年份、命名空间等并在模板文件中以{{键名}}引用。警告Mustache 标签定界符与 Clojure 语法的冲突Mustache 默认定界符是双花括号{{ }}而 Clojure 的 map 解构语法也使用{{ }}。例如下面这段在解构嵌套 map 的 Clojure 代码(let [{{:keys [a b]} :ab} some-map] (do-something a b))Stencil 会把{{识别为 Mustache 标签的开始但标签内容不是合法的 Mustache渲染必然失败。解决办法是临时修改 Mustache 的定界符例如改成%和%{{! Change mustache delimiter to % and % }} {{% %}} (let [{{:keys [a b]} :ab} some-map] (do-something a b)) %! Reset mustache delimiter % %{{ }}%第一行{{% %}}把定界符切换为% %中间的 Clojure 代码得以原样保留最后一行%{{ }}%把定界符恢复为默认的双花括号。如果你需要渲染包含{{..}}这类与 Stencil 冲突标签的内容renderer还支持传入自定义渲染函数作为第二个参数来替换默认渲染器。分发你的模板模板本质上就是 Maven artifact即依赖只需要在lein new调用时位于 classpath 上即可。因此你可以把模板打成 jar 发布到 Clojars让用户像安装普通 Leiningen 插件一样使用它。模板在本地找不到时会按需拉取例如执行lein new com.heroku/hello myprojectlein new会从 Clojars 找到com.heroku/lein-template.hello的最新版本并自动使用它。从源码看src/leiningen/new.clj模板坐标解析的逻辑是如果模板名包含/如com.heroku/hello就拆成 group-idcom.heroku与 artifact-idhello然后查询坐标为com.heroku/lein-template.hello如果模板名不含/旧式则视为模板名/lein-template。解析时还会构造一个伪项目fake-project把模板放进:templates依赖向量版本默认取RELEASE指定--snapshot时取(0.0.0,)即最新快照并按用户 profile 中的:plugin-repositories与:mirrors扩展仓库配置然后调用cp/resolve-dependencies拉取并加入 classpath。与lein new相关的实用选项lein new任务src/leiningen/new.clj还支持以下与模板使用相关的选项--to-dir $DIR生成到指定目录而非默认的项目名目录--force允许写入已存在的目录默认拒绝--snapshot使用未发布的 SNAPSHOT 版本模板--template-version $VERSION指定模板的具体版本--分隔lein new自身的参数与传给模板的参数例如lein new $TEMPLATE $PROJECT --to-dir $DIR -- template-arg-1 template-arg-2lein new :show $TEMPLATE查看某个模板的文档与参数列表从模板入口函数的元数据读取。此外create函数还会校验项目名包含jure/eauxure的滑稽命名、大写字母项目名LEIN_BREAK_CONVENTION环境变量可绕过、以及非合法 Clojure symbol 的名字都会被拒绝以保证生成的项目能正常被 Clojars/Central 等仓库接受。旧式模板与命名规范Legacy Templates在 Leiningen 2.9.6 之前模板默认以模板名作为 group-id、以lein-template作为 artifact-id。由于 Clojars 政策变更新模板必须采用每个模板名都包含 group-id 和 artifact-id的新风格模板 artifact 采用给定的 group-id并在模板名给出的 artifact-id 前加上lein-template.前缀。例如模板名us.technomancy/liquid-cool对应的 artifact 是us.technomancy/lein-template.liquid-cool。旧式风格在使用已有模板时仍受支持但不推荐用于创建新模板。当你用不带 group-id 的名字执行lein new template时src/leiningen/new/template.clj 会打印警告提示你无法将其发布到 Clojars。结语模板开发的核心可以概括为三条约定文件放在resources/leiningen/new/模板名/下、入口函数在src/leiningen/new/模板名.clj中并通过-files声明生成、模板文件内容用 Mustache 语法渲染。这三条约定在lein new的解析、renderer的资源查找与-files的 DSL 中层层呼应也决定了模板既是依赖又是函数的本质——分发时只需打成 jar 发布到 Clojars用户执行lein new时它就会被按需拉取。更完整的参考实现可以阅读仓库内置模板 resources/leiningen/new/ 下的app、default、plugin、template四套资源文件以及 src/leiningen/new/templates.clj 中的全部工具函数。赞分享构建工具CLI【免费下载链接】leiningenMoved to Codeberg; this is a temporary convenience mirror项目地址https://gitcode.com/gh_mirrors/le/leiningen点击查看免费下载相关推荐Leiningen 模板项目生成全解析lein new template 与 README 脚手架的 Mustache 渲染机制Leiningen 模板项目生成全解析 lein new template 与 README 脚手架的 Mustache 渲染机制 Leiningen 内置的构建工具CLILeiningen lein new 与 default 模板深度解析从 README 模板到库项目脚手架Leiningen lein new 与 default 模板深度解析从 README 模板到库项目脚手架 lein new 是 Leiningen 中用于生构建工具CLILeiningen自定义模板开发快速生成项目脚手架Leiningen自定义模板开发快速生成项目脚手架 作为Clojure项目构建工具Leiningen莱宁根提供了强大的项目脚手架功能。本文将详细介绍如何构建工具CLI创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

直接上代码!用 TaoToken 统一 Key 拆解 MCP 的 N+M 复杂度 2026/9/29 21:10:10

直接上代码!用 TaoToken 统一 Key 拆解 MCP 的 N+M 复杂度

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
JVM内存模型与垃圾回收全解析:从OOM排查到性能调优实践 2026/9/29 21:10:09

JVM内存模型与垃圾回收全解析:从OOM排查到性能调优实践

说实话,身边不少写了好几年 Java 的老同事,一到排查线上问题还是会犯怵:CPU 飙到 100% 不知道先看哪,内存疯狂上涨不知道怎么抓证据,动不动抛 OutOfMemoryError 更是一头雾水。归根结底,是对 JVM 还不够熟。…

阅读更多 →
用游标批量生成数据库空表:TaoToken 配置与验证实战 2026/9/29 21:10:03

用游标批量生成数据库空表:TaoToken 配置与验证实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
从 PHP 到 AI + Golang,程序员自救转型手记(二十四):登录接口整合点选验证码,TaoToken 配置踩坑与修复 2026/9/29 21:09:49

从 PHP 到 AI + Golang,程序员自救转型手记(二十四):登录接口整合点选验证码,TaoToken 配置踩坑与修复

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
OpenHarmony I2C驱动开发与实战排障指南 2026/9/29 21:09:49

OpenHarmony I2C驱动开发与实战排障指南

1. I2C 总线不是“接上线就能通”的黑盒子——它是一条需要被读懂的双向对话通道I2C(Inter-Integrated Circuit)总线在OpenHarmony设备开发中,远不止是两根线(SCL SDA)加几个上拉电阻那么简单。它是一套精密的、带状态…

阅读更多 →
OpenClawan 安装指南:从架构讲解到多智能体配置与故障排除 2026/9/29 21:09:49

OpenClawan 安装指南:从架构讲解到多智能体配置与故障排除

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉