Issue: Slug for root index.md file generates wrong preview URL #634

Closed
opened 2026-10-05 02:57:39 +02:00 by adam · 10 comments
Owner

Hi Elio,

looks like the issue is still there. I have installed latest Front Matter CMS v10.1.0.

// frontmatter.json
{
  "$schema": "https://frontmatter.codes/frontmatter.schema.json",
  "frontMatter.framework.id": "astro",
  "frontMatter.preview.host": "http://localhost:4321",
  "frontMatter.content.publicFolder": {
    "path": "src/assets",
    "relative": true
  },
  "frontMatter.content.pageFolders": [{
      "title": "Docs",
      "path": "[[workspace]]/src/content/docs/",
      "previewPath": "{{pathToken.relPath}}"
    }
  ]
}
$ tree content
src
└── content
    └── docs
        └── index.md // http://localhost:4321/docs -> expected http://localhost:4321/
        └── test.md // http://localhost:4321/test
            └── nested
                └── index.md // http://localhost:4321/nested // This works

If I can help out with some additional context, feel free to ask.
Have a nice day 👋

Originally posted by @theinfinit in https://github.com/estruyf/vscode-front-matter/issues/603#issuecomment-2117437985

Hi Elio, looks like the issue is still there. I have installed latest Front Matter CMS `v10.1.0`. ```jsonc // frontmatter.json { "$schema": "https://frontmatter.codes/frontmatter.schema.json", "frontMatter.framework.id": "astro", "frontMatter.preview.host": "http://localhost:4321", "frontMatter.content.publicFolder": { "path": "src/assets", "relative": true }, "frontMatter.content.pageFolders": [{ "title": "Docs", "path": "[[workspace]]/src/content/docs/", "previewPath": "{{pathToken.relPath}}" } ] } ``` ```js $ tree content src └── content └── docs └── index.md // http://localhost:4321/docs -> expected http://localhost:4321/ └── test.md // http://localhost:4321/test └── nested └── index.md // http://localhost:4321/nested // This works ``` If I can help out with some additional context, feel free to ask. Have a nice day 👋 _Originally posted by @theinfinit in https://github.com/estruyf/vscode-front-matter/issues/603#issuecomment-2117437985_ <!-- github-sync-id:2302856807 -->
adam closed this issue 2026-10-05 02:57:39 +02:00
Author
Owner

@theinfinit I included a fix in the latest beta, would you be able to verify it?

@theinfinit I included a fix in the latest beta, would you be able to verify it? <!-- github-comment-id:2117717352 -->
Author
Owner

Oh, that's great, thank you. Works like a charm! Paths, both in the root and nested, are correct.

In the root it is displayed with a dot http://localhost:4321/., but works just fine.

Cheers 👋

Oh, that's great, thank you. Works like a charm! Paths, both in the root and nested, are correct. In the root it is displayed with a dot `http://localhost:4321/.`, but works just fine. Cheers 👋 <!-- github-comment-id:2117859600 -->
Author
Owner

In the root it is displayed with a dot http://localhost:4321/., but works just fine.

@theinfinit, what do you mean with the root? The src/content/docs/index.md file?

> In the root it is displayed with a dot [http://localhost:4321/.](http://localhost:4321/), but works just fine. @theinfinit, what do you mean with the root? The `src/content/docs/index.md` file? <!-- github-comment-id:2118767126 -->
Author
Owner

Yes exactly. Sorry, I wasn't clear enough. The docs in src/content/docs/ is just Astro' content collection and src/content/docs/index.md is the "root" of the site.

I did more testing on the matter.

Case 1

Configuration without trailing slash in the previewPath

"frontMatter.content.pageFolders": [
  {
    "title": "Root",
    "path": "[[workspace]]/src/content/docs/",
    "previewPath": "{{pathToken.relPath}}",
    "excludeSubdir": true,
    "defaultLocale": "en",
  },
]

Resulting preview paths (everything is working here):

$ tree content
src
└── content
    └── docs
        └── index.md // http://localhost:4321/.
        └── test.md // http://localhost:4321/test
        └── nested
            └── index.md // http://localhost:4321/nested

Case 2

Configuration with trailing slash in the previewPath

"frontMatter.content.pageFolders": [
  {
    "title": "Root",
    "path": "[[workspace]]/src/content/docs/",
    "previewPath": "{{pathToken.relPath}}/", // <- Added the trailing slash at the end
    "excludeSubdir": true,
    "defaultLocale": "en",
  },
]

Resulting preview paths:

$ tree content
src
└── content
    └── docs
        └── index.md // http://localhost:4321/docs -> expected http://localhost:4321/
        └── test.md // http://localhost:4321/test -> expected http://localhost:4321/test/
        └── nested
            └── index.md // http://localhost:4321/nested/nested -> expected http://localhost:4321/nested/

Case 3

The behavior without {{pathToken.relPath}} placeholder is the same:

"frontMatter.content.pageFolders": [
  {
    "title": "Blog",
    "path": "[[workspace]]/src/content/docs/blog/",
    "previewPath": "/blog",
  }
]
// Working as expected
$ tree content
src
└── content
    └── docs
        └── blog
            └── index.md // http://localhost:4321/blog
            └── my-post.md // http://localhost:4321/blog/my-post

And with trailing slash:

"frontMatter.content.pageFolders": [
  {
    "title": "Blog",
    "path": "[[workspace]]/src/content/docs/blog/",
    "previewPath": "/blog/", // <- Added the trailing slash at the end
  }
]
$ tree content
src
└── content
    └── docs
        └── blog
            └── index.md // http://localhost:4321/blog/blog -> expected http://localhost:4321/blog/
            └── my-post.md // http://localhost:4321/blog/my-post -> expected http://localhost:4321/blog/my-post/

Why I tried to add trailing slash?

In one of my Astro projects I have trailingSlash configuration set to 'always' (the lack of trailing slash leads to the 404 during development).

To take that into account, I have added the trailing slash to the previewPath of the frontMatter.content.pageFolders configuration. But the slash seems to be stripped away.


Hope it helps 👋

Yes exactly. Sorry, I wasn't clear enough. The `docs` in `src/content/docs/` is just [Astro' content collection](https://docs.astro.build/en/guides/content-collections/) and `src/content/docs/index.md` is the "root" of the site. I did more testing on the matter. ## Case 1 **Configuration without trailing slash in the `previewPath`** ```jsonc "frontMatter.content.pageFolders": [ { "title": "Root", "path": "[[workspace]]/src/content/docs/", "previewPath": "{{pathToken.relPath}}", "excludeSubdir": true, "defaultLocale": "en", }, ] ``` Resulting preview paths (everything is working here): ```js $ tree content src └── content └── docs └── index.md // http://localhost:4321/. └── test.md // http://localhost:4321/test └── nested └── index.md // http://localhost:4321/nested ``` ## Case 2 **Configuration _with_ trailing slash in the `previewPath`** ```jsonc "frontMatter.content.pageFolders": [ { "title": "Root", "path": "[[workspace]]/src/content/docs/", "previewPath": "{{pathToken.relPath}}/", // <- Added the trailing slash at the end "excludeSubdir": true, "defaultLocale": "en", }, ] ``` Resulting preview paths: ```js $ tree content src └── content └── docs └── index.md // http://localhost:4321/docs -> expected http://localhost:4321/ └── test.md // http://localhost:4321/test -> expected http://localhost:4321/test/ └── nested └── index.md // http://localhost:4321/nested/nested -> expected http://localhost:4321/nested/ ``` --- ## Case 3 The behavior without `{{pathToken.relPath}}` placeholder is the same: ```json "frontMatter.content.pageFolders": [ { "title": "Blog", "path": "[[workspace]]/src/content/docs/blog/", "previewPath": "/blog", } ] ``` ```js // Working as expected $ tree content src └── content └── docs └── blog └── index.md // http://localhost:4321/blog └── my-post.md // http://localhost:4321/blog/my-post ``` And with trailing slash: ```jsonc "frontMatter.content.pageFolders": [ { "title": "Blog", "path": "[[workspace]]/src/content/docs/blog/", "previewPath": "/blog/", // <- Added the trailing slash at the end } ] ``` ```js $ tree content src └── content └── docs └── blog └── index.md // http://localhost:4321/blog/blog -> expected http://localhost:4321/blog/ └── my-post.md // http://localhost:4321/blog/my-post -> expected http://localhost:4321/blog/my-post/ ``` --- **Why I tried to add trailing slash?** In one of my Astro projects I have [`trailingSlash` configuration](https://docs.astro.build/en/reference/configuration-reference/#trailingslash) set to `'always'` (the lack of trailing slash leads to the 404 during development). To take that into account, I have added the trailing slash to the `previewPath` of the `frontMatter.content.pageFolders` configuration. But the slash seems to be stripped away. --- Hope it helps 👋 <!-- github-comment-id:2118805289 -->
Author
Owner

@theinfinit, the previewPath property comes before the slug. That is why it does not matter if you add a slash or not after {{pathToken.relPath}}.

You can add the "frontMatter.taxonomy.slugSuffix": "/", setting to your config to add a trailing slash at the end.

Thinking of it, it would be a good option to enhance the settings to have a previewTrailingSlash option.

@theinfinit, the `previewPath` property comes before the `slug.` That is why it does not matter if you add a slash or not after `{{pathToken.relPath}}`. You can add the `"frontMatter.taxonomy.slugSuffix": "/",` setting to your config to add a trailing slash at the end. Thinking of it, it would be a good option to enhance the settings to have a `previewTrailingSlash` option. <!-- github-comment-id:2122129631 -->
Author
Owner

Ah, thank you for explanation. After adding the "frontMatter.taxonomy.slugSuffix": "/", setting, everything works just fine. Including the the "Case 3" from my previous comment (tesed on updated beta version v10.2.9210096. Without this setting, index.md from "Case 3" is stil duplicated.

Mentioning "frontMatter.taxonomy.slugSuffix": "/", setting in the "Site Preview" documentation, could probably help with discoverability.


@theinfinit, the previewPath property comes before the slug. That is why it does not matter if you add a slash or not after {{pathToken.relPath}}.

But I somehow expected that {{pathToken.relPath}} includes the slug 😅 Anyways, thank you for pointing me in the right direction.


Thinking of it, it would be a good option to enhance the settings to have a previewTrailingSlash option.

Yes, that might be good idea. Especially for cases when certain static site generators doesn't support slug with slashes in the frontmatter.

Or, as an alternative idea, something like this might be quite intuitive too: "previewPath": "{{pathToken.relPath}}/{{slug}}/". And it might serve as a good groundwork for i18n improvements. Something like this would be really helpful: "previewPath": "{{localePath}}/{{pathToken.relPath}}".

Currently, I found a workaround like this, to define nested pageFolders:

"frontMatter.content.i18n": [
  { "title": "English", "locale": "en", "path": "." },
  { "title": "Deutsch", "locale": "de", "path": "de" },
  { "title": "Español", "locale": "es", "path": "es" },
],
"frontMatter.content.pageFolders": [
  {
    "title": "Root",
    "path": "[[workspace]]/src/content/docs/",
    "previewPath": "{{pathToken.relPath}}/",
    "excludeSubdir": true,
    "defaultLocale": "en",
  },
  {
    "title": "Blog",
    "path": "[[workspace]]/src/content/docs/blog/",
    "previewPath": "/blog/",
    "defaultLocale": "en",
    "locales": [
      { "title": "English",              "locale": "en" },
      { "title": "Deutsch",              "locale": "de",    "path": "../../de/blog/guides/" },
      { "title": "Español",              "locale": "es",    "path": "../../es/blog/guides/" },
    ]
  },
],

Or maybe, I'm doing it wrong? I haven't found case like this in the documentation.

Ah, thank you for explanation. After adding the `"frontMatter.taxonomy.slugSuffix": "/",` setting, everything works just fine. Including the the "Case 3" from my previous comment (tesed on updated beta version `v10.2.9210096`. Without this setting, index.md from "Case 3" is stil duplicated. Mentioning `"frontMatter.taxonomy.slugSuffix": "/",` setting [in the "Site Preview" documentation](https://frontmatter.codes/docs/site-preview#configuration), could probably help with discoverability. --- > @theinfinit, the previewPath property comes before the slug. That is why it does not matter if you add a slash or not after {{pathToken.relPath}}. But I somehow expected that `{{pathToken.relPath}}` includes the `slug` 😅 Anyways, thank you for pointing me in the right direction. --- > Thinking of it, it would be a good option to enhance the settings to have a `previewTrailingSlash` option. Yes, that might be good idea. Especially for cases when certain static site generators doesn't support `slug` with slashes in the frontmatter. Or, as an alternative idea, something like this might be quite intuitive too: `"previewPath": "{{pathToken.relPath}}/{{slug}}/"`. And it might serve as a good groundwork for i18n improvements. Something like this would be really helpful: `"previewPath": "{{localePath}}/{{pathToken.relPath}}"`. Currently, I found a workaround like this, to define nested `pageFolders`: ```json "frontMatter.content.i18n": [ { "title": "English", "locale": "en", "path": "." }, { "title": "Deutsch", "locale": "de", "path": "de" }, { "title": "Español", "locale": "es", "path": "es" }, ], "frontMatter.content.pageFolders": [ { "title": "Root", "path": "[[workspace]]/src/content/docs/", "previewPath": "{{pathToken.relPath}}/", "excludeSubdir": true, "defaultLocale": "en", }, { "title": "Blog", "path": "[[workspace]]/src/content/docs/blog/", "previewPath": "/blog/", "defaultLocale": "en", "locales": [ { "title": "English", "locale": "en" }, { "title": "Deutsch", "locale": "de", "path": "../../de/blog/guides/" }, { "title": "Español", "locale": "es", "path": "../../es/blog/guides/" }, ] }, ], ``` Or maybe, I'm doing it wrong? I haven't found case like this in the documentation. <!-- github-comment-id:2127675829 -->
Author
Owner

Mentioning "frontMatter.taxonomy.slugSuffix": "/", setting in the "Site Preview" documentation, could probably help with discoverability.

Good feedback.

Or, as an alternative idea, something like this might be quite intuitive too: "previewPath": "{{pathToken.relPath}}/{{slug}}/"

The preview path and the slug are intentionally separated, as the slug can depend on other properties and can be defined with the frontMatter.taxonomy.slugTemplate setting or slugTemplate property on the content type.

And it might serve as a good groundwork for i18n improvements. Something like this would be beneficial: "previewPath": "{{localePath}}/{{pathToken.relPath}}".

{{locale}} should become its own placeholder which can be used in the preview path as well. Good feedback. I'll create a new issue for it to track it.

> Mentioning "frontMatter.taxonomy.slugSuffix": "/", setting [in the "Site Preview" documentation](https://frontmatter.codes/docs/site-preview#configuration), could probably help with discoverability. Good feedback. > Or, as an alternative idea, something like this might be quite intuitive too: "previewPath": "{{pathToken.relPath}}/{{slug}}/" The preview path and the slug are intentionally separated, as the slug can depend on other properties and can be defined with the `frontMatter.taxonomy.slugTemplate` setting or `slugTemplate` property on the content type. > And it might serve as a good groundwork for i18n improvements. Something like this would be beneficial: "previewPath": "{{localePath}}/{{pathToken.relPath}}". `{{locale}}` should become its own placeholder which can be used in the preview path as well. Good feedback. I'll create a new issue for it to track it. <!-- github-comment-id:2127741147 -->
Author
Owner

The preview path and the slug are intentionally separated, as the slug can depend on other properties and can be defined with the frontMatter.taxonomy.slugTemplate setting or slugTemplate property on the content type.

Ah, I see. Then, all I can ask for is the improvement of the "Site Preview" documentation. Pointing to the slug related configuration for the "trailing slash" case, and the "Slug" guide in general, should avoid the confusion.

{{locale}} should become its own placeholder which can be used in the preview path as well. Good feedback. I'll create a new issue for it to track it.

That's fantastic! I'm happy to hear that 😆

> The preview path and the slug are intentionally separated, as the slug can depend on other properties and can be defined with the `frontMatter.taxonomy.slugTemplate` setting or `slugTemplate` property on the content type. Ah, I see. Then, all I can ask for is the improvement of the ["Site Preview" documentation](https://frontmatter.codes/docs/site-preview#configuration). Pointing to the slug related configuration for the "trailing slash" case, and the ["Slug" guide](https://frontmatter.codes/docs/content-creation/slug) in general, should avoid the confusion. > `{{locale}}` should become its own placeholder which can be used in the preview path as well. Good feedback. I'll create a new issue for it to track it. That's fantastic! I'm happy to hear that 😆 <!-- github-comment-id:2127807284 -->
Author
Owner

I've been testing it a bit more, and adding the trailingslash setting/option will make it easier than using the frontMatter.taxonomy.slugTemplate.

In the upcoming beta, you can use the following:

Globally

"frontMatter.preview.trailingSlash": true

Page folder level

"frontMatter.content.pageFolders": [
  {
    "title": "Root",
    "path": "[[workspace]]/src/content/docs/blog",
    "previewPath": "/blog",
    "trailingSlash": true
  }
]

Content type level

"frontMatter.taxonomy.contentTypes": [
  {
    "name": "simple",
    "pageBundle": false,
    "previewPath": null,
    "trailingSlash": true,
    "fields": []
  }
]

To document

  • Add global documentation -> https://frontmatter.codes/docs/settings/overview#frontmatter.preview.trailingslash
  • Add page folder property
  • Add content type property
I've been testing it a bit more, and adding the `trailingslash` setting/option will make it easier than using the `frontMatter.taxonomy.slugTemplate`. In the upcoming beta, you can use the following: ### Globally ```json "frontMatter.preview.trailingSlash": true ``` ### Page folder level ```json "frontMatter.content.pageFolders": [ { "title": "Root", "path": "[[workspace]]/src/content/docs/blog", "previewPath": "/blog", "trailingSlash": true } ] ``` ### Content type level ```json "frontMatter.taxonomy.contentTypes": [ { "name": "simple", "pageBundle": false, "previewPath": null, "trailingSlash": true, "fields": [] } ] ``` ## To document - [x] Add global documentation -> `https://frontmatter.codes/docs/settings/overview#frontmatter.preview.trailingslash` - [x] Add page folder property - [x] Add content type property <!-- github-comment-id:2127884755 -->
Author
Owner

I just tested the latest beta v10.2.9236459, and you did a really good job. Everything works as expected in my environment on all 3 levels (globally, page folder and content type level).

For the record,

  • I performed all tests with previewPath config containing trailing slash,
  • for both, root and nested pageFolders,
  • and for, index.md and named-pages.md
"frontMatter.content.pageFolders": [
  {
    "title": "Root",
    "path": "[[workspace]]/src/content/docs/",
    "previewPath": "{{pathToken.relPath}}/",
    "trailingSlash": true
  },
],

For me, the issue is resolved. Thank you!

I just tested the latest beta `v10.2.9236459`, and you did a really good job. Everything works as expected in my environment on all 3 levels (globally, page folder and content type level). For the record, - I performed all tests with `previewPath` config containing trailing slash, - for both, root and nested `pageFolders`, - and for, `index.md` and `named-pages.md` ```json "frontMatter.content.pageFolders": [ { "title": "Root", "path": "[[workspace]]/src/content/docs/", "previewPath": "{{pathToken.relPath}}/", "trailingSlash": true }, ], ``` For me, the issue is resolved. Thank you! <!-- github-comment-id:2142028597 -->
Sign in to join this conversation.
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: adam/vscode-front-matter#634