-
Notifications
You must be signed in to change notification settings - Fork 101
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
Bundle multi-module Scala.JS projects #115
Comments
scalajs-bundler uses the output of Scala.js. If you have a multi-module build, then scalajs-bundles uses the .js file that results from the linking of all the modules. What’s the problem with that? How would you do things differently? |
Using webpack that way doesn't give you much value because all it would do is create big monolithic bundles, it would be better to use something like rollup.js which is faster and simpler. You could give each module custom webpack configs and instruct each one to spit out multiple modules but the scope is still just the single module each time. And what about all the assets? It's rare that you'd never share any assets between multiple bundles in the same project. In a multi-module app, what you'd generally want is to feed the JS of each SBT module to webpack as separate entry points, configure it to have access to your webapp assets and 3rd-party libs, then let it do it's thing with a view of the project as a whole. This allows webpack to identify common code amongst the various entry points (SJS modules) and better extract shared bundles reducing the total size of all JS through smarter splitting and sharing. It also allows you to infuse bundles into the HTML without having to worry about dependencies or links going stale. The list goes on and it's all genuinely useful real-world stuff; the reason I'm raising this issue is because I'm not sure how scalajs-bundler's current approach facilitates those kind of needs. If anything it seems to hinder it and I think that's a huge show-stopper. Also I think that if a change along the lines of scala-js/scala-js#2833 is made to Scala.JS itself, solving this issue will become much, much easier. |
Is the basic The closest to documentation I found was the approach in this PR by setting However, unlike regular (non-js) So instead, until I see a cleaner approach I'm currently copying my
The benefits to separating projects into multiple modules is of course immeasurably huge. I like to keep pure scala functions in my Does my approach make sense? Is there a cleaner way to bundle multi-module scalajs projects? |
I used to work on a multi-(sbt)-modules project, where module dependencies were expressed using I think this issue was initially about producing multiple JavaScript modules, not about managing multiple sbt modules. I suggest that you open a different issue to report the problem you are facing when using |
I agree the OP use-case is more focused on pure scalajs modules, whereas mine is more focused on the special case of packaging scalajs code with pure scala code or "backend" in this case. In that example special case, unlike usual sbt multi-module projects, you don't use So my comment is more about integrating scalajs as part of a multi-module scala build. So if that's outside the scope of scalajs-bundler, then I'm happy to just live with my workarounds! Otherwise, let me know and I'll try submitting a new issue if there's interest in this use-case, and why my use of |
Your backend has to use the output of the |
Yes, I am using the pseudo-code representation (if it helps): My work around is to let the scalajs submodule use sourceGeneration to copy other module classes it depends on into its target classes folder (from Sorry if this is further polluting this issue with outside topics... |
Hi @evbo, lazy val common = (crossProject.crossType(CrossType.Pure) in file ("common"))
.settings(...)
lazy val ui = project.in(file("ui"))
.settings(...)
.dependsOn(common.js)
lazy val backend = project.in(file("backend"))
.settings(...)
.dependsOn(common.jvm) Please, note the |
Thanks, yes
Thanks, and sorry if I've hijacked this issue ;) |
Hi, what needs to be done to support multi-module webpack builds? My use-case is: I want backend and frontend code to live in the same sbt-subproject and then create two separate javascript bundles, one for the browser, one for a node backend. Example: package my.app
import scala.scalajs.js.annotation._
import io.scalajs.nodejs.fs
object Backend {
@JSExportTopLevel(name = "start", moduleID = "backend")
def start(): Unit = {
println("hello from backend: " + Shared.x)
fs.Fs.mkdirSync("a")
}
}
object WebApp {
@JSExportTopLevel(name = "main", moduleID = "frontend")
def main(): Unit = {
println("hello browser: " + Shared.x)
}
}
object Shared {
val x = 1337
} build.sbt import org.scalajs.linker.interface.ModuleInitializer
import org.scalajs.linker.interface.OutputPatterns
ThisBuild / scalaVersion := "3.0.0"
lazy val main = project
.enablePlugins(ScalaJSPlugin, ScalaJSBundlerPlugin)
.in(file("main"))
.settings(
scalaJSLinkerConfig ~= { _.withModuleKind(ModuleKind.CommonJSModule) },
libraryDependencies ++= Seq(
("net.exoego" %%% "scala-js-nodejs-v14" % "0.13.0").cross(CrossVersion.for3Use2_13),
),
Compile / scalaJSModuleInitializers += {
ModuleInitializer.mainMethod("my.app.WebApp", "main").withModuleID("frontend")
},
) The error message I get:
The message is thrown here: |
@fdietze as error message suggests
try to comment out one of the methods annotated with You can also try to structure it bit differently, instead of having one sbt module and generate two different bundles out of it, you can extract most of the code into common shared sbt module, and have two additional sbt modules (backend, frontend) that depend on common. See one of my previous comments with idea how to do it in sbt. |
@viktor-podzigun Yes, that's what I have right now and I find it a bit inflexible. Especially if I want to output multiple js bundles for different aws lambda deployments. Removing one |
Thinking about it, @viktor-podzigun you made me realize that I could have all scala code in a single sbt-subproject and only have separate sbt projects for the different js modules. This way I can easily have different webpack configs for each module. |
@fdietze happy it was helpful for you :) This way you will have your code more structured and will overcome the above issue. Please, don't hesitate to ask if you need help to set it up (one common sbt module and several others that depends on it). |
I just created a proof of concept, let's see how it works out in a bigger project. I still like the idea of a single subproject and ScalaJS itself already supports this. It's just scalajs-bundler which cannot handle multi-module output yet. |
Currently, this plugin applies to single SBT modules in isolation. When you're working on a multi-module project and that has multiple modules exporting Scala.JS, then you need to bundle everything together.
This is the situation I'm currently in and one of the reasons I think I'm going to use webpack without scalajs-bundler. I think someone is going to have to work out what that means for this project and how best to solve it if scalajs-bundler is going to be used for Big Serious (™) work projects. My OSS quota is already full so it won't be me but I'm certainly open to share info, ideas and opinions if it can provide some value so feel free to ask.
The text was updated successfully, but these errors were encountered: