-
Notifications
You must be signed in to change notification settings - Fork 10
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
Reduce JS bundle size #14
Comments
There's some further info in the Scala.js repo: scala-js/scala-js#4482 It seems to be a few people considering / waiting on a native solution in the Scala.js toolchain. In the meantime, it's not ideal, but it's possible to use Terser to minimise assets (tested with Vite 4.4.X). Although, be cautious if dynamic imports are used as described in the above issue threads.
|
@Lukah0173 Thanks for linking the relevant issues. Terser looks cool, I'll probably try it. Does it affect 3rd party JS (non-Scala.js) libraries? I think they deserve a more conservative approach (unless we are sure we can perform some more aggressive optimizations). |
Yep, it should also work for the third-party libraries - I'm not sure about external JS that haven't been transpiled by Scala.js. I've tested with the following and no issues, but I don't know enough about the concepts to be certain of safety / effectiveness. We're using the following dependencies:
and, in addition to our source, here's the result of the build:
It only takes a few seconds or so to build, ymmv. |
I have similar list of JS dependencies (bootstrap, chart.js, moment +tz, chartjs-adapter-moment and comma-separated-values). The resulting size is much better, but still by ~330KiB larger than it is with closure compiler:
Also, it doesn't like the moment's style of calling functions:
For now, I'll probably use Vite for dev only, keeping sbt-web for production. |
That looks like there is a namespace import in a facade instead of a default import. |
I still believe there must be a way to proceed with Google Closure Compiler, even with few hacks. I believe I've almost reached the result, albeit with some hacks:
It seems to produce a sane result with the exception of calls to 3rd-party code. Calls to module's top-level functions seem to be OK, but calls to methods of their objects are mangled. I've looked how Scala.js configures the Closure Compiler. It seems that the difference is primarily in the externs. It however seems that I cannot easily export them, as they seem to be kept in-memory. But maybe, when I adjust the code, I can get the externs. |
The externs in a tiny part of it. What really matters is that we emit external method/property references as |
Makes sense, but I wonder why it works with CommonJS modules. IIUC, there
should be the same issue.
|
For CommonJS, GCC leaves the |
In my experiment, I've replaced all external JS imports (i.e., those that
don't start with "./"*) by require function call before passing to GoCC, so
the reason shouldn't be there. The difference might be in the type
annotation of the require function. Maybe I need some recursive typedef
like Dynamic = Object<String, Dynamic>.
*) Well, my hacky regex checks just for the initial dot.
|
Aha, I got it. Scala.js uses withOptimizeBracketSelect(false) when using GoCC, so GoCC doesn't mangle the references. With ES module, there is no way to configure optimizeBracketSelect, so GoCC mangles it. I can play a bit more with that, and hopefully even send a PR. However, I probably can't get rid of the hack (rewriting imports to function calls before passing to GCC and rewriting it back when GCC is done). I just can write it in somewhat cleaner way (using AST transformations instead of regex, using a dedicated scalajs-specific name rather than |
Probably not. But if it allows us to reliably use GCC with ES modules, we can at least consider it. |
I hope I can make GoCC reliably working with ES modules. It should work even for multi-module projects (internal modules are inlined). Inlining seems to be a suitable option for many scenarios (server/client/webworker code). However, my willingness to work on it depends on your willingness to accept such patch. If you say that this hack would be probably unacceptable, I don't want to spend much time on that. |
Well ... it shouldn't contradict what the |
Ad ModuleSplitStyle: OK, it sounds like some redesign would be needed for what I want. I'd like to use small modules for fast link and fat modules (=inlined internal modules) for production. I have some good and bad news: The bad: I struggle with AST rewriting. The good: I've mostly succeeded by going some hacky way. It seems that I need to slightly adjust imports of moment.js and BS Modal, but everything else is probably fine. (EDIT: I've done few more adjustments and it works 100%! Also, the bundle size roughly matches the original non-Vite bundle size.) How I did it:
Updated script (it currently does both adjustments automatically): https://gist.github.com/v6ak/ccd0cadb43993afa854769519646ed46 |
Thinking a bit more conceptually about it. For most of the parts, I can send a PR if you are interested: 1. Option for disabling optimizeBracketSelectsThis allows running GoCC afterwards, outside of Scala.js SBT plugin. What to do: I can prepare a PR. 2.
|
Prepared a PR for multiple subprojects: #16 |
Interesting, I'm following your progress - Let me know if there's anything I can do to help. It's outside my area of focus but I'm eager to see a solution for this 👍 |
Note that different configs for fastLink / fullLink have always been possible. In fact, it is how their difference is implemented: |
@Lukah0173 Thinking about it again:
|
@v6ak just fyi, there may be an official solution in-progress for this: |
I have a static site generated by Scala.js + sbt-web + HTML generators. It currently uses Play framework for development (not for production). I have tried to replace Play by Vite in order to speed up development and get a newer SASS compiler. The main issue is bundle size, which increased from ~1MiB to ~1.9MiB.
I know this is related to ES modules (required by Vite), which cause the Google Closure Compiler to be disabled. Related project-specific issue: v6ak/zbdb-stats#57
The text was updated successfully, but these errors were encountered: