I believe most of the brokenness of current day frameworks comes from templates. Here is what you get by JSX being JavaScript:
1. Easy to write typechecking for the templates.
The compiled template is just function calls (or well, factory function calls) and the typechecker can work with that.
How many template language authors will write a typechecker for the template language?
2. Sane scope sharing - you can take advantage of all existing encapsulation and modularization tools of JavaScript. How do I expose functions to JSX? I simply bring them in scope e.g. by importing them or defining them. How do I expose functions to the template? Well... it depends. There is this $scope object (Angular)... Or there is this components property which informs the template whats in scope (Vue: https://vuejs.org/v2/guide/components.html#Local-Registratio...). I guess there are worse options, like having to register your helper functions or components into some sort of global registry and pray that there wont be a conflict.
3. First class components - want to write a list component that takes an item component as a parameter in props? Tough luck, its likely that the template language of your average framework doesn't support this. JSX gets this for free because its just JavaScript, and JavaScript is a proper language with first-class support for passing around functions and classes.
Its not that its impossible to do this... its just that most template languages aren't advanced enough, and somehow we think thats a good thing.
Angular template, and expressions, should be treated
similarly to code and user-provided input should not be
used to generate templates, or expressions
If you are distributing the compiler with your framework, there is this urge to expose it to the developers. If you expose it to the developers, there is the chance that it will end up compiling user input. And then you spend ungodly amount of time building a sandbox, unsuccessfully.
-
svelte seems to be built by people with deep interest and expertise in compilers, so I'm somewhat hopeful that its template language will not suffer from the usual template language problems. On the other hand, the task is much harder (compiling to code without runtime), so that seems like a driving force in the opposite direction (less powerful template language). I guess we'll see how it goes.
IMHO the next step in frameworks isn't this (compilers are hammers, and everything else is nails). The next step is, after current frameworks fight things out, we take the common subset of the "infrastructure code" that the most popular ones use (DOM diffing? events that are the same across browsers to remove the need for synthetic events? PropTypes? Maybe someone at whatwg should start thinking about this list) and include it in the browser API, then let frameworks build on top of that and be 10 times smaller on average.
Thank you for the detailed answer, I have a few questions here but I think you've nailed it for the most part, I'm just trying to gauge how well I understood what you wrote.
1) what is meant by type checking in this context? do you mean that now that HTML is converted to JSX in JS context, you can test HTML as if they were Javascript Objects?
2) so the ease of importing functions to JSX + use of existing "encapsulation and modularization" (I'm not sure what this menas) libraries.
3) what makes it difficult to support it from templates point of view? JSX is easier because?
4) why is sandboxing harmful? how does giving developers compilers create sandbox fallacy?
With the last paragraph, you are saying that the lowest common denominators such as DOM diffing will become a common cross platform feature in all browsers?
By type checking I mean something like typescript which is able to statically verify whether the right types of attributes are passed to the right component, or whether expressions embedded in the template are of the right type.
Re encapsulation, the way that JS provides it is scope. JavaScript's lexical scope ensures that things you define in a function are only visible in that function, or that things you define in an ES6 module are only visible in that module. Even with the tiny quirks of function based lexical scope, its natural and intuitive: if you can see the definition (or import) in the (function/module) parent(s) of the code you're looking at, its available. Its a tried and true solution.
Template languages don't always bother to add something like "import" or the concept of lexical scope, so when you want to share something from JS (or other templates) with them (like data, or processing functions, or components) you need to somehow put it in their own custom scope. Many template based frameworks make the mistake of working around this not by adding import mechanisms to the template language, but by registering things globally - e.g. when you register a component in Angular or Vue it becomes globally available. This has the same problem any other global variables have. (I suspect this in Angular 1 is what led to the totally parallel "module system" with dependency injection, although maybe they just didn't like the existing ones)
Regarding supporting first class components in template languages, its not really that difficult. Its just that we believe the fallacy that we need the template language to be underpowered. Also, once you add support for first class components and JS scope sharing (or at least import/export) mechanisms to a template language, you've basically reinvented JSX (perhaps with a different syntax)
Sandboxing isn't harmful, its just extremely hard. Angular spent years trying to write a proper expression sandbox and every new version of it was broken successfully - thats why 1.6 removed the sandbox.
What I'm hoping for is that someone works out what contributes the most to popular framework's size, takes the common parts and provides them as built in API in the browser in such a way that the frameworks can take advantage of that instead of writing their own implementations.
1. Easy to write typechecking for the templates.
The compiled template is just function calls (or well, factory function calls) and the typechecker can work with that.
How many template language authors will write a typechecker for the template language?
2. Sane scope sharing - you can take advantage of all existing encapsulation and modularization tools of JavaScript. How do I expose functions to JSX? I simply bring them in scope e.g. by importing them or defining them. How do I expose functions to the template? Well... it depends. There is this $scope object (Angular)... Or there is this components property which informs the template whats in scope (Vue: https://vuejs.org/v2/guide/components.html#Local-Registratio...). I guess there are worse options, like having to register your helper functions or components into some sort of global registry and pray that there wont be a conflict.
3. First class components - want to write a list component that takes an item component as a parameter in props? Tough luck, its likely that the template language of your average framework doesn't support this. JSX gets this for free because its just JavaScript, and JavaScript is a proper language with first-class support for passing around functions and classes.
Its not that its impossible to do this... its just that most template languages aren't advanced enough, and somehow we think thats a good thing.
4. The sandboxing fallacy
From https://angularjs.blogspot.co.uk/2016/09/angular-16-expressi...
If you are distributing the compiler with your framework, there is this urge to expose it to the developers. If you expose it to the developers, there is the chance that it will end up compiling user input. And then you spend ungodly amount of time building a sandbox, unsuccessfully.-
svelte seems to be built by people with deep interest and expertise in compilers, so I'm somewhat hopeful that its template language will not suffer from the usual template language problems. On the other hand, the task is much harder (compiling to code without runtime), so that seems like a driving force in the opposite direction (less powerful template language). I guess we'll see how it goes.
IMHO the next step in frameworks isn't this (compilers are hammers, and everything else is nails). The next step is, after current frameworks fight things out, we take the common subset of the "infrastructure code" that the most popular ones use (DOM diffing? events that are the same across browsers to remove the need for synthetic events? PropTypes? Maybe someone at whatwg should start thinking about this list) and include it in the browser API, then let frameworks build on top of that and be 10 times smaller on average.