Class properties syntax error

So I thought that the syntax support in cells was just up to whatever the browser you happen to use supports. For instance, dynamic imports didn’t work for me before in Firefox (on Ubuntu), but now that I’m using latest Chrome again (on OS X) they do.

However, writing “class properties” doesn’t work for me at the moment, even though my browser does support them, see the image below.

I can imagine this is just an artefact of the shallow parsing you guys perform in order to separate the “Observable” stuff from the ordinary JavaScript (mutable, cellname = { ... }, viewof, etc). If this is the case, then this post is a bug report :slight_smile: If not, do you know what’s going on? (I like writing my React components using class property defined methods.)

BTW, I did try some alternatives, but they kept giving me the same error:

class A {
  state = []
}
{
  return (class A {
    state = []
  })
}
(class {
  state = []
})
{
  return (class {
    state = []
  })
}

Observable has its own full parser (based on Acorn), so we don’t necessarily support every language feature that your browser supports. We don’t support class properties yet, but as language features become stage 4 (or perhaps in limited cases stage 3, like dynamic import), we’ll add support for them. I believe class fields are currently in stage 3.

3 Likes

I see.

Did this use to be different? (I haven’t been active on Observable for a while, maybe I missed this change?)

I feel I remember reading on these forums that JS features depended on your browser; in discussions about whether it’d be possible to do babel transpilations, etc. Does this also mean that dynamic imports would now work regardless of browser? (Or maybe they just parse, but the JS still is run with an eval so that it still depends on the browser?)

If this parse step is new, BTW, does that also mean that you guys are considering a transpiration step?

Adding a whole parser but not an interpreter seems a bit of a weird step if you only want to strip out mutable etc, and it’s also a bit weird if “all it does” is disallow certain (stage 3) features that your browser already supports; but it makes sense from the transpiration perspective.

I’m a fan of vanilla JavaScript too, but nevertheless I do think it’d be smart to support at least the popular kids in town like TypeScript and JSX. I now have a new job teaching React (and related stuff), and do think there are a lot of people out there like us that would love to experiment with react, jsx, typescript, etc on Observable. Not really sure if this is your audience of course (education).

2 Likes

The following description of how notebooks on observablehq.com are run might be helpful. (My terminology is probably a bit off… would appreciate corrections.) The way I see it, notebooks have two representations:

  • The code that you type beneath each cell of the notebook is what I’ve been calling the “raw source” of the cell.

These raw source strings are processed (using the Observable parser) to become:

Note that the JS files in the “Download code” links for each notebook are generated via a similar process. You can see that they consist of definitions of runtime modules, either in array format (for runtime V1) or using the methods of the Observable Runtime class (for runtime V3).

One consequence of the above is that some features which would work fine inside a standalone JS project using the Observable runtime library (where you would have to place your code in runtime variables by hand) won’t work on observablehq.com where the runtime variables are generated from raw source via the parser.

As an illustration, see

where I put your class A into a handwritten runtime module which is then run in an iframe where it works (in Chrome only!).

We’ve always parsed JavaScript in Observable, even pre-d3.express. The parsing serves several purposes:

  • To identify the name of the cell and references to other cells, and compute the topology

  • To allow transpilation of cell bodies into definition functions (of the appropriate type, such as async generators), taking the referenced inputs as arguments

  • To support Observable’s language extensions, including viewof, mutable, static imports, and dynamic imports

So, while the actual transpilation is fairly minimal, parsing is essential so that we can both extract references and support language extensions.

The language features you can use in Observable are the intersection between what Observable’s parser supports and what your browser supports. We don’t currently use transpilation to provide legacy support for JavaScript language features.

We’re considering support for user-specified transpilers, but this would add a lot of complexity. In the meantime, we recommend using tagged template literals to support other languages, and in particular, HTM if you want something like JSX:

2 Likes

Of course, I should’ve thought of that, haha! (That you need to identify cell name variables.) Thanks for the comments :slight_smile:

1 Like