Skip to content

Instantly share code, notes, and snippets.

@megri
Last active March 24, 2024 08:29
Show Gist options
  • Save megri/9b82e3fc0cbf9b87f1c36ef477129300 to your computer and use it in GitHub Desktop.
Save megri/9b82e3fc0cbf9b87f1c36ef477129300 to your computer and use it in GitHub Desktop.
Simple Indigo config with hot reloading
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline'">
<meta charset="UTF-8">
<title>Hello, Indigo!</title>
<style>
body {
padding: 0;
margin: 0;
overflow-x: hidden;
overflow-y: hidden;
background-color: black;
}
#indigo-container {
display: flex;
align-items: center;
justify-content: center;
padding: 0;
margin: 0;
width: 100vw;
height: 100vh;
}
</style>
</head>
<body>
<!-- This div's id is hardcoded, and several parts of this reference implementation look for it. -->
<div id="indigo-container"></div>
<script type="text/javascript" src="main.js"></script>
<script type="text/javascript">
IndigoGame.launch("indigo-container", { "width": window.innerWidth.toString(), "height": window.innerHeight.toString() })
</script>
</body>
</html>
const { app, BrowserWindow } = require('electron')
try {
const electronReloader = require('electron-reloader')
electronReloader(module, { debug: false })
} catch {}
const createWindow = () => {
const win = new BrowserWindow({
width: 800,
height: 300
})
win.loadFile('index.html')
}
app.whenReady().then(createWindow)
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') app.quit()
})
import mill._, scalalib._, scalajslib._
import scala.collection.mutable
object ElectronModule {
class Worker(val dstRoot: os.Path) extends AutoCloseable {
private val updateTimes = mutable.Map[os.Path, Long]()
private var process: os.SubProcess = null
def updateApp(watchedSourceRoots: Seq[os.Path])(implicit ctx: mill.api.Ctx): Unit = {
watchedSourceRoots.foreach { srcRoot =>
os.walk.stream.attrs(srcRoot).foreach{
case (src, attrs) => replicate(srcRoot, src, attrs)
}
}
if (process == null || !process.isAlive()) {
T.log.info(s"Restarting app.")
process = os.proc("npx", "--no-install", "electron", ".").spawn(cwd = dstRoot)
}
}
private def replicate(srcRoot: os.Path, src: os.Path, srcAttrs: os.StatInfo)(implicit ctx: mill.api.Ctx): Unit = {
val dst = dstRoot / src.relativeTo(srcRoot)
if (srcAttrs.isDir) {
os.makeDir.all(dst)
} else {
val srcUpdatedAt = srcAttrs.mtime.toMillis
val dstUpdatedAt = updateTimes.getOrElse(dst, 0L)
if (dstUpdatedAt < srcUpdatedAt) {
val relDst = dst.relativeTo(dstRoot)
T.log.debug(s"Replacing '$relDst' as $dstUpdatedAt < $srcUpdatedAt.")
if (srcAttrs.isSymLink) {
os.remove(dst)
// os.symlink(dst, dstRoot / os.readLink.absolute(src).relativeTo(srcRoot), os.perms(src)) // gives weird "Initial file attributesnot supported when creating symbolic link" error
os.symlink(dst, dstRoot / os.readLink.absolute(src).relativeTo(srcRoot))
} else {
os.copy(src, dst, replaceExisting = true, copyAttributes = true)
}
updateTimes(dst) = srcUpdatedAt
}
}
}
def close(): Unit = {
if (process.isAlive()) {
process.destroy()
}
process = null
}
}
}
trait ElectronModule extends ScalaJSModule {
def electronVersion: T[Option[String]] = None
def appRoot = T.source {
PathRef(millSourcePath / "app-root")
}
def devWorker = T.worker {
new ElectronModule.Worker(T.dest)
}
def installElectron = T {
val electronArtifact = electronVersion() match {
case Some(v) => s"electron@$v"
case None => "electron"
}
T.log.info(s"Installing $electronArtifact…")
os.proc("npm", "install", "-D", electronArtifact, "electron-reloader").call(cwd = T.dest)
T.log.info(s"Electron installed to '${T.dest}'.")
PathRef(T.dest)
}
def dev = T {
val electronRootPath = installElectron().path
val appRootPath = appRoot().path
val appCodePath = fastLinkJS().dest.path
devWorker().updateApp(Seq(electronRootPath, appRootPath, appCodePath))
}
}
object core extends ElectronModule {
def scalaVersion = "3.3.3"
def ammoniteVersion = "3.0.0-M1"
def scalacOptions = Seq("-Wunused:imports")
def scalaJSVersion = "1.16.0"
val indigoVersion = "0.16.0"
def ivyDeps = Agg(
ivy"io.indigoengine::indigo::$indigoVersion",
ivy"io.indigoengine::indigo-json-circe::$indigoVersion",
ivy"io.indigoengine::indigo-extras::$indigoVersion",
ivy"com.outr::scribe::3.13.0",
)
object test extends ScalaJSTests with TestModule.Munit {
def ivyDeps = Agg(
ivy"org.scalameta::munit::1.0.0-M10",
)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment