scalacenter / scalajs-bundler

https://scalacenter.github.io/scalajs-bundler
Other
237 stars 101 forks source link

Add support for Scala.js 1.x #292

Closed julienrf closed 5 years ago

julienrf commented 5 years ago

Specific source directories have been created for Scala.js 0.6 and Scala.js 1.x, but most of the code cross-compiles.

Some tests are stuck on Scala.js 0.6 because they use libraryDependencies that are not yet available for Scala.js 1.x.

Usage of some internal APIs of Scala.js (e.g. org.scalajs.core.tools.json), which are not source compatible between 0.6 and 1.x has been replaced with play-json, which scalajs-bundler already depended on.

Usage of JSApp in tests has been removed.

ngbinh commented 5 years ago

Omg, this is huge! Thanks!

julienrf commented 5 years ago

The following tests are failing with Scala.js 1.0.0-M7:

sbt-web-scalajs-bundler / play (fixed)

The build doesn’t even load and reports the following error:

[info] java.lang.NoClassDefFoundError: org/scalajs/jsdependencies/sbtplugin/JSDependenciesPlugin$

I don’t understand where we have a dependency on that class.

sbt-scalajs-bundler / sharedconfig (fixed)

The project loads and some tests pass, but this line fails. This line loads an HTML page that includes the bundle created by scalajs-bundler. The reported JavaScript error is:

TypeError: [object Object] is not a function, it is object. (file:/tmp/sbt_c80d120e/sharedconfig/target/scala-2.11/scalajs-bundler/main/sharedconfig-opt-bundle.js#18)

Of course, line 18 of the file is unreadable because it contains the output of fullOptJS. The weird thing is that the same test, with fastOptJS does pass (line 4).

Has anyone any clue of what’s happening or want to help to debug?

sjrd commented 5 years ago

For the sbt-web-scalajs-bundler error, that's probably because it unconditionally depends on "com.vmunier" % "sbt-web-scalajs" % "1.0.8-0.6" which is clearly for Scala.js 0.6.x. I guess the dependency should be adapted according to scalaJSVersion.

julienrf commented 5 years ago

Indeed, then we have another issue: sbt-web-scalajs depends on 1.0.0-M3, which is binary incompatible with 1.0.0-M7. I will make a PR on sbt-web-scalajs to update to 1.0.0-M7.

ngbinh commented 5 years ago

Of course, line 18 of the file is unreadable because it contains the output of fullOptJS. The weird thing is that the same test, with fastOptJS does pass (line 4).

I am no expert but could it be the new GCC and Common Module?

julienrf commented 5 years ago

I think I’ve found the problem with the remaining failing tests. Unless I’m wrong, the problem was present before as well, but just didn’t show up. The fullOptJS output uses a name that is also used by a library (leaflet) that the program depends on. So, they just clash. Is there a way to tell the Scala.js optimizer to not use certain reserved identifiers?

sjrd commented 5 years ago

Is there a way to tell the Scala.js optimizer to not use certain reserved identifiers?

No, that's not possible, because Scala.js shouldn't have to ignore certain identifiers. CommonJS modules have dedicated scopes per spec. The bundler shouldn't mangle the scopes of different modules together.

julienrf commented 5 years ago

I’ve pushed a commit that disables the Scala.js optimizer on that test, because I think that’s the only solution for now. In the long run, I would like to remove the LibraryAndApplication and LibraryOnly bundling modes, because they are just hacks that try make it possible to execute CommonJS modules in the browser, but this example shows that they are not robust options.

glmars commented 5 years ago

@julienrf

Unless I’m wrong, the problem was present before as well, but just didn’t show up

No. Some time ago Scala.js team removed IIFE wrapper around a module output and the problem with LibraryOnly mode was introduced. See https://github.com/scalacenter/scalajs-bundler/issues/282 for details.

The LibraryOnly mode is important feature of scalajs-bundler, without it the compilation speed is unacceptable. We should found a way to preserve it!

dispalt commented 5 years ago

I agree with keeping LibraryOnly and don't mean to pile on, it makes compilation fast for dev, which is basically the only way the Compile->Run loop is tolerable.

julienrf commented 5 years ago

The LibraryOnly mode is important feature of scalajs-bundler, without it the compilation speed is unacceptable. We should found a way to preserve it!

Even with the latest webpack, is it still too slow?

ramnivas commented 5 years ago

Even with the latest webpack, is it still too slow?

Yes, it is quite slow even with the latest webpack. I don't think webpack can do anything better since the core issue is huge single fastOptJs file (about 27 MB in our case), so webpack has to at least parse it every time and that is going to take significant time.

Until Scala.js produces multiple small js files with only a few changing in each incremental compilation (which would be a wonderful feature by itself, anyway), removing LibraryOnly mode will be very detrimental to developer productivity.

glmars commented 5 years ago

Even with the latest webpack, is it still too slow?

The latest webpack still parses a huge Scala.js output. So the speed is the same. Thanks @easel for introducing the LibraryOnly mode, it is the only option to develop a real Scala.js application comfortably.

exoego commented 5 years ago

Our team cannot use LibraryOnly mode for some reasons, so now use default mode with a WebPack configuration like

const webpack = require('webpack');
const merge = require("webpack-merge");
const TerserPlugin = require("terser-webpack-plugin");
const scalajsBundlerConfig = require("./scalajs.webpack.config.js");

module.exports = merge(scalajsBundlerConfig, {
    target: 'node',
    output: {
        libraryTarget: "commonjs2"
    },
    optimization: {
        minimizer: [
            new TerserPlugin({
                terserOptions: {
                    // Disable since Scala.js is already compressed by GCC
                    compress: false,
                    // mangling is also disabled due to trade off between optimization-time and space-efficiency
                    mangle: false,
                    output: {
                        comments: false,
                    },
                },
            }),
        ],
    },
});

which reduces optJS time reasonable amount.

glmars commented 5 years ago

@exoego Did you write this about a fastOptJS task? As I know there are all optimizations already disabled (GCC isn't used) in fastOptJS.

exoego commented 5 years ago

@glmars Sorry, the above config was meant for fullOptJS for production.

glmars commented 5 years ago

Ah, ok, but a speed of fullOptJS isn't so important for developers. The LibraryOnly mode is especially significant in fastOptJS to improve a Change->Compile->Run->Change ... cycle

julienrf commented 5 years ago

Thanks to all for your feedback on the usage of the Library* bundling modes. You convinced me that we should keep it for now ;)

I’ve rebased the PR, I think it is ready to be merged.

cquiroz commented 5 years ago

Thanks a lot @julienrf. this is a key component for the 1.x ecosystem

oyvindberg commented 5 years ago

One more huge thanks for this, now Scala.js 1.0 milestones are finally useful for me! :)