Open johnhungerford opened 9 months ago
This process is unfamiliar and - I got to be honest - a bit funky to me, I wonder if it can be modified somewhat to fit the tooling better. I have no experience in Scala.js and Javascript project interop though. But I know that workflows not always translate one-to-one - for example a single Javascript project might have to become multiple sbt Scala.js modules, because Scala.js plugin does not support emitting for multiple environments/purposes from a single sbt module too well - I had my frustrations on that with Electron plugins I have been working on. It would be easier to just conform to how Scala.js plugin and sbt works, rather than trying to fight them.
If you need non-bundled exported Scala.js components, then @JSExportTopLevel
should be enough. If you need them bundled, then I think you need to do library bundling. Can you see that working for you?
If you need non-bundled exported Scala.js components, then
@JSExportTopLevel
should be enough.
Just to correctly myself, I should have just linked https://www.scala-js.org/doc/interoperability/export-to-javascript.html and https://www.scala-js.org/doc/project/module.html.
Best course of actions might just be to try and implement a library project with scalajs-vite
as an sbt-test
and see what is missing to successfully achieve that.
And also on this:
This leads to potential name clashes, however, especially if you want to name a JS entrypoint main.js, which is the default entrypoint of Scala.js outputs.
I think you might just want to split exports (the library part) and main module intializer (the entrypoint) into separate Scala.js modules and not try to do both at once.
I'm going to paste what I put in the testing thread here, since it is more relevant to this issue. As I said there, I see three cases in which Scala.js exports are going to need to be resolved properly:
Just to be clear, all three of these cases apply to me! I'm currently migrating an application from JS to Scala.js, and I need to be able to migrate components one at a time. This means the original TS codebase has to be able to import parts of my Scala.js codebase, and my Scala.js codebase needs to be able to import parts of my TS codebase. I currently have this working in my jsbundler project (see this example project).
I totally understand your issue, but just to repeat https://github.com/ptrdom/scalajs-vite/issues/39#issuecomment-1930390189, I think you have both a bundler and a workspace issue, and this project should only be solving the former and enable you to implement the latter yourself.
Ok so it's clear now that there is not the issue I thought there was here (see my comment on #39).
Let me then reduce my proposal to this: to avoid, or at least reduce the likelihood of, file collisions, would it be acceptable to inject the xLinkJS
outputs into a scalajs
directory within the build directory? The result would be that you could import Scala.js outputs into JS sources using import xxx from '/scalajs/main.js';
and not worry that it's going to collide with your main.js
file in viteResourceDirectory
.
Sure, that seems like a reasonable feature to implement.
Currently viteCompile
task does the copying from scalaJSLinkerOutputDirectory
to viteInstall / crossTarget
. The way I see it the implementation can be done in two ways:
viteCompile / crossTarget
setting that would allow copying scalaJSLinkerOutputDirectory
to something other than viteInstall / crossTarget
. New viteCompile / crossTarget
setting would default to viteInstall / crossTarget
.viteCompile
and just point scalaJSLinkerOutputDirectory
to the subdirectory in viteInstall / crossTarget
. Would probably need to add https://www.scala-sbt.org/1.x/docs/Howto-Track-File-Inputs-and-Outputs.html for file change detection.Case 1
is easier to implement, but 2
is probably more forward thinking. I am leaning towards 1
just for the sake of simplicity.
Case 2 had not occurred to me. I think I prefer case 1 by a small margin simply because I could see users getting confused that xLinkJS
was not putting artifacts in the usual place. For instance, case 2 would break any scripts a user might have had in place that pulled artifacts from target/scala-[x.x.x]/[project]-opt/
, which is not that uncommon.
If I understand correctly, scalajs-vite currently injects Scala.js compiled (
xLinkJS
) outputs into the root of the build directory. This means that it should be possible for other non-Scala.js sources to import from these files just as, e.g.,import App from '/main.js';
. This leads to potential name clashes, however, especially if you want to name a JS entrypointmain.js
, which is the default entrypoint of Scala.js outputs.I propose using the convention established by vite-plugin-scalajs, which is to allow users to import Scala.js by prefixing their import paths with
scalajs:
. So you if do a default top level export to a named module such asJSImportTopLevel("default", "myModule")
, you can import it in your JS code as:import MyModule from 'scalajs:myModule.js';
. I propose additionally allowing users to usescalajs:
with nothing after the colon to stand in for a reference to the default modulemain.js
so that they don't need to know the Scala.js linker's conventions to use its outputs.I have adapted the
vite-scalajs-plugin
functionality to accomplish this in sbt-vite. Note that this also requires generating a vite.config.js which imports the plugin.