scalajs-bundler
scalajs-bundler copied to clipboard
top level anonymous given gives syntax error when loaded in browser
scala 3.0.0-M2
import cats._
import cats.syntax.all._
trait CanSing[F[_]]:
def sing(song: String): F[String]
given [F[_] : Applicative] as CanSing[F]:
def sing(song: String) = song.pure
object TestMain:
@main
def run(): Unit =
val canSing = summon[CanSing[Option]]
println(canSing.sing("bad") *> canSing.sing("good"))
above compiles and bundles fine but the browser raises "Uncaught SyntaxError: Invalid or unexpected token" when loading the bundled js. looking into the bundled js, the following js seems to be the culprit:
...TestMain$package$given_CanSing_F__f_evidence$1=null,...
if i give a name to the anonymous given so it's no longer anonymous, the bundled js loads fine.
another curious thing is this bundling is done under the setting "webpackEmitSourceMaps := false". if i turn it on, "fastOptJS::webpack" will give error:
[info] Bundling the application with its NPM dependencies
[error] .../consumer/target/scala-3.0.0-M2/scalajs-bundler/main/node_modules/source-map/lib/source-map-generator.js:298
[error] throw new Error('Invalid mapping: ' + JSON.stringify({
[error] ^
[error] Error: Invalid mapping: {"generated":{"line":1173,"column":2},"source":".../consumer/src/main/scala/trueown/client/consumer/TestMain.scala","original":{"line":8,"column":-1},"name":null}
[error] at SourceMapGenerator_validateMapping [as _validateMapping] (.../consumer/target/scala-3.0.0-M2/scalajs-bundler/main/node_modules/source-map/lib/source-map-generator.js:298:13)
[error] at SourceMapGenerator_addMapping [as addMapping] (...
Thanks for the report. Can this be reproduced without scalajs-bundler?
No, plain fastOptJS works fine.
On Mon, Nov 30, 2020, 2:41 AM Sébastien Doeraene [email protected] wrote:
Thanks for the report. Can this be reproduced without scalajs-bundler?
— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/scalacenter/scalajs-bundler/issues/385#issuecomment-735436926, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAAHSG2OCFVPMSMXBFG7MA3SSKIVTANCNFSM4UGVTV5A .
So, here is what happens:
- Scala 3 generates names for anonymous givens, and uses the character FULL WIDTH LOW LINE (
_,\uff3f) as connector between the parts. So for example the anonymous given here is calledgiven_CanSing_F. - Since
_is a valid character for a JavaScript identifier, Scala.js keeps it as is. However, the Scala.js linker always emits an ASCII output, so it escapes it as\uff3fin the .js file. - Webpack correctly parses that as being
_, but when it emits its output it does not escape it. Instead it writes it down as is, encoded as UTF-8 (which is perfectly valid per se as well; it's just "less safe" than what Scala.js core does). - Your browser/editor seems to interpret that .js as being encoded in latin1 (ISO-8859-1). Under that encoding, the UTF-8 bytes of
_are interpreted as_, which contains characters that are not valid in a JS identifier. - The source map generator may also have an issue with that UTF-8 sequence, although it's unclear how that translates into the error we see.
My conclusions:
- There is definitely no bug in Scala.js core.
- I don't think there is a bug in scalajs-bundler either.
- IMO the bug is in how the Webpack-generated .js file is interpreted by the things further downstream: they should be read in UTF-8, not latin1.
- There might be a Webpack configuration to force it to emit the output in ASCII. If yes, I suggest you use it as a workaround.
you are absolutely right. adding attribute 'charset="utf-8"' to the script tag solves the problem. so somehow my chrome defaults to latin1 when interpreting js. when i tested in firefox, it works with or without 'charset="utf-8"'.
adding <meta charset="UTF-8"> in the head does the trick as well. but all these still doesn't explain the error i encountered when generating source map though.
I believe it's the same kind of issue for the source map stuff. It's that whatever code trying to parse/load the .js file to then construct source maps, somewhere inside Webpack and its dependencies, defaults to reading in latin1. It might be possible to produce a small reproduction for that that is independent of Scala.js or scalajs-bundler.
I have a similar issue with a project as simple as:
// project/build.properties
sbt.version=1.4.6
// project/plugins.sbt
addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.3.1")
addSbtPlugin("ch.epfl.scala" % "sbt-scalajs-bundler" % "0.20.0")
addSbtPlugin("ch.epfl.lamp" % "sbt-dotty" % "0.5.1")
// build.sbt
lazy val root = (project in file(".")).
settings(
scalaVersion := "3.0.0-M3",
scalaJSUseMainModuleInitializer := true,
// webpackEmitSourceMaps := false
)
.enablePlugins(ScalaJSPlugin, ScalaJSBundlerPlugin)
// src/main/scala/Main.scala
object Main extends App {
println("Hello, World!")
}
> sbt fastOptJS / webpack
[info] compiling 1 Scala source to /home/piquerez/adpi2/foo/target/scala-3.0.0-M3/classes ...
[info] Fast optimizing /home/piquerez/adpi2/foo/target/scala-3.0.0-M3/root-fastopt
[info] Updating NPM dependencies
[error] npm WARN deprecated [email protected]: Chokidar 2 will break on node v14+. Upgrade to chokidar 3 with 15x less dependencies.
[error] npm WARN deprecated [email protected]: fsevents 1 will break on node v14+ and could be using insecure binaries. Upgrade to fsevents 2.
[error] npm WARN deprecated [email protected]: https://github.com/lydell/resolve-url#deprecated
[error] npm WARN deprecated [email protected]: Please see https://github.com/lydell/urix#deprecated
[info] > [email protected] postinstall /home/piquerez/adpi2/foo/target/scala-3.0.0-M3/scalajs-bundler/main/node_modules/webpack-cli
[info] > node ./bin/opencollective.jsendencies 11s
[info] Thanks for using Webpack!
[info] Please consider donating to our Open Collective
[info] to help us maintain this package.
[info] Donate: https://opencollective.com/webpack/donate
[error] npm notice created a lockfile as package-lock.json. You should commit this file.
[error] npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@~2.3.1 (node_modules/chokidar/node_modules/fsevents):
[error] npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for [email protected]: wanted {"os":"darwin","arch":"any"} (current: {"os":"linux","arch":"x64"})
[error] npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@^1.2.7 (node_modules/watchpack-chokidar2/node_modules/chokidar/node_modules/fsevents):
[error] npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for [email protected]: wanted {"os":"darwin","arch":"any"} (current: {"os":"linux","arch":"x64"})
[error] npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@^1.2.7 (node_modules/webpack-dev-server/node_modules/chokidar/node_modules/fsevents):
[error] npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for [email protected]: wanted {"os":"darwin","arch":"any"} (current: {"os":"linux","arch":"x64"})
[info] added 590 packages from 364 contributors and audited 593 packages in 12.508s
[info] 26 packages are looking for funding
[info] run `npm fund` for details
[info] found 2 low severity vulnerabilities
[info] run `npm audit fix` to fix them, or `npm audit` for details
[info] Writing scalajs.webpack.config.js
[info] Bundling the application with its NPM dependencies
[error] /home/piquerez/adpi2/foo/target/scala-3.0.0-M3/scalajs-bundler/main/node_modules/source-map/lib/source-map-generator.js:298
[error] throw new Error('Invalid mapping: ' + JSON.stringify({
[error] ^
[error] Error: Invalid mapping: {"generated":{"line":699,"column":0},"source":"/home/piquerez/adpi2/foo/src/main/scala/Main.scala","original":{"line":0,"column":6},"name":null}
[error] at SourceMapGenerator_validateMapping [as _validateMapping] (/home/piquerez/adpi2/foo/target/scala-3.0.0-M3/scalajs-bundler/main/node_modules/source-map/lib/source-map-generator.js:298:13)
[error] at SourceMapGenerator_addMapping [as addMapping] (/home/piquerez/adpi2/foo/target/scala-3.0.0-M3/scalajs-bundler/main/node_modules/source-map/lib/source-map-generator.js:110:12)
[error] at /home/piquerez/adpi2/foo/target/scala-3.0.0-M3/scalajs-bundler/main/node_modules/source-map/lib/source-node.js:351:13
[error] at SourceNode_walk [as walk] (/home/piquerez/adpi2/foo/target/scala-3.0.0-M3/scalajs-bundler/main/node_modules/source-map/lib/source-node.js:230:9)
[error] at SourceNode_walk [as walk] (/home/piquerez/adpi2/foo/target/scala-3.0.0-M3/scalajs-bundler/main/node_modules/source-map/lib/source-node.js:226:13)
[error] at SourceNode_walk [as walk] (/home/piquerez/adpi2/foo/target/scala-3.0.0-M3/scalajs-bundler/main/node_modules/source-map/lib/source-node.js:226:13)
[error] at SourceNode_toStringWithSourceMap [as toStringWithSourceMap] (/home/piquerez/adpi2/foo/target/scala-3.0.0-M3/scalajs-bundler/main/node_modules/source-map/lib/source-node.js:342:8)
[error] at ConcatSource.proto.sourceAndMap (/home/piquerez/adpi2/foo/target/scala-3.0.0-M3/scalajs-bundler/main/node_modules/webpack-sources/lib/SourceAndMapMixin.js:29:32)
[error] at CachedSource.sourceAndMap (/home/piquerez/adpi2/foo/target/scala-3.0.0-M3/scalajs-bundler/main/node_modules/webpack-sources/lib/CachedSource.js:58:31)
[error] at getTaskForFile (/home/piquerez/adpi2/foo/target/scala-3.0.0-M3/scalajs-bundler/main/node_modules/webpack/lib/SourceMapDevToolPlugin.js:37:30)
[error] at /home/piquerez/adpi2/foo/target/scala-3.0.0-M3/scalajs-bundler/main/node_modules/webpack/lib/SourceMapDevToolPlugin.js:136:20
[error] at Array.forEach (<anonymous>)
[error] at /home/piquerez/adpi2/foo/target/scala-3.0.0-M3/scalajs-bundler/main/node_modules/webpack/lib/SourceMapDevToolPlugin.js:130:12
[error] at SyncHook.eval [as call] (eval at create (/home/piquerez/adpi2/foo/target/scala-3.0.0-M3/scalajs-bundler/main/node_modules/tapable/lib/HookCodeFactory.js:19:10), <anonymous>:7:1)
[error] at SyncHook.lazyCompileHook (/home/piquerez/adpi2/foo/target/scala-3.0.0-M3/scalajs-bundler/main/node_modules/tapable/lib/Hook.js:154:20)
[error] at /home/piquerez/adpi2/foo/target/scala-3.0.0-M3/scalajs-bundler/main/node_modules/webpack/lib/Compilation.js:1319:42
[error] at AsyncSeriesHook.eval [as callAsync] (eval at create (/home/piquerez/adpi2/foo/target/scala-3.0.0-M3/scalajs-bundler/main/node_modules/tapable/lib/HookCodeFactory.js:33:10), <anonymous>:6:1)
[error] at AsyncSeriesHook.lazyCompileHook (/home/piquerez/adpi2/foo/target/scala-3.0.0-M3/scalajs-bundler/main/node_modules/tapable/lib/Hook.js:154:20)
[error] at /home/piquerez/adpi2/foo/target/scala-3.0.0-M3/scalajs-bundler/main/node_modules/webpack/lib/Compilation.js:1315:36
[error] at AsyncSeriesHook.eval [as callAsync] (eval at create (/home/piquerez/adpi2/foo/target/scala-3.0.0-M3/scalajs-bundler/main/node_modules/tapable/lib/HookCodeFactory.js:33:10), <anonymous>:6:1)
[error] at AsyncSeriesHook.lazyCompileHook (/home/piquerez/adpi2/foo/target/scala-3.0.0-M3/scalajs-bundler/main/node_modules/tapable/lib/Hook.js:154:20)
[error] at /home/piquerez/adpi2/foo/target/scala-3.0.0-M3/scalajs-bundler/main/node_modules/webpack/lib/Compilation.js:1311:32
[error] at AsyncSeriesHook.eval [as callAsync] (eval at create (/home/piquerez/adpi2/foo/target/scala-3.0.0-M3/scalajs-bundler/main/node_modules/tapable/lib/HookCodeFactory.js:33:10), <anonymous>:6:1)
[error] at AsyncSeriesHook.lazyCompileHook (/home/piquerez/adpi2/foo/target/scala-3.0.0-M3/scalajs-bundler/main/node_modules/tapable/lib/Hook.js:154:20)
[error] at Compilation.seal (/home/piquerez/adpi2/foo/target/scala-3.0.0-M3/scalajs-bundler/main/node_modules/webpack/lib/Compilation.js:1248:27)
[error] at /home/piquerez/adpi2/foo/target/scala-3.0.0-M3/scalajs-bundler/main/node_modules/webpack/lib/Compiler.js:625:18
[error] at /home/piquerez/adpi2/foo/target/scala-3.0.0-M3/scalajs-bundler/main/node_modules/webpack/lib/Compilation.js:1171:4
[error] at AsyncSeriesHook.eval [as callAsync] (eval at create (/home/piquerez/adpi2/foo/target/scala-3.0.0-M3/scalajs-bundler/main/node_modules/tapable/lib/HookCodeFactory.js:33:10), <anonymous>:15:1)
[error] at AsyncSeriesHook.lazyCompileHook (/home/piquerez/adpi2/foo/target/scala-3.0.0-M3/scalajs-bundler/main/node_modules/tapable/lib/Hook.js:154:20)
[error] at Compilation.finish (/home/piquerez/adpi2/foo/target/scala-3.0.0-M3/scalajs-bundler/main/node_modules/webpack/lib/Compilation.js:1163:28)
[error] Failure on parsing the output of webpack: No content to map due to end-of-input
[error] at [Source: (ProcessPipeInputStream); line: 1, column: 0]
[error] You can try to manually execute the command
[error] node /home/piquerez/adpi2/foo/target/scala-3.0.0-M3/scalajs-bundler/main/node_modules/webpack/bin/webpack --bail --profile --json --config /home/piquerez/adpi2/foo/target/scala-3.0.0-M3/scalajs-bundler/main/scalajs.webpack.config.js
[error]
[error] stack trace is suppressed; run last Compile / fastOptJS for the full output
[error] (Compile / fastOptJS / webpack) Non-zero exit code: 1
[info] fastOptJS / webpack completed
[error] Total time: 14 s, completed Jan 7, 2021 5:51:58 PM
I am not familiar enough with webpack and source-map to find the cause of this error in the produced .js or .map files.
With webpackEmitSourceMaps := false it works well and I can execute the bundled file in the browser.
Similar issue when running sbt fastOptJS / webpack with webpack source-map, after changing Scala from 2.13.8 to 3.1.2.
[info] Bundling the application with its NPM dependencies
[error] .../target/scala-3.1.1/scalajs-bundler/main/node_modules/source-map/lib/source-map-generator.js:298
[error] throw new Error('Invalid mapping: ' + JSON.stringify({
[error] ^
[error] Error: Invalid mapping: {"generated":{"line":1144,"column":134},"source":"...REMOVED...scala","original":{"line":2,"column":-1},"name":null}
// project/build.properties
sbt.version=1.6.2
// project/plugins.sbt
addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.10.0")
addSbtPlugin("ch.epfl.scala" % "sbt-scalajs-bundler" % "0.20.0")
// build.sbt
enablePlugins(ScalaJSPlugin)
enablePlugins(ScalaJSBundlerPlugin)
scalaVersion := "3.1.2"
scalaJSLinkerConfig ~= { _.withModuleKind(ModuleKind.CommonJSModule) }
// webpackEmitSourceMaps := false
I can also confirm, that my js file output from fastOptJS also contains the \uff3f char.
e.g.
var _\uff3fself = this$1.EMPTY_SET__ju_Set();
Another side note: switching from fastOptJS to fullOptJS also "fixes" it for us.
So sbt fullOptJS/webpack works even without webpackEmitSourceMaps := false.