美文网首页
clojure之制作lein模板(一)

clojure之制作lein模板(一)

作者: 小马将过河 | 来源:发表于2019-09-29 09:01 被阅读0次

    传送门

    Writing Templates
    Writing Lein template — quick tutorial

    制作目标项目

    1、创建工程

    ➜  mygitrepo lein new template hc-template --to-dir hc-template
    Generating a Luminus project.
    ➜  mygitrepo 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
    ➜  hc-template
    
    

    2、 根目录手动增加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}
    
    

    3、引入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>
    
    

    5、启动项目,验证是否正常

    ➜  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)
    

    参考luminus-template实现机制编写source加载代码

    参考leiningen的原因是Writing Lein template — quick tutorial这文中妹子没有考虑clojure本身两个大括号{{ }}这种语法是存在的,所以如果用她的方式,代码中本来就是{{的语法将创建模板不成功,我想这也是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

    开发步骤:

    1. 将自己的代码文件保存在resources/leiningen/new/hc_template/对应的目录下。
    2. 修改文件的namespace名称为待赋值的<<project-ns>>,需要引入的其他变量也一样用尖括号括起来,比如项目名称<<name>>。
    3. 将自己的源代码在src/leiningen/new/hc_template.clj 加入到render队列里。
    4. cd到模板项目rcclojuretemplate,执行如下命令
    lein new hc-template test
    
    1. testing 目录则为用模板创建的目标工程
    2. 运行前端,分别执行
    yarn 
    
    yarn start
    

    启动后在浏览器本地9630端口查看项目编译情况,8000端口查看前端页面是否加载正常

    1. 运行后端:通过ide启动后台项目,查看能否正常启动,查看3000端口swagger显示否能正常显示
    2. 前后台都测试通过后,删除testing目录,提交源代码。
    3. 部署更新:修改根目录下project.clj里的版本号,最后一位+1即可,
      通过命令lein deploy部署最新版,账号密码:marvin/Mw99267@,首次部署,会有release版本授权错误提示,需要安装gpg,关于gpg的使用,请参考
    1. 如果本地更新测试不充分或者不想配置gpg,可以先push代码,找马海强发布新版本。

    相关文章

      网友评论

          本文标题:clojure之制作lein模板(一)

          本文链接:https://www.haomeiwen.com/subject/gwukectx.html