summaryrefslogblamecommitdiff
path: root/scalajslib/src/mill/scalajslib/ScalaJSModule.scala
blob: b3737da1dd30bd9e92cd3f4efed28671948bacfd (plain) (tree)
1
2
3
4
5
6
7
8
9
            
                  
 
                                                 
                     
                                     
                                  
                               
                                            
                                                             
                             
 
                                                           


                               
                                         
                                                
                                                              




                                                        
                                                                           

                                                                                        
 
                              
                                                                                       

                                        
                                                          
                   
                                                                   
     

   
                                                        







                                                                                                

                        
                                           



                          
                                                                             


                   
                                       
                       
                     
                                   

                  




                   
                                       
                       
                     
                                   

                  
     

   
                                                                   

                                               


                                           
                                             
                                       
                         


                             

     

   


                                                                                 
 

                                                                            

   

                                        
                                      
                                     
                              
                                                                          
                                        
 
                   
                  
 





                                                    

                                 

                 
                      
                

                      
                     

   

                                       
                                                                 
   
                                       

                                                               
 






                                                                                  
                                                                                           

                                                                  

                                         

                                                           

 











                                                                     
                                       
                       
                                          
           

                  





                                                                     
                                                                                           
                                     
                       
                              


                               
                                                 
                            



                                    






                                                                                 


   
package mill
package scalajslib

import ammonite.ops.{Path, exists, ls, mkdir, rm}
import coursier.Cache
import coursier.maven.MavenRepository
import mill.eval.{PathRef, Result}
import mill.eval.Result.Success
import mill.scalalib.Lib.resolveDependencies
import mill.scalalib.{DepSyntax, Lib, TestModule, TestRunner}
import mill.util.{Ctx, Loose}

trait ScalaJSModule extends scalalib.ScalaModule { outer =>

  def scalaJSVersion: T[String]

  trait Tests extends TestScalaJSModule {
    override def scalaWorker = outer.scalaWorker
    override def scalaOrganization = outer.scalaOrganization()
    override def scalaVersion = outer.scalaVersion()
    override def scalaJSVersion = outer.scalaJSVersion()
    override def moduleDeps = Seq(outer)
  }

  def scalaJSBinaryVersion = T { Lib.scalaBinaryVersion(scalaJSVersion()) }

  def scalaJSBridgeVersion = T{ scalaJSVersion().split('.').dropRight(1).mkString(".") }

  def sjsBridgeClasspath = T {
    val jsBridgeKey = "MILL_SCALAJS_BRIDGE_" + scalaJSBridgeVersion().replace('.', '_')
    mill.modules.Util.millProjectModule(
      jsBridgeKey,
      s"mill-scalajslib-worker-${scalaJSBridgeVersion()}",
      repositories,
      resolveFilter = _.toString.contains("mill-scalajslib-worker")
    )
  }

  def scalaJSLinkerClasspath: T[Loose.Agg[PathRef]] = T{
    val commonDeps = Seq(
      ivy"org.scala-js::scalajs-tools:${scalaJSVersion()}",
      ivy"org.scala-js::scalajs-sbt-test-adapter:${scalaJSVersion()}"
    )
    val envDep = scalaJSBinaryVersion() match {
      case v if v.startsWith("0.6") => ivy"org.scala-js::scalajs-js-envs:${scalaJSVersion()}"
      case v if v.startsWith("1.0") => ivy"org.scala-js::scalajs-env-nodejs:${scalaJSVersion()}"
    }
    resolveDependencies(
      repositories,
      Lib.depToDependency(_, "2.12.4", ""),
      commonDeps :+ envDep
    )
  }

  def toolsClasspath = T { sjsBridgeClasspath() ++ scalaJSLinkerClasspath() }

  def fastOpt = T {
    link(
      ScalaJSWorkerApi.scalaJSBridge(),
      toolsClasspath(),
      runClasspath(),
      finalMainClassOpt().toOption,
      FastOpt,
      moduleKind()
    )
  }

  def fullOpt = T {
    link(
      ScalaJSWorkerApi.scalaJSBridge(),
      toolsClasspath(),
      runClasspath(),
      finalMainClassOpt().toOption,
      FullOpt,
      moduleKind()
    )
  }

  override def runLocal(args: String*) = T.command { run(args:_*) }

  override def run(args: String*) = T.command {
    finalMainClassOpt() match{
      case Left(err) => Result.Failure(err)
      case Right(_) =>
        ScalaJSWorkerApi.scalaJSBridge().run(
          toolsClasspath().map(_.path),
          nodeJSConfig(),
          fastOpt().path.toIO
        )
        Result.Success(())
    }

  }

  override def runMainLocal(mainClass: String, args: String*) = T.command[Unit] {
    mill.eval.Result.Failure("runMain is not supported in Scala.js")
  }

  override def runMain(mainClass: String, args: String*) = T.command[Unit] {
    mill.eval.Result.Failure("runMain is not supported in Scala.js")
  }

  def link(worker: ScalaJSWorker,
           toolsClasspath: Agg[PathRef],
           runClasspath: Agg[PathRef],
           mainClass: Option[String],
           mode: OptimizeMode,
           moduleKind: ModuleKind)(implicit ctx: Ctx): Result[PathRef] = {
    val outputPath = ctx.dest / "out.js"

    mkdir(ctx.dest)
    rm(outputPath)

    val classpath = runClasspath.map(_.path)
    val sjsirFiles = classpath
      .filter(path => exists(path) && path.isDir)
      .flatMap(ls.rec)
      .filter(_.ext == "sjsir")
    val libraries = classpath.filter(_.ext == "jar")
    worker.link(
      toolsClasspath.map(_.path),
      sjsirFiles,
      libraries,
      outputPath.toIO,
      mainClass,
      mode == FullOpt,
      moduleKind
    ).map(PathRef(_))
  }

  override def scalacPluginIvyDeps = T{
    super.scalacPluginIvyDeps() ++
    Seq(ivy"org.scala-js:::scalajs-compiler:${scalaJSVersion()}")
  }
  override def scalaLibraryIvyDeps = T{
    Seq(ivy"org.scala-js::scalajs-library:${scalaJSVersion()}")
  }

  // publish artifact with name "mill_sjs0.6.4_2.12" instead of "mill_sjs0.6_2.12"
  def crossFullScalaJSVersion: T[Boolean] = false
  def artifactScalaJSVersion: T[String] = T {
    if (crossFullScalaJSVersion()) scalaJSVersion()
    else scalaJSBinaryVersion()
  }

  override def artifactSuffix: T[String] = s"${platformSuffix()}_${artifactScalaVersion()}"

  override def platformSuffix = s"_sjs${artifactScalaJSVersion()}"

  def nodeJSConfig = T { NodeJSConfig() }

  def moduleKind: T[ModuleKind] = T { ModuleKind.NoModule }
}

trait TestScalaJSModule extends ScalaJSModule with TestModule {
  def scalaJSTestDeps = T {
    resolveDeps(T.task {
      Loose.Agg(
        ivy"org.scala-js::scalajs-library:${scalaJSVersion()}",
        ivy"org.scala-js::scalajs-test-interface:${scalaJSVersion()}"
      )
    })
  }

  def fastOptTest = T {
    link(
      ScalaJSWorkerApi.scalaJSBridge(),
      toolsClasspath(),
      scalaJSTestDeps() ++ runClasspath(),
      None,
      FastOpt,
      moduleKind()
    )
  }

  override def testLocal(args: String*) = T.command { test(args:_*) }

  override def test(args: String*) = T.command {
    val (close, framework) = mill.scalajslib.ScalaJSWorkerApi.scalaJSBridge().getFramework(
        toolsClasspath().map(_.path),
        nodeJSConfig(),
        testFrameworks().head,
        fastOptTest().path.toIO
      )

    val (doneMsg, results) = TestRunner.runTests(
        _ => Seq(framework),
        runClasspath().map(_.path),
        Agg(compile().classes.path),
        args
      )
    val res = TestModule.handleResults(doneMsg, results)
    // Hack to try and let the Node.js subprocess finish streaming it's stdout
    // to the JVM. Without this, the stdout can still be streaming when `close()`
    // is called, and some of the output is dropped onto the floor.
    Thread.sleep(100)
    close()
    res
  }

}