Fork me on GitHub
#polylith
<
2022-12-07
>
danielgrosse13:12:57

Hello, I'm very interested in the Polylith approach. How is the structure usable with some framework like kit or luminous? Do you also hosted normal javascript frontends with it? Like an SPA and a JSON api?

seancorfield16:12:06

Kit and Luminus aren't really frameworks (in the traditional sense) -- they are "curated collections of libraries" in a project template, so there's no reason why you can't use Polylith for your code while still using those libraries -- but they are opinionated templates so their default organization of code looks nothing like Polylith. I think for full-stack apps, people are putting their front end in one base and their primary JSON API in another base, with a project for each to describe any "build" process needed.

seancorfield21:12:02

Just updated our CI process to use poly ws get:changes:changed-or-affected-projects since:release skip:dev color-mode:none so we can build and deploy only the artifacts that actually need it, to cut our build times (since we otherwise build 20 artifacts!). build.clj code in ๐Ÿงต

๐Ÿ‘ 5
polylith 6
seancorfield21:12:46

(defn- changed-projects
  "Produce the list of projects that need building.

  `since` should be `:before-tag` or `:after-tag`"
  [since]
  (let [basis    (b/create-basis {:aliases [:poly]})
        combined (t/combine-aliases basis [:poly])
        cmds     (b/java-command
                  {:basis     basis
                   :java-cmd  (find-java)
                   :java-opts (:jvm-opts combined)
                   :main      'clojure.main
                   :main-args (into (:main-opts combined)
                                    ["ws"
                                     "get:changes:changed-or-affected-projects"
                                     (str "since:"
                                          (case since
                                            :before-tag "release"
                                            :after-tag  "previous-release"))
                                     "skip:dev"
                                     "color-mode:none"])})
        {:keys [exit out err]}
        (b/process (assoc cmds :out :capture))]
    (when (seq err) (println err))
    (if (zero? exit)
      (edn/read-string out)
      (throw (ex-info "Unable to determine changed projects"
                      {:exit exit :out :out})))))
and then
(defn build-all-uberjars
  "Build uberjars for all changed artifacts."
  [params]
  (let [projects (-> (changed-projects (get params :since :before-tag))
                     (set)
                     (set/difference (set billing-build-artifacts)))]
    (uberjars (assoc params :projects projects))))

(defn upload-all-uberjars
  "Upload 'all' artifacts to staging."
  [params]
  (let [projects (-> (changed-projects (get params :since :before-tag))
                     (set)
                     (set/difference (set billing-build-artifacts)))]
  (uploads (assoc params :projects projects))))
The conditional is so we can get the right answer both before and after tagging the release (which we do after testing but before building, so that the release tag is available to our build process that bakes the tag into our uberjars).

seancorfield21:12:16

We haven't migrated our three billing-related projects to Polylith yet, hence the set/difference stuff.

seancorfield21:12:06

Building and deploying all our projects can take ~15 minutes. Building just one takes 1-2 minutes (including running that changed-projects command twice). So it shaves quite a bit of time off CI. A blog post will be coming about all this "soon"...

๐Ÿ™Œ 3