-
-
Notifications
You must be signed in to change notification settings - Fork 4.4k
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: add preprocessor nesting #6031
Proposal: add preprocessor nesting #6031
Conversation
This allows for developers to ensure that certain `markup` functions are run *after* other `script` or `style` functions have run.
c0524ea
to
f732bc5
Compare
I'm a bit unsure if this is a good enhancement. The current API obviously has these ordering drawbacks. My envisioned solution to this is to just ditch the script and style preprocessors and instead require all preprocessors to preprocess on the whole code, like the current markup preprocessor. That and providing utility-functions to extract the script/style tags with attributes should give the same power with more ordering flexibility. |
I am 100 percent in favor of a breaking change that would make this processor ordering more usable and have a simple api. However, this suggestion is in lieu of something that isn’t backwards compatible. I suppose another alternative would be a flag to indicate you are using a new version of the config. In the meantime, I’ll keep this open. |
I don't fully understand your answer. Are you in favor of my envisioned proposal and want it sooner rather than later through a config setting (we agree that we can't just change it, because it's a breaking change)? |
I am in favor of either
Option 2 seems the better solution to me. However, I am completely ignorant of how this kind of thing might affect the Language Services stuff. |
Right now svelte.preprocess is completely decoupled from svelte.compile. svelte.preprocess expects either and object with one of markup/style/script, or an array of these objects. We could change the code in svelte.preprocess to also support receiving a plain function, which signals that the new experimental version should be used. That would make this experimental change completely transparent for language tools and the rollup/webpack/vite plugin. If we did that, I'm not sure about interop with preprocessors written the "old" way. Throw an error, but also provide a transformation function? Support both modes in parallel? |
As long as the only action required is on the part of the developer of an app, not the developer of a preprocessor. I am guessing that many of those projects will be slow to transition, if ever. So if we provide access to utility functions as you describe that can be used to provide the old api to the preprocessors, I think that's a decent solution. Something like this? // somewhere in "svelte/compiler"
export function getScript(content) { /* details */ }
export function getStyle(content) { /* details */ }
export function mergeParts(body, script, style) { /* details */ }
export function legacyPreprocessor(preprocessor) {
return {
markup: async ({ content, filename }) => {
const processedBody =
await (
preprocessor?.markup({ content, filename }) ??
Promise.resolve({ code: content })
);
const script = getScript(processedBody.code);
const processedScript =
await (
preprocessor?.script({ content: script, filename }) ??
Promise.resolve({ code: script })
);
const style = getStyle(processedBody.code);
const processedStyle =
await (
preprocessor?.style({ content: style, filename }) ??
Promise.resolve({ code: style })
);
return mergeParts(processedBody, processedScript, processedStyle);
},
};
} // in the config file (or similar depending on your project)
import { legacyPreprocessor } from "svelte/compiler";
import sveltePreprocess from "svelte-preprocess"
import svelteImage from "svelte-image"
const someConfig = {}
const otherConfig = {}
module.exports = {
// Passing a function to `preprocess` signals only markup will be provided,
// and everything will execute in order, top to bottom.
preprocess: () => [
legacyPreprocessor(sveltePreprocess(someConfig)),
svelteImage(otherConfig),
],
}; Is this getting into RFC territory? I'd love to solve this problem once and for all. |
A RFC would be great for this I think. Would you be willing to write one based on your previous observations and this discussion? |
I could, but don’t know how soon I could do it. Do you know the original reason for the different ordering of preprocessing? Seems like a very specific choice. I’ve just never known the upside to doing it that way. I wouldn’t want to write up an rfc if there is some very good reason to keep the ordering as is |
Closing in favor of sveltejs/rfcs#56 |
This allows for developers to ensure that certain
markup
functionsare run after other
script
orstyle
functions have run.I will take care of further addition of tests and whatnot if there is agreement that this is a feature worth having.I couldn't resist making the tests pass. 😅Problem
Some preprocessors need to run against the
markup
function to be useful. In the particular case of Svelte Image, it uses themarkup
function to gain access to the whole component, then usessvelte.parse
to get an AST.But whoops! If you like developing with Typescript, Svelte Image won't work for you because Typescript isn't removed until the
script
phase of the preprocessor function, andsvelte.parse
doesn't understand Typescript.Workaround
Preprocessors that really need access to
markup
after all other processors have finished could be forced last in this way (again with svelte image as the example)So this solution works, but wouldn't we be calling
svelte.preprocess
more than necessary, ultimately? not sure if that has any downsides. Like maybe you lose all sense of "who did what" when it comes to dependencies and source maps. But I could be wrong. I don't know a whole lot about the internals of Svelte, but I do know that if we were to nest everything, all the processing would be done against one instance ofPreprocessResult
, instead of multiple ones.Perhaps if my proposal isn't up to snuff, we should at least consider adding documentation that points people toward the workaround above, since this issue comes up from time to time.
My proposal: allow nested preprocessors
Here is my addition to the documentation:
My main goal here is to get this pushed all the way into the config files for Svelte, Sapper, and SvelteKit projects. I am guessing that this is either the exact way to do it, or that it is the start of that goal.
Before submitting the PR, please make sure you do the following
Tests
npm test
and lint the project withnpm run lint