Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Link Scala.js using Directory path when available #1714

Merged
merged 2 commits into from
Jan 29, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions scalajslib/src/ScalaJSModule.scala
Original file line number Diff line number Diff line change
Expand Up @@ -134,10 +134,9 @@ trait ScalaJSModule extends scalalib.ScalaModule { outer =>
moduleKind: ModuleKind,
esFeatures: ESFeatures
)(implicit ctx: Ctx): Result[PathRef] = {
val outputPath = ctx.dest / "out.js"
val outputPath = ctx.dest

os.makeDir.all(ctx.dest)
os.remove.all(outputPath)

val classpath = runClasspath.map(_.path)
val sjsirFiles = classpath
Expand Down
26 changes: 26 additions & 0 deletions scalajslib/test/resources/top-level-exports/src/App.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package my.app

import scala.collection.mutable
import scala.scalajs.js.annotation._

object AppA {
@JSExportTopLevel(name = "start", moduleID = "a")
def a(): Unit = println("hello from a")
}

object AppB {
private val x = mutable.Set.empty[String]

@JSExportTopLevel(name = "start", moduleID = "b")
def b(): Unit = {
println("hello from b")
println(x)
}

def main(): Unit = x.add("something")
}
object App {
def main(args: Array[String]): Unit = {
println("Hello")
}
}
49 changes: 49 additions & 0 deletions scalajslib/test/src/TopLevelExportsTests.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package mill.scalajslib

import mill._
import mill.define.Discover
import mill.scalajslib.api._
import mill.util.{TestEvaluator, TestUtil}
import utest._

object TopLevelExportsTests extends TestSuite {
val workspacePath = TestUtil.getOutPathStatic() / "top-level-exports"

object TopLevelExportsModule extends TestUtil.BaseModule {

object topLevelExportsModule extends ScalaJSModule {
override def millSourcePath = workspacePath
override def scalaVersion = sys.props.getOrElse("TEST_SCALA_2_13_VERSION", ???)
override def scalaJSVersion = "1.8.0"
override def moduleKind = ModuleKind.ESModule
}

override lazy val millDiscover = Discover[this.type]
}

val millSourcePath = os.pwd / "scalajslib" / "test" / "resources" / "top-level-exports"

val evaluator = TestEvaluator.static(TopLevelExportsModule)

val tests: Tests = Tests {
prepareWorkspace()

test("top level exports") {
println(evaluator(TopLevelExportsModule.topLevelExportsModule.sources))
val Right((PathRef(outFile, _, _), _)) =
evaluator(TopLevelExportsModule.topLevelExportsModule.fastOpt)
assert(os.exists(outFile))
assert(os.exists(outFile / os.up / "a.js"))
assert(os.exists(outFile / os.up / "a.js.map"))
assert(os.exists(outFile / os.up / "b.js"))
assert(os.exists(outFile / os.up / "b.js.map"))
}
}

def prepareWorkspace(): Unit = {
os.remove.all(workspacePath)
os.makeDir.all(workspacePath / os.up)
os.copy(millSourcePath, workspacePath)
}

}
3 changes: 2 additions & 1 deletion scalajslib/worker/0.6/src/ScalaJSWorkerImpl.scala
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ class ScalaJSWorkerImpl extends mill.scalajslib.api.ScalaJSWorkerApi {
def link(
sources: Array[File],
libraries: Array[File],
dest: File,
destDir: File,
main: String,
testBridgeInit: Boolean, // ignored in 0.6
fullOpt: Boolean,
Expand All @@ -84,6 +84,7 @@ class ScalaJSWorkerImpl extends mill.scalajslib.api.ScalaJSWorkerApi {
val jars =
libraries.map(jar => IRContainer.Jar(new FileVirtualBinaryFile(jar) with VirtualJarFile))
val jarSJSIRs = jars.flatMap(_.jar.sjsirFiles)
val dest = new File(destDir, "out.js")
val destFile = AtomicWritableFileVirtualJSFile(dest)
val logger = new ScalaConsoleLogger
val initializer = Option(main).map { cls => ModuleInitializer.mainMethodWithArgs(cls, "main") }
Expand Down
47 changes: 32 additions & 15 deletions scalajslib/worker/1/src/ScalaJSWorkerImpl.scala
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,13 @@ import java.io.File
import mill.api.{Result, internal}
import mill.scalajslib.api.{ESFeatures, ESVersion, JsEnvConfig, ModuleKind}
import org.scalajs.ir.ScalaJSVersions
import org.scalajs.linker.{PathIRContainer, PathIRFile, PathOutputFile, StandardImpl}
import org.scalajs.linker.{
PathIRContainer,
PathIRFile,
PathOutputDirectory,
PathOutputFile,
StandardImpl
}
import org.scalajs.linker.interface.{
ESFeatures => ScalaJSESFeatures,
ESVersion => ScalaJSESVersion,
Expand All @@ -32,6 +38,10 @@ class ScalaJSWorkerImpl extends mill.scalajslib.api.ScalaJSWorkerApi {
esFeatures: ESFeatures,
dest: File
)
private def minorIsGreaterThan(number: Int) = ScalaJSVersions.binaryEmitted match {
case s"1.$n" if n.toIntOption.exists(_ < number) => false
case _ => true
}
private object ScalaJSLinker {
private val cache = mutable.Map.empty[LinkerInput, WeakReference[Linker]]
def reuseOrCreate(input: LinkerInput): Linker = cache.get(input) match {
Expand All @@ -41,10 +51,6 @@ class ScalaJSWorkerImpl extends mill.scalajslib.api.ScalaJSWorkerApi {
cache.update(input, WeakReference(newLinker))
newLinker
}
private def minorIsGreaterThan(number: Int) = ScalaJSVersions.binaryEmitted match {
case s"1.$n" if n.toIntOption.exists(_ < number) => false
case _ => true
}
private def createLinker(input: LinkerInput): Linker = {
val semantics = input.fullOpt match {
case true => Semantics.Defaults.optimized
Expand Down Expand Up @@ -111,18 +117,12 @@ class ScalaJSWorkerImpl extends mill.scalajslib.api.ScalaJSWorkerApi {
esFeatures: ESFeatures
) = {
import scala.concurrent.ExecutionContext.Implicits.global
val linker =
ScalaJSLinker.reuseOrCreate(LinkerInput(fullOpt, moduleKind, esFeatures, dest))
val outFile = new File(dest, "out.js")
val linker = ScalaJSLinker.reuseOrCreate(LinkerInput(fullOpt, moduleKind, esFeatures, dest))
val cache = StandardImpl.irFileCache().newCache
val sourceIRsFuture = Future.sequence(sources.toSeq.map(f => PathIRFile(f.toPath())))
val irContainersPairs = PathIRContainer.fromClasspath(libraries.map(_.toPath()))
val libraryIRsFuture = irContainersPairs.flatMap(pair => cache.cached(pair._1))
val jsFile = dest.toPath()
val sourceMap = jsFile.resolveSibling(jsFile.getFileName + ".map")
val linkerOutput = LinkerOutput(PathOutputFile(jsFile))
.withJSFileURI(java.net.URI.create(jsFile.getFileName.toString))
.withSourceMap(PathOutputFile(sourceMap))
.withSourceMapURI(java.net.URI.create(sourceMap.getFileName.toString))
val logger = new ScalaConsoleLogger
val mainInitializer = Option(main).map { cls =>
ModuleInitializer.mainMethodWithArgs(cls, "main")
Expand All @@ -136,9 +136,26 @@ class ScalaJSWorkerImpl extends mill.scalajslib.api.ScalaJSWorkerApi {
val resultFuture = (for {
sourceIRs <- sourceIRsFuture
libraryIRs <- libraryIRsFuture
_ <- linker.link(sourceIRs ++ libraryIRs, moduleInitializers, linkerOutput, logger)
_ <-
if (minorIsGreaterThan(2)) {
val linkerOutput = PathOutputDirectory(dest.toPath())
linker.link(
sourceIRs ++ libraryIRs,
moduleInitializers.map(_.withModuleID("out")),
linkerOutput,
logger
)
} else {
val jsFile = outFile.toPath()
val sourceMap = jsFile.resolveSibling(jsFile.getFileName + ".map")
val linkerOutput = LinkerOutput(PathOutputFile(jsFile))
.withJSFileURI(java.net.URI.create(jsFile.getFileName.toString))
.withSourceMap(PathOutputFile(sourceMap))
.withSourceMapURI(java.net.URI.create(sourceMap.getFileName.toString))
linker.link(sourceIRs ++ libraryIRs, moduleInitializers, linkerOutput, logger)
}
} yield {
Result.Success(dest)
Result.Success(outFile)
}).recover {
case e: org.scalajs.linker.interface.LinkingException =>
Result.Failure(e.getMessage)
Expand Down