-
-
Notifications
You must be signed in to change notification settings - Fork 4.3k
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
[Proposal] Run js expressions in markup template through Svelte script preprocessor code #4701
Comments
This comment has been minimized.
This comment has been minimized.
I feel like running script preprocessors on every JS expression in the template would slow down compilation considerably but have no data to back that up. The other option here would be to expose an api to parse the template without passing the JS expressions to acorn yet. At least then you could write a relatively simple markup preprocessor to handle this case. |
The main technical problem here is that it involves Svelte identifying template expressions written in a language that it cannot parse. The beginnings of template expressions are found via the As a sort-of solution, the preprocessor could just count opening an closing braces, but this would be thrown off by, say, expressions containing strings containing mismatched braces. A proper solution to this seems more to be to create a new callback that will be called, one at a time, with the start of each expression, and returns the preprocessed code and how many characters it ate, or else throws an exception. I don't have any opinions yet on what this API should look like or what it should be a part of. |
If completely avoiding duplicating Svelte parser logic in a preprocessor is not a goal, this all could be fairly straightforwardly implemented in userland in a template preprocessor. The template preprocessor runs before the script or style preprocessors, and the initial intention was that it would do something like convert Pug to HTML, but there's nothing stopping it from transforming any part of the component that it wants. The script and style preprocessors are pretty much sugar on top of the template preprocessor, in that they extract the script or style tags and then operate only on that, leaving the rest of the component unchanged. |
indeed we discussed a userland preprocessor solution - but it seemed less than ideal bc it would basically duplicate work that Svelte/Acorn is already doing, and involve wiring up babel twice (once for script, once for template) as a Svelte user, the mental model for script preprocessor is "ok this thing works on everything inside the re: the speed - the syntax transpiles here are going to be very light. will have to benchmark to know for sure ofc but we're definitely not going thru the whole es5 dance here. I dont know much about the Svelte-Acorn handoff, so this wrinkle with the parsing is interesting. happy to explore that new callback, but i wonder if it should just be the same callback that the preprocessor is |
Wanted to chime in here as no googling found this issue (attributing this to the age of the issue) which lead to me creating the above duplicate. To distill what I was trying to say in the above issue I think irrespective of the decision made here it would be good to have some formal documentation on this (also mentioned in #3388) to guide new users and help mitigate wasted effort in trying to set this up when it is currently not possible. |
based on what conduitry said, it sounds like some R&D is needed on improving that svelte-acorn parsing. having different systems take care of the { and the } seems a little brittle? idk |
just throwing some of my thoughts over here, the current preprocessor is more of a string based preprocessor, doing string replacements before letting svelte compiles it.
so i would like to propose that, maybe instead of preprocessor, we can have a parser plugin. we can have a default acorn plugin to help parse JS, but also allow user to provide custom JS parser, as long as they are estree compliant. |
i didnt quite understand the difference between preprocessor or parser plugin, but i also didnt really understand the whole post haha. if this seems like the better idea, where is a good place to start? also...what does "same idea can go to css too" mean? how would this help? |
oh i think i didnt explain it clearly.. i think what i was trying to say is that currently it's hard to make its hard to run js expression in markup through preprocessor as it is run before the svelte parsing. so maybe an alternative is to provide a way to tap into the parsing, to allow user to provide custom callback to parse JS expression |
If we did integrate this into the parsing by making it an option to the compiler (rather than handling it in an earlier preprocessing step), we'd need to enforce that those plugins are synchronous. And then we'd have two different ways of doing what would seem to users to be very similar things, and each would have different limitations, which sounds confusing. |
yeah we definitely dont want that ☝️ . ok so are we back to a preprocessor solution? how hard is matching going back to conduitry's initial thoughts:
i just find this a little weird and wonder if it can be better? would there be side benefits of parsing the { and } in svelte, and then handing off the complete chunks to Acorn? and i'll be transparent, if it just seems not worth it, im happy to back off/close. just thought like itd be a good idea if it were easy. |
Without some understanding of the underlying language used within the Running preprocessors on the There probably is still a reasonable way to handle this within Svelte using preprocessors (perhaps by running through the |
While looking at sveltejs/prettier-plugin-svelte#70 it occurred to me that things like the string What I'm getting at is that I'm starting to look more positively on the idea of going through the input file in order and calling the preprocessors in series. Glossing over some details: In the general situation of a partially preprocessed file, we look for the next occurrence of As I was writing this, I realized that one of the detail I glossed over was how to handle |
that's encouraging! altho i'm not sure i follow what the solution is. are we happy with the current behavior of i feel like we make things a little harder for ourselves with the freewheeling order of script, style, and template. i thought for a while about proposing a fixed order to make life easier for ourselves, but decided against it bc we dont want to break the language (and personally, i enjoy doing script -> template -> style, i know its a little weird). |
Fun thing i just found in the TS 3.9 RC: https://devblogs.microsoft.com/typescript/announcing-typescript-3-9-rc/#breaking-changes |
I was hoping the same, but it seems that vuejs can't achieve this either. It is hard! Hope svelte can get rid of this problem, that would be awesome!! |
When thinking about a solution, please also take into consideration how to handle source maps. Right now this is already problematic because there may be a script and a module-script tag, each producing its own source maps. Ideally, only one big source map would be returned after transpiling everything, as part of the result of the preprocess function. Not sure how much of that is handled by #5015 |
How about we treat all codes and templates are written in |
Disclaimer, I'm not familiar with the Svelte internals. I do have a parser/compiler background though, so allow me to speculate. As I understand it, Svelte presently uses Acorn to parse javascript in templates. Given that typescript is a superset of javascript, couldn't Svelte use typescript's parsing layer exclusively, and kill two birds with one stone? To address the problem of parsing within {} braces, couldn't a grammar that describes the entire scope of a .svelte file be defined, and the present TS syntax be embedded in the appropriate places within that outer grammar? This might be less modular, but modularity is a secondary concern, and could in principle be addressed by using plugins within the grammar description. |
|
Not sure if anyone is still having this problem but I solve this using reactive statements. This also helps with typing stuff for component parameters and such.
|
It turns out type guards handle the values of the object better when parsed this way for some reason.
|
Huh, that actually makes sense. Thank you! |
This problem is made much worse by svelte-check with TypeScript throwing an error on this line:
whereas onKey is defined as When I add the type, as demanded by svelte-check:
then Svelte barfs: (This svelte-check error apparently happens only on generic HTML elements which don't have The fact that TypeScript doesn't work in The only workaround I know is to add another dummy wrapper function in the Most importantly, there doesn't seem to be any solution for the svelte-check error. I don't know how to make svelte-check happy, because it creates a hard error, which makes our CI pipeline fail, and Svelte has a parse error on the solution that svelte-check demands. |
svelte-check throws the error, both locally and on CI (which is a hard block in our CI pipeline, so I cannot land). I'm not the only one, as the Stack Overflow question shows. A simple function call might work, due to type inference. To reproduce, you need the function parameter as in my example. |
The editor tooling uses the same libraries as svelte-check (assuming everything is up to date) and I cannot produce any such error, neither in editor nor via svelte-check. I even tried to recreate the structure of the handler's code and it does nothing. function onKey(e: KeyboardEvent) { }
function showErrors(cb: () => any) { } <div on:keydown={event => showErrors(() => onKey(event))} tabindex={0}> As I said, please create a minimal example. |
I found the Acorn parser TypeScript plugin today. I think using |
Thanks for sharing @ota-meshi! We're pretty interested in this approach. If you have made any progress we'd love to see what you're working on. Or we'd be happy to chat about how we might integrate such an approach if you'd like to hop into the #contributing channel on the Svelte Discord and leave us a message |
that the Nevertheless, as this is JS and TS, I cannot specify a type here. As a result, I cannot see any way to make svelte-check happy. Things get even worse when using enumerations. This:
errors out that the type 'string' cannot be used to index type 'SampleEnum'. Again, this is not the case, so I cannot say something like: SampleEnum[enumMemberKey as SampleEnum]. At the same time we would love to have the |
Exactly that. I reported that 4 months ago above and elsewhere. Until a proper fix (like this feature here) is in place, could svelte-check at least be configured by default to not check such expressions at all, or (if possible) to not expect TypeScript in them? At least that would avoid that all developers try to "fix" their own code, just to find that this is a bug in svelte-check (or svelte). |
Is there any progress towards this? I love Svelte, but this is bugging me so much, I'm seriously thinking to switch back to Next.js or something else. |
Svelte 5 will have native support for TypeScript in the template (#9482). |
closed? |
Is your feature request related to a problem? Please describe.
i would like to use babel/typescript syntax inside of Svelte markup template code.
For example, let's say i have the babel optional chaining enabled:
This lets me use new JS syntax in my script tag:
this is great! however we try to move it down and Svelte complains:
Error:
This is somewhat of a break of the mental model, since Svelte should accept the same kinds of JS inside templates as it does inside script tags. You can imagine other good usecases for this, e.g.
{#if data?.foo?.bar}
in order to fix this, i would have to hook into a markup preprocessor, and then parse the template contents to sift out the js expressions, and then transpile it, and then stitch the markup back together. seems like repeat work to what Svelte already does anyway.
Describe the solution you'd like
Svelte should reuse the
script
preprocessor for in-template js expressions, as well as for<script>
tags.Describe alternatives you've considered
no change
How important is this feature to you?
it's a nice to have. i dont have any proof, but i suspect this might help the TypeScript effort too in case any assertions are needed (this is rare, though; more likely the "new syntax" usecase is more important than the "need to specify types in expressions" usecase)
The text was updated successfully, but these errors were encountered: