diff --git a/README.md b/README.md index 79a6ebe..8d428b2 100644 --- a/README.md +++ b/README.md @@ -1,36 +1,36 @@ -golem-scala -=========== +sbt-wasm-component +================== Avoid any boilerplate in your project by using just one annotation to export your Golem worker from Scala to JS. Setup ----- -Add golem-scala as a dependency in `project/plugins.sbt`: +Add sbt-wasm-component as a dependency in `project/plugins.sbt`: ```scala -addSbtPlugin("cloud.golem" % "golem-scala" % "x.y.z") +addSbtPlugin("cloud.golem" % "sbt-wasm-component" % "x.y.z") ``` Usage ----- -Golem-scala is automatically loaded, it just needs to be enabled with `enablePlugins(GolemScalaPlugin)` in your `build.sbt`: +The WASM component plugin is automatically loaded, it just needs to be enabled with `enablePlugins(WasmComponentPlugin)` in your `build.sbt`: ```scala ThisBuild / version := "0.1.0-SNAPSHOT" ThisBuild / scalaVersion := "2.13.13" lazy val root = (project in file(".")) - .enablePlugins(GolemScalaPlugin) + .enablePlugins(WasmComponentPlugin) ``` -Then you will be able to annotate your Golem worker object with the `@cloud.golem.Worker` annotation: +Then you will be able to annotate your Golem worker object with the `@cloud.golem.WitExport` annotation: ```scala package example -@cloud.golem.Worker +@cloud.golem.WitExport object ShoppingCart { self => def initializeCart(userId: String): String = { @@ -45,5 +45,5 @@ object ShoppingCart { self => ``` -Once done that, it will be enough to run `sbt fullLinkJS` and the plugin will take care of exporting your worker in JS. +Once done that, it will be enough to run `sbt wasmComponent` and the plugin will take care of exporting your worker in WASM. diff --git a/build.sbt b/build.sbt index 19be5ab..a5b08c6 100755 --- a/build.sbt +++ b/build.sbt @@ -5,7 +5,7 @@ ThisBuild / organization := "cloud.golem" lazy val root = (project in file(".")) .settings( - name := "golem-scala", + name := "sbt-wasm-component", addSbtPlugin("org.scala-js" % "sbt-scalajs" % Versions.scalaJS) ) .settings(scriptedLaunchOpts += s"-Dplugin.version=${version.value}") @@ -15,7 +15,7 @@ lazy val root = (project in file(".")) lazy val macros = project .settings( - name := "golem-scala-macros", + name := "sbt-wasm-component-macros", crossScalaVersions += Versions.scala2_13, libraryDependencies += "org.scala-lang" % "scala-reflect" % scalaVersion.value, ) diff --git a/macros/src/main/scala/cloud/golem/Worker.scala b/macros/src/main/scala/cloud/golem/WitExport.scala similarity index 91% rename from macros/src/main/scala/cloud/golem/Worker.scala rename to macros/src/main/scala/cloud/golem/WitExport.scala index 4c7007f..4240eb8 100755 --- a/macros/src/main/scala/cloud/golem/Worker.scala +++ b/macros/src/main/scala/cloud/golem/WitExport.scala @@ -5,11 +5,11 @@ import scala.language.experimental.macros import scala.reflect.macros.whitebox @compileTimeOnly("Enable macro paradise to expand macro annotations") -final class Worker extends StaticAnnotation { - def macroTransform(annottees: Any*): Any = macro WorkerExport.impl +final class WitExport extends StaticAnnotation { + def macroTransform(annottees: Any*): Any = macro WitExportMacro.impl } -object WorkerExport { +object WitExportMacro { def impl(c: whitebox.Context)(annottees: c.Expr[Any]*): c.Expr[Any] = { import c.universe._ diff --git a/src/main/scala/cloud/golem/GolemScalaPlugin.scala b/src/main/scala/cloud/golem/GolemScalaPlugin.scala deleted file mode 100644 index dd09068..0000000 --- a/src/main/scala/cloud/golem/GolemScalaPlugin.scala +++ /dev/null @@ -1,40 +0,0 @@ -package cloud.golem - -import sbt.* -import org.scalajs.sbtplugin.ScalaJSPlugin -import sbt.plugins.JvmPlugin - -object GolemScalaPlugin extends AutoPlugin { - object autoImport { - lazy val golemScalaOutputDirectory = SettingKey[File]( - "golemScalaOutputDirectory", - "Output directory", - KeyRanks.Invisible - ) - lazy val golemScalaWitPath = SettingKey[File]( - "golemScalaWitPath", - "Path to the wit file", - KeyRanks.Invisible - ) - lazy val golemScalaPackageName = SettingKey[String]( - "golemScalaPackageName", - "Package name", - KeyRanks.Invisible - ) - lazy val witBindgen = - taskKey[Seq[File]]( - "Runs golem-scalajs-wit-bindgen to generate WIT bindings" - ) - lazy val component = - taskKey[Unit]("Runs componentize-js on the generated main.js file") - } - - override def trigger: PluginTrigger = allRequirements - - override def requires: Plugins = JvmPlugin && ScalaJSPlugin - - override lazy val projectSettings: Seq[Setting[?]] = - GolemScalaPluginInternal.baseSettings ++ - GolemScalaPluginInternal.scalaJsSettings ++ - GolemScalaPluginInternal.macroParadiseSettings -} diff --git a/src/main/scala/cloud/golem/GolemScalaPluginInternal.scala b/src/main/scala/cloud/golem/GolemScalaPluginInternal.scala deleted file mode 100644 index 875698a..0000000 --- a/src/main/scala/cloud/golem/GolemScalaPluginInternal.scala +++ /dev/null @@ -1,86 +0,0 @@ -package cloud.golem - -import sbt.* -import sbt.Keys.* -import org.scalajs.sbtplugin.ScalaJSPlugin.autoImport.* - -private[golem] object GolemScalaPluginInternal { - import GolemScalaPlugin.autoImport.* - - private object Versions { - val macros = "0.1.0" - val scalaMacrosParadise = "2.1.1" - } - - lazy val baseSettings: Seq[Setting[?]] = { - lazy val golemScalaWitFullPath = - Def - .task(golemScalaWitPath.value / s"${golemScalaPackageName.value}.wit") - Def.settings( - golemScalaOutputDirectory := target.value / "dist", - golemScalaWitPath := (ThisBuild / baseDirectory).value / "wit", - golemScalaPackageName := moduleName.value, - witBindgen := { - if (!golemScalaWitFullPath.value.exists()) { - sys.error(s""" - |'${golemScalaWitFullPath.value.getAbsolutePath}' does not exist. - |Make sure 'golemScalaPackageName' is set correctly in your build.sbt - """.stripMargin) - } else { - val golemScalaWitBindgenOutput = (Compile / sourceManaged).value / "scala" / golemScalaPackageName.value / "Api.scala" - import scala.sys.process.* - - val output = Seq( - "bash", - "-xc", - s"golem-scalajs-wit-bindgen -w ${golemScalaWitFullPath.value} -p ${golemScalaPackageName.value}" - ).!! - - IO.write(golemScalaWitBindgenOutput, output) - Seq(golemScalaWitBindgenOutput) - } - }, - component := { - import scala.sys.process.* - Seq("bash", "-xc", "npm install").!! - Seq("bash", "-xc", "npm run build").!! - }, - component := (component dependsOn (Compile / fullLinkJS)).value, - Compile / sourceGenerators += Def.taskIf { - if (golemScalaWitFullPath.value.exists()) witBindgen.value - else { - println( - s""" - |'${golemScalaWitFullPath.value.getAbsolutePath}' does not exist. - |Make sure 'golemScalaPackageName' is set correctly in your build.sbt""".stripMargin - ) - Nil - } - }.taskValue - ) - } - - lazy val scalaJsSettings: Seq[Setting[?]] = - Def.settings( - scalaJSLinkerConfig ~= { _.withModuleKind(ModuleKind.ESModule) }, - Compile / fullLinkJS / scalaJSLinkerOutputDirectory := golemScalaOutputDirectory.value, - Compile / fastLinkJS / scalaJSLinkerOutputDirectory := golemScalaOutputDirectory.value, - libraryDependencies += "cloud.golem" %% "golem-scala-macros" % Versions.macros - ) - - lazy val macroParadiseSettings: Seq[Setting[?]] = Def.settings( - scalacOptions ++= { - if (scalaVersion.value.startsWith("2.13")) Seq("-Ymacro-annotations") - else Nil - }, - libraryDependencies ++= { - if (scalaVersion.value.startsWith("2.12")) { - Seq( - compilerPlugin( - "org.scalamacros" % "paradise" % Versions.scalaMacrosParadise cross CrossVersion.full - ) - ) - } else Nil - } - ) -} diff --git a/src/main/scala/cloud/golem/WasmComponentPlugin.scala b/src/main/scala/cloud/golem/WasmComponentPlugin.scala new file mode 100644 index 0000000..9d632b5 --- /dev/null +++ b/src/main/scala/cloud/golem/WasmComponentPlugin.scala @@ -0,0 +1,40 @@ +package cloud.golem + +import sbt.* +import org.scalajs.sbtplugin.ScalaJSPlugin +import sbt.plugins.JvmPlugin + +object WasmComponentPlugin extends AutoPlugin { + object autoImport { + lazy val wasmComponentOutputDirectory = SettingKey[File]( + "wasmComponentOutputDirectory", + "Output directory", + KeyRanks.Invisible + ) + lazy val wasmComponentWitPath = SettingKey[File]( + "wasmComponentWitPath", + "Path to the wit file", + KeyRanks.Invisible + ) + lazy val wasmComponentPackageName = SettingKey[String]( + "wasmComponentPackageName", + "Package name", + KeyRanks.Invisible + ) + lazy val wasmComponentWitBindgen = + taskKey[Seq[File]]( + "Runs golem-scalajs-wit-bindgen to generate WIT bindings" + ) + lazy val wasmComponent = + taskKey[Unit]("Runs componentize-js on the generated ScalaJS file") + } + + override def trigger: PluginTrigger = allRequirements + + override def requires: Plugins = JvmPlugin && ScalaJSPlugin + + override lazy val projectSettings: Seq[Setting[?]] = + WasmComponentPluginInternal.baseSettings ++ + WasmComponentPluginInternal.scalaJsSettings ++ + WasmComponentPluginInternal.macroParadiseSettings +} diff --git a/src/main/scala/cloud/golem/WasmComponentPluginInternal.scala b/src/main/scala/cloud/golem/WasmComponentPluginInternal.scala new file mode 100644 index 0000000..c6680ce --- /dev/null +++ b/src/main/scala/cloud/golem/WasmComponentPluginInternal.scala @@ -0,0 +1,89 @@ +package cloud.golem + +import sbt.* +import sbt.Keys.* +import org.scalajs.sbtplugin.ScalaJSPlugin.autoImport.* + +private[golem] object WasmComponentPluginInternal { + import WasmComponentPlugin.autoImport.* + + private object Versions { + val macros = "0.1.0" + val scalaMacrosParadise = "2.1.1" + } + + lazy val baseSettings: Seq[Setting[?]] = { + lazy val wasmComponentWitFullPath = + Def + .task( + wasmComponentWitPath.value / s"${wasmComponentPackageName.value}.wit" + ) + Def.settings( + wasmComponentOutputDirectory := target.value / "dist", + wasmComponentWitPath := (ThisBuild / baseDirectory).value / "wit", + wasmComponentPackageName := moduleName.value, + wasmComponentWitBindgen := { + if (!wasmComponentWitFullPath.value.exists()) { + sys.error(s""" + |'${wasmComponentWitFullPath.value.getAbsolutePath}' does not exist. + |Make sure 'wasmComponentPackageName' is set correctly in your build.sbt + """.stripMargin) + } else { + val wasmComponentWitBindgenOutput = (Compile / sourceManaged).value / "scala" / wasmComponentPackageName.value / "Api.scala" + import scala.sys.process.* + + val output = Seq( + "bash", + "-xc", + s"golem-scalajs-wit-bindgen -w ${wasmComponentWitFullPath.value} -p ${wasmComponentPackageName.value}" + ).!! + + IO.write(wasmComponentWitBindgenOutput, output) + Seq(wasmComponentWitBindgenOutput) + } + }, + wasmComponent := { + import scala.sys.process.* + Seq("bash", "-xc", "npm install").!! + Seq("bash", "-xc", "npm run build").!! + }, + wasmComponent := (wasmComponent dependsOn (Compile / fullLinkJS)).value, + Compile / sourceGenerators += Def.taskIf { + if (wasmComponentWitFullPath.value.exists()) + wasmComponentWitBindgen.value + else { + println( + s""" + |'${wasmComponentWitFullPath.value.getAbsolutePath}' does not exist. + |Make sure 'wasmComponentPackageName' is set correctly in your build.sbt""".stripMargin + ) + Nil + } + }.taskValue + ) + } + + lazy val scalaJsSettings: Seq[Setting[?]] = + Def.settings( + scalaJSLinkerConfig ~= { _.withModuleKind(ModuleKind.ESModule) }, + Compile / fullLinkJS / scalaJSLinkerOutputDirectory := wasmComponentOutputDirectory.value, + Compile / fastLinkJS / scalaJSLinkerOutputDirectory := wasmComponentOutputDirectory.value, + libraryDependencies += "cloud.golem" %% "sbt-wasm-component-macros" % Versions.macros + ) + + lazy val macroParadiseSettings: Seq[Setting[?]] = Def.settings( + scalacOptions ++= { + if (scalaVersion.value.startsWith("2.13")) Seq("-Ymacro-annotations") + else Nil + }, + libraryDependencies ++= { + if (scalaVersion.value.startsWith("2.12")) { + Seq( + compilerPlugin( + "org.scalamacros" % "paradise" % Versions.scalaMacrosParadise cross CrossVersion.full + ) + ) + } else Nil + } + ) +} diff --git a/src/sbt-test/golem-scala/example2/build.sbt b/src/sbt-test/scala-js/example1/build.sbt similarity index 79% rename from src/sbt-test/golem-scala/example2/build.sbt rename to src/sbt-test/scala-js/example1/build.sbt index a0fd24c..538cbb0 100644 --- a/src/sbt-test/golem-scala/example2/build.sbt +++ b/src/sbt-test/scala-js/example1/build.sbt @@ -3,4 +3,4 @@ ThisBuild / scalaVersion := "2.13.13" ThisBuild / crossScalaVersions += "2.12.19" lazy val root = (project in file(".")) - .enablePlugins(GolemScalaPlugin) + .enablePlugins(WasmComponentPlugin) diff --git a/src/sbt-test/golem-scala/example1/project/build.properties b/src/sbt-test/scala-js/example1/project/build.properties similarity index 100% rename from src/sbt-test/golem-scala/example1/project/build.properties rename to src/sbt-test/scala-js/example1/project/build.properties diff --git a/src/sbt-test/golem-scala/example1/project/plugins.sbt b/src/sbt-test/scala-js/example1/project/plugins.sbt similarity index 69% rename from src/sbt-test/golem-scala/example1/project/plugins.sbt rename to src/sbt-test/scala-js/example1/project/plugins.sbt index ab9a6c0..e9b8f58 100644 --- a/src/sbt-test/golem-scala/example1/project/plugins.sbt +++ b/src/sbt-test/scala-js/example1/project/plugins.sbt @@ -1,5 +1,6 @@ sys.props.get("plugin.version") match { - case Some(version) => addSbtPlugin("cloud.golem" % "golem-scala" % version) + case Some(version) => + addSbtPlugin("cloud.golem" % "sbt-wasm-component" % version) case _ => sys.error("""|The system property 'plugin.version' is not defined. |Specify this property using the scriptedLaunchOpts -D.""".stripMargin) diff --git a/src/sbt-test/golem-scala/example1/src/main/scala/example/ShoppingCart.scala b/src/sbt-test/scala-js/example1/src/main/scala/example/ShoppingCart.scala similarity index 90% rename from src/sbt-test/golem-scala/example1/src/main/scala/example/ShoppingCart.scala rename to src/sbt-test/scala-js/example1/src/main/scala/example/ShoppingCart.scala index a9d3931..67de036 100644 --- a/src/sbt-test/golem-scala/example1/src/main/scala/example/ShoppingCart.scala +++ b/src/sbt-test/scala-js/example1/src/main/scala/example/ShoppingCart.scala @@ -1,6 +1,6 @@ package example -@cloud.golem.Worker +@cloud.golem.WitExport object ShoppingCart { self => def initializeCart(userId: String): String = { diff --git a/src/sbt-test/golem-scala/example1/test b/src/sbt-test/scala-js/example1/test similarity index 100% rename from src/sbt-test/golem-scala/example1/test rename to src/sbt-test/scala-js/example1/test diff --git a/src/sbt-test/golem-scala/example1/build.sbt b/src/sbt-test/scala-js/example2/build.sbt similarity index 79% rename from src/sbt-test/golem-scala/example1/build.sbt rename to src/sbt-test/scala-js/example2/build.sbt index a0fd24c..538cbb0 100644 --- a/src/sbt-test/golem-scala/example1/build.sbt +++ b/src/sbt-test/scala-js/example2/build.sbt @@ -3,4 +3,4 @@ ThisBuild / scalaVersion := "2.13.13" ThisBuild / crossScalaVersions += "2.12.19" lazy val root = (project in file(".")) - .enablePlugins(GolemScalaPlugin) + .enablePlugins(WasmComponentPlugin) diff --git a/src/sbt-test/golem-scala/example2/project/build.properties b/src/sbt-test/scala-js/example2/project/build.properties similarity index 100% rename from src/sbt-test/golem-scala/example2/project/build.properties rename to src/sbt-test/scala-js/example2/project/build.properties diff --git a/src/sbt-test/golem-scala/example2/project/plugins.sbt b/src/sbt-test/scala-js/example2/project/plugins.sbt similarity index 69% rename from src/sbt-test/golem-scala/example2/project/plugins.sbt rename to src/sbt-test/scala-js/example2/project/plugins.sbt index ab9a6c0..e9b8f58 100644 --- a/src/sbt-test/golem-scala/example2/project/plugins.sbt +++ b/src/sbt-test/scala-js/example2/project/plugins.sbt @@ -1,5 +1,6 @@ sys.props.get("plugin.version") match { - case Some(version) => addSbtPlugin("cloud.golem" % "golem-scala" % version) + case Some(version) => + addSbtPlugin("cloud.golem" % "sbt-wasm-component" % version) case _ => sys.error("""|The system property 'plugin.version' is not defined. |Specify this property using the scriptedLaunchOpts -D.""".stripMargin) diff --git a/src/sbt-test/golem-scala/example2/src/main/scala/example/Api.scala b/src/sbt-test/scala-js/example2/src/main/scala/example/Api.scala similarity index 100% rename from src/sbt-test/golem-scala/example2/src/main/scala/example/Api.scala rename to src/sbt-test/scala-js/example2/src/main/scala/example/Api.scala diff --git a/src/sbt-test/golem-scala/example2/src/main/scala/example/ShoppingCart.scala b/src/sbt-test/scala-js/example2/src/main/scala/example/ShoppingCart.scala similarity index 92% rename from src/sbt-test/golem-scala/example2/src/main/scala/example/ShoppingCart.scala rename to src/sbt-test/scala-js/example2/src/main/scala/example/ShoppingCart.scala index c1c77f6..91f264b 100644 --- a/src/sbt-test/golem-scala/example2/src/main/scala/example/ShoppingCart.scala +++ b/src/sbt-test/scala-js/example2/src/main/scala/example/ShoppingCart.scala @@ -1,6 +1,6 @@ package example -@cloud.golem.Worker +@cloud.golem.WitExport object ShoppingCart extends Api { self => def initializeCart(userId: String): WitResult[String, String] = { diff --git a/src/sbt-test/golem-scala/example2/test b/src/sbt-test/scala-js/example2/test similarity index 100% rename from src/sbt-test/golem-scala/example2/test rename to src/sbt-test/scala-js/example2/test