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

Injecting variables / including static assets (ie. images) #475

Closed
cass-e-design opened this issue Oct 10, 2022 · 8 comments
Closed

Injecting variables / including static assets (ie. images) #475

cass-e-design opened this issue Oct 10, 2022 · 8 comments

Comments

@cass-e-design
Copy link

First off, thanks for creating this! I've only found svelte/sveltekit recently, and together with this I've been really enjoying the process of building, and it's very well put together! This markdown implementation is very clean compared to my previous template-based setup. I'm new to this system, please let me know if I'm asking in the wrong place or coming at this from the wrong direction. I'm hoping I'm missing something simple.

TL;DR: I'd like to optimize my images (used in markdown documents) and pass in the updated sources at build time. I'm assuming there must be a way to pass dynamic variables into MDsveX at render (via (await import(filename)).default.render() ?) like other svelte components can accept data via export let data, so I can pass in updated URLs.

My use case: I'm trying to build a static blog that avoids unecessary bloat (filesize, huge javascript bundles, etc), and I was hoping svelte would let me do that and use a modern component system. My content structure is similar to alec's in #122 (comment) (folders containing page.md and a series of images/static assets). I'm using MDsveX for the content of posts and pages where I can. I'm import()ing the markdown files on the server side (+page.server.ts), and then including the result of page.default.render() in +page.svelte with {@html}. This is working great for loading markdown!

My issue is that I'd like to optimize my images/other assets, and include multiple sizes/formats. I currently can't know their final URLs until build time. I'd like to be able to include these assets in my markdown documents, but I can't find a way to get the URLs in there on server-side.

I'm currently exporting any assets I need in a document via its frontmatter so I can retrieve the assets, optimize them, and have them ready to compile the file body. This works up to that point, but I can't find a way to pass the information into the document for use.


Workarounds I've come up with, which I haven't tried yet:

  • I'm currently optimizing my images in a svelte endpoint, after importing the markdown document but before rendering. I'm not sure if a markdown plugin could do this earlier in the process, and make the data available where I need it?
  • A custom frontmatter parser or transformer, ala Can the frontmatter be dynamic? #287 (I'm unsure if this is out of scope, or if the 'simple' transformers described there were implemented?)
  • Creating a 'variables' file which I import from the markdown document, updating it at build time and reimporting the markdown document.

If there's a whole different way I should be approaching this, I'm open to feedback. Thank you for your time!

@nosovk
Copy link

nosovk commented Oct 16, 2022

We have the similar issue. Current workaround is transform plugin.
As example you can check: https://github.com/NodeArt/BusinessforUkraine/blob/main/mdsvexplugins/mdsvex-formatter-to-import.js

We define link to asset in formatter, after in processor we change it to "dynamic" import with viteimagetools, and store resulting asset links in metadata property. As a result we can use new generated field in layout.
It looks strange, because we define 'thumbImage' in formatter, and use 'thumbImageSrc' in layout. And that new variable is implicitly declared in transformer plugin, not it frontmatter. But it works.

@nosovk
Copy link

nosovk commented Oct 16, 2022

And for images inside md, relative to .md file there was another solution mentioned somewhere in discussions.
https://github.com/NodeArt/BusinessforUkraine/blob/main/mdsvexplugins/mdsvex-url-to-import.js
this will change all image src to srcset from imagetools.
Then you have to define some additional component like that: https://github.com/NodeArt/BusinessforUkraine/blob/main/src/lib/components/MdLayouts/img.svelte
to work with newly created scrset.

Probably it could be done better if move to tag, but that one also works.

@cass-e-design
Copy link
Author

I appreciate the response! I will look into a transform plugin as a workaround.

https://github.com/NodeArt/BusinessforUkraine/blob/main/mdsvexplugins/mdsvex-url-to-import.js

I can't find a repository at NodeArt/BusinessForUkraine. Is it possible this is a private repo?

@nosovk
Copy link

nosovk commented Oct 16, 2022

Oups, sorry, my fault.
Public repo with similar solution is here: https://github.com/MailCheck-co/mailcheck.site/tree/master/mdsvexplugins

@nosovk
Copy link

nosovk commented Oct 16, 2022

it just note updated to new +page schema, but transform implementation is the same.

@cass-e-design
Copy link
Author

cass-e-design commented Oct 25, 2022

@nosovk Thank you for the examples! I've got an adapted version of this transformer working for me very nicely.

With that said, I've just discovered that this workflow (import() markdown in +server, pass it to +page.svelte, render with {@html}) doesn't seem to load JS for components, so everything becomes readonly. With this in mind, it seems like this import() setup just doesn't do what I need so I'll have to try a workflow closer to mdsvex-template.

Edit:
With testing, I'm still able to use the frontmatter transformers alongside importing data with export let data, so I'm doing that. Saves me from having to run that transformer in +server. It's a bit odd, like I can't use [params] to get the post slug anymore so I need to scrape the URL, but the stuff I cared about is better so far. I can load arbitrary data I in +layout.server. which was the original point of this ticket.

I still think there's value to keeping content separate from your routes if possible, and I feel certain I'm still going to run into problems with keeping source media files under routes, but so far this is promising.

@cass-e-design
Copy link
Author

@nosovk I wanted to thank you again for the help, and I found a slight tweak for my use-case which I hoped might be helpful to you as well. I don't mean to come off as presumptous, sorry if you knew this already or this isn't useful.

In the current version of the transform plugin, at least in my setup, the code injected by the mdsvex-frontmatter-to-import only runs when I navigate to the blog posts themselves, so thumbnails for each post are only available when I'm on their route (/blog/post-slug), and there are no thumbnails available from my equivalent of getPublishedPosts(). So it's impossible to include thumbnails on a /blog page alongside post snippets.

I changed my version to instead inject into <script context="module"></script> instead of just <script></script>, and now the transformer-injected code runs when I use my equivalent of getPublishedPosts(), and I can use thumbnails on my /blog page.

Hope this might help, and thanks again either way!


As far as this issue is concerned, I think the answer seems to be "You can't inject data when importing markdown. To inject data, you have to use sveltekit's layout/server system, or transform plugins." My solution is working well enough on my end that I'm confident closing the issue. I feel it would be beneficial to consider including this pattern more explicitly in the documentation, but that's a separate issue. Thank you for your time!

@ABSanthosh
Copy link

For anyone who is trying to host their seveltkit site on github pages, you might've already resolved all the links in the app like this

<script>
  import { base } from "$app/paths";
</script>

<img src={`${base}/assets/img.png`} />

Just do the same thing in .md file(or any equivalent) but use context="module":

<script context="module">
  import { base } from "$app/paths";
</script>

<img src="{base}/assets/Images/Articles/01.webp"/>

Note: don't use $. This is not Js.


To author:

I know this is not a templating language, but it would be nice to directly pass the props from .render() like this

import { base } from "$app/paths";
const post = await import(
   `../../../data/articles/${params.type}/${params.slug}.md`
 );
 return {
   html: post.default.render({base: base}).html,
   meta: post.metadata,
 }; 

and in the markdown:

<img src="%base%/assets/Images/Articles/01.webp"/> 

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

No branches or pull requests

3 participants