【问题标题】:Mixed Clojure and ClojureScript Build With Clojurephant使用 Clojurephant 混合 Clojure 和 ClojureScript 构建
【发布时间】:2020-04-07 22:28:29
【问题描述】:

我正在考虑将一个项目从 boot 转移到 Gradle,clojurephant 希望利用更多的 Gradle 生态系统。该项目构建了一个大型 uberjar,其中包含一个带有 Ring 和 Jetty 的 Clojure 项目,该项目又提供了一个使用 re-frame 构建的 ClojureScript 应用程序。

在启动时,我基本上只需要boot-cljs,添加

(boot-cljs/cljs :optimizations :advanced)

到我的构建任务,它也调用(pom)(aot)(uber)(所有标准启动任务),一切顺利。

使用 Clojurephant,我发现 Clojure 和 ClojureScript 部分最终位于不同的子目录中。特别是我在build下方找到了

  • clojure/main
  • clojurescript/main
  • resources/main(基本上是我的 resources 项目文件夹的副本)

让我更加困惑的是,这些路径并没有以我可以看到的方式转换为 Gradle 使用 shadow plugin 构建的 Uberjar 的结构

摘自我的build.gradle

plugins {
    id 'dev.clojurephant.clojure' version '0.5.0'
    id 'dev.clojurephant.clojurescript' version '0.5.0'
    id 'application'
    id 'com.github.johnrengelman.shadow' version '5.0.0'
    id 'maven-publish'
    id 'distribution'
    id 'com.meiuwa.gradle.sass' version '2.0.0'
}
// ...
clojure {
  builds {
    main {
      aotAll()
    }
  }
}
// ...
clojurescript {
  builds {
    all {
      compiler {
        outputTo = 'public/app.js'
        outputDir = 'public/js/out'
        main = 'com.example.mycljsstuff'
        assetPath = 'js/out'
      }
    }
    main {
      compiler {
        optimizations = 'advanced'
        sourceMap = 'public/app.js.map'
      }
    }
    dev {
      compiler {
        optimizations = 'none'
        preloads = ['com.example.mycljsstuff']
      }
    }
  }
}

编辑:忘了提到启动时我配置了 init 函数以开始将 CLJS 代码加载到一个名为 app.cljs.edn 的文件中。使用 Clojurephant,我只找到了一种设置主命名空间的方法,而不是一个函数。

我的问题归根结底是,如何配置 ClojureScript 构建以便它在从 Uberjar 交付时最终工作?

Clojure 的东西似乎有效。 Ring 和 Jetty 运行并愉快地交付了第一个静态网页。但是所有 CLJS/JS 的东西都找不到。

如果能收到一些指向我可以学习的其他项目、文档或教程的指针,我会非常高兴。我没有找到很多,然后迷失在理解 Clojurephant 本身的代码中。

【问题讨论】:

  • 注意:我正在取得进展,如果我能够解决它,我会分享一个解决方案。

标签: gradle clojure clojurescript


【解决方案1】:

一年前在工作中,我能够将一个组合的 CLJ 和 CLJS(后端/前端)项目拆分为 2 个单独的项目:用于后端的纯 Clojure 和用于前端的纯 ClojureScript。这解决了我们遇到的很多很多问题,我再也不会尝试将两个代码库保留在同一个项目中。

  • 后端CLJ部分继续使用Lein作为构建工具。它并不完美,但很好理解。
  • 前端 CLJS 部分已从原始 Figwheel(又名“1.0”)过渡到新的 Figwheel-Main(又名“2.0”)。跟随figwheel.org的领导 我们选择将构建重组为使用 Deps/CLI(最初的组合项目使用 Lein 进行所有操作)。从 Lein 到 Deps/CLI 的转变是 CLJS 工作的真正赢家。

虽然 Deps/CLI 非常适合纯 Clojure 代码,但请注意,它本身并不支持包含 Java 源代码。我有a template project 您可以克隆它显示一个简单的解决方法。

对于任何 CLJS 项目,我强烈推荐使用 Figwheel-Main 而不是原来的 Figwheel,因为它是主要的“2.0”类型的升级,并且将使你的生活好多了。

享受吧!

【讨论】:

  • 谢谢。我的问题真的集中在 Clojurephant 的使用上。你能告诉它支持哪个版本的无花果吗?也许我应该跳过设置 Figwheel 开发的障碍,然后一切都会自行解决?它可能需要我的 cljs 代码遵循 Clojurephant 也可能期望的一些约定。
  • 看起来像 figwheel-main 0.2.0
【解决方案2】:

试图在这里回答我自己的问题,因为我设法让它运行起来。

Clojure

plugins {
    id 'dev.clojurephant.clojure' version '0.5.0'
    id 'application'
    id 'com.github.johnrengelman.shadow' version '5.0.0'
    // ... more to come further down
}
group = 'com.example'
version = '1.0.0-SNAPSHOT'
targetCompatibility = 1.8
mainClassName = 'com.example.myproject'

dependencies {
    implementation(
        'org.clojure:clojure:1.10.1',
        'ring:ring:1.8.0',
        // and many more
    )
    testImplementation(
        'junit:junit:4.12',
        'clj-http-fake:clj-http-fake:1.0.3',
        'ring:ring-mock:0.4.0'
    )
    devImplementation(
        'org.clojure:tools.namespace:0.3.0-alpha4',
        'cider:cider-nrepl:0.21.1',
        'org.clojure:java.classpath',
        'jonase:eastwood:0.3.11',
        'lein-bikeshed:lein-bikeshed:0.5.2'
    )
}

clojure {
  builds {
    main {
      aotAll()
    }
  }
}

clojureRepl {
  handler = 'cider.nrepl/cider-nrepl-handler'
}

当从命令行调用./gradlew shadowJar 时,这足以从com.example.myproject 命名空间获得一个运行-main 的可执行JAR。不确定application 插件是否与此处相关。此外,./gradlew clojureRepl 启动了一个 Emacs/Cider 可以连接的 nrepl。

ClojureScript

// Merge with plugins above. Reproduced only the CLJS relevant
// part here
plugins {
    id 'dev.clojurephant.clojurescript' version '0.5.0'
}

// Again, merge with dependencies above
dependencies {
    implementation(
        // ....
        'org.clojure:clojurescript:1.10.597',
        're-frame:re-frame:0.10.5',
        'reagent:reagent:0.7.0',
        // and a few more
    )
}

clojurescript {
    builds {
        all {
            compiler {
                outputTo = 'public/app.js'
                outputDir = 'public/state/'
                main = 'com.example.myproject.webui'
                assetPath = 'status/app.out'
            }
        }
        main {
            compiler {
                optimizations = 'advanced'
                sourceMap = 'public/app.js.map'
            }
        }
        dev {
            compiler {
                optimizations = 'none'
                preloads = ['com.example.myproject.webui']
            }
        }
    }
}

这会在 JAR 的顶层创建一个 /public 文件夹,并在该文件夹内创建一个 app.js,这是 Ring 传递的 HTML 文件所期望的位置。

对我来说重要的一步是在 CLJS 文件中调用我的 init CLJS 函数,该函数之前由其他一些组件处理。我不确定这个设置是否完全正确,最终会进行无花果设置。也许那时就不需要打电话给init了。

CSS

// Merge ....
plugins {
    id 'com.meiuwa.gradle.sass' version '2.0.0'
}
sassCompile {
    output = file("$buildDir/resources/main/public/")
    source = fileTree("${rootDir}/src/main/resources/public/")
    include("**/*.scss")
    exclude("**/_*.sass", "**/_*.scss")
}

这会将我的app.scss 编译为app.css 在正确的位置,我的HTML 文件会在其中搜索它。

优缺点

迁移后,我免费获得

  • 正确设置缓存后,本地和 CI 编译速度更快。
  • 使用插件 com.github.jk1.dependency-license-reportorg.owasp.dependencycheck 的许可证和 OWASP 开发检查报告,这些插件在 leiningen 中存在但不启动 (AFAIK)。
  • Maven 发布通过 HTTP 标头进行身份验证,而不是引导时不可用的用户名/密码。

缺点:

  • 我的构建文件中有令人讨厌的语法。不,真的。
  • 我必须在 Emacs 中手动输入 nrepl 端口号。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多