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

mdsvex.compile(content, options) adds extra {@html and } wrapper for no reason #392

Open
Tracked by #588
swyxio opened this issue Jan 15, 2022 · 12 comments
Open
Tracked by #588
Labels
assigned Whether or not this bug has been assigned some to some other issues as a subtask or pre-req

Comments

@swyxio
Copy link
Contributor

swyxio commented Jan 15, 2022

in here: https://github.com/sw-yx/swyxkit

this section https://swyxkit.netlify.app/welcome#setup

image

this {@html seems to be injected by mdsvex. i presume its how mdsvex injects itself in normal operation, but the usecase for .compile users seems to be overlooked.

right now i'm thinking of just using regex to take it out but ofc would be nice to fix at source

simple repro

run

npm i mdsvex
node

inside the node env, do:

  compile(`
  \`\`\`js
  let foo = 123
  \`\`\`
  `).then(console.log)

the result is

'<pre class="language-js">{@html let foo = 123}</pre>\n'

which has the extra {@html stuff

@swyxio
Copy link
Contributor Author

swyxio commented Jan 15, 2022

alright this works:

  compile(`
  \`\`\`js
  let foo = 123
  \`\`\`
  `).then(x => console.log(x.code
			.replace(/>{@html `<code class="language-/g, '><code class="language-')
			.replace(/<\/code>`}<\/pre>/g, '</code></pre>');
  ))

but its ugly af of course

@pngwn
Copy link
Owner

pngwn commented Jan 18, 2022

compile still returns a Svelte component, there is plenty more that could break when using mdsvex as a markdown -> html tool but appreciate this usecase.

Another way to work around this would be to use a custom highlight function, it may be possible to expose the internal highlight function that produces the correct markup without the @html wrapper.

Or maybe I could expose a to_html version of compile that avoids any svelte specific insertions, there would still be lots that could break however.

@swyxio
Copy link
Contributor Author

swyxio commented Jan 18, 2022

ah i see. if compile returns a Svelte component its not very obvious to me how to consume it from within a svelte app. do i use svelte:component?

hmm.. when i try <svelte:component this={content} /> with the raw output of compile, the error says <svelte:component this={...}> is not a valid SSR component. You may need to review your build config to ensure that dependencies are compiled, rather than imported as pre-compiled modules

@pngwn
Copy link
Owner

pngwn commented Jan 18, 2022

Yeah this is trickier. It also returns an uncompiled svelte component so needs to be compiled by svelte too (and any imports would need to be resolved), you'd also need some and SSR versions of the component.

I think using vites glob imports might work in this case, as I think you get both the SSR and dom mode components that way. But not sure how nicely that would play with kit routes.

And the final option would be to just generate an SSR version of the component (if it is all static markdown) and then you could inject the html that is returned from render. If you are doing your markdown parsing/ conversion in an endpoint of some description and this is a statically generated site then you could do this work there without any issues.

@pngwn
Copy link
Owner

pngwn commented Jan 18, 2022

Of course this all far too complicated for a pretty common use case, so I need to improve this story a bit here.

There are some technical details that can't be avoided but I'm certain there are DX improvements that can be made. I just haven't had time to explore this thoroughly enough so far.

@swyxio
Copy link
Contributor Author

swyxio commented Jan 18, 2022

ok gotcha thank you for understanding. i think i should be able to compile it with svelte serverside. will try another day

agree that this is a common enough usecase that it should be addressed first class eventually

@swyxio
Copy link
Contributor Author

swyxio commented Jun 9, 2022

@felixsanz see my solution in swyxkit

@williamviktorsson
Copy link

williamviktorsson commented Dec 8, 2022

Thanks @sw-yx for the temporary solution, feels dirty though. Any edge cases where this might not work?

@iansamz
Copy link

iansamz commented Jan 12, 2023

Useful but ugly. Thanks @sw-yx

@swyxio
Copy link
Contributor Author

swyxio commented Jan 12, 2023

@williamviktorsson you tell me haha

@williamviktorsson
Copy link

@williamviktorsson you tell me haha

So far so good lol 😂

@brunobely
Copy link

brunobely commented Nov 19, 2023

Adding this as a comment as I've tried to use compile and found myself in this issue. Happy to open a new question-type issue if this is off-topic.

When I use @swyxio's solution then render the generated code (I'm trying to do this while using custom components) I get a whole <layout_mdsvex_default {...$$props}> ... in there, which I assume is what you mean by "compile still returns a Svelte component", @pngwn?

The use case is I'm writing a blog that has accompanying code snippets which are used to

  1. render a p5.js canvas; and
  2. display the source in a "Code" tab.

My approach to this has been to dynamically import the p5.js sketch's .ts file and accompanying description.md in +page.ts:

// +page.ts
  // in load
  sketch = await import(`../sketches/${params.slug}.ts`);
  description = await import(`../sketches/${params.slug}.md`);

  return {
    sketch: sketch.default,
    Description: description.default,
  };

Which I then render in my page as <Description /> and <SketchComponent {sketch} />. I can't quite figure out how to read the source from the .ts file, parse it as a Markdown code block, and prettify it using my MDsveX setup (with rehype-pretty-code), but so far I'm doing it like this:

// +page.server.ts
  // in load
  const formattedSource = await prettier.format(fs.readFileSync(filePath, "utf-8"));

  // Transpile to JS so it's easier for readers to paste into p5.js web editor and run it.
  const jsSource = await esbuild.transform(strippedSource, {
    loader: 'ts',
  });

  const mdx = await compile('```js\n' + jsSource.code + '\n```', mdsvexConfig);  // imported from mdsvex.config.js.

  return mdx.code  // @swyxio's workaround.
      .replace(/>{@html `<code class="language-/g, '><code class="language-')
      .replace(/<\/code>`}<\/pre>/g, '</code></pre>');

Any idea if there's a simpler solution to this or how to further compile it into a proper Svelte component? I tried remark-code-import but got errors when trying to load files.

@pngwn pngwn mentioned this issue Feb 23, 2024
13 tasks
@pngwn pngwn added the assigned Whether or not this bug has been assigned some to some other issues as a subtask or pre-req label Feb 24, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
assigned Whether or not this bug has been assigned some to some other issues as a subtask or pre-req
Projects
None yet
Development

No branches or pull requests

5 participants