Mill: deploy same app to different platforms

I am working on a game engine in Scala which I want to support both a web implementation and a jvm implementation, so game creators can deploy their same game to different platforms through a single command. Note that I am not talking about “publishing” my modules as libraries on the internet to Maven etc., I want this command to produce executables locally.

I would like to do this using mill but as I am very new to the tool I have a faint idea how to do it. I have read this Scala Web Project Examples :: The Mill Build Tool
And I roughly understand how to share code between folders that use different platforms.

What I don’t understand, is how I can make a deploy js/jvm command that will take the source code of my game and then compile it to whatever platform was specified. My game code might say import physics.*, but which physics will that import as? the js implementation or the jvm implementation?

My current understanding for what to do is to make submodules for each major part of my engine gui physics assetloading, which my actual game modules will consume. Supposing I am making the game mario

build.sc
gui/
  src/
  src-js/
  src-jvm/
physics/
  src/
  src-js/
  src-jvm/
assetloading/
  src/
  src-js/
  src-jvm/
mario/
  src/
    main.scala // <-- imports gui, physics, assetloading etc. is the real game

And I want to be able to say something like

mario deploy js
mario deploy jvm

and have it take the contents of mario (which should be totally platform agnostic and contain no mentions of jvm/js) and then do a sort of “dependency injection” to give the appropriate providers? Similar analogy to dynamic dispatch in OOP? All references to renderer in the mario game code would be replaced with JSRenderer or JVMRenderre respectively.

Is my thinking correct? How difficult is this, and how should I approach it? Is it mill’s “Tasks” system?

Indigo engine does something not quite like that but similar (they target JS not JVM, the desktop is via Electron), they support both SBT and Mill, you might want to ask in their Discord, they might have some ideas.

Similar advice to the one I gave on Discord.
Solve one step at a time, you haven’t made your engine yet, and you are already thinking about how the users will deploy their games.

I would even say it is more important to first solve the fact that you would want to publish your engine as a library. I don’t think you would want your users to have to download your repo and start coding on top of it.
Anyways, once you actually publish your library, then you can create a sample project / game using that library, and see how to manually publish it to both targets. Once you know the process your users would need to do, then you can analyze both if it is too hard / complex, and if abstracted away, what DX you would want and what it should do.

Nonetheless, to answer your actual question.
You would want to create a mill or sbt plugin, the plugin would provide the custom commands you want, as well as other stuff like maybe even adding the proper libraries, setting up the project structure, generating code, managing assets, etc. Anything and everything you would like to do for your users. Then, your users, rather than adding the game engine libraries, they would add the game engine plugin.
Smithy4s works more or less like this.

3 Likes

Yep, Indigo took that approach as well.

Indigo is built entirely on Scala.js + WebGL, but it’s sbt and Mill plugins will export games for web, desktop (via Electron), and mobile (via Cordova). Hypothetically consoles could also be supported.

1 Like