Skip to content
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

top level anonymous given gives syntax error when loaded in browser #385

Open
weihsiu opened this issue Nov 29, 2020 · 9 comments
Open

top level anonymous given gives syntax error when loaded in browser #385

weihsiu opened this issue Nov 29, 2020 · 9 comments

Comments

@weihsiu
Copy link

weihsiu commented Nov 29, 2020

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] (...
@sjrd
Copy link
Collaborator

sjrd commented Nov 29, 2020

Thanks for the report. Can this be reproduced without scalajs-bundler?

@weihsiu
Copy link
Author

weihsiu commented Nov 30, 2020 via email

@sjrd
Copy link
Collaborator

sjrd commented Nov 30, 2020

So, here is what happens:

  1. 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 called given_CanSing_F.
  2. 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 \uff3f in the .js file.
  3. 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).
  4. 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.
  5. 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.

@weihsiu
Copy link
Author

weihsiu commented Nov 30, 2020

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.

@sjrd
Copy link
Collaborator

sjrd commented Nov 30, 2020

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.

@adpi2
Copy link
Member

adpi2 commented Jan 7, 2021

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 chokidar@2.1.8: Chokidar 2 will break on node v14+. Upgrade to chokidar 3 with 15x less dependencies.
[error] npm WARN deprecated fsevents@1.2.13: fsevents 1 will break on node v14+ and could be using insecure binaries. Upgrade to fsevents 2.
[error] npm WARN deprecated resolve-url@0.2.1: https://github.com/lydell/resolve-url#deprecated
[error] npm WARN deprecated urix@0.1.0: Please see https://github.com/lydell/urix#deprecated
[info] > webpack-cli@3.3.2 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 fsevents@2.3.1: 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 fsevents@1.2.13: 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 fsevents@1.2.13: 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.

@mims-github
Copy link

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

@mims-github
Copy link

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();

@mims-github
Copy link

Another side note: switching from fastOptJS to fullOptJS also "fixes" it for us.
So sbt fullOptJS/webpack works even without webpackEmitSourceMaps := false.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants