Code Monkey home page Code Monkey logo

Comments (10)

joost-de-vries avatar joost-de-vries commented on May 9, 2024

Hm. So if I understand correctly you want to have a multi project typescript build?

It's a feature that I need in my current project as well. But I haven't built that yet for sbt-typescript.

I see two challenges:

  • the typescript compiler is a bit challenging to support as soon as there are more than one rootdir. Because it will not move the output files to the correct directory anymore. So I need to guess what it has emitted and move the files to the correct place. I've made a beginning of supporting that for compiling both source files and test files. But it's error prone logic. So I'll have to work myself up to get this really well working for both multi project files and compiling tests.
  • it would be efficient from a compilation point of view to have one tsc call compile all subprojects. I don't see how to map that on how sbt deals with subprojects. There are two options: either all subprojects will entail their own tsc call. Or tsc compilation is only performed on the level of the top project. And sbt will not manage the subproject structure. The second option is probably wisest....

In my professional project I wanted to spread the typescript code over subprojects. But I haven't yet because of the above reasons.

I'd like to support multiproject builds but it's a thing that I'll have to find some unfragmented attention for in my spare time....

from sbt-typescript.

iadcode avatar iadcode commented on May 9, 2024

Regarding the first challenge:
If you determined the common root between the current project and any projects it depends on, I think you can safely use this for the rootDir. I reckon that if you then found the relative path from rootDir to the asset Dir/test Dir, you could safely use those to find the TypeScript output for the current project.

The sbt code below is a bit verbose and probably wrong in parts (I'm pretty sure this will crash on Linux due to mishandling getRoot), but it demonstrates a way of determining the root folder of a top project and its sub projects. From there, you could then use relativeTo to find the path to look for in the TypeScript output.

val showProjects = TaskKey[Unit]("show-projects", "shows projects")

showProjects := Def.taskDyn {
  Def.task {
    var commonRoot: Option[File] = None

    def findCommon(a: File, b: File): Option[File] = {
      var finalFile: Option[File] = None

      val aIter = a.toPath.iterator()
      val bIter = b.toPath.iterator()

      var aPart: String = a.toPath.getRoot.toString
      var bPart: String = b.toPath.getRoot.toString

      while (aPart == bPart) {
        finalFile = finalFile match {
          case Some(file) => Some(file / aPart)
          case None => Some(file(aPart))
        }

        if (!aIter.hasNext || !bIter.hasNext()) {
          return finalFile
        }
        aPart = aIter.next().toString
        bPart = bIter.next().toString
      }

      finalFile
    }

    Def.task { thisProject.value }
      .all(ScopeFilter(inAnyProject)).value
      .foreach { project: ResolvedProject =>
        commonRoot = commonRoot match {
          case Some(file) => {
            findCommon(file, project.base)
          }

          case None => {
            Some(project.base)
          }
        }

        println(s"Current CommonRoot: ${commonRoot.getOrElse("None")}")

        println(s"${name.value}: ${project.id} => ${project.base}")
      }
  }
}.value

Regarding the second challenge:
It would indeed be more efficient for tsc to be called once. However, I don't think it's compatible with how sbt-web handles things. Due to the aggregation of tasks from projects to sub projects (that is, sub projects have their tasks called first), you'd struggle to have the top project compile TypeScript files for the sub projects in a way that makes sense.

You might as well just do the compilation for each project - I don't see that hurting, really. Sure, you do some extra processing for the top projects, but I've used other sbt-web plugins that do too much work as well, and everything seems fine.

As long as you're not including the sub project files in the top project asset output, I'm pretty sure everything works out.

from sbt-typescript.

joost-de-vries avatar joost-de-vries commented on May 9, 2024

Tx for your suggestion. I hope I can soon make some time for making sbt-typescript support multi project builds.
I'll let you know.

from sbt-typescript.

joost-de-vries avatar joost-de-vries commented on May 9, 2024

I've implemented multi-project builds for the most part.
What I did was have each subproject be its own typescript compiler run. The compilation results from the dependee subproject are added to the js dependencies of the depender subproject.

The problem I'm hitting right now is that JsTask seems to include the source files when publishing the dependee subproject. And then the typescript compiler thinks it has to compile those files again and doesn't understand the source directory structure anymore.

Any idea how I can prevent the ts source files from being published along with the compilation results? I think it is somewhere in sbt-web that this is being done. And I'm not aware of a config that allows for not including the sources.

from sbt-typescript.

iadcode avatar iadcode commented on May 9, 2024

I'm not sure if you can prevent sbt-web from including the source files with a source task. I keep my .ts files out of my asset jars using sbt-filter, but doing something like that would be too late for sbt-typescript.

At the same time, I'm not sure if you actually do want to exclude submodule source files from compilation in the top level module. I think it's a legitimate scenario to have a TypeScript source file living in a top level module referring to a TypeScript source file in a submodule, in which case you will have to include the submodule source file in the compilation of the top level module. Excluding it would mean TypeScript would fail compilation because it could not find the referenced source file from the submodule.

from sbt-typescript.

joost-de-vries avatar joost-de-vries commented on May 9, 2024

Maybe I didn't explain too well.
What I meant is that if there is a subproject B depending on subproject A. I got that working: the js + d.ts type defs build results of A are added as a dependency to the webmodules of B. That would work perfectly. But unfortunately the sources are also copied to B. And that confuses the typescript compiler. Unfortunately the tsc first looks for ts files before looking for the d.ts files. Grr.

You can try it out for yourself in the test subproject of the multi-project branch.

Options I can think of are:

  • finding out which component does the copying of the sources. (probably sbt-web) And create a pullrequest that makes it configurable whether to copy the sources. But that might be quite complicated.
  • seeing if I can make the ts compiler find the d.ts files first. But I haven't find any configuration option that enables this.
  • creating a separate delete task that runs after sbt-typescript runs on project A but before it runs on project B. And deletes the .ts files. I'm not quite sure yet how easy that is.
    ....

from sbt-typescript.

iadcode avatar iadcode commented on May 9, 2024

After delving around the code for a while, I think I've figured something out which may help. This probably isn't the best solution, but it's something.

When sbt-web does its compilation, all exported assets for the project in question end up under target/web/classes/main/META-INF/resources/webjars/<projectname>/<version>/

In the case of web depending on common, web was importing all files from modules/common/target/web/classes/main/META-INF/resources/webjars/common/<version>/, which included the component.a.ts file causing problems

I figured there must be some way of excluding assets from this directory, and I think I stumbled across it:

excludeFilter in Assets := (excludeFilter in Assets).value || "*.ts"

This prevents the component.a.ts file from appearing in the folder. I suspect that this exclusion occurs after sbt-typescript compiles the TypeScript files but before the output of sbt-typescript is copied to this location, since component.a.d.ts was still put into the folder (like we'd want it to).

I guess the best solution would to be to have sbt-typescript do something similar in a configurable way, but I dunno if you can reliably set excludeFilter in Assets like this without the chance someone might set a different value in their build.sbt.

from sbt-typescript.

joost-de-vries avatar joost-de-vries commented on May 9, 2024

Cool! I didn't think of that.
Wow. I'm glad we have a way of dealing with multi-project builds now.
I'll have to release this as a beta version and write some unittests to make sure everything still works. Since it uses webModules now instead of nodeModules to resolve dependencies.
Tx.

from sbt-typescript.

joost-de-vries avatar joost-de-vries commented on May 9, 2024

I created version 0.4.0-alfa.1 for this a while back. Any news on that?

from sbt-typescript.

iadcode avatar iadcode commented on May 9, 2024

I tried using 0.4.0-alfa.1 against the example I referenced in the OP, objectmastery/rootdir-error-example. It still has the same issue when I did a sbt dist:

[error] tsconfig.json:0: TS6059 File 'C:/github/objectmastery/rootdir-error-example/sub/app/assets/javascripts/sub.ts' is not under 'rootDir' 'C:/github/objectmastery/rootdir-error-example/main/app/assets'. 'rootDir' is expected to contain all source files.
[error] one error found
[error] (main/web-assets:typescript) com.typesafe.sbt.web.CompileProblemsException

I can ignore the error using the tsCodesToIgnore key, but the javascript files do not appear in the assets JAR once the distribution finishes.

from sbt-typescript.

Related Issues (18)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.