duct

pez 2020-03-19T20:57:55.044800Z

Hi! I am trying to figure out how to use Calva with a fresh duct +cljs project. Is there somewhere I can read about how to set things up to use Cider with duct +cljs? That would help me figure the Calva options out, I think.

2020-03-20T17:43:37.121300Z

Oh, sorry, not lein-ring. I meant lein-duct.

2020-03-20T17:44:15.121500Z

The lein-duct plugin is for local templates out of source control.

2020-03-20T17:44:28.121700Z

It’s in the Duct repository.

pez 2020-03-20T18:30:13.122100Z

👍

pez 2020-03-19T20:58:52.045800Z

Right now all my attempts end complaints about :cljs-build lacking in project.clj.

kwrooijen 2020-03-19T21:00:58.047Z

I personally would just use Duct for server side, and a separate CLJS frontend with shadow-cljs. Not sure how to have it inside of Duct. I know someone had recently created a shadow-cljs module though

2020-03-19T21:01:03.047100Z

It’s been a while, but should just work with Cider, unless Cider has changed things around. The +cljs option should add a piggyback dependency.

kwrooijen 2020-03-19T21:01:11.047400Z

This one: https://github.com/g7s/module.shadow-cljs

2020-03-19T21:02:09.048600Z

One advantage to using cljs with Duct rather than a separate project is that your frontend is always in sync with your backend.

2020-03-19T21:03:14.048700Z

Oh, actually, I think I remember this now. Cider did change some things around. Let me see if I can find the workaround.

kwrooijen 2020-03-19T21:05:20.050600Z

That's true. I'm not saying it's a bad thing. It's just not my preferred method. I personally like being able to iterate over my frontend without having to deploy the backend as well, since most of my work ends up there anyway

2020-03-20T09:33:20.058700Z

You can have the best of both worlds here. It’s trivial to support multiple workflows in the same repo; including ones that run the front end components independently from your backend etc. Also it makes building isomorphic apps with server side rendering totally possible. We have our shadow-cljs front end in the same source tree as our backend duct which makes integration testing a million times easier; and ensures that features that touch both the backend and frontend can be reviewed together.

kwrooijen 2020-03-20T09:59:23.075200Z

You mean a mono repo?

2020-03-20T10:00:29.075400Z

no I mean a single application repo. If the backend and frontend are the same application, and a front end feature requires a backend change etc put them together.

2020-03-20T10:01:35.075700Z

otherwise you’ll spend forever version bumping / commit locking etc.

2020-03-20T10:01:50.075900Z

I’ve done the later too; and it’s not fun.

2020-03-20T10:03:54.076100Z

e.g. if you’re not careful every time anyone changes branches or merges master they’ll be forgetting to also fetch the new backend; and running into issues that are hard to recreate.

2020-03-20T10:04:40.076300Z

and each PR for new features will be two or more PRs that need to be linked together

2020-03-20T10:05:35.076600Z

so you’ll be using lein checkouts a lot; or tools.deps classpath overrides — which are easy to make mistakes with.

kwrooijen 2020-03-20T13:13:07.102900Z

Sorry I think I'm misunderstanding something. Why would you have to use lein checkouts if frontend and backend are separate?

2020-03-20T13:31:35.113800Z

well it depends entirely on what you’re doing and your architecture — if your front end is purely an spa or whether it includes some server side html; and whether you think that’s backend or frontend. Either way the important problem is that you need to tie the front end and backend versions together somehow, and verify them as working together; and try and avoid issues with version mismatches etc. There are literally a million ways to do that; what I was assuming you were doing was having your backend (clj http server) include your front end project as a dependency, and serve it off the resource path for example. Or you could do it the other way round…

kwrooijen 2020-03-20T13:32:48.114Z

Ahhh ok. No the backend is just purely and API, and the frontend is completely separate, and communicates with it through the API

kwrooijen 2020-03-20T13:33:05.114300Z

They don't actually have context of eachother

2020-03-20T13:33:31.114500Z

so how do you tie the versions together?

kwrooijen 2020-03-20T13:33:32.114700Z

The backend just has a v1 endpoint, which should always be backwards compatible

kwrooijen 2020-03-20T13:34:04.114900Z

They have separate project.clj versions

2020-03-20T13:34:21.115100Z

> should always In my experience this is rarely the case; least of all for intermediate WIP, feature branch releases etc

2020-03-20T13:35:17.115300Z

but you will end up in situations where the front end feature requires a backend bug fix that hasn’t been merged yet etc.

kwrooijen 2020-03-20T13:35:22.115500Z

If it isn't then you introduced a bug, and it shouldn't have gone past the staging environment

kwrooijen 2020-03-20T13:37:14.115700Z

Currently at my work we use a mono repo, which is a single git repo containing both the frontend and backend as separate project. So you keep them in sync that way (you have to deploy both)

kwrooijen 2020-03-20T13:37:31.115900Z

But I'm not a very huge fan of that method

2020-03-20T13:39:46.116100Z

ok sorry I misread separate project as being separate repo too — not separate project in the same repo. There’s a spectrum of options here.

2020-03-20T13:41:14.116300Z

I’m not a big fan of mono-repos either. I’m a fan of carving your repos / projects across the right seams to minimise problems with coordinating changes/releases, and balancing other concerns too — e.g. licensing.

2020-03-20T13:41:43.116500Z

Splitting by layer though is usually a mistake in my book. I prefer to split applications by feature.

kwrooijen 2020-03-20T13:48:11.118900Z

Understandable

2020-03-20T13:49:39.119200Z

I should clarify; it’s a mistake if you don’t have a good reason. Scaling is usually the one people one cite; which I think is fair, if and only if you can’t make splitting vertically scale.

2020-03-19T21:06:18.050700Z

I think you can add to your .dir-locals.el something like:

((nil
  (cider-custom-cljs-repl-init-form . "(do (dev) (cljs-repl))"
  (cider-default-cljs-repl . custom))

pez 2020-03-19T21:07:32.050900Z

Thanks! Let me try that.

2020-03-19T21:08:30.051100Z

It’s actually something that needs to be added back to the .dir-locals.el template. I seem to remember I had to remove the auto-integration of cljs when Cider changed.

pez 2020-03-19T21:11:38.051300Z

Now I get this:

Execution error (AssertionError) at duct.server.figwheel/start-piggieback-repl (figwheel.clj:124).
Assert failed: (some? build)

pez 2020-03-19T21:12:17.051500Z

(Not using CIder here, trying it at the REPL directly.)

2020-03-19T21:12:47.051700Z

Oh! The server has to be started. I forgot that.

2020-03-19T21:12:56.051900Z

(do (dev) (go) (cljs-repl))

pez 2020-03-19T21:18:10.052100Z

Getting closer! 😃 Getting a 404 in the browser...

pez 2020-03-19T21:18:45.052300Z

I might not have set up routes and stuff. Just created this with lein new

2020-03-19T21:19:13.052500Z

Oh yeah, you need some routes. If you use the +example as well as +site +cljs it should work.

pez 2020-03-19T21:22:03.052700Z

I did: lein new duct duct-cljs +site +example +cljs

pez 2020-03-19T21:23:27.052900Z

And now accessed /example and am up and running with my cljs repl and all. 😃

🎉 1
2020-03-19T21:24:18.053100Z

Let me know if the Cider options work

2020-03-19T21:24:25.053300Z

But that’s good news 🙂

pez 2020-03-19T21:25:21.053500Z

I'm using Calva. Want to write a guide how to get it going with Duct, much like this one, for Luminus: https://calva.readthedocs.io/en/latest/luminus.html

💯 1
pez 2020-03-19T21:26:40.053700Z

To get it that streamlined, I would need to provide some Calva settings with the Duct template. Would you consider accepting such a PR?

2020-03-19T21:27:44.053900Z

Yes - though add them to the “lein-ring” plugin, as that’s the one that adds locals outside source control.

pez 2020-03-19T21:34:58.054100Z

OK. will do.

pez 2020-03-19T22:17:28.054300Z

So these are the settings I'd like to provide together with a fresh lein new duct +cljs project.

{
    "calva.replConnectSequences": [
        {
            "name": "Server only",
            "projectType": "Leiningen",
            "afterCLJReplJackInCode": "(do (dev) (go))",
            "cljsType": "none"
        },
        {
            "name": "Server + Client",
            "projectType": "Leiningen",
            "cljsType": {
                "dependsOn": "lein-figwheel",
                "connectCode": "(do (dev) (go) (println \"Server started\") (cljs-repl))",
                "isReadyToStartRegExp": "Server started",
                "printThisLineRegExp": ":duct.server.http.jetty/starting-server"
            }
        }
    ]
}

pez 2020-03-19T22:18:11.054500Z

Doesn't seem to fit in lein-ring, but I am completely new to this so I might misunderstand something.

pez 2020-03-19T22:20:20.054700Z

What the settings achieve is to make Calva jack-in prompt the user for starting the server only or the sever + client. If server + client is selected, it will make calva spawn the cljs-repl.