ClojureScript Support #301
Replies: 11 comments 22 replies
-
not sure I really get this structure, the structure I have been using is simply in projects i have projects like backend-api frontend-ui web-worker etc with bases to match and components that comprise of clj code or components that contain cljs for frontend stuff and cljc components where I require interop or want to share code between the frontend and backend. running two workspaces seems a strange idea when the concept of a projects seems well suited to have fronend backend electron or any other type, the place where I have mainly struggled is around tooling and hot reloading of components with shadow and figwheel which seems to be because those tools are not that keen on relative paths from what I can tell from the warnings. on a side note i tend to prefix a lot of my components with things like ui- and api- to indicate that the component is providing frontend code or is specifically for working with a specific api. no idea if this is helpful but that's my thoughts guides on how to get things like the hot reloading working well would actually be very helpful in this regard. |
Beta Was this translation helpful? Give feedback.
-
In this case I would have for starters a:
I have an integration test project that dockerizes the backend and runs against multiple JVM clients (because blocking and deref'ing is easier). I guess that's another workspace? I note that I have I'm not eager to change our structure, but happy to watch these developments from the sidelines :-) |
Beta Was this translation helpful? Give feedback.
-
We could easily support mixing frontend and backend code in the same workspace (answering @olymk2 and @seancorfield from this Slack thread). I think we can combine support for having both "pure" workspaces (as we suggest) and mixed workspaces. If we have a mixed workspace, we could let the type be set to If we start a shell, we could use Having easy access to different workspaces would be convenient. The polylith workspace has five sub workspaces in its examples directory, and today I have to type I sometimes clone other Polylith repos, e.g. the usermanager-example app, or the polylith workspace where I checkout different branches or hashes, or workspace files that I ask people to send me when I try to understand their problems. If I just want to have a quick look at one of those workspaces, it's convenient to use |
Beta Was this translation helpful? Give feedback.
-
Yes I agree @furkan3ayraktar, it feels cleaner to me to put all
Or like this (alt 2):
The If people really want to mix But if people are convinced that a mixed workspaces is needed and is the best choice for them, then I think we should support it. But right now, I can't see any downsides with our "pure" proposal, except maybe the tooling issue that Sean mentioned in Slack. Maybe you can elaborate a bit on that @seancorfield ? |
Beta Was this translation helpful? Give feedback.
-
The tooling issue that I encountered was for VS Code and clojure-lsp: there's a pretty strong assumption that the "root" of the Clojure code -- the "workspace" in Polylith terms -- is colocated with the "root" of the repo (or workspace in VS Code terms). For quite a while, we had multiple "workspaces" in our repo, a la your "pure" proposal, and it was almost impossible to get LSP working properly with VS Code if you opened the repo directly. I tried a variety of workarounds, with different configurations, at the suggestions of the maintainers, but finally gave up and moved the main Clojure "workspace" up to the top-level of our repo -- at which point everything worked smoothly out-of-the-box. Hence I am strongly against any Polylith setup that does not have the workspace at the top of the repo -- or would require trying to open VS Code for multiple subdirectories inside a repo (i.e., opening VS Code in the Polylith workspace, rather than the repo root). I want one VS Code instance open at my repo root with all my code -- both Clojure and ClojureScript -- accessible in a natural way from that same directory. As for the REPL setup, aren't there some IDE/editor configurations that support both a Clojure REPL and a ClojureScript REPL concurrently, where the cljs REPL is started up from the clj REPL -- and the editor knows how to evaluate code of either type into the appropriate REPL? (I think there's a limitation with VS Code of only one active REPL connection but that certainly is not true of Emacs/CIDER/Piggyback, right?) |
Beta Was this translation helpful? Give feedback.
-
We had an excellent discussion with @PEZ and @tengstrand today. I want to share the outcome and hear what you think. As @seancorfield already mentioned, not having a @PEZ’s expertise in the topic showed us that we could run a single REPL over multiple workspaces with mixed Clojure dialects. The suggestion is to have the following directory structure if you want to split your workspace into multiple workspaces:
With the structure above, we can Jack-In a single
{:paths [; dev sources
"development/src"
; test sources
"bases/rest-api/test"
"components/foo/test"
"components/shared/test"]
:deps {poly/rest-api {:local/root "bases/rest-api"}
poly/foo {:local/root "components/foo"}
poly/shared {:local/root "components/shared"}}}
{:paths [; dev sources
"development/src"
; test sources
"bases/app/test"
"components/bar/test"]
:deps {poly/app {:local/root "bases/app"}
poly/bar {:local/root "components/bar"}
reagent/reagent {:mvn/version "1.2.0"}}} In addition to the two changes above, we have three new files at the repository's root: Root {:aliases {:dev {:extra-deps {poly/backend {:local/root "backend"}
poly/frontend {:local/root "frontend"}
org.clojure/clojure {:mvn/version "1.11.1"}
thheller/shadow-cljs {:mvn/version "2.22.10"}}}
:poly {:main-opts ["-m" "polylith.clj.core.poly-cli.core"]
:extra-deps {polyfy/polylith
{:git/url "https://github.com/polyfy/polylith"
:sha "bd84789c9fe41eaaf19d431f1fc8772808c9eaad"
:deps/root "projects/poly"}}}}}
{:deps true
:dev-http {3000 {:root "frontend/projects/app/public"}}
:nrepl {:write-port-file true}
:builds {:app {:target :browser
:output-dir "frontend/projects/app/public/js"
:asset-path "/js"
:compiler-options {:output-wrapper true}
:modules {:main {:init-fn polylith.example.frontend.app.core/init!}}}}}
{:workspaces {:backend {:dir "backend"
:alias "b"}
:frontend {:dir "frontend"
:alias "f"}}} These changes enable us to share bricks between multiple Polylith workspaces inside a repository and a unified REPL experience for Clojure and ClojureScript. The multi-dialect support can be achieved within a single workspace using I've created a working example at furkan3ayraktar/polylith-multi-ws-experiment. If you follow the REPL instructions, you will have a backend server and a frontend application running simultaneously. |
Beta Was this translation helpful? Give feedback.
-
Not contributing anything meaningful today, except to say I’m very excited about this direction 😊 |
Beta Was this translation helpful? Give feedback.
-
Just a reminder. When this is implemented, we should add cljs to Polylith in clojure-toolbox. |
Beta Was this translation helpful? Give feedback.
-
Hi! I am trying to use the proposed architecture for a clj/cljs monorepo. My backend is Clojure, my frontend is Clojurescript/shadow-cljs/react-native with Reagent and re-frame. The proposed structure appeals to me and I decided to risk trying it out. Question: am I able to run the poly command in the subprojects? I haven't been able to make that work yet. Thanks for polylith! |
Beta Was this translation helpful? Give feedback.
-
Hi, We would not use cljc files and we would not like a separation between front-end and backend code. Just wanted to make sure that the people who write backend with cljs are not being forgotten. We are very excited that polylith will be supporting cljs in the future. We would also be happy to test out alpha versions if that can help, we have some pretty big codebases. Thank you for your awesome work on polylith! |
Beta Was this translation helpful? Give feedback.
-
My suggestion is that we include support for workspaces to contain both |
Beta Was this translation helpful? Give feedback.
-
Until now, Polylith did not support ClojureScript files. There were several reasons for this, mainly because the Polylith team needed more experience with ClojureScript. That has changed in the last two years, mostly because I started to work almost 100% with a beast ClojureScript project. As a result, our initial thoughts about supporting ClojureScript have also changed.
Discussions on adding ClojureScript support started with @tengstrand recently asking me a simple question: “Do you share code between the frontend and the backend?”. Rather than simply answering with a no, I shared a recent discussion within my team about using Polylith in our ClojureScript repository.
In our project, we do not share code between the frontend and the backend. The backend and frontend projects live in different repositories, and we do not have any significant shared code that could be valuable to extract into a commonplace. However, there are other benefits of adding ClojureScript support to Polylith. We realized that our 50K LOC-strong project started to become too complicated even though we kept a good workspace structure inspired by the Polylith. If we used Polylith, with a good naming strategy for the bricks, we could have the best ClojureScript project in the world. Okay, if we want to support ClojureScript in the poly tool, how should it work? Together with @tengstrand, we developed the following proposal.
Clojure uses the
clj
file extension for source files, and ClojureScript usescljs
. A project cannot mixclj
andcljs
source files. The bridge between them is thecljc
file extension. From this basic rule, we came up with the following suggestions to enable the poly tool supporting ClojureScript::type
attribute to the workspace. It is defined in theworkspace.edn
, and can only have the values:clj
or:cljs
.:clj
, the poly tool will considerclj
andcljc
files as the sources and ignore the rest.:cljs
, the poly tool will considercljs
andcljc
files as the sources and ignore the rest.clj
,cljs
, orcljc
files. This way, we can depend on acljc
component from aclj
orcljs
component, even between workspaces.:clj
and another with:cljs
. Then from one of the workspaces, we can depend on a shared code in acljc
brick in the other workspace using the:local/root
syntax.:local/root
dependencies outside the workspace are considered external and appear in the command outputs underlibs
, notdeps
. If we want to consider the dependencies to the bricks in the other Polyliyh workspaces asdeps
, we add a new configuration attribute:workspaces
in theworkspace.edn
file. This configuration points the poly tool to the location of the other workspaces in the file system and assigns them an alias to show them nicely in the command outputs, e.g.s/anothercomponent
.clj
orcljs
bricks and project code or a mix of eitherclj+cljc
orcljs+cljc
. Other types of source code will be ignored.An example directory structure for a git repository with multiple Polylith workspaces:
workspace.edn
file formybackend
project:workspace.edn
file formyfrontend
project:If the backend project has a component called
shared
and if the frontend project uses it, the poly tool commands can display it asb/shared
using the alias from theworkspaces
configuration as a prefix.What do you think about this idea? Is the workspace a good level to separate Clojure and ClojureScript? Does it make sense to keep the Clojure and ClojureScript in separate workspaces within the same git repository and allow sharing bricks between them?
Beta Was this translation helpful? Give feedback.
All reactions