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

Should support for functions be removed? #12

Closed
ericf opened this issue Oct 13, 2013 · 11 comments
Closed

Should support for functions be removed? #12

ericf opened this issue Oct 13, 2013 · 11 comments
Assignees

Comments

@ericf
Copy link
Collaborator

ericf commented Oct 13, 2013

Serializing functions is tricky business that is basically not possible to get 100% correct without doing insane things. It also encourages bad practices of shipping app code over the wire by serializing it in the HTML. If this foot-gun is left it, it needs big scary docs about how this feature ought to be used!

@ghost ghost assigned ericf Oct 13, 2013
@clarle
Copy link

clarle commented Oct 13, 2013

We do want to share functions between client and server somehow, though, right? At the very least, with what we do with templates and internationalization, those functions are wrapped up into their modules, and accessed through a registry to be used.

If we do remove this from express-state, I think it's still useful to discuss an alternative, such as how the template and internationalization registry system works, and how you would be able to create something similar.

@caridy
Copy link
Contributor

caridy commented Oct 14, 2013

@clarle, in principle, express-state is about transitioning the state of the app from server to client, and a serialized function does not carry any state. What's probably the main reason why we want to remove support for them. Effectible, we could expose monads functions per request, but that doesn't mean we should.

Also, keep in mind that this is a very low level component, with a low level api. It doesn't, and shouldn't, care about templates, loader registry or i18n registry, it cares about data that carry the current state of the app per request.

That been said, we are using function serialization for app.yui.ready() and app.yui.use(), and the reason for that is performance. Sending a little bit of a payload to the client side to boot the client side app without the need to wait for a javascript file to be loaded independently. It is true that we could expose the blob with the functions right after {{{state}}} in our layout template, but then we need to find a mechanism for app developers to overrule that blob somehow, something that is already well implemented in express-state.

So, I vote for keeping support for it, but as @ericf said, adding the proper docs explaining in details what are the implications about serializing functions, and adding few guidelines on how and when to use them.

@ericf
Copy link
Collaborator Author

ericf commented Oct 15, 2013

@caridy good points. I think you explained the pros/cons and primary use cases well. What I'll do, for now, is add docs and guidance about only serializing dependency-free, monadic functions that are for advanced configuration (like YUI config feature tests or Express route param formatters).


@clarle my main worry is that people will use express-state as to ship their application code to the client (which would be very brittle) instead of using a module system and loader. Ideally the source code should be static and independent of state/configuration (which is dynamic).

@caridy the reason I wanted to add support for functions to begin with is to support monadic config functions, like feature tests in YUI config or formatters for Express route params. I think code-inlining is a different problem that we want to solve with another package because it will involve modules, loaders, dependency resolution, and could simply deal with the string contents of a files to concat into the response body.

ericf added a commit that referenced this issue Oct 16, 2013
@ericf
Copy link
Collaborator Author

ericf commented Jun 6, 2014

Closing this. We are keeping support for functions.

@ericf ericf closed this as completed Jun 6, 2014
@juandopazo
Copy link
Contributor

So this is something I´ve been thinking about for a couple of weeks.

dependency-free, monadic functions

Let's use the right terms: we can safely share functions with the client as long as they don't access anything in an outer scope. Remarkably, this is easy to check statically. I've been playing around with this small tool that Gozala wrote exactly for this use case: https://github.com/gozala/isoscope. Isoscope takes the AST for a function and gives you back a list of all the variables that function is closing over. For example:

var esprima = require("esprima")
var enclosed = require("isoscope/enclosed")

// Parse some code
var form = esprima.parse(String(function fn(a, b) {
  console.log(String(a) + b)
}))

// Get a function form we'll be analyzing
var fn = form.body[0]
fn.id
// => { type: "Identifier", name: "fn" }

// Get names of enclosed references
enclosed(fn)
// => [ "console", "String" ]

This means express-state could try to parse the function, analyze it and if it contains one or more unknown enclosed variables it could throw an error saying it can't safely expose the function to the client.

@ericf
Copy link
Collaborator Author

ericf commented Jun 24, 2014

This means express-state could try to parse the function, analyze it and if it contains one or more unknown enclosed variables it could throw an error saying it can't safely expose the function to the client.

Sounds like a cool idea. If we do this, we'd only want to do in dev-mode and not in prod because of the runtime cost.

@caridy
Copy link
Contributor

caridy commented Jun 24, 2014

that means express-state will depend on esprima an isoscope, that will be a mistake IMO. We could provide express-state-dev, that they can include in their devDependencies, and require it to add extra verifications when exposing stuff during dev time, but modifying express-state, which is a lightweight pkg today, just to provide this extra check in dev will be a hard to sell.

@ericf
Copy link
Collaborator Author

ericf commented Jun 24, 2014

Yeah true, and the function will throw on the client because it will try to access something in the outer scope which doesn't exist.

@juandopazo
Copy link
Contributor

@ericf you don't know when it'll throw, which is dangerous part.

@ericf
Copy link
Collaborator Author

ericf commented Jun 24, 2014

How about this… someone could use these tools or some isFunctionSerializable() wrapper which they can pass their function into before trying to expose it.

Making this feature exist outside of express-state to avoid @caridy's concerns.

@juandopazo
Copy link
Contributor

Yes, if I want to, I can check for myself. I just thought it could be a nice addition to prevent errors.

I think it'd be nice if JS itself had a reflection API for this BTW.

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

No branches or pull requests

4 participants