mirror of
https://github.com/facebook/docusaurus.git
synced 2025-05-10 15:47:23 +02:00
feat(v2): introduce docs slug in front matter (#2771)
* feat: docs pathname frontmatter (for #2697) * feat: docs pathname frontmatter (for #2697) * chore: comment typo * feat: add slug frontmatter for docs * test: add tests for versioned sites slugs * docs: document slug feature * test: fix tests and snapshots about doc slug feature * docs(v2): doc slug wording * Update website/docs/docs.md Co-authored-by: Alexey Pyltsyn <lex61rus@gmail.com> Co-authored-by: Alexey Pyltsyn <lex61rus@gmail.com>
This commit is contained in:
parent
a32422caa2
commit
b8de9c6ded
10 changed files with 71 additions and 24 deletions
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
slug: hello/super
|
||||
---
|
||||
|
||||
Lorem
|
|
@ -1,6 +1,7 @@
|
|||
---
|
||||
id: baz
|
||||
title: baz
|
||||
slug: bazSlug.html
|
||||
---
|
||||
|
||||
## Images
|
||||
|
|
|
@ -1 +1,4 @@
|
|||
---
|
||||
slug: barSlug
|
||||
---
|
||||
This is `next` version of bar.
|
||||
|
|
|
@ -1 +1,4 @@
|
|||
---
|
||||
slug: barSlug
|
||||
---
|
||||
Bar `1.0.0` !
|
||||
|
|
|
@ -14,7 +14,7 @@ Object {
|
|||
"type": "link",
|
||||
},
|
||||
Object {
|
||||
"href": "/docs/foo/baz",
|
||||
"href": "/docs/foo/bazSlug.html",
|
||||
"label": "baz",
|
||||
"type": "link",
|
||||
},
|
||||
|
@ -85,7 +85,7 @@ Array [
|
|||
"modules": Object {
|
||||
"content": "@site/docs/foo/baz.md",
|
||||
},
|
||||
"path": "/docs/foo/baz",
|
||||
"path": "/docs/foo/bazSlug.html",
|
||||
},
|
||||
Object {
|
||||
"component": "@theme/DocItem",
|
||||
|
@ -159,7 +159,7 @@ Array [
|
|||
"modules": Object {
|
||||
"content": "@site/versioned_docs/version-1.0.0/foo/bar.md",
|
||||
},
|
||||
"path": "/docs/1.0.0/foo/bar",
|
||||
"path": "/docs/1.0.0/foo/barSlug",
|
||||
},
|
||||
Object {
|
||||
"component": "@theme/DocItem",
|
||||
|
@ -193,7 +193,7 @@ Array [
|
|||
"modules": Object {
|
||||
"content": "@site/docs/foo/bar.md",
|
||||
},
|
||||
"path": "/docs/next/foo/bar",
|
||||
"path": "/docs/next/foo/barSlug",
|
||||
},
|
||||
Object {
|
||||
"component": "@theme/DocItem",
|
||||
|
@ -241,7 +241,7 @@ Object {
|
|||
"collapsed": true,
|
||||
"items": Array [
|
||||
Object {
|
||||
"href": "/docs/next/foo/bar",
|
||||
"href": "/docs/next/foo/barSlug",
|
||||
"label": "bar",
|
||||
"type": "link",
|
||||
},
|
||||
|
@ -267,7 +267,7 @@ Object {
|
|||
"collapsed": true,
|
||||
"items": Array [
|
||||
Object {
|
||||
"href": "/docs/1.0.0/foo/bar",
|
||||
"href": "/docs/1.0.0/foo/barSlug",
|
||||
"label": "bar",
|
||||
"type": "link",
|
||||
},
|
||||
|
@ -330,7 +330,7 @@ Object {
|
|||
"collapsed": true,
|
||||
"items": Array [
|
||||
Object {
|
||||
"href": "/docs/1.0.0/foo/bar",
|
||||
"href": "/docs/1.0.0/foo/barSlug",
|
||||
"label": "bar",
|
||||
"type": "link",
|
||||
},
|
||||
|
@ -358,7 +358,7 @@ Object {
|
|||
],
|
||||
},
|
||||
"permalinkToSidebar": Object {
|
||||
"/docs/1.0.0/foo/bar": "version-1.0.0/docs",
|
||||
"/docs/1.0.0/foo/barSlug": "version-1.0.0/docs",
|
||||
"/docs/1.0.0/foo/baz": "version-1.0.0/docs",
|
||||
"/docs/1.0.0/hello": "version-1.0.0/docs",
|
||||
},
|
||||
|
@ -412,7 +412,7 @@ Object {
|
|||
"collapsed": true,
|
||||
"items": Array [
|
||||
Object {
|
||||
"href": "/docs/next/foo/bar",
|
||||
"href": "/docs/next/foo/barSlug",
|
||||
"label": "bar",
|
||||
"type": "link",
|
||||
},
|
||||
|
@ -435,7 +435,7 @@ Object {
|
|||
],
|
||||
},
|
||||
"permalinkToSidebar": Object {
|
||||
"/docs/next/foo/bar": "docs",
|
||||
"/docs/next/foo/barSlug": "docs",
|
||||
"/docs/next/hello": "docs",
|
||||
},
|
||||
"version": "next",
|
||||
|
|
|
@ -163,7 +163,7 @@ describe('simple website', () => {
|
|||
permalink: '/docs/hello',
|
||||
previous: {
|
||||
title: 'baz',
|
||||
permalink: '/docs/foo/baz',
|
||||
permalink: '/docs/foo/bazSlug.html',
|
||||
},
|
||||
sidebar: 'docs',
|
||||
source: path.join('@site', pluginPath, 'hello.md'),
|
||||
|
@ -175,7 +175,7 @@ describe('simple website', () => {
|
|||
id: 'foo/bar',
|
||||
next: {
|
||||
title: 'baz',
|
||||
permalink: '/docs/foo/baz',
|
||||
permalink: '/docs/foo/bazSlug.html',
|
||||
},
|
||||
permalink: '/docs/foo/bar',
|
||||
sidebar: 'docs',
|
||||
|
@ -300,7 +300,7 @@ describe('versioned website', () => {
|
|||
expect(docsMetadata['version-1.0.1/foo/baz']).toBeUndefined();
|
||||
expect(docsMetadata['foo/bar']).toEqual({
|
||||
id: 'foo/bar',
|
||||
permalink: '/docs/next/foo/bar',
|
||||
permalink: '/docs/next/foo/barSlug',
|
||||
source: path.join('@site', routeBasePath, 'foo', 'bar.md'),
|
||||
title: 'bar',
|
||||
description: 'This is next version of bar.',
|
||||
|
@ -321,7 +321,7 @@ describe('versioned website', () => {
|
|||
sidebar: 'docs',
|
||||
previous: {
|
||||
title: 'bar',
|
||||
permalink: '/docs/next/foo/bar',
|
||||
permalink: '/docs/next/foo/barSlug',
|
||||
},
|
||||
});
|
||||
expect(docsMetadata['version-1.0.1/hello']).toEqual({
|
||||
|
@ -363,7 +363,7 @@ describe('versioned website', () => {
|
|||
},
|
||||
previous: {
|
||||
title: 'bar',
|
||||
permalink: '/docs/1.0.0/foo/bar',
|
||||
permalink: '/docs/1.0.0/foo/barSlug',
|
||||
},
|
||||
});
|
||||
|
||||
|
|
|
@ -79,7 +79,7 @@ describe('simple site', () => {
|
|||
|
||||
expect(data).toEqual({
|
||||
id: 'foo/baz',
|
||||
permalink: '/docs/foo/baz',
|
||||
permalink: '/docs/foo/bazSlug.html',
|
||||
source: path.join('@site', routeBasePath, source),
|
||||
title: 'baz',
|
||||
editUrl:
|
||||
|
@ -172,7 +172,7 @@ describe('simple site', () => {
|
|||
});
|
||||
|
||||
test('docs with invalid id', async () => {
|
||||
const badSiteDir = path.join(fixtureDir, 'bad-site');
|
||||
const badSiteDir = path.join(fixtureDir, 'bad-id-site');
|
||||
const options = {
|
||||
routeBasePath,
|
||||
};
|
||||
|
@ -189,6 +189,25 @@ describe('simple site', () => {
|
|||
),
|
||||
);
|
||||
});
|
||||
|
||||
test('docs with invalid slug', async () => {
|
||||
const badSiteDir = path.join(fixtureDir, 'bad-slug-site');
|
||||
const options = {
|
||||
routeBasePath,
|
||||
};
|
||||
|
||||
return processMetadata({
|
||||
source: 'invalid-slug.md',
|
||||
refDir: path.join(badSiteDir, 'docs'),
|
||||
context,
|
||||
options,
|
||||
env,
|
||||
}).catch((e) =>
|
||||
expect(e).toMatchInlineSnapshot(
|
||||
`[Error: Document slug cannot include "/".]`,
|
||||
),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('versioned site', () => {
|
||||
|
@ -225,7 +244,7 @@ describe('versioned site', () => {
|
|||
|
||||
expect(dataA).toEqual({
|
||||
id: 'foo/bar',
|
||||
permalink: '/docs/next/foo/bar',
|
||||
permalink: '/docs/next/foo/barSlug',
|
||||
source: path.join('@site', routeBasePath, sourceA),
|
||||
title: 'bar',
|
||||
description: 'This is next version of bar.',
|
||||
|
@ -283,7 +302,7 @@ describe('versioned site', () => {
|
|||
|
||||
expect(dataA).toEqual({
|
||||
id: 'version-1.0.0/foo/bar',
|
||||
permalink: '/docs/1.0.0/foo/bar',
|
||||
permalink: '/docs/1.0.0/foo/barSlug',
|
||||
source: path.join('@site', path.relative(siteDir, versionedDir), sourceA),
|
||||
title: 'bar',
|
||||
description: 'Bar 1.0.0 !',
|
||||
|
|
|
@ -98,13 +98,18 @@ export default async function processMetadata({
|
|||
// Default base id is the file name.
|
||||
const baseID: string =
|
||||
frontMatter.id || path.basename(source, path.extname(source));
|
||||
|
||||
if (baseID.includes('/')) {
|
||||
throw new Error('Document id cannot include "/".');
|
||||
}
|
||||
|
||||
// Append subdirectory as part of id.
|
||||
const baseSlug: string = frontMatter.slug || baseID;
|
||||
if (baseSlug.includes('/')) {
|
||||
throw new Error('Document slug cannot include "/".');
|
||||
}
|
||||
|
||||
// Append subdirectory as part of id/slug.
|
||||
const id = dirName !== '.' ? `${dirName}/${baseID}` : baseID;
|
||||
const slug = dirName !== '.' ? `${dirName}/${baseSlug}` : baseSlug;
|
||||
|
||||
// Default title is the id.
|
||||
const title: string = frontMatter.title || baseID;
|
||||
|
@ -114,8 +119,9 @@ export default async function processMetadata({
|
|||
// The last portion of the url path. Eg: 'foo/bar', 'bar'.
|
||||
const routePath =
|
||||
version && version !== 'next'
|
||||
? id.replace(new RegExp(`^version-${version}/`), '')
|
||||
: id;
|
||||
? slug.replace(new RegExp(`^version-${version}/`), '')
|
||||
: slug;
|
||||
|
||||
const permalink = normalizeUrl([
|
||||
baseUrl,
|
||||
routeBasePath,
|
||||
|
|
|
@ -20,7 +20,7 @@ website # Root directory of your site
|
|||
└── hello.md
|
||||
```
|
||||
|
||||
However, the last part of the `id` can be defined by user in the front matter. For example, if `guide/hello.md`'s content is defined as below, its final `id` is `guide/part1`.
|
||||
However, the **last part** of the `id` can be defined by user in the front matter. For example, if `guide/hello.md`'s content is defined as below, its final `id` is `guide/part1`.
|
||||
|
||||
```yml
|
||||
---
|
||||
|
@ -29,6 +29,16 @@ id: part1
|
|||
Lorem ipsum
|
||||
```
|
||||
|
||||
If you want more control over the last part of the document URL, it is possible to add a `slug` (defaults to the `id`).
|
||||
|
||||
```yml
|
||||
---
|
||||
id: part1
|
||||
slug: part1.html
|
||||
---
|
||||
Lorem ipsum
|
||||
```
|
||||
|
||||
## Home page docs
|
||||
|
||||
Using the `homePageId` property, you can create a home page of your docs. To do this, you can create a new document, especially for this purpose with the id as `_index`, or you could specify an existing document id.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue