diff --git a/build.sbt b/build.sbt index f5ef8587..d9548b38 100644 --- a/build.sbt +++ b/build.sbt @@ -1,4 +1,4 @@ -val scalaJSVersion = sys.env.getOrElse("SCALAJS_VERSION", "1.0.0") +val scalaJSVersion = sys.env.getOrElse("SCALAJS_VERSION", "1.3.0") lazy val `scalajs-bundler-linker` = project.in(file("scalajs-bundler-linker")) diff --git a/sbt-scalajs-bundler/src/main/scala/scalajsbundler/sbtplugin/Settings.scala b/sbt-scalajs-bundler/src/main/scala/scalajsbundler/sbtplugin/Settings.scala index bd8532a1..ed0ee5b4 100644 --- a/sbt-scalajs-bundler/src/main/scala/scalajsbundler/sbtplugin/Settings.scala +++ b/sbt-scalajs-bundler/src/main/scala/scalajsbundler/sbtplugin/Settings.scala @@ -3,6 +3,7 @@ package scalajsbundler.sbtplugin import java.nio.charset.StandardCharsets import java.nio.file.{Files, Path} import scala.collection.JavaConverters._ +import org.scalajs.jsenv.Input._ import org.scalajs.linker.interface._ import org.scalajs.sbtplugin._ import org.scalajs.sbtplugin.ScalaJSPlugin.autoImport._ @@ -61,37 +62,26 @@ private[sbtplugin] object Settings { ) // Settings that must be applied for each stage in each configuration - private def scalaJSStageSettings(stage: Stage, key: TaskKey[Attributed[File]]): Seq[Setting[_]] = { + private def scalaJSStageSettings(stage: Stage, key: TaskKey[Attributed[Report]], + legacyKey: TaskKey[Attributed[File]]): Seq[Setting[_]] = { val entryPointOutputFileName = s"entrypoints-${stage.toString.toLowerCase}.txt" Def.settings( - scalaJSLinker in key := { + scalaJSLinker in legacyKey := { val config = (scalaJSLinkerConfig in key).value val box = (scalaJSLinkerBox in key).value val linkerImpl = (scalaJSLinkerImpl in key).value - val projectID = thisProject.value.id - val configName = configuration.value.name - val log = streams.value.log val entryPointOutputFile = crossTarget.value / entryPointOutputFileName - if (config.moduleKind != scalaJSLinkerConfig.value.moduleKind) { - val keyName = key.key.label - log.warn( - s"The module kind in `scalaJSLinkerConfig in ($projectID, " + - s"$configName, $keyName)` is different than the one `in " + - s"`($projectID, $configName)`. " + - "Some things will go wrong.") - } - box.ensure { linkerImpl.asInstanceOf[BundlerLinkerImpl] .bundlerLinker(config, entryPointOutputFile.toPath) } }, - scalaJSBundlerImportedModules in key := { - val _ = key.value + scalaJSBundlerImportedModules in legacyKey := { + val _ = legacyKey.value val entryPointOutputFile = crossTarget.value / entryPointOutputFileName val lines = Files.readAllLines(entryPointOutputFile.toPath, StandardCharsets.UTF_8) lines.asScala.toList @@ -105,8 +95,45 @@ private[sbtplugin] object Settings { // Override Scala.js’ jsEnvInput to first run `npm update` jsEnvInput := jsEnvInput.dependsOn(npmUpdate).value, - scalaJSStageSettings(FastOptStage, fastOptJS), - scalaJSStageSettings(FullOptStage, fullOptJS) + /* Moreover, force it to use the output of the legacy key, because lots + * of things in scalajs-bundler assume that there is only one .js file + * that we can put in a specific directory to make things work. + */ + jsEnvInput := { + val prev = jsEnvInput.value + val linkingResult = scalaJSLinkerResult.value + val legacyKeyOutput = scalaJSLinkedFile.value + + // Compute the path to the `main` module, which is what sbt-scalajs puts in jsEnvInput + val report = linkingResult.data + val optMainModule = report.publicModules.find(_.moduleID == "main") + val optMainModulePath = optMainModule.map { mainModule => + val linkerOutputDirectory = linkingResult.get(scalaJSLinkerOutputDirectory.key).getOrElse { + throw new MessageOnlyException( + "Linking report was not attributed with output directory. " + + "Please report this as a Scala.js bug.") + } + (linkerOutputDirectory / mainModule.jsFileName).toPath + } + + // Replace the path to the `main` module by the path to the legacy key output + optMainModulePath match { + case Some(mainModulePath) => + prev.map { inputItem => + inputItem match { + case CommonJSModule(module) if module == mainModulePath => + CommonJSModule(legacyKeyOutput.data.toPath()) + case _ => + inputItem + } + } + case None => + prev + } + }, + + scalaJSStageSettings(FastOptStage, fastLinkJS, fastOptJS), + scalaJSStageSettings(FullOptStage, fullLinkJS, fullOptJS) ) // Settings that must be applied in the Test configuration @@ -129,8 +156,6 @@ private[sbtplugin] object Settings { // Use the product of bundling in jsEnvInput if requireJsDomEnv is true jsEnvInput := Def.task { - import org.scalajs.jsenv.Input._ - assert(ensureModuleKindIsCommonJSModule.value) val prev = jsEnvInput.value val sjsOutput = scalaJSLinkedFile.value.data diff --git a/sbt-scalajs-bundler/src/sbt-test/sbt-scalajs-bundler/browserless/test b/sbt-scalajs-bundler/src/sbt-test/sbt-scalajs-bundler/browserless/test index cb1754c5..154ba7e4 100644 --- a/sbt-scalajs-bundler/src/sbt-test/sbt-scalajs-bundler/browserless/test +++ b/sbt-scalajs-bundler/src/sbt-test/sbt-scalajs-bundler/browserless/test @@ -1,8 +1,9 @@ > run -> clean -> test -> set useYarn := true -> clean -> run -> clean > test + +# Deactivated because `clean` followed by `run` kills the AppVeyor build. +# Testing yarn support is done enough in other tests. +#> set useYarn := true +#> clean +#> run +#> test diff --git a/sbt-scalajs-bundler/src/sbt-test/sbt-scalajs-bundler/newer-linker/project/newer-scala-js.sbt b/sbt-scalajs-bundler/src/sbt-test/sbt-scalajs-bundler/newer-linker/project/newer-scala-js.sbt index 8ad9c6e8..446469ff 100644 --- a/sbt-scalajs-bundler/src/sbt-test/sbt-scalajs-bundler/newer-linker/project/newer-scala-js.sbt +++ b/sbt-scalajs-bundler/src/sbt-test/sbt-scalajs-bundler/newer-linker/project/newer-scala-js.sbt @@ -1 +1,2 @@ -addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.1.0") +// TODO Set this to a version > 1.3.0 when there is one +addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.3.0") diff --git a/sbt-scalajs-bundler/src/sbt-test/sbt-scalajs-bundler/newer-linker/src/test/scala/example/NewerLinkerTest.scala b/sbt-scalajs-bundler/src/sbt-test/sbt-scalajs-bundler/newer-linker/src/test/scala/example/NewerLinkerTest.scala index 6f110465..65431e08 100644 --- a/sbt-scalajs-bundler/src/sbt-test/sbt-scalajs-bundler/newer-linker/src/test/scala/example/NewerLinkerTest.scala +++ b/sbt-scalajs-bundler/src/sbt-test/sbt-scalajs-bundler/newer-linker/src/test/scala/example/NewerLinkerTest.scala @@ -6,7 +6,10 @@ import org.junit.Test class NewerLinkerTest { @Test def newerLinker(): Unit = { - assertEquals("1.1.0", System.getProperty("java.vm.version")) + /* TODO Set this to a version > 1.3.0 when there is one, and adapt the + * test below to something that would have been fixed in the meantime. + */ + assertEquals("1.3.0", System.getProperty("java.vm.version")) /* Test the fix to https://github.com/scala-js/scala-js/issues/3984, which * was shipped in Scala.js 1.0.1. diff --git a/sbt-scalajs-bundler/src/sbt-test/sbt-scalajs-bundler/static/test b/sbt-scalajs-bundler/src/sbt-test/sbt-scalajs-bundler/static/test index 8b5742ad..3116e1e2 100644 --- a/sbt-scalajs-bundler/src/sbt-test/sbt-scalajs-bundler/static/test +++ b/sbt-scalajs-bundler/src/sbt-test/sbt-scalajs-bundler/static/test @@ -11,7 +11,7 @@ $ exists target/scala-2.11/scalajs-bundler/main/static-opt-bundle.js target/scal # Disabling source maps in Scala.js also disables it for scalajs-bundler -> clean +$ delete target/scala-2.11/scalajs-bundler/main/static-fastopt-bundle.js.map target/scala-2.11/scalajs-bundler/main/static-opt-bundle.js.map > set scalaJSLinkerConfig := scalaJSLinkerConfig.value.withSourceMap(false) > fastOptJS::webpack $ absent target/scala-2.11/scalajs-bundler/main/static-fastopt-bundle.js.map @@ -20,7 +20,6 @@ $ absent target/scala-2.11/scalajs-bundler/main/static-opt-bundle.js.map # webpackEmitSourceMaps controls source maps emission for the webpack task -> clean > set scalaJSLinkerConfig := scalaJSLinkerConfig.value.withSourceMap(true) > set webpackEmitSourceMaps in (Compile, fastOptJS) := false > fastOptJS::webpack diff --git a/sbt-scalajs-bundler/src/sbt-test/sbt-scalajs-bundler/yarn-interactive/build.sbt b/sbt-scalajs-bundler/src/sbt-test/sbt-scalajs-bundler/yarn-interactive/build.sbt index a006f9be..8ab99487 100644 --- a/sbt-scalajs-bundler/src/sbt-test/sbt-scalajs-bundler/yarn-interactive/build.sbt +++ b/sbt-scalajs-bundler/src/sbt-test/sbt-scalajs-bundler/yarn-interactive/build.sbt @@ -4,6 +4,8 @@ useYarn := true yarnExtraArgs in Compile := Seq("--silent") +scalaJSUseMainModuleInitializer := true + npmDependencies in Compile += "neat" -> "1.1.2" enablePlugins(ScalaJSBundlerPlugin) diff --git a/sbt-scalajs-bundler/src/sbt-test/sbt-scalajs-bundler/yarn-interactive/src/main/scala/example/Main.scala b/sbt-scalajs-bundler/src/sbt-test/sbt-scalajs-bundler/yarn-interactive/src/main/scala/example/Main.scala new file mode 100644 index 00000000..1397038d --- /dev/null +++ b/sbt-scalajs-bundler/src/sbt-test/sbt-scalajs-bundler/yarn-interactive/src/main/scala/example/Main.scala @@ -0,0 +1,7 @@ +package example + +object Main { + def main(args: Array[String]): Unit = { + println("yarn-interactive main") + } +} diff --git a/sbt-web-scalajs-bundler/src/sbt-test/sbt-web-scalajs-bundler/play/test b/sbt-web-scalajs-bundler/src/sbt-test/sbt-web-scalajs-bundler/play/test index 09e0bdf8..66dab2d5 100644 --- a/sbt-web-scalajs-bundler/src/sbt-test/sbt-web-scalajs-bundler/play/test +++ b/sbt-web-scalajs-bundler/src/sbt-test/sbt-web-scalajs-bundler/play/test @@ -1,15 +1,14 @@ -> clean > server/assets $ exists client/target/scala-2.13/scalajs-bundler/main/client-fastopt-bundle.js $ absent client/target/scala-2.13/scalajs-bundler/main/client-opt-bundle.js +$ delete client/target/scala-2.13/scalajs-bundler/main/client-fastopt-bundle.js -> clean > set scalaJSStage in Global := FullOptStage > server/assets $ exists client/target/scala-2.13/scalajs-bundler/main/client-opt-bundle.js $ absent client/target/scala-2.13/scalajs-bundler/main/client-fastopt-bundle.js +$ delete client/target/scala-2.13/scalajs-bundler/main/client-opt-bundle.js -> clean > set scalaJSStage in Global := FastOptStage > server/test > client/test diff --git a/scalajs-bundler-linker/src/main/scala/scalajsbundler/bundlerlinker/EntryPointAnalyzerBackend.scala b/scalajs-bundler-linker/src/main/scala/scalajsbundler/bundlerlinker/EntryPointAnalyzerBackend.scala index d63e3bdc..f74d29f2 100644 --- a/scalajs-bundler-linker/src/main/scala/scalajsbundler/bundlerlinker/EntryPointAnalyzerBackend.scala +++ b/scalajs-bundler-linker/src/main/scala/scalajsbundler/bundlerlinker/EntryPointAnalyzerBackend.scala @@ -6,14 +6,12 @@ import scala.collection.JavaConverters._ import java.nio.charset.StandardCharsets import java.nio.file.{Files, Path} -import org.scalajs.ir.Trees.JSNativeLoadSpec - import org.scalajs.logging.Logger import org.scalajs.linker.interface._ import org.scalajs.linker.standard._ -final class EntryPointAnalyzerBackend(linkerConfig: StandardConfig, entryPointOutputFile: Path) extends LinkerBackend { +final class EntryPointAnalyzerBackend(linkerConfig: StandardConfig, entryPointOutputFile: Path) extends LinkerBackend { private val standard = StandardLinkerBackend(linkerConfig) val coreSpec: CoreSpec = standard.coreSpec @@ -21,32 +19,10 @@ final class EntryPointAnalyzerBackend(linkerConfig: StandardConfig, entryPointOu def injectedIRFiles: Seq[IRFile] = standard.injectedIRFiles - def emit(unit: LinkingUnit, output: LinkerOutput, logger: Logger)( - implicit ec: ExecutionContext): Future[Unit] = { - - val modules = importedModules(unit) + def emit(moduleSet: ModuleSet, output: OutputDirectory, logger: Logger)( + implicit ec: ExecutionContext): Future[Report] = { + val modules = moduleSet.modules.flatMap(_.externalDependencies).toSet Files.write(entryPointOutputFile, modules.toIterable.asJava, StandardCharsets.UTF_8) - - standard.emit(unit, output, logger) - } - - private def importedModules(linkingUnit: LinkingUnit): List[String] = { - if (linkerConfig.moduleKind == ModuleKind.NoModule) { - Nil - } else { - def importedModulesOf(loadSpec: JSNativeLoadSpec): List[String] = { - import JSNativeLoadSpec._ - loadSpec match { - case Import(module, _) => List(module) - case ImportWithGlobalFallback(Import(module, _), _) => List(module) - case Global(_, _) => Nil - } - } - - linkingUnit.classDefs - .flatMap(_.jsNativeLoadSpec) - .flatMap(importedModulesOf(_)) - .distinct - } + standard.emit(moduleSet, output, logger) } }