Potential JS Parse Error / ASI failure in Native Modules

66 views
Skip to first unread message

Corey Trampe

unread,
Aug 1, 2015, 3:50:57 PM8/1/15
to Elm Discuss
In the current native module boilerplate, we say:

//...
Elm.Native.Foo.make = function(elm) {
  //...
}

Notice that this is a function expression, and thus should have been terminated with a semicolon?
I didn't, in my little vendor prefix module. I omitted the semicolon (and it passed through native code review).

In my little tests, it worked fine, and I published it. Thanks, Automatic Semicolon Insertion!

And it turns out that in some cases (I still don't know which) we see a runtime error, where the JS parser is tripping up on something in the module loader,
and lands flat on it's face right where that semicolon should have been.

Has anyone else seen this?

I've looked around and seen that a bunch of native modules (including core) are missing that precious little terminator.

I'd really like to know what is causing ASI to fail in these cases, but regardless... we shouldn't be relying on it.


So, for posterity:

The error:
    Uncaught TypeError: (intermediate value)(intermediate value)(intermediate value)(intermediate value)(intermediate value)(intermediate value)(...) is not a function(anonymous function)

points to the module loader:
    (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){

Go home, JavaScript; you're drunk.

If you landed here because you searched for this lovely error message, please check the expression *preceding* the one that took a piss, and see if it needs a semicolon.
Thank you for programming JavaScript, and have a nice day!


Jason Merrill

unread,
Aug 3, 2015, 12:07:41 PM8/3/15
to Elm Discuss
Maybe this is already obvious, but this problem usually surfaces as a result of concatenation (ofthen the first step of minification). For example, you might have

file a:
var a = function () {
  // ...
} // no semicolon at the end

file b:
(function () {
  var b = 5
  // do stuff with b
)(); // This is the "Immediately Invoked Function Expression" pattern

This works fine when these files are pulled in as separate scripts, but if you concatenate them, you get

var a = function () {
  //...
}(function () {
  var b = 5
  // do stuff with b
)();

Which ends up invoking the function that was supposed to be assigned to "a" and assigning its result instead (or throwing an error).

Whether you see this error depends on which modules are pulled into the minified result, and also depends on which order they are included in. This makes it a pretty nefarious problem because it may not be reproducible in simple examples.

It seems like there are at least a couple possible solutions to this problem.

1. Replace the minifier with something smarter that will not make this mistake
2. Run jshint or some other javascript linter on native code to enforce sane formatting.

Both of these are probably good ideas.

Corey Trampe

unread,
Aug 3, 2015, 12:12:12 PM8/3/15
to elm-d...@googlegroups.com
Very insightful, Jason. Thanks!

--
You received this message because you are subscribed to the Google Groups "Elm Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elm-discuss...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Jason Merrill

unread,
Aug 3, 2015, 12:21:08 PM8/3/15
to Elm Discuss, corey...@gmail.com
Corey, can you post some code that triggers this issue, maybe as a gist (https://gist.github.com/)?

It'll be a lot easier to verify a fix if there are known test cases.

GlenDC

unread,
Aug 3, 2015, 12:39:34 PM8/3/15
to Elm Discuss, corey...@gmail.com
It was happening in the native code of elm-vendor before this commit: https://github.com/coreytrampe/elm-vendor/commit/c1f13efbbf78139218a34b11307b727f7ee6f50e

So as soon as you would import the elm-vendor in your Elm application, the generated javascript code would get that runtime exception. Thanks to that commit (the semicolon at the end) you don't get it.

Evan Czaplicki

unread,
Aug 3, 2015, 2:44:14 PM8/3/15
to elm-d...@googlegroups.com, corey...@gmail.com
PSA to folks reading this in the future: the way of writing native code will change. This is not a public API that is intended for general use. It is a safety valve that allowed us to make elm-webgl work when we knew it'd be a while before we had a general solution! A properly designed version of this is in the pipeline.

--
Reply all
Reply to author
Forward
0 new messages