Open rchrdnsh opened 4 years ago
I would like to create some guides, templates, tutorials on this in the future to go through a few ways of achieving it. I doubt I'll get this done anytime soon but I would like to get a half decent blog starter figured out in the short term as a reference. I'll see if I can dedicate some time to this soon.
A reference would be awesome, thank you :-) Maybe add it to the MDsveX starter! XD
I was using MDsveX precisely to make my blog, where each post is a .svx file.
Maybe it can helps you :smiley_cat:: https://github.com/shiryel/shiryel_blog_sapper
Hi @shiryel :-) It's a bit hard for me to follow your code...where do you grab the svx files and parse them into svelte files in your codebase?
Hi @pngwn...I have a semi working version of basic markdown support using the following code:
first, in index.json.js
:
import fs from 'fs'
import path from 'path'
import marked from 'marked'
import grayMatter from 'gray-matter'
function getAllPosts(filesPath) {
const data = fs.readdirSync(filesPath).map((fileName) => {
const post = fs.readFileSync(path.resolve(filesPath, fileName), "utf-8");
// Parse Front matter from string
const { data, content } = grayMatter(post);
// Turns markdown into html
const renderer = new marked.Renderer();
const html = marked(content, { renderer });
// Builds data
return {
...data,
html
};
});
return data;
}
export function get(req, res) {
const posts = getAllPosts("src/posts");
res.writeHead(200, {
"Content-Type": "application/json",
});
res.end(JSON.stringify(posts));
}
...and in [slug].json.js
:
import fs from "fs";
import path from "path";
import marked from "marked";
import grayMatter from "gray-matter";
export function get(req, res) {
// the `slug` parameter is available because
// this file is called [slug].json.js
const { slug } = req.params;
res.writeHead(200, {
"Content-Type": "application/json",
});
// Reading correct file
const post = fs.readFileSync(
path.resolve("src/posts", `${slug}.md`),
"utf-8"
);
// Parse front matter
const { data, content } = grayMatter(post);
// Render html from string
const renderer = new marked.Renderer();
const html = marked(content, { renderer });
res.end(
JSON.stringify({
...data,
html
})
);
}
...which are both used in the index and slug svelte files respectively:
first, in index.svelte
:
<script context="module">
export async function preload({ params, query }) {
const res = await this.fetch(`blog.json`);
const posts = await res.json();
return { posts };
console.log(posts);
}
</script>
<script>
export let posts;
</script>
<style>
ul {
margin: 0 0 1em 0;
line-height: 1.5;
}
</style>
<svelte:head>
<title>Blog</title>
</svelte:head>
<div>
<h1>Home Page of Posts and stuff :-)</h1>
<ul>
{#each posts as post}
<li>
<a rel="prefetch" href="blog/{post.slug}">{post.title}</a>
</li>
{/each}
</ul>
</div>
and in [slug].svelte
:
<script context="module">
export async function preload({ params, query }) {
const res = await this.fetch(`blog/${params.slug}.json`);
const data = await res.json();
if (res.status === 200) {
return { post: data };
} else {
this.error(res.status, data.message);
}
}
</script>
<script>
export let post;
</script>
<styles> ...styles go here... </styles>
<svelte:head>
<title>{post.title}</title>
</svelte:head>
<div class="content">
<h1 class='title'>{post.title}</h1>
{@html post.html}
</div>
...I got all this from Level up Tuts, btw, not by myself :-(
Anyway, my question is would the process of using .svx
files instead .md
files be similar to this approach, or would it require a completely different approach? Off the top of my head I would imagine that gray-matter
and marked
probably aren't needed, but one would still need to traverse the file system, no? Does JSON need to be generated for .svx
files? Or does MDsveX
handle that already? Would it be simpler? More complex?
Apologies, for all the questions, I would just love to figure this all out XD
@rchrdnsh:
Anyway, my question is would the process of using
.svx
files instead.md
files be similar to this approach, or would it require a completely different approach? Off the top of my head I would imagine thatgray-matter
andmarked
probably aren't needed, but one would still need to traverse the file system, no? Does JSON need to be generated for.svx
files? Or doesMDsveX
handle that already? Would it be simpler? More complex?
If you can't wait for pngwn, some of your questions are answered already in this thread, starting with Larry's comment from May 31.
@rchrdnsh
I recommend you using a sapper template (you can find it in the docs on integrations), they will setup all the basics for what you want to do, like using the --ext '.svelte .svx'
on package.json
. And they will work like a .svelte on sapper, you just need to follow the sapper guides on how to make your blog :smile_cat:
PS: Sorry for the late response, a game jam wiped my free time xD
@rchrdnsh I also struggled a long time with getting .svx
up and running, but I managed by taking a look at @shiryel implementation (thanks a lot!!) and now it works fine. Frontmatter gets used accordingly, images in the blog posts are lazy loaded, code snippets highlighted with prism.
You can take a look here for reference: https://github.com/mhatvan/markushatvan.com
hmmmm...so i've been trying to go through everybody's code and I noticed that content is living inside of the routes folder, which won't work for me, unfortunately.
Firstly, I want to eventually use some sort of cms in the future, like netlify CMS, and it expects content to live in a certain place in the file structure, outside of the routes folder. So now I am trying to figure out how to use mdsvex in this capacity, where the content lives somewhere OUTSIDE of the routes folder and also each post is not named using the name of the article, but rather its parent folder is the name of the article. All the posts themselves are labeled index.md
and exist in a folder with the post name, like this:
src/content/articles/post-one/index.md
...the reason for this is that each post has associated assets, like images and audio and video clips, sometimes many of them per article, and I don't want to have to chase these down over the entire known universe. I was able to achieve this all in gatsby using their gatsby-node
file, so I'm trying to figure out how to essentially recreate that particular workflow in svelte/sapper/sveltekit
any thoughts as to how this might be achieved would be very welcome :-) Extremely new to node, so learning as I go here...
While I'm glad I found this, I'm curious about something.
In the example you give, @mhatvan, there's the use of marked
here, but from what I understand, mdsvex's job is to create valid Svelte code, and then that's handled by the svelte compiler. In the case of Sapper, you could run npm export
and you'd get static HTML, Javascript, and CSS (if I have that correctly).
So isn't the use of marked
redundant?
All we need to do is make use of mdsvex's compile
function, yes? Then make sure the created corresponding [slug].svelte
files are passed along to the svelte compiler? I imagine with rollup this isn't quite hard with the svelte-preprocessor
plugin, but I'm not entirely sure.
Again, I don't exactly know for sure, I'm just asking.
A lot of time has passed since I set this up, so I don't have a good answer to your question. I assume that it is necessary to run the code through marked to be able to identify code snippets which can be highlighted with prismjs.
hey, I've been chasing a problem for a few days now.
I'm trying to separate my markdowns from the files in /routes
and load them from a separate folder on the disk. Everyhing I tried failed, I wasn't able to find any approach that allows to dynamically load a markdown (with fs.readFile
) that contains a svelte component.
I tried to use mdsvex programatically (mdsvex.compile()
), but I don't know how to handle it next.
I tried:
(based on an example a nice person in the svelte discord put together)
import { compile as mdsvexCompile } from "mdsvex";
const preprocessed = await mdsvexCompile(testSource, mdsvexConfig);
const compiled = svelte.compile(preprocessed.code);
but this just gives back JS which I couldn't turn back into HTML, I even tried to use eval(compiled.js.code);
(which felt dirty but after many tries worked, but failed to actually load the referenced svelte component as JS code).
/routes
I feel this almost worked - it fails with:
Cannot find module 'svelte/internal' from '<my-project>/src/routes/p'
which makes me think it's looking for svelte in the symlinked folder and not in the folder where sveltekit is installed.
Any advice? I don't want to put markdowns in the same folder where I put code and .svelte
files.
@Madd0g
What is in compiled.js.code
? Just a bunch of jumbled JS code?
@alecStewart1 - yes
I forgot to mention that these are the parameters I'm compiling with (it's in the linked gist)
const compiled = svelteCompile(
preprocessed.code,
{
generate: 'ssr',
format: "cjs",
hydratable: false,
}
);
so basically I'm getting an SSR version of the compiled component with require statements (because of the format: "cjs"
)
Hi MDsveX! XD
I recently cloned the mdsvex starter and it's quite nice :-) However, I noticed that the blog portion of the MDSveX starter is still a single file of js objects, rather than a folder of separate
.svx
files for each post, so I was wondering how one might go about altering the starter to include an MDSveX powered.svx
blog :-)Would it be similar to some of the sapper/markdown tutorials floating around or would it require something completely different in regards to parsing the
.svx
files and spitting them out as valid svelte/html?Would love to see this added/implemented/instructed in the near future XD
That's exactly what I have done here - https://github.com/sharu725/hagura-sveltekit. It is live here - https://hagura-sveltekit.netlify.app/
The main problem was getting all the posts in an index file(homepage)
Vite has a nice utility called import.meta.glob()
which can be used like this
const posts = import.meta.glob("./blog/*.{md,svx}")
This will fetch all the frontmatter in .md
and .svx
files.
Here is how I have done it - https://github.com/sharu725/hagura-sveltekit/blob/main/src/routes/index.svelte
This is great @sharu725 I'm doing something similar with globEager
I'll use your example for getting the path because at the moment I'm using a frontmatter slug.
This may be considered off topic so I'll open another issue for it but I would really like to be able to get the post headings so I can use them in a ToC, have you had explored doing that?
This is great @sharu725 I'm doing something similar with
globEager
I'll use your example for getting the path because at the moment I'm using a frontmatter slug.This may be considered off topic so I'll open another issue for it but I would really like to be able to get the post headings so I can use them in a ToC, have you had explored doing that?
I'm trying that. Apparently I'm facing an issue in Sveltekit. Let me know if you've found some solution to get headers.
<script context="module">
const modules = import.meta.globEager("./*.md");
export const body = Object.entries(modules).map(([filepath, module]) => {
const { metadata } = module;
const { html } = module.default.render();
return {
html,
...metadata,
};
});
export const load = async () => {
const posts = await Promise.all(body);
return {
props: {
posts,
},
};
};
</script>
In the above code
const { html } = module.default.render()
runs fine on server. But not on the browser.
It throws a 500 error
module.default.render is not a function
I'm with same issue here, module.default.render is not a function
As for a guide/template/source of inspiration, there's also https://github.com/mvasigh/sveltekit-mdsvex-blog by @mvasigh which looks very well done.
This is great @sharu725 I'm doing something similar with
globEager
I'll use your example for getting the path because at the moment I'm using a frontmatter slug. This may be considered off topic so I'll open another issue for it but I would really like to be able to get the post headings so I can use them in a ToC, have you had explored doing that?I'm trying that. Apparently I'm facing an issue in Sveltekit. Let me know if you've found some solution to get headers.
<script context="module"> const modules = import.meta.globEager("./*.md"); export const body = Object.entries(modules).map(([filepath, module]) => { const { metadata } = module; const { html } = module.default.render(); return { html, ...metadata, }; }); export const load = async () => { const posts = await Promise.all(body); return { props: { posts, }, }; }; </script>
In the above code
const { html } = module.default.render()
runs fine on server. But not on the browser.
It throws a 500 error
module.default.render is not a function
So, just for reference and anyone else coming across this discussion I've been informed by @babichjacob that using globEager
in a .svelte
file should be avoided as it loads every single file from globEager
into memory of the svelte component.
So glob
, yes with the specified file path but globEager
no.
I'm still yet to fin an effective way to do this with the filing structure I use for my .md
files.
Hi MDsveX! XD
I recently cloned the mdsvex starter and it's quite nice :-) However, I noticed that the blog portion of the MDSveX starter is still a single file of js objects, rather than a folder of separate
.svx
files for each post, so I was wondering how one might go about altering the starter to include an MDSveX powered.svx
blog :-)Would it be similar to some of the sapper/markdown tutorials floating around or would it require something completely different in regards to parsing the
.svx
files and spitting them out as valid svelte/html?Would love to see this added/implemented/instructed in the near future XD