使用开源luminus模板策略,制作属于自己的项目模板
传送门
Writing Templates
Writing Lein template — quick tutorial
制作目标项目
- 创建工程
➜ lein new template hc-template --to-dir hc-template
Generating a Luminus project.
➜ cd hc-template
➜ hc-template tree
.
├── CHANGELOG.md
├── LICENSE
├── README.md
├── project.clj
├── resources
│ └── leiningen
│ └── new
│ └── hc_template
│ └── foo.clj
└── src
└── leiningen
└── new
└── hc_template.clj
7 directories, 6 files
➜
- 根目录手动增加shadow-cljs.edn文件
;; This file is generated by lein-shadow, do not manually edit. Instead, edit project.clj shadow-cljs key.
{:nrepl {:port 7002},
:builds
{:app
{:target :browser,
:output-dir "target/cljsbuild/public/js",
:asset-path "/js",
:modules {:app
{:entries [hc-template.app]}},
:devtools {:watch-dir "resources/public",
:preloads [re-frisk.preload]},
:dev {:closure-defines {"re_frame.trace.trace_enabled_QMARK_" true}}
:release {:output-dir "dist/"
:module-hash-names true
:build-options {:manifest-name "cljs-manifest.json"}}}} ,
:test {:target :node-test,
:output-to "target/test/test.js",
:autorun true}},
:dev-http {8000 {:roots ["resources/public" "target/cljsbuild/public"]}}
:lein true}
- 引入antd
npm install antd --save
package.json配置文件
{
"dependencies": {
"antd": "^3.22.0",
"create-react-class": "15.6.3",
"react": "16.8.6",
"react-dom": "16.8.6",
"shadow-cljs": "2.8.39"
},
"devDependencies": {}
}
4、配置入口文件
在resources/public
目录下新建index.html文件,内容如下:
<!DOCTYPE html>
<html lang="cn">
<head>
<title>后台管理系统</title>
<meta charset="utf-8"/>
<meta content="width=device-width, initial-scale=1.0" name="viewport" />
<link href="https://cdn.bootcss.com/antd/3.18.0/antd.min.css" rel="stylesheet">
</head>
<body>
<!-- Our JavaScript will modify the DOM inside this element -->
<div id="app"></div>
<!-- All our ClojureScript gets compiled into this file -->
<script>
document.write("<script type='text/javascript' src='/js/app.js?v="+Math.random()+"' type='text/javascript'><\/script>");
</script>
</body>
</html>
- 启动项目,验证是否正常
➜ shadow-cljs server
Preparing npm packages
Installing npm packages
npm packages successfully installed
Running shadow-cljs...
2019-08-25 20:13:00,880 [main] DEBUG org.jboss.logging - Logging Provider: org.jboss.logging.Slf4jLoggerProvider
2019-08-25 20:13:02,199 [main] DEBUG io.undertow - starting undertow server io.undertow.Undertow@31ff0947
2019-08-25 20:13:02,207 [main] INFO org.xnio - XNIO version 3.7.0.Final
2019-08-25 20:13:02,398 [main] INFO org.jboss.threads - JBoss Threads version 2.3.2.Final
2019-08-25 20:13:02,423 [main] DEBUG io.undertow - Configuring listener with protocol HTTP for interface 0.0.0.0 and port 9630
shadow-cljs - server version: 2.8.39 running at http://localhost:9630
shadow-cljs - nREPL server started on port 7002
shadow-cljs - watching build :app
[:app] Configuring build.
[:app] Compiling ...
[:app] Build completed. (345 files, 344 compiled, 0 warnings, 62.36s)
- clojure编译器概览: http://localhost:9630
- 实时开发的预览: http://localhost:8000
参考luminus-template实现机制编写source加载代码
参考leiningen的原因是Writing Lein template — quick tutorial这文中妹子没有考虑clojure本身两个大括号{{xxx}}
这种语法是存在的,所以如果用她的方式,代码中本来就是{{xxx}}
的语法将创建模板不成功,我想这也是leiningen使用连个尖括号<<name>>
来给变量赋值的原因。
上核心代码:
(ns leiningen.new.common
(:require
[selmer.parser :as selmer]
[leiningen.new.templates :refer [renderer raw-resourcer ->files]]
[clojure.pprint :refer [code-dispatch pprint with-pprint-dispatch]]
[clojure.string :as string]
[clojure.java.io :as io]))
(def template-name "hc-template")
(defn render-template [template options]
(selmer/render
(str "<% safe %>" template "<% endsafe %>")
options
{:tag-open \< :tag-close \> :filter-open \< :filter-close \>}))
(defn init-render []
(renderer template-name render-template))
(defn slurp-resource [path]
(-> (str "leiningen/new/hc_template/" path)
io/resource
slurp))
(selmer/add-tag!
:include
(fn [args context-map]
(-> (slurp-resource (first args))
(render-template context-map)
(string/replace #"^\n+" "")
(string/replace #"\n+$" ""))))
(defn render-asset [render options asset]
(if (string? asset)
asset
(let [[target source] asset]
[target (render source options)])))
(defn render-assets [assets binary-assets options]
(let [render (init-render)
raw (raw-resourcer template-name)]
(apply ->files options
(into
(map (partial render-asset render options) assets)
(map (fn [[target source]] [target (raw source)]) binary-assets)))))
需要加载的资源文件目录是sources/leiningen/new/hc_template
目录下,加载文件:
(ns leiningen.new.hc-template
(:require [leiningen.new.templates :refer [multi-segment sanitize-ns renderer
name-to-path ->files project-name year sanitize]]
[leiningen.core.main :as main]
[selmer.parser :as selmer]
[clojure.string :as string]
[leiningen.new.common :refer :all]
[clojure.java.io :as io]))
(def timestamp (.format
(java.text.SimpleDateFormat. "yyyyMMddHHmmss")
(java.util.Date.)))
(def project-assets
[["dev-config.edn" "dev-config.edn"]
[".gitignore" "gitignore" ]
["Procfile" "Procfile" ]
["project.clj" "project.clj" ]
["Dockerfile" "Dockerfile" ]
["Capstanfile" "Capstanfile" ]
["README.md" "README.md"]
["shadow-cljs.edn" "shadow-cljs.edn" ]
["package.json" "package.json" ]])
(def clj-core-assets
[["{{backend-path}}/{{sanitized}}/core.clj" "src/clj/core.clj"]
["{{backend-path}}/{{sanitized}}/nrepl.clj" "src/clj/nrepl.clj" ]
["{{backend-path}}/{{sanitized}}/config.clj" "src/clj/config.clj"]
["{{backend-path}}/{{sanitized}}/handler.clj" "src/clj/handler.clj"]
["{{backend-path}}/{{sanitized}}/middleware.clj" "src/clj/middleware.clj"]
["{{backend-path}}/{{sanitized}}/middleware/formats.clj" "src/clj/middleware/formats.clj"]
["{{backend-path}}/{{sanitized}}/middleware/exception.clj" "src/clj/middleware/exception.clj"]
["{{backend-path}}/{{sanitized}}/db/core.clj" "src/clj/db/core.clj"]
["{{backend-path}}/{{sanitized}}/routes/services.clj" "src/clj/routes/services.clj"]
["{{backend-path}}/{{sanitized}}/routes/guestbook.clj" "src/clj/routes/guestbook.clj"]
;;test
["{{backend-test-path}}/{{sanitized}}/test/handler.clj" "test/clj/handler.clj"]
["{{backend-test-path}}/{{sanitized}}/test/db/core.clj" "test/clj/db/core.clj"]
;; hc clj
["{{backend-path}}/{{sanitized}}/db/redis.clj" "src/clj/db/redis.clj"]
["{{backend-path}}/{{sanitized}}/common/result.clj" "src/clj/common/result.clj"]])
;;这里还有其他很多代码。。。。。
(def db-assets
[[(str "{{resource-path}}/migrations/" timestamp "-add-users-table.down.sql") "resources/migrations/20190831145908-add-users-table.down.sql"]
[(str "{{resource-path}}/migrations/" timestamp "-add-users-table.up.sql") "resources/migrations/20190831145908-add-users-table.up.sql"]
["{{resource-path}}/sql/queries.sql" "resources/sql/queries.sql"]])
(def binary-assets
[["{{resource-path}}/public/favicon.ico" "resources/public/favicon.ico"]
["{{resource-path}}/public/index.html" "resources/public/index.html"]
["{{resource-path}}/public/img/warning_clojure.png" "resources/public/img/warning_clojure.png"]])
(def core-assets
(vec (concat project-assets
clj-core-aeests
environment-assets
db-assets
cljs-core-assets
system-assets)))
(def project-relative-paths
{:backend-path "src/clj"
:backend-test-path "test/clj"
:client-path "src/cljs"
:client-test-path "test/cljs"
:resource-path "resources"
:cljc-path "src/cljc"
:db-path "src/clj"
:source-paths ["src/clj"]
:resource-paths ["resources"]
:now (java.util.Date.)})
(def render (renderer "hc-template" render-template))
(defn generate-project
"Create a new Luminus project"
[options]
(main/info "Generating a hc-template project.")
(main/info "Please read README.md firstly!!!")
(render-assets core-assets binary-assets options))
(defn hc-template
"init function"
[name]
(let [options (merge
project-relative-paths
{:name (project-name name)
:selmer-renderer render-template
:min-lein-version "2.0.0"
:project-ns (sanitize-ns name)
:sanitized (name-to-path name)
:year (year)
})]
(generate-project options)))
模板开发和测试
源代码目录: resources/leiningen/new/hc_template/
加载模板文件:src/leiningen/new/hc_template.clj
开发步骤:
- 将自己的代码文件保存在resources/leiningen/new/hc_template/对应的目录下。
- 修改文件的namespace名称为待赋值的
<<project-ns>>
,需要引入的其他变量也一样用尖括号括起来,比如项目名称<>。 - 将自己的源代码在
src/leiningen/new/hc_template.clj
加入到render队列里。 - cd到模板项目rcclojuretemplate,执行如下命令
lein new hc-template test
- testing 目录则为用模板创建的目标工程
- 运行前端,分别执行
启动yarn
启动后在浏览器本地9630端口查看项目编译情况,8000端口查看前端页面是否加载正常yarn start
- 运行后端:通过ide启动后台项目,查看能否正常启动,查看3000端口swagger显示否能正常显示
- 前后台都测试通过后,删除testing目录,提交源代码。
- 部署更新:修改根目录下
project.clj
里的版本号,最后一位+1即可,
通过命令lein deploy
部署最新版,账号密码:marvin/Mw99267@,首次部署,会有release版本授权错误提示,需要安装gpg,关于gpg的使用,请参考
- 如果本地更新测试不充分或者不想配置gpg,可以先push代码,找马海强发布新版本。