raquo / scala-dom-types

Scala types for your library to represent HTML tags, attributes, properties and CSS styles
MIT License
91 stars 27 forks source link

Consider publishing an SBT Plugin? #103

Open markschaake opened 1 month ago

markschaake commented 1 month ago

Hi! My understanding (correct me if I'm wrong) is that scala-dom-types is now really a build tool - whose purpose is to be used at build / compile time to generate code. If that's accurate, then it seems to me the elegant way to provide build tool functionality is via SBT AutoPlugin. Has this been considered? If you are open to the idea, I would be happy to whip together a pull request adding an sbt-scala-domtypes subproject for this. (I already have the start of the code locally in my fork).

I have quite a bit of experience with SBT plugins and would be happy to contribute to this project in this way, unless of course there is a reason to avoid SBT plugins?

raquo commented 1 month ago

Heyo, it's true that we're using SDT somewhat as a build tool – at compile time as a code generator – however keep in mind that this is not the only use case, so core functionality must remain sbt-free. For example, some users may want to use mill instead of sbt, others may want to load SDT as a runtime dependency, e.g. to make some interactive website with the data contained in SDT.

I haven't made it an sbt plugin mainly because I'm trying to minimize dependencies, including dependencies on specialized knowledge and concepts.

My lack of sbt skill is a big part of not having any fancy integration with it. I'm not even sure, what exactly could AutoPlugin give us? If you look at how Laminar uses SDT, then what can we get by making an AutoPlugin? Can it save our users (libraries like Laminar) some boilerplate under /project? That would be nice I think.

markschaake commented 1 month ago

If you look at how Laminar uses SDT, then what can we get by making an AutoPlugin? Can it save our users (libraries like Laminar) some boilerplate under /project? That would be nice I think.

Yes, exactly. A plugin would / could eliminate the need to have the boilerplate code in /project for those client SBT projects using SDT as a build tool. It also would not impact non-SBT and runtime-dependent client projects which would just continue to depend on the library itself. We could add an SBT plugin fairly simply. I think having a plugin would also simplify the use of SDT by future web component binding generator projects (such as laminar-shoelace-components).

In case I haven't been clear: adding an SBT plugin to this project would leave the core library unchanged. The result would be publishing both a library and a complimentary SBT plugin.

If I have time, I'll put together a pull request to illustrate and for discussion.

cornerman commented 1 month ago

Nice idea with the sbt-plugin! The configuration surface of such a plugin might be quite big, because I am guessing, we would need to add an option for everything that is currently configured in the projects/* scala files regarding dom-types. But I think, I would like such a declarative way. Still have to upgrade to the new version of scala-dom-types in outwatch - so all of this sounds great to me if it is possible 👍

I have just recently created two code-generation projects as well and for both have created an sbt and a mill plugin, so I am happy to help on that front if I can.

Actually, I was taking the idea of @raquo for the shoelace-components and tried to write a generic web-components generator project: https://github.com/cornerman/scala-web-components-codegen. You can write your own template to generate code for your ui framework, or it includes a predefined one for outwatch.

markschaake commented 1 month ago

One of the great things about AutoPlugins is how they are composable. I imagine a separate AutoPlugin per use case, each with configuration (setting and task keys) specific to their uses. I.e. one for code gen, one for custom-elements.json parsing, etc. My pull request (coming soon) will illustrate.

raquo commented 1 month ago

@markschaake Sounds good, thanks! If I understand correctly, it seems that the sbt part will be pretty small / self-contained.

It would be nice if you could keep the sbt API surface reasonably small. For example, we have methods like generateTagsTrait that take lots of params. I would prefer to avoid duplicating all those params as sbt keys, otherwise any developer who wants to e.g. add some params to generateTagsTrait would need to understand all the sbt stuff and duplicate their changes there. If we could call existing functions like generateTagsTrait from build.sbt instead, that would be great. If the functions' contract / signature needs to change for that (while retaining the ability for non-sbt usage), that would be ok I think.

markschaake commented 1 month ago

@raquo yes agreed on keeping the API surface small. It might be only two SBT settings and one task, where one of the settings allows the user to do all the default configuration overrides.

I'll try to get something small up tomorrow so we can have a concrete reference to discuss (if I can steal an hour from family time).

markschaake commented 1 month ago

Thanks for the discussion on #104 . I closed it with the following takeaways:

Thanks again for taking the time to help me learn. I know for me and @YakimaProgrammer this knowledge will help us with work we're doing this summer around Shoelace.js integration with Laminar.

@cornerman I will taking a look at your https://github.com/cornerman/scala-web-components-codegen project along with @YakimaProgrammer. It looks like there is some overlap with what we're trying to do this summer - hopefully we can help out!