pngwn / MDsveX

A markdown preprocessor for Svelte.
https://mdsvex.pngwn.io
MIT License
2.27k stars 96 forks source link

Layouts Break MDsveX+TypeScript #485

Open joshpoll opened 1 year ago

joshpoll commented 1 year ago

Hello! Thanks so much for creating this project. It's really great.

I'm aware that MDsveX doesn't officially support TS. e.g. https://github.com/pngwn/MDsveX/issues/277#issuecomment-1013644865

However, I can use MDsveX and TypeScript just fine as long as I don't use a layout.

Minimal repro

test-import.svx

<script lang="ts">
  export let name: string;
</script>

<div>
  <h1>{name}</h1>
</div>

App.svx

<script lang="ts">
  import TestImport from "./test-import.svx";
</script>

<TestImport name="Bob" />

This code works fine if I don't specify the layout field in the mdsvex preprocessor config. But it breaks if I do.

Given that the markdown parsing appears to work fine in my MDsveX projects without layouts, and because the layout behavior seems (to me at least) to be "just" injecting some props and placing a child svelte component into a slot, it seems like this problem might be fixable without having to rewrite the project in a major way.

This is one of the last major hurdles for my ability to use MDsveX in my svelte+TS project, and it would be really awesome to have it!

I'm happy to contribute to fixing the code in some way, but I'm having trouble building MDsveX locally.

Thanks!

joshpoll commented 1 year ago

For those looking for a workaround, you can write a custom Layout component that uses the frontmatter metadata e.g. put this in your script:

import App, { metadata } from './App.svx';

You can still use a layout field! It just requires a bit more boilerplate.

jokull commented 1 year ago

Transitioned my blog to SvelteKit 1.0+ and had to ditch layout because of this. I actually kind of prefer using +page.ts to load things manually. It's less magic and you get total control over routing and rendering:

Here's the +page.ts for a route with /[slug]

import { z } from 'zod';

const postSchema = z.object({
    title: z.string(),
    date: z.coerce.date(),
    slug: z.string(),
    image: z.string().optional(),
    locale: z.string().optional(),
    isDraft: z.coerce.boolean().default(false)
});

export async function load({ params }) {
    const { slug } = params;

    const post = await import(/* @vite-ignore */ `../../_posts/${slug}/post.md`);

    const { default: page, metadata } = post;

    if (!page) {
        return {
            status: 404
        };
    }

    const result = postSchema.safeParse({ ...(metadata ?? {}), slug });

    if (!result.success) {
        return { status: 404 };
    }

    return { page, metadata: result.data };
}

And here's the +page.svelte

<script lang="ts">
    import type { PageData } from './$types';
    export let data: PageData;
    let { date, title, image, locale } = data.metadata!;
</script>

<svelte:head>
    <title>{title} - Jökull Sólberg</title>
</svelte:head>

<div>
    <h1>{title}</h1>
    <svelte:component this={data.page} />
</div>