mirror of
https://github.com/facebook/docusaurus.git
synced 2025-05-12 16:47:26 +02:00
feat(v2): docs version configuration: lastVersion, version.{path,label} (#3357)
* add new docs versioning options * Add some tests for new versioning options * Add some docs for version configurations * try to fix broken link detection after /docs/ root paths have been removed on deploy previews * improve dev/deploypreview versioning configurations * disable custom current version path, as it produces broken links * readVersionDocs should not be order sensitive * fix versions page according to versioning config * fix versions page according to versioning config
This commit is contained in:
parent
4bfc3bbbe7
commit
ae877f2990
15 changed files with 387 additions and 79 deletions
|
@ -290,6 +290,7 @@ Object {
|
|||
}",
|
||||
"version-current-metadata-prop-751.json": "{
|
||||
\\"version\\": \\"current\\",
|
||||
\\"label\\": \\"Next\\",
|
||||
\\"docsSidebars\\": {
|
||||
\\"docs\\": [
|
||||
{
|
||||
|
@ -613,6 +614,7 @@ Object {
|
|||
}",
|
||||
"version-1-0-0-metadata-prop-608.json": "{
|
||||
\\"version\\": \\"1.0.0\\",
|
||||
\\"label\\": \\"1.0.0\\",
|
||||
\\"docsSidebars\\": {
|
||||
\\"version-1.0.0/community\\": [
|
||||
{
|
||||
|
@ -628,6 +630,7 @@ Object {
|
|||
}",
|
||||
"version-current-metadata-prop-751.json": "{
|
||||
\\"version\\": \\"current\\",
|
||||
\\"label\\": \\"Next\\",
|
||||
\\"docsSidebars\\": {
|
||||
\\"community\\": [
|
||||
{
|
||||
|
@ -1069,6 +1072,7 @@ Object {
|
|||
}",
|
||||
"version-1-0-0-metadata-prop-608.json": "{
|
||||
\\"version\\": \\"1.0.0\\",
|
||||
\\"label\\": \\"1.0.0\\",
|
||||
\\"docsSidebars\\": {
|
||||
\\"version-1.0.0/docs\\": [
|
||||
{
|
||||
|
@ -1110,6 +1114,7 @@ Object {
|
|||
}",
|
||||
"version-1-0-1-metadata-prop-e87.json": "{
|
||||
\\"version\\": \\"1.0.1\\",
|
||||
\\"label\\": \\"1.0.1\\",
|
||||
\\"docsSidebars\\": {
|
||||
\\"version-1.0.1/docs\\": [
|
||||
{
|
||||
|
@ -1145,6 +1150,7 @@ Object {
|
|||
}",
|
||||
"version-current-metadata-prop-751.json": "{
|
||||
\\"version\\": \\"current\\",
|
||||
\\"label\\": \\"Next\\",
|
||||
\\"docsSidebars\\": {
|
||||
\\"docs\\": [
|
||||
{
|
||||
|
@ -1180,6 +1186,7 @@ Object {
|
|||
}",
|
||||
"version-with-slugs-metadata-prop-2bf.json": "{
|
||||
\\"version\\": \\"withSlugs\\",
|
||||
\\"label\\": \\"withSlugs\\",
|
||||
\\"docsSidebars\\": {
|
||||
\\"version-1.0.1/docs\\": [
|
||||
{
|
||||
|
|
|
@ -135,7 +135,8 @@ describe('simple site', () => {
|
|||
|
||||
test('readVersionDocs', async () => {
|
||||
const docs = await readVersionDocs(currentVersion, options);
|
||||
expect(docs.map((doc) => doc.source)).toMatchObject([
|
||||
expect(docs.map((doc) => doc.source).sort()).toEqual(
|
||||
[
|
||||
'hello.md',
|
||||
'ipsum.md',
|
||||
'lorem.md',
|
||||
|
@ -149,7 +150,8 @@ describe('simple site', () => {
|
|||
'slugs/relativeSlug.md',
|
||||
'slugs/resolvedSlug.md',
|
||||
'slugs/tryToEscapeSlug.md',
|
||||
]);
|
||||
].sort(),
|
||||
);
|
||||
});
|
||||
|
||||
test('normal docs', async () => {
|
||||
|
|
|
@ -36,6 +36,16 @@ describe('normalizeDocsPluginOptions', () => {
|
|||
excludeNextVersionDocs: true,
|
||||
includeCurrentVersion: false,
|
||||
disableVersioning: true,
|
||||
versions: {
|
||||
current: {
|
||||
path: 'next',
|
||||
label: 'next',
|
||||
},
|
||||
version1: {
|
||||
path: 'hello',
|
||||
label: 'world',
|
||||
},
|
||||
},
|
||||
};
|
||||
const {value, error} = await OptionsSchema.validate(userOptions);
|
||||
expect(value).toEqual(userOptions);
|
||||
|
@ -117,4 +127,32 @@ describe('normalizeDocsPluginOptions', () => {
|
|||
`"\\"remarkPlugins\\" must be an array"`,
|
||||
);
|
||||
});
|
||||
|
||||
test('should reject bad lastVersion', () => {
|
||||
expect(() => {
|
||||
normalizePluginOptions(OptionsSchema, {
|
||||
lastVersion: false,
|
||||
});
|
||||
}).toThrowErrorMatchingInlineSnapshot(
|
||||
`"\\"lastVersion\\" must be a string"`,
|
||||
);
|
||||
});
|
||||
|
||||
test('should reject bad versions', () => {
|
||||
expect(() => {
|
||||
normalizePluginOptions(OptionsSchema, {
|
||||
versions: {
|
||||
current: {
|
||||
hey: 3,
|
||||
},
|
||||
version1: {
|
||||
path: 'hello',
|
||||
label: 'world',
|
||||
},
|
||||
},
|
||||
});
|
||||
}).toThrowErrorMatchingInlineSnapshot(
|
||||
`"\\"versions.current.hey\\" is not allowed"`,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -94,7 +94,63 @@ describe('simple site', () => {
|
|||
]);
|
||||
});
|
||||
|
||||
test('readVersionsMetadata simple site with base url', () => {
|
||||
test('readVersionsMetadata simple site with current version config', () => {
|
||||
const versionsMetadata = readVersionsMetadata({
|
||||
options: {
|
||||
...defaultOptions,
|
||||
versions: {
|
||||
current: {
|
||||
label: 'current-label',
|
||||
path: 'current-path',
|
||||
},
|
||||
},
|
||||
},
|
||||
context: {
|
||||
...defaultContext,
|
||||
baseUrl: '/myBaseUrl',
|
||||
},
|
||||
});
|
||||
|
||||
expect(versionsMetadata).toEqual([
|
||||
{
|
||||
...vCurrent,
|
||||
versionPath: '/myBaseUrl/docs/current-path',
|
||||
versionLabel: 'current-label',
|
||||
routePriority: undefined,
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
test('readVersionsMetadata simple site with unknown lastVersion should throw', () => {
|
||||
expect(() =>
|
||||
readVersionsMetadata({
|
||||
options: {...defaultOptions, lastVersion: 'unknownVersionName'},
|
||||
context: defaultContext,
|
||||
}),
|
||||
).toThrowErrorMatchingInlineSnapshot(
|
||||
`"Docs option lastVersion=unknownVersionName is invalid. Available version names are: current"`,
|
||||
);
|
||||
});
|
||||
|
||||
test('readVersionsMetadata simple site with unknown version configurations should throw', () => {
|
||||
expect(() =>
|
||||
readVersionsMetadata({
|
||||
options: {
|
||||
...defaultOptions,
|
||||
versions: {
|
||||
current: {label: 'current'},
|
||||
unknownVersionName1: {label: 'unknownVersionName1'},
|
||||
unknownVersionName2: {label: 'unknownVersionName2'},
|
||||
},
|
||||
},
|
||||
context: defaultContext,
|
||||
}),
|
||||
).toThrowErrorMatchingInlineSnapshot(
|
||||
`"Docs versions option provided configuration for unknown versions: unknownVersionName1,unknownVersionName2. Available version names are: current"`,
|
||||
);
|
||||
});
|
||||
|
||||
test('readVersionsMetadata simple site with disableVersioning while single version should throw', () => {
|
||||
expect(() =>
|
||||
readVersionsMetadata({
|
||||
options: {...defaultOptions, disableVersioning: true},
|
||||
|
@ -105,7 +161,7 @@ describe('simple site', () => {
|
|||
);
|
||||
});
|
||||
|
||||
test('readVersionsMetadata simple site with base url', () => {
|
||||
test('readVersionsMetadata simple site without including current version should throw', () => {
|
||||
expect(() =>
|
||||
readVersionsMetadata({
|
||||
options: {...defaultOptions, includeCurrentVersion: false},
|
||||
|
@ -205,6 +261,42 @@ describe('versioned site, pluginId=default', () => {
|
|||
]);
|
||||
});
|
||||
|
||||
test('readVersionsMetadata versioned site with version options', () => {
|
||||
const versionsMetadata = readVersionsMetadata({
|
||||
options: {
|
||||
...defaultOptions,
|
||||
lastVersion: '1.0.0',
|
||||
versions: {
|
||||
current: {
|
||||
path: 'current-path',
|
||||
},
|
||||
'1.0.0': {
|
||||
label: '1.0.0-label',
|
||||
},
|
||||
},
|
||||
},
|
||||
context: defaultContext,
|
||||
});
|
||||
|
||||
expect(versionsMetadata).toEqual([
|
||||
{...vCurrent, versionPath: '/docs/current-path'},
|
||||
{
|
||||
...v101,
|
||||
isLast: false,
|
||||
routePriority: undefined,
|
||||
versionPath: '/docs/1.0.1',
|
||||
},
|
||||
{
|
||||
...v100,
|
||||
isLast: true,
|
||||
routePriority: -1,
|
||||
versionLabel: '1.0.0-label',
|
||||
versionPath: '/docs',
|
||||
},
|
||||
vwithSlugs,
|
||||
]);
|
||||
});
|
||||
|
||||
test('readVersionsMetadata versioned site with disableVersioning', () => {
|
||||
const versionsMetadata = readVersionsMetadata({
|
||||
options: {...defaultOptions, disableVersioning: true},
|
||||
|
|
|
@ -33,8 +33,19 @@ export const DEFAULT_OPTIONS: Omit<PluginOptions, 'id'> = {
|
|||
excludeNextVersionDocs: false,
|
||||
includeCurrentVersion: true,
|
||||
disableVersioning: false,
|
||||
lastVersion: undefined,
|
||||
versions: {},
|
||||
};
|
||||
|
||||
const VersionOptionsSchema = Joi.object({
|
||||
path: Joi.string().allow('').optional(),
|
||||
label: Joi.string().optional(),
|
||||
});
|
||||
|
||||
const VersionsOptionsSchema = Joi.object()
|
||||
.pattern(Joi.string().required(), VersionOptionsSchema)
|
||||
.default(DEFAULT_OPTIONS.versions);
|
||||
|
||||
export const OptionsSchema = Joi.object({
|
||||
path: Joi.string().default(DEFAULT_OPTIONS.path),
|
||||
editUrl: URISchema,
|
||||
|
@ -58,6 +69,8 @@ export const OptionsSchema = Joi.object({
|
|||
DEFAULT_OPTIONS.includeCurrentVersion,
|
||||
),
|
||||
disableVersioning: Joi.bool().default(DEFAULT_OPTIONS.disableVersioning),
|
||||
lastVersion: Joi.string().optional(),
|
||||
versions: VersionsOptionsSchema,
|
||||
});
|
||||
|
||||
// TODO bad validation function types
|
||||
|
|
|
@ -8,14 +8,13 @@
|
|||
/* eslint-disable camelcase */
|
||||
|
||||
declare module '@docusaurus/plugin-content-docs-types' {
|
||||
export type VersionName = string;
|
||||
|
||||
export type PermalinkToSidebar = {
|
||||
[permalink: string]: string;
|
||||
};
|
||||
|
||||
export type PropVersionMetadata = {
|
||||
version: VersionName;
|
||||
version: string;
|
||||
label: string;
|
||||
docsSidebars: PropSidebars;
|
||||
permalinkToSidebar: PermalinkToSidebar;
|
||||
};
|
||||
|
|
|
@ -66,6 +66,7 @@ export function toVersionMetadataProp(
|
|||
): PropVersionMetadata {
|
||||
return {
|
||||
version: loadedVersion.versionName,
|
||||
label: loadedVersion.versionLabel,
|
||||
docsSidebars: toSidebarsProp(loadedVersion),
|
||||
permalinkToSidebar: loadedVersion.permalinkToSidebar,
|
||||
};
|
||||
|
|
|
@ -39,8 +39,19 @@ export type PathOptions = {
|
|||
sidebarPath: string;
|
||||
};
|
||||
|
||||
export type VersionOptions = {
|
||||
path?: string;
|
||||
label?: string;
|
||||
};
|
||||
|
||||
export type VersionsOptions = {
|
||||
lastVersion?: string;
|
||||
versions: Record<string, VersionOptions>;
|
||||
};
|
||||
|
||||
export type PluginOptions = MetadataOptions &
|
||||
PathOptions & {
|
||||
PathOptions &
|
||||
VersionsOptions & {
|
||||
id: string;
|
||||
include: string[];
|
||||
docLayoutComponent: string;
|
||||
|
|
|
@ -7,7 +7,12 @@
|
|||
|
||||
import path from 'path';
|
||||
import fs from 'fs-extra';
|
||||
import {PluginOptions, VersionMetadata} from './types';
|
||||
import {
|
||||
PluginOptions,
|
||||
VersionMetadata,
|
||||
VersionOptions,
|
||||
VersionsOptions,
|
||||
} from './types';
|
||||
import {
|
||||
VERSIONS_JSON_FILE,
|
||||
VERSIONED_DOCS_DIR,
|
||||
|
@ -18,6 +23,7 @@ import {
|
|||
import {DEFAULT_PLUGIN_ID} from '@docusaurus/core/lib/constants';
|
||||
import {LoadContext} from '@docusaurus/types';
|
||||
import {normalizeUrl} from '@docusaurus/utils';
|
||||
import {difference} from 'lodash';
|
||||
|
||||
// retro-compatibility: no prefix for the default plugin id
|
||||
function addPluginIdPrefix(fileOrDir: string, pluginId: string): string {
|
||||
|
@ -161,7 +167,10 @@ function createVersionMetadata({
|
|||
versionName: string;
|
||||
isLast: boolean;
|
||||
context: Pick<LoadContext, 'siteDir' | 'baseUrl'>;
|
||||
options: Pick<PluginOptions, 'id' | 'path' | 'sidebarPath' | 'routeBasePath'>;
|
||||
options: Pick<
|
||||
PluginOptions,
|
||||
'id' | 'path' | 'sidebarPath' | 'routeBasePath' | 'versions'
|
||||
>;
|
||||
}): VersionMetadata {
|
||||
const {sidebarFilePath, docsDirPath} = getVersionMetadataPaths({
|
||||
versionName,
|
||||
|
@ -169,16 +178,20 @@ function createVersionMetadata({
|
|||
options,
|
||||
});
|
||||
|
||||
// TODO hardcoded for retro-compatibility
|
||||
// TODO Need to make this configurable
|
||||
const versionLabel =
|
||||
// retro-compatible values
|
||||
const defaultVersionLabel =
|
||||
versionName === CURRENT_VERSION_NAME ? 'Next' : versionName;
|
||||
const versionPathPart = isLast
|
||||
const defaultVersionPathPart = isLast
|
||||
? ''
|
||||
: versionName === CURRENT_VERSION_NAME
|
||||
? 'next'
|
||||
: versionName;
|
||||
|
||||
const versionOptions: VersionOptions = options.versions[versionName] ?? {};
|
||||
|
||||
const versionLabel = versionOptions.label ?? defaultVersionLabel;
|
||||
const versionPathPart = versionOptions.path ?? defaultVersionPathPart;
|
||||
|
||||
const versionPath = normalizeUrl([
|
||||
context.baseUrl,
|
||||
options.routeBasePath,
|
||||
|
@ -219,7 +232,7 @@ function checkVersionMetadataPaths({
|
|||
// TODO for retrocompatibility with existing behavior
|
||||
// We should make this configurable
|
||||
// "last version" is not a very good concept nor api surface
|
||||
function getLastVersionName(versionNames: string[]) {
|
||||
function getDefaultLastVersionName(versionNames: string[]) {
|
||||
if (versionNames.length === 1) {
|
||||
return versionNames[0];
|
||||
} else {
|
||||
|
@ -229,6 +242,34 @@ function getLastVersionName(versionNames: string[]) {
|
|||
}
|
||||
}
|
||||
|
||||
function checkVersionsOptions(
|
||||
availableVersionNames: string[],
|
||||
options: VersionsOptions,
|
||||
) {
|
||||
const availableVersionNamesMsg = `Available version names are: ${availableVersionNames.join(
|
||||
', ',
|
||||
)}`;
|
||||
if (
|
||||
options.lastVersion &&
|
||||
!availableVersionNames.includes(options.lastVersion)
|
||||
) {
|
||||
throw new Error(
|
||||
`Docs option lastVersion=${options.lastVersion} is invalid. ${availableVersionNamesMsg}`,
|
||||
);
|
||||
}
|
||||
const unknownVersionNames = difference(
|
||||
Object.keys(options.versions),
|
||||
availableVersionNames,
|
||||
);
|
||||
if (unknownVersionNames.length > 0) {
|
||||
throw new Error(
|
||||
`Docs versions option provided configuration for unknown versions: ${unknownVersionNames.join(
|
||||
',',
|
||||
)}. ${availableVersionNamesMsg}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export function readVersionsMetadata({
|
||||
context,
|
||||
options,
|
||||
|
@ -242,10 +283,17 @@ export function readVersionsMetadata({
|
|||
| 'routeBasePath'
|
||||
| 'includeCurrentVersion'
|
||||
| 'disableVersioning'
|
||||
| 'lastVersion'
|
||||
| 'versions'
|
||||
>;
|
||||
}): VersionMetadata[] {
|
||||
const versionNames = readVersionNames(context.siteDir, options);
|
||||
const lastVersionName = getLastVersionName(versionNames);
|
||||
|
||||
checkVersionsOptions(versionNames, options);
|
||||
|
||||
const lastVersionName =
|
||||
options.lastVersion ?? getDefaultLastVersionName(versionNames);
|
||||
|
||||
const versionsMetadata = versionNames.map((versionName) =>
|
||||
createVersionMetadata({
|
||||
versionName,
|
||||
|
|
|
@ -17,6 +17,16 @@ import TOC from '@theme/TOC';
|
|||
|
||||
import clsx from 'clsx';
|
||||
import styles from './styles.module.css';
|
||||
import {useActivePlugin, useActiveVersion} from '@theme/hooks/useDocs';
|
||||
|
||||
// TODO can't we receive the version as props instead?
|
||||
const useDocVersion = () => {
|
||||
const version = useActiveVersion(useActivePlugin().pluginId);
|
||||
if (!version) {
|
||||
throw new Error("unexpected, can't get version data of doc"); // should not happen
|
||||
}
|
||||
return version;
|
||||
};
|
||||
|
||||
function DocItem(props: Props): JSX.Element {
|
||||
const {siteConfig = {}} = useDocusaurusContext();
|
||||
|
@ -30,7 +40,6 @@ function DocItem(props: Props): JSX.Element {
|
|||
editUrl,
|
||||
lastUpdatedAt,
|
||||
lastUpdatedBy,
|
||||
version,
|
||||
} = metadata;
|
||||
const {
|
||||
frontMatter: {
|
||||
|
@ -40,6 +49,7 @@ function DocItem(props: Props): JSX.Element {
|
|||
hide_table_of_contents: hideTableOfContents,
|
||||
},
|
||||
} = DocContent;
|
||||
const version = useDocVersion();
|
||||
|
||||
const metaTitle = title ? `${title} | ${siteTitle}` : siteTitle;
|
||||
const metaImageUrl = useBaseUrl(metaImage, {absolute: true});
|
||||
|
@ -76,7 +86,7 @@ function DocItem(props: Props): JSX.Element {
|
|||
{version && (
|
||||
<div>
|
||||
<span className="badge badge--secondary">
|
||||
Version: {version}
|
||||
Version: {version.label}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
|
|
|
@ -43,8 +43,6 @@ function DocVersionSuggestions(): JSX.Element {
|
|||
return <></>;
|
||||
}
|
||||
|
||||
const activeVersionName = activeVersion.name;
|
||||
|
||||
// try to link to same doc in latest version (not always possible)
|
||||
// fallback to main doc of latest version
|
||||
const suggestedDoc =
|
||||
|
@ -54,15 +52,15 @@ function DocVersionSuggestions(): JSX.Element {
|
|||
<div className="alert alert--warning margin-bottom--md" role="alert">
|
||||
{
|
||||
// TODO need refactoring
|
||||
activeVersionName === 'current' ? (
|
||||
activeVersion.name === 'current' ? (
|
||||
<div>
|
||||
This is unreleased documentation for {siteTitle}{' '}
|
||||
<strong>{activeVersionName}</strong> version.
|
||||
<strong>{activeVersion.label}</strong> version.
|
||||
</div>
|
||||
) : (
|
||||
<div>
|
||||
This is documentation for {siteTitle}{' '}
|
||||
<strong>v{activeVersionName}</strong>, which is no longer actively
|
||||
<strong>{activeVersion.label}</strong>, which is no longer actively
|
||||
maintained.
|
||||
</div>
|
||||
)
|
||||
|
@ -72,7 +70,7 @@ function DocVersionSuggestions(): JSX.Element {
|
|||
<strong>
|
||||
<Link to={suggestedDoc.path}>latest version</Link>
|
||||
</strong>{' '}
|
||||
({latestVersionSuggestion.name}).
|
||||
({latestVersionSuggestion.label}).
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -335,6 +335,33 @@ module.exports = {
|
|||
* in `/docs/next` directory, only versioned docs.
|
||||
*/
|
||||
excludeNextVersionDocs: false,
|
||||
/**
|
||||
* The last version is the one we navigate to in priority on versioned sites
|
||||
* It is the one displayed by default in docs navbar items
|
||||
* By default, the last version is the first one to appear in versions.json
|
||||
* By default, the last version is at the "root" (docs have path=/docs/myDoc)
|
||||
* Note: it is possible to configure the path and label of the last version
|
||||
* Tip: using lastVersion: 'current' make sense in many cases
|
||||
*/
|
||||
lastVersion: undefined,
|
||||
/**
|
||||
* The docusaurus versioning defaults don't make sense for all projects
|
||||
* This gives the ability customize the label and path of each version
|
||||
* You may not like that default versin
|
||||
*/
|
||||
versions: {
|
||||
/*
|
||||
Example configuration:
|
||||
current: {
|
||||
label: 'Android SDK v2.0.0 (WIP)',
|
||||
path: 'android-2.0.0',
|
||||
},
|
||||
'1.0.0': {
|
||||
label: 'Android SDK v1.0.0',
|
||||
path: 'android-1.0.0',
|
||||
},
|
||||
*/
|
||||
},
|
||||
},
|
||||
],
|
||||
],
|
||||
|
|
|
@ -64,9 +64,9 @@ When tagging a new version, the document versioning mechanism will:
|
|||
- Create a versioned sidebars file based from your current [sidebar](docs.md#sidebar) configuration (if it exists) - saved as `versioned_sidebars/version-<version>-sidebars.json`.
|
||||
- Append the new version number to `versions.json`.
|
||||
|
||||
## Files
|
||||
## Docs
|
||||
|
||||
### Creating new files
|
||||
### Creating new docs
|
||||
|
||||
1. Place the new file into the corresponding version folder.
|
||||
1. Include the reference for the new file into the corresponding sidebar file, according to version number.
|
||||
|
@ -91,7 +91,7 @@ versioned_docs/version-1.0.0/new.md
|
|||
versioned_sidebars/version-1.0.0-sidebars.json
|
||||
```
|
||||
|
||||
### Linking files
|
||||
### Linking docs
|
||||
|
||||
- Remember to include the `.md` extension.
|
||||
- Files will be linked to correct corresponding version.
|
||||
|
@ -138,6 +138,35 @@ Example:
|
|||
|
||||
## Recommended practices
|
||||
|
||||
### Figure out the behavior for the "current" version
|
||||
|
||||
The "current" version is the version name for the `./docs` folder.
|
||||
|
||||
There are different ways to manage versioning, but two very common patterns are:
|
||||
|
||||
- You release v1, and start immediately working on v2 (including its docs)
|
||||
- You release v1, and will maintain it for some time before thinking about v2.
|
||||
|
||||
Docusaurus defaults work great for the first usecase.
|
||||
|
||||
**For the 2nd usecase**: if you release v1 and don't plan to work on v2 anytime soon, instead of versioning v1 and having to maintain the docs in 2 folders (`./docs` + `./versioned_docs/version-1.0.0`), you may consider using the following configuration instead:
|
||||
|
||||
```json
|
||||
{
|
||||
"lastVersion": "current",
|
||||
"versions": {
|
||||
"current": {
|
||||
"label": "1.0.0",
|
||||
"path": "1.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The docs in `./docs` will be served at `/docs/1.0.0` instead of `/docs/next`, and `1.0.0` will become the default version we link to in the navbar dropdown, and you will only need to maintain a single `./docs` folder.
|
||||
|
||||
See [docs plugin configuration](using-plugins#docusaurusplugin-content-docs) for more details.
|
||||
|
||||
### Version your documentation only when needed
|
||||
|
||||
For example, you are building a documentation for your npm package `foo` and you are currently in version 1.0.0. You then release a patch version for a minor bug fix and it's now 1.0.1.
|
||||
|
@ -156,3 +185,23 @@ Don't use relative paths import within the docs. Because when we cut a version t
|
|||
- import Foo from '../src/components/Foo';
|
||||
+ import Foo from '@site/src/components/Foo';
|
||||
```
|
||||
|
||||
### Global or versioned colocated assets
|
||||
|
||||
You should decide if assets like images and files are per version or shared between versions
|
||||
|
||||
If your assets should be versioned, put them in the docs version, and use relative paths:
|
||||
|
||||
```md
|
||||

|
||||
|
||||
[dowload this file](./file.pdf)
|
||||
```
|
||||
|
||||
If your assets are global, put them in `/static` and use absolute paths:
|
||||
|
||||
```md
|
||||

|
||||
|
||||
[dowload this file](/file.pdf)
|
||||
```
|
||||
|
|
|
@ -14,13 +14,15 @@ const allDocHomesPaths = [
|
|||
...versions.slice(1).map((version) => `/docs/${version}/`),
|
||||
];
|
||||
|
||||
const isDev = process.env.NODE_ENV === 'development';
|
||||
|
||||
const isDeployPreview =
|
||||
process.env.NETLIFY && process.env.CONTEXT === 'deploy-preview';
|
||||
|
||||
const baseUrl = process.env.BASE_URL || '/';
|
||||
const isBootstrapPreset = process.env.DOCUSAURUS_PRESET === 'bootstrap';
|
||||
const isVersioningDisabled = !!process.env.DISABLE_VERSIONING;
|
||||
|
||||
if (isBootstrapPreset) {
|
||||
console.log('Will use bootstrap preset!');
|
||||
}
|
||||
const isVersioningDisabled = !!process.env.DISABLE_VERSIONING;
|
||||
|
||||
module.exports = {
|
||||
title: 'Docusaurus',
|
||||
|
@ -175,6 +177,16 @@ module.exports = {
|
|||
showLastUpdateTime: true,
|
||||
remarkPlugins: [require('./src/plugins/remark-npm2yarn')],
|
||||
disableVersioning: isVersioningDisabled,
|
||||
lastVersion: isDev || isDeployPreview ? 'current' : undefined,
|
||||
versions: {
|
||||
current: {
|
||||
// path: isDev || isDeployPreview ? '' : 'next',
|
||||
label:
|
||||
isDev || isDeployPreview
|
||||
? `Next (${isDeployPreview ? 'deploy preview' : 'dev'})`
|
||||
: 'Next',
|
||||
},
|
||||
},
|
||||
},
|
||||
blog: {
|
||||
// routeBasePath: '/',
|
||||
|
|
|
@ -6,20 +6,21 @@
|
|||
*/
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import Layout from '@theme/Layout';
|
||||
|
||||
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
|
||||
import Link from '@docusaurus/Link';
|
||||
import useBaseUrl from '@docusaurus/useBaseUrl';
|
||||
import Layout from '@theme/Layout';
|
||||
|
||||
import versions from '../../versions.json';
|
||||
import {useVersions, useLatestVersion} from '@theme/hooks/useDocs';
|
||||
|
||||
function Version() {
|
||||
const context = useDocusaurusContext();
|
||||
const {siteConfig = {}} = context;
|
||||
const latestVersion = versions[0];
|
||||
const pastVersions = versions.filter((version) => version !== latestVersion);
|
||||
const {siteConfig} = useDocusaurusContext();
|
||||
const versions = useVersions();
|
||||
const latestVersion = useLatestVersion();
|
||||
const currentVersion = versions.find((version) => version.name === 'current');
|
||||
const pastVersions = versions.filter(
|
||||
(version) => version !== latestVersion && version.name !== 'current',
|
||||
);
|
||||
|
||||
const repoUrl = `https://github.com/${siteConfig.organizationName}/${siteConfig.projectName}`;
|
||||
return (
|
||||
<Layout
|
||||
|
@ -34,12 +35,12 @@ function Version() {
|
|||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>{latestVersion}</th>
|
||||
<th>{latestVersion.label}</th>
|
||||
<td>
|
||||
<Link to={useBaseUrl('/docs')}>Documentation</Link>
|
||||
<Link to={latestVersion.path}>Documentation</Link>
|
||||
</td>
|
||||
<td>
|
||||
<a href={`${repoUrl}/releases/tag/v${latestVersion}`}>
|
||||
<a href={`${repoUrl}/releases/tag/v${latestVersion.name}`}>
|
||||
Release Notes
|
||||
</a>
|
||||
</td>
|
||||
|
@ -47,6 +48,7 @@ function Version() {
|
|||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{currentVersion !== latestVersion && (
|
||||
<div className="margin-bottom--lg">
|
||||
<h3 id="next">Next version (Unreleased)</h3>
|
||||
<p>Here you can find the documentation for unreleased version.</p>
|
||||
|
@ -55,7 +57,7 @@ function Version() {
|
|||
<tr>
|
||||
<th>master</th>
|
||||
<td>
|
||||
<Link to={useBaseUrl('/docs/next')}>Documentation</Link>
|
||||
<Link to={currentVersion.path}>Documentation</Link>
|
||||
</td>
|
||||
<td>
|
||||
<a href={repoUrl}>Source Code</a>
|
||||
|
@ -64,6 +66,7 @@ function Version() {
|
|||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
)}
|
||||
{pastVersions.length > 0 && (
|
||||
<div className="margin-bottom--lg">
|
||||
<h3 id="archive">Past Versions</h3>
|
||||
|
@ -74,15 +77,13 @@ function Version() {
|
|||
<table>
|
||||
<tbody>
|
||||
{pastVersions.map((version) => (
|
||||
<tr key={version}>
|
||||
<th>{version}</th>
|
||||
<tr key={version.name}>
|
||||
<th>{version.label}</th>
|
||||
<td>
|
||||
<Link to={useBaseUrl(`/docs/${version}`)}>
|
||||
Documentation
|
||||
</Link>
|
||||
<Link to={version.path}>Documentation</Link>
|
||||
</td>
|
||||
<td>
|
||||
<a href={`${repoUrl}/releases/tag/v${version}`}>
|
||||
<a href={`${repoUrl}/releases/tag/v${version.name}`}>
|
||||
Release Notes
|
||||
</a>
|
||||
</td>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue