fix(v2): fix recent baseurl issues (#3093)

* try to fix the baseUrl related issues

* fix some newly detected broken links

* fix baseurl and broken link issues

* try to configure netlify to use baseUrl deployment

* add proper netlify settings?

* add proper netlify settings?

* add proper netlify settings?

* test commit

* try to fix the redirects

* cleanup working conf

* minor redirect fix
This commit is contained in:
Sébastien Lorber 2020-07-22 19:55:40 +02:00 committed by GitHub
parent 27f384a67c
commit 811c7ae4e9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
30 changed files with 2639 additions and 146 deletions

3
.gitignore vendored
View file

@ -27,3 +27,6 @@ packages/docusaurus-plugin-debug/lib/
packages/docusaurus-plugin-sitemap/lib/ packages/docusaurus-plugin-sitemap/lib/
packages/docusaurus-plugin-ideal-image/lib/ packages/docusaurus-plugin-ideal-image/lib/
packages/docusaurus-theme-classic/lib/ packages/docusaurus-theme-classic/lib/
website/netlifyDeploy
_redirects

26
netlify.toml Normal file
View file

@ -0,0 +1,26 @@
# Note: this file's config override the Netlify UI admin config
# default/production build
[build]
base = "/"
command = "yarn netlify:build:production"
publish = "website/build"
# we build deploy previews with a /build/ baseUrl on purpose
# permits to test that baseUrl works fine (this often breaks!)
[context.deploy-preview]
command = "yarn netlify:build:deployPreview"
publish = "website/netlifyDeploy"
# TODO this does not seem to work
# workaroud: a _redirect file is created in website/netlifyDeploy
# can't we have context-based redirects with Netlify? :'(
[[context.deploy-preview.redirects]]
from = "/build/*"
to = "/build/404.html"
status = 200
[[context.deploy-preview.redirects]]
from = "/*"
to = "/build/"

View file

@ -7,20 +7,29 @@
"packages/docusaurus-init/templates/*" "packages/docusaurus-init/templates/*"
], ],
"scripts": { "scripts": {
"testBaseUrl": "yarn build:v2:baseUrl && yarn serve:v2:baseUrl",
"start": "yarn build:packages && yarn start:v2", "start": "yarn build:packages && yarn start:v2",
"start:v1": "yarn workspace docusaurus-1-website start", "start:v1": "yarn workspace docusaurus-1-website start",
"start:v2": "yarn workspace docusaurus-2-website start", "start:v2": "yarn workspace docusaurus-2-website start",
"start:v2:watch": "nodemon --watch \"./packages/*/lib/**/*.*\" --exec \"yarn start:v2\"", "start:v2:watch": "nodemon --watch \"./packages/*/lib/**/*.*\" --exec \"yarn start:v2\"",
"start:v2:baseUrl": "BASE_URL='/build/' yarn start:v2",
"build": "yarn build:packages && yarn build:v2", "build": "yarn build:packages && yarn build:v2",
"build:packages": "lerna run build --no-private", "build:packages": "lerna run build --no-private",
"build:v1": "yarn workspace docusaurus-1-website build", "build:v1": "yarn workspace docusaurus-1-website build",
"build:v2": "yarn workspace docusaurus-2-website build", "build:v2": "yarn workspace docusaurus-2-website build",
"build:v2:baseUrl": "BASE_URL='/build/' yarn build:v2",
"serve:v1": "serve website-1.x/build/docusaurus", "serve:v1": "serve website-1.x/build/docusaurus",
"serve:v2": "serve website/build", "serve:v2": "serve website/build",
"serve:v2:baseUrl": "serve website",
"serve:v2:ssl": "yarn serve:v2:ssl:gencert && yarn serve:v2:ssl:message && yarn serve:v2:ssl:serve", "serve:v2:ssl": "yarn serve:v2:ssl:gencert && yarn serve:v2:ssl:message && yarn serve:v2:ssl:serve",
"serve:v2:ssl:gencert": "openssl req -x509 -nodes -days 365 -newkey rsa:4096 -subj \"/C=US/ST=Docusaurus/L=Anywhere/O=Dis/CN=localhost\" -keyout ./website/.docusaurus/selfsigned.key -out ./website/.docusaurus/selfsigned.crt", "serve:v2:ssl:gencert": "openssl req -x509 -nodes -days 365 -newkey rsa:4096 -subj \"/C=US/ST=Docusaurus/L=Anywhere/O=Dis/CN=localhost\" -keyout ./website/.docusaurus/selfsigned.key -out ./website/.docusaurus/selfsigned.crt",
"serve:v2:ssl:message": "echo '\n\n\nServing Docusaurus with HTTPS on localhost requires to disable the Chrome security: chrome://flags/#allow-insecure-localhost\n\n\n'", "serve:v2:ssl:message": "echo '\n\n\nServing Docusaurus with HTTPS on localhost requires to disable the Chrome security: chrome://flags/#allow-insecure-localhost\n\n\n'",
"serve:v2:ssl:serve": "serve website/build --ssl-cert ./website/.docusaurus/selfsigned.crt --ssl-key ./website/.docusaurus/selfsigned.key", "serve:v2:ssl:serve": "serve website/build --ssl-cert ./website/.docusaurus/selfsigned.crt --ssl-key ./website/.docusaurus/selfsigned.key",
"netlify:build:production": "yarn build:v2",
"netlify:build:deployPreview": "yarn build:v2:baseUrl && yarn netlify:build:deployPreview:moveBuild && yarn netlify:build:deployPreview:redirects",
"netlify:build:deployPreview:moveBuild": "yarn rimraf website/netlifyDeploy && mkdir website/netlifyDeploy && mv website/build website/netlifyDeploy",
"netlify:build:deployPreview:redirects": "echo 'Writing Netlify baseUrl deployPreview _redirects file' && echo '/build/* /build/404.html 200' >> website/netlifyDeploy/_redirects && echo '/* /build/' >> website/netlifyDeploy/_redirects",
"netlify:test": "yarn netlify:build:deployPreview && yarn netlify dev --debug",
"changelog": "lerna-changelog", "changelog": "lerna-changelog",
"postinstall": "yarn build:packages", "postinstall": "yarn build:packages",
"prettier": "prettier --config .prettierrc --write \"**/*.{js,ts}\"", "prettier": "prettier --config .prettierrc --write \"**/*.{js,ts}\"",
@ -37,8 +46,8 @@
"clear": "yarn rimraf website/.docusaurus && rimraf -rf website/node_modules/.cache && yarn lerna exec 'yarn rimraf lib' --ignore docusaurus" "clear": "yarn rimraf website/.docusaurus && rimraf -rf website/node_modules/.cache && yarn lerna exec 'yarn rimraf lib' --ignore docusaurus"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.9.0",
"@babel/cli": "^7.9.0", "@babel/cli": "^7.9.0",
"@babel/core": "^7.9.0",
"@babel/plugin-proposal-nullish-coalescing-operator": "^7.8.3", "@babel/plugin-proposal-nullish-coalescing-operator": "^7.8.3",
"@babel/plugin-proposal-optional-chaining": "^7.9.0", "@babel/plugin-proposal-optional-chaining": "^7.9.0",
"@babel/preset-typescript": "^7.9.0", "@babel/preset-typescript": "^7.9.0",
@ -88,6 +97,7 @@
"lerna": "^3.19.0", "lerna": "^3.19.0",
"lerna-changelog": "^1.0.1", "lerna-changelog": "^1.0.1",
"lint-staged": "^10.1.2", "lint-staged": "^10.1.2",
"netlify-cli": "^2.58.0",
"nodemon": "^2.0.4", "nodemon": "^2.0.4",
"prettier": "^2.0.2", "prettier": "^2.0.2",
"react": "^16.8.4", "react": "^16.8.4",

View file

@ -16,9 +16,9 @@
}, },
"dependencies": { "dependencies": {
"@docusaurus/mdx-loader": "^2.0.0-alpha.58", "@docusaurus/mdx-loader": "^2.0.0-alpha.58",
"@docusaurus/core": "^2.0.0-alpha.58",
"@docusaurus/types": "^2.0.0-alpha.58", "@docusaurus/types": "^2.0.0-alpha.58",
"@docusaurus/utils": "^2.0.0-alpha.58", "@docusaurus/utils": "^2.0.0-alpha.58",
"@docusaurus/core": "2.0.0-alpha.58",
"@hapi/joi": "^17.1.1", "@hapi/joi": "^17.1.1",
"feed": "^4.1.0", "feed": "^4.1.0",
"fs-extra": "^8.1.0", "fs-extra": "^8.1.0",

View file

@ -19,6 +19,7 @@
}, },
"dependencies": { "dependencies": {
"@docusaurus/mdx-loader": "^2.0.0-alpha.58", "@docusaurus/mdx-loader": "^2.0.0-alpha.58",
"@docusaurus/core": "^2.0.0-alpha.58",
"@docusaurus/types": "^2.0.0-alpha.58", "@docusaurus/types": "^2.0.0-alpha.58",
"@docusaurus/utils": "^2.0.0-alpha.58", "@docusaurus/utils": "^2.0.0-alpha.58",
"execa": "^3.4.0", "execa": "^3.4.0",
@ -33,8 +34,7 @@
"lodash.pickby": "^4.6.0", "lodash.pickby": "^4.6.0",
"lodash.sortby": "^4.6.0", "lodash.sortby": "^4.6.0",
"remark-admonitions": "^1.2.1", "remark-admonitions": "^1.2.1",
"shelljs": "^0.8.4", "shelljs": "^0.8.4"
"@docusaurus/core": "^2.0.0-alpha.58"
}, },
"peerDependencies": { "peerDependencies": {
"react": "^16.8.4", "react": "^16.8.4",

View file

@ -178,7 +178,7 @@ Object {
"pluginName": Object { "pluginName": Object {
"pluginId": Object { "pluginId": Object {
"latestVersionName": null, "latestVersionName": null,
"path": "docs", "path": "/docs",
"versions": Array [ "versions": Array [
Object { Object {
"docs": Array [ "docs": Array [
@ -469,7 +469,7 @@ Object {
"pluginName": Object { "pluginName": Object {
"pluginId": Object { "pluginId": Object {
"latestVersionName": "1.0.1", "latestVersionName": "1.0.1",
"path": "docs", "path": "/docs",
"versions": Array [ "versions": Array [
Object { Object {
"docs": Array [ "docs": Array [

View file

@ -20,12 +20,12 @@ describe('docsClientUtils', () => {
test('getActivePlugin', () => { test('getActivePlugin', () => {
const data: Record<string, GlobalPluginData> = { const data: Record<string, GlobalPluginData> = {
pluginIosId: { pluginIosId: {
path: 'ios', path: '/ios',
latestVersionName: 'xyz', latestVersionName: 'xyz',
versions: [], versions: [],
}, },
pluginAndroidId: { pluginAndroidId: {
path: 'android', path: '/android',
latestVersionName: 'xyz', latestVersionName: 'xyz',
versions: [], versions: [],
}, },

View file

@ -30,7 +30,7 @@ export const getActivePlugin = (
const activeEntry = Object.entries(allPluginDatas).find( const activeEntry = Object.entries(allPluginDatas).find(
([_id, pluginData]) => { ([_id, pluginData]) => {
return !!matchPath(pathname, { return !!matchPath(pathname, {
path: `/${pluginData.path}`, path: pluginData.path,
exact: false, exact: false,
strict: false, strict: false,
}); });

View file

@ -323,7 +323,7 @@ Available document ids=
const {addRoute, createData, setGlobalData} = actions; const {addRoute, createData, setGlobalData} = actions;
const pluginInstanceGlobalData: GlobalPluginData = { const pluginInstanceGlobalData: GlobalPluginData = {
path: options.path, path: normalizeUrl([baseUrl, options.path]),
latestVersionName: versioning.latestVersion, latestVersionName: versioning.latestVersion,
// Initialized empty, will be mutated // Initialized empty, will be mutated
versions: [], versions: [],

View file

@ -24,10 +24,6 @@ export default {
return children; return children;
}, },
a: (props: ComponentProps<'a'>): JSX.Element => { a: (props: ComponentProps<'a'>): JSX.Element => {
if (/\.[^./]+$/.test(props.href || '')) {
// eslint-disable-next-line jsx-a11y/anchor-has-content
return <a {...props} />;
}
return <Link {...props} />; return <Link {...props} />;
}, },
pre: (props: ComponentProps<'div'>): JSX.Element => ( pre: (props: ComponentProps<'div'>): JSX.Element => (

View file

@ -28,10 +28,8 @@ function NavLink({
activeClassName?: string; activeClassName?: string;
prependBaseUrlToHref?: string; prependBaseUrlToHref?: string;
} & ComponentProps<'a'>) { } & ComponentProps<'a'>) {
const toUrl = useBaseUrl(to);
const activeBaseUrl = useBaseUrl(activeBasePath); const activeBaseUrl = useBaseUrl(activeBasePath);
const normalizedHref = useBaseUrl(href, {forcePrependBaseUrl: true}); const normalizedHref = useBaseUrl(href, {forcePrependBaseUrl: true});
return ( return (
<Link <Link
{...(href {...(href
@ -43,7 +41,7 @@ function NavLink({
: { : {
isNavLink: true, isNavLink: true,
activeClassName, activeClassName,
to: toUrl, to,
...(activeBasePath || activeBaseRegex ...(activeBasePath || activeBaseRegex
? { ? {
isActive: (_match, location) => isActive: (_match, location) =>

View file

@ -11,6 +11,7 @@ import {NavLink, Link as RRLink} from 'react-router-dom';
import isInternalUrl from './isInternalUrl'; import isInternalUrl from './isInternalUrl';
import ExecutionEnvironment from './ExecutionEnvironment'; import ExecutionEnvironment from './ExecutionEnvironment';
import {useLinksCollector} from '../LinksCollector'; import {useLinksCollector} from '../LinksCollector';
import {useBaseUrlUtils} from './useBaseUrl';
declare global { declare global {
interface Window { interface Window {
@ -21,15 +22,37 @@ declare global {
interface Props { interface Props {
readonly isNavLink?: boolean; readonly isNavLink?: boolean;
readonly to?: string; readonly to?: string;
readonly activeClassName?: string;
readonly href?: string; readonly href?: string;
readonly activeClassName?: string;
readonly children?: ReactNode; readonly children?: ReactNode;
// escape hatch in case broken links check is annoying for a specific link
readonly 'data-noBrokenLinkCheck'?: boolean;
} }
function Link({isNavLink, activeClassName, ...props}: Props): JSX.Element { function Link({
isNavLink,
to,
href,
activeClassName,
'data-noBrokenLinkCheck': noBrokenLinkCheck,
...props
}: Props): JSX.Element {
const {withBaseUrl} = useBaseUrlUtils();
const linksCollector = useLinksCollector(); const linksCollector = useLinksCollector();
const {to, href} = props;
const targetLink = to || href; // IMPORTANT: using to or href should not change anything
// For example, MDX links will ALWAYS give us the href props
// Using one prop or the other should not be used to distinguish
// internal links (/docs/myDoc) from external links (https://github.com)
const targetLinkUnprefixed = to || href;
// Automatically apply base url in links
const targetLink =
typeof targetLinkUnprefixed !== 'undefined'
? withBaseUrl(targetLinkUnprefixed)
: undefined;
const isInternal = isInternalUrl(targetLink); const isInternal = isInternalUrl(targetLink);
const preloaded = useRef(false); const preloaded = useRef(false);
const LinkComponent = isNavLink ? NavLink : RRLink; const LinkComponent = isNavLink ? NavLink : RRLink;
@ -89,10 +112,7 @@ function Link({isNavLink, activeClassName, ...props}: Props): JSX.Element {
const isAnchorLink = targetLink?.startsWith('#') ?? false; const isAnchorLink = targetLink?.startsWith('#') ?? false;
const isRegularHtmlLink = !targetLink || !isInternal || isAnchorLink; const isRegularHtmlLink = !targetLink || !isInternal || isAnchorLink;
if (targetLink && isInternal && !isAnchorLink) { if (targetLink && isInternal && !isAnchorLink && !noBrokenLinkCheck) {
if (targetLink && targetLink.startsWith('/http')) {
console.log('collectLink', props);
}
linksCollector.collectLink(targetLink); linksCollector.collectLink(targetLink);
} }

View file

@ -67,6 +67,8 @@ describe('useBaseUrl', () => {
expect(useBaseUrl('/hello/byebye', {absolute: true})).toEqual( expect(useBaseUrl('/hello/byebye', {absolute: true})).toEqual(
'https://v2.docusaurus.io/docusaurus/hello/byebye', 'https://v2.docusaurus.io/docusaurus/hello/byebye',
); );
expect(useBaseUrl('/docusaurus/')).toEqual('/docusaurus/');
expect(useBaseUrl('/docusaurus/hello')).toEqual('/docusaurus/hello');
}); });
}); });
@ -125,5 +127,7 @@ describe('useBaseUrlUtils().withBaseUrl()', () => {
expect(withBaseUrl('/hello/byebye', {absolute: true})).toEqual( expect(withBaseUrl('/hello/byebye', {absolute: true})).toEqual(
'https://v2.docusaurus.io/docusaurus/hello/byebye', 'https://v2.docusaurus.io/docusaurus/hello/byebye',
); );
expect(withBaseUrl('/docusaurus/')).toEqual('/docusaurus/');
expect(withBaseUrl('/docusaurus/hello')).toEqual('/docusaurus/hello');
}); });
}); });

View file

@ -6,11 +6,9 @@
*/ */
import useDocusaurusContext from './useDocusaurusContext'; import useDocusaurusContext from './useDocusaurusContext';
import isInternalUrl from './isInternalUrl'; import {hasProtocol} from './isInternalUrl';
type BaseUrlOptions = Partial<{ type BaseUrlOptions = Partial<{
// note: if the url has a protocol, we never prepend it
// (it never makes any sense to do so)
forcePrependBaseUrl: boolean; forcePrependBaseUrl: boolean;
absolute: boolean; absolute: boolean;
}>; }>;
@ -25,7 +23,8 @@ function addBaseUrl(
return url; return url;
} }
if (!isInternalUrl(url)) { // it never makes sense to add a base url to an url with a protocol
if (hasProtocol(url)) {
return url; return url;
} }
@ -33,7 +32,11 @@ function addBaseUrl(
return baseUrl + url; return baseUrl + url;
} }
const basePath = baseUrl + url.replace(/^\//, ''); // sometimes we try to add baseurl to an url that already has a baseurl
// we should avoid adding the baseurl twice
const shouldAddBaseUrl = !url.startsWith(baseUrl);
const basePath = shouldAddBaseUrl ? baseUrl + url.replace(/^\//, '') : url;
return absolute ? siteUrl + basePath : basePath; return absolute ? siteUrl + basePath : basePath;
} }

View file

@ -39,7 +39,7 @@ export default async function build(
outDir, outDir,
generatedFilesDir, generatedFilesDir,
plugins, plugins,
siteConfig: {onBrokenLinks}, siteConfig: {baseUrl, onBrokenLinks},
routes, routes,
} = props; } = props;
@ -139,7 +139,13 @@ export default async function build(
}), }),
); );
handleBrokenLinks({allCollectedLinks, routes, onBrokenLinks}); await handleBrokenLinks({
allCollectedLinks,
routes,
onBrokenLinks,
outDir,
baseUrl,
});
const relativeDir = path.relative(process.cwd(), outDir); const relativeDir = path.relative(process.cwd(), outDir);
console.log( console.log(

View file

@ -11,5 +11,6 @@ export const CONFIG_FILE_NAME = 'docusaurus.config.js';
export const GENERATED_FILES_DIR_NAME = '.docusaurus'; export const GENERATED_FILES_DIR_NAME = '.docusaurus';
export const SRC_DIR_NAME = 'src'; export const SRC_DIR_NAME = 'src';
export const STATIC_DIR_NAME = 'static'; export const STATIC_DIR_NAME = 'static';
export const STATIC_ASSETS_DIR_NAME = 'assets'; // webpack file-loader files
export const THEME_PATH = `${SRC_DIR_NAME}/theme`; export const THEME_PATH = `${SRC_DIR_NAME}/theme`;
export const DEFAULT_PORT = 3000; export const DEFAULT_PORT = 3000;

View file

@ -5,7 +5,8 @@ exports[`brokenLinks getBrokenLinksErrorMessage 1`] = `
- Page path = /docs/mySourcePage: - Page path = /docs/mySourcePage:
-> link to ./myBrokenLink (resolved as: /docs/myBrokenLink) -> link to ./myBrokenLink (resolved as: /docs/myBrokenLink)
-> link to ../otherBrokenLink (resolved as: /otherBrokenLink), -> link to ../otherBrokenLink (resolved as: /otherBrokenLink)
- Page path = /otherSourcePage: - Page path = /otherSourcePage:
-> link to /badLink -> link to /badLink

View file

@ -8,8 +8,10 @@
import {matchRoutes, RouteConfig as RRRouteConfig} from 'react-router-config'; import {matchRoutes, RouteConfig as RRRouteConfig} from 'react-router-config';
import resolvePathname from 'resolve-pathname'; import resolvePathname from 'resolve-pathname';
import chalk from 'chalk'; import chalk from 'chalk';
import fs from 'fs-extra';
import {mapValues, pickBy, flatMap} from 'lodash'; import {mapValues, pickBy, flatMap} from 'lodash';
import {RouteConfig, OnBrokenLinks} from '@docusaurus/types'; import {RouteConfig, OnBrokenLinks} from '@docusaurus/types';
import {removePrefix} from '@docusaurus/utils';
function toReactRouterRoutes(routes: RouteConfig[]): RRRouteConfig[] { function toReactRouterRoutes(routes: RouteConfig[]): RRRouteConfig[] {
// @ts-expect-error: types incompatible??? // @ts-expect-error: types incompatible???
@ -107,37 +109,79 @@ export function getBrokenLinksErrorMessage(
return ( return (
`Broken links found!` + `Broken links found!` +
`${Object.entries(allBrokenLinks).map(([pagePath, brokenLinks]) => `${Object.entries(allBrokenLinks)
pageBrokenLinksMessage(pagePath, brokenLinks), .map(([pagePath, brokenLinks]) =>
)} pageBrokenLinksMessage(pagePath, brokenLinks),
)
.join('\n')}
` `
); );
} }
export function handleBrokenLinks({ // If a file actually exist on the file system, we know the link is valid
// even if docusaurus does not know about this file, so we don't report it
async function filterExistingFileLinks({
baseUrl,
outDir,
allCollectedLinks,
}: {
baseUrl: string;
outDir: string;
allCollectedLinks: Record<string, string[]>;
}): Promise<Record<string, string[]>> {
// not easy to make this async :'(
function linkFileDoesNotExist(link: string): boolean {
const filePath = `${outDir}/${removePrefix(link, baseUrl)}`;
const exists = fs.existsSync(filePath);
return !exists;
}
return mapValues(allCollectedLinks, (links) => {
return links.filter(linkFileDoesNotExist);
});
}
export async function handleBrokenLinks({
allCollectedLinks, allCollectedLinks,
onBrokenLinks, onBrokenLinks,
routes, routes,
baseUrl,
outDir,
}: { }: {
allCollectedLinks: Record<string, string[]>; allCollectedLinks: Record<string, string[]>;
onBrokenLinks: OnBrokenLinks; onBrokenLinks: OnBrokenLinks;
routes: RouteConfig[]; routes: RouteConfig[];
baseUrl: string;
outDir: string;
}) { }) {
if (onBrokenLinks === 'ignore') { if (onBrokenLinks === 'ignore') {
return; return;
} }
const allBrokenLinks = getAllBrokenLinks({allCollectedLinks, routes});
// If we link to a file like /myFile.zip, and the file actually exist for the file system
// it is not a broken link, it may simply be a link to an existing static file...
const allCollectedLinksFiltered = await filterExistingFileLinks({
allCollectedLinks,
baseUrl,
outDir,
});
const allBrokenLinks = getAllBrokenLinks({
allCollectedLinks: allCollectedLinksFiltered,
routes,
});
const errorMessage = getBrokenLinksErrorMessage(allBrokenLinks); const errorMessage = getBrokenLinksErrorMessage(allBrokenLinks);
if (errorMessage) { if (errorMessage) {
const finalMessage = `${errorMessage}\nNote: it's possible to ignore broken links with the 'onBrokenLinks' Docusaurus configuration.\n\n`;
// Useful to ensure the CI fails in case of broken link // Useful to ensure the CI fails in case of broken link
if (onBrokenLinks === 'throw') { if (onBrokenLinks === 'throw') {
throw new Error( throw new Error(finalMessage);
`${errorMessage}\nNote: it's possible to ignore broken links with the 'onBrokenLinks' Docusaurus configuration.`,
);
} else if (onBrokenLinks === 'error') { } else if (onBrokenLinks === 'error') {
console.error(chalk.red(errorMessage)); console.error(chalk.red(finalMessage));
} else if (onBrokenLinks === 'log') { } else if (onBrokenLinks === 'log') {
console.log(chalk.blue(errorMessage)); console.log(chalk.blue(finalMessage));
} else { } else {
throw new Error(`unexpected onBrokenLinks value=${onBrokenLinks}`); throw new Error(`unexpected onBrokenLinks value=${onBrokenLinks}`);
} }

View file

@ -12,6 +12,7 @@ import webpack, {Configuration, Loader, RuleSetRule, Stats} from 'webpack';
import {TransformOptions} from '@babel/core'; import {TransformOptions} from '@babel/core';
import {ConfigureWebpackFn} from '@docusaurus/types'; import {ConfigureWebpackFn} from '@docusaurus/types';
import {version as cacheLoaderVersion} from 'cache-loader/package.json'; import {version as cacheLoaderVersion} from 'cache-loader/package.json';
import {STATIC_ASSETS_DIR_NAME} from '../constants';
// Utility method to get style loaders // Utility method to get style loaders
export function getStyleLoaders( export function getStyleLoaders(
@ -174,14 +175,12 @@ export function compile(config: Configuration[]): Promise<void> {
// Inspired by https://github.com/gatsbyjs/gatsby/blob/8e6e021014da310b9cc7d02e58c9b3efe938c665/packages/gatsby/src/utils/webpack-utils.ts#L447 // Inspired by https://github.com/gatsbyjs/gatsby/blob/8e6e021014da310b9cc7d02e58c9b3efe938c665/packages/gatsby/src/utils/webpack-utils.ts#L447
export function getFileLoaderUtils() { export function getFileLoaderUtils() {
const assetsRelativeRoot = 'assets/';
const loaders = { const loaders = {
file: (options = {}) => { file: (options = {}) => {
return { return {
loader: require.resolve(`file-loader`), loader: require.resolve(`file-loader`),
options: { options: {
name: `${assetsRelativeRoot}[name]-[hash].[ext]`, name: `${STATIC_ASSETS_DIR_NAME}/[name]-[hash].[ext]`,
...options, ...options,
}, },
}; };
@ -191,7 +190,7 @@ export function getFileLoaderUtils() {
loader: require.resolve(`url-loader`), loader: require.resolve(`url-loader`),
options: { options: {
limit: 10000, limit: 10000,
name: `${assetsRelativeRoot}[name]-[hash].[ext]`, name: `${STATIC_ASSETS_DIR_NAME}[name]-[hash].[ext]`,
fallback: require.resolve(`file-loader`), fallback: require.resolve(`file-loader`),
...options, ...options,
}, },

View file

@ -964,6 +964,7 @@ or
![](./assets/docusaurus-asset-example-banner.png) ![](./assets/docusaurus-asset-example-banner.png)
``` ```
The ES imports syntax also works: The ES imports syntax also works:
```mdx ```mdx

View file

@ -47,4 +47,4 @@ For themes that supports TypeScript theme components, you can add the `--typescr
npm run swizzle @docusaurus/theme-classic Footer --typescript npm run swizzle @docusaurus/theme-classic Footer --typescript
``` ```
At this moment, the only official Docusaurus theme that supports TypeScript theme components is `@docusaurus/theme-classic`. If you are a Docusaurus theme package author who wants to add TypeScript support, see the [Lifecycle APIs docs](./lifecycle-apis#gettypescriptthemepath). At this moment, the only official Docusaurus theme that supports TypeScript theme components is `@docusaurus/theme-classic`. If you are a Docusaurus theme package author who wants to add TypeScript support, see the [Lifecycle APIs docs](./lifecycle-apis.md#gettypescriptthemepath).

View file

@ -61,7 +61,7 @@ npm run docusaurus docs:version 1.1.0
When tagging a new version, the document versioning mechanism will: When tagging a new version, the document versioning mechanism will:
- Copy the full `docs/` folder contents into a new `versioned_docs/version-<version>/` folder. - Copy the full `docs/` folder contents into a new `versioned_docs/version-<version>/` folder.
- Create a versioned sidebars file based from your current [sidebar](sidebar.md) configuration (if it exists) - saved as `versioned_sidebars/version-<version>-sidebars.json`. - 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`. - Append the new version number to `versions.json`.
## Files ## Files

View file

@ -14,12 +14,14 @@ const allDocHomesPaths = [
...versions.slice(1).map((version) => `/docs/${version}/`), ...versions.slice(1).map((version) => `/docs/${version}/`),
]; ];
const baseUrl = process.env.BASE_URL || '/';
module.exports = { module.exports = {
title: 'Docusaurus', title: 'Docusaurus',
tagline: 'Build optimized websites quickly, focus on your content', tagline: 'Build optimized websites quickly, focus on your content',
organizationName: 'facebook', organizationName: 'facebook',
projectName: 'docusaurus', projectName: 'docusaurus',
baseUrl: '/', baseUrl,
url: 'https://v2.docusaurus.io', url: 'https://v2.docusaurus.io',
onBrokenLinks: 'throw', onBrokenLinks: 'throw',
favicon: 'img/docusaurus.ico', favicon: 'img/docusaurus.ico',
@ -189,7 +191,7 @@ module.exports = {
activeBaseRegex: `docs/next/(support|team|resources)`, activeBaseRegex: `docs/next/(support|team|resources)`,
}, },
{ {
to: 'versions', to: '/versions',
label: 'All versions', label: 'All versions',
position: 'right', position: 'right',
}, },

View file

@ -63,7 +63,7 @@ npm run docusaurus docs:version 1.1.0
When tagging a new version, the document versioning mechanism will: When tagging a new version, the document versioning mechanism will:
- Copy the full `docs/` folder contents into a new `versioned_docs/version-<version>/` folder. - Copy the full `docs/` folder contents into a new `versioned_docs/version-<version>/` folder.
- Create a versioned sidebars file based from your current [sidebar](sidebar.md) configuration (if it exists). Saved it as `versioned_sidebars/version-<version>-sidebars.json`. - Create a versioned sidebars file based from your current sidebar configuration (if it exists). Saved it as `versioned_sidebars/version-<version>-sidebars.json`.
- Append the new version number into `versions.json`. - Append the new version number into `versions.json`.
## Files ## Files

View file

@ -61,7 +61,7 @@ npm run docusaurus docs:version 1.1.0
When tagging a new version, the document versioning mechanism will: When tagging a new version, the document versioning mechanism will:
- Copy the full `docs/` folder contents into a new `versioned_docs/version-<version>/` folder. - Copy the full `docs/` folder contents into a new `versioned_docs/version-<version>/` folder.
- Create a versioned sidebars file based from your current [sidebar](sidebar.md) configuration (if it exists). Saved it as `versioned_sidebars/version-<version>-sidebars.json`. - Create a versioned sidebars file based from your current [sidebar](docs.md#sidebar) configuration (if it exists). Saved it as `versioned_sidebars/version-<version>-sidebars.json`.
- Append the new version number into `versions.json`. - Append the new version number into `versions.json`.
## Files ## Files

View file

@ -61,7 +61,7 @@ npm run docusaurus docs:version 1.1.0
When tagging a new version, the document versioning mechanism will: When tagging a new version, the document versioning mechanism will:
- Copy the full `docs/` folder contents into a new `versioned_docs/version-<version>/` folder. - Copy the full `docs/` folder contents into a new `versioned_docs/version-<version>/` folder.
- Create a versioned sidebars file based from your current [sidebar](sidebar.md) configuration (if it exists) - saved as `versioned_sidebars/version-<version>-sidebars.json`. - 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`. - Append the new version number to `versions.json`.
## Files ## Files

View file

@ -61,7 +61,7 @@ npm run docusaurus docs:version 1.1.0
When tagging a new version, the document versioning mechanism will: When tagging a new version, the document versioning mechanism will:
- Copy the full `docs/` folder contents into a new `versioned_docs/version-<version>/` folder. - Copy the full `docs/` folder contents into a new `versioned_docs/version-<version>/` folder.
- Create a versioned sidebars file based from your current [sidebar](sidebar.md) configuration (if it exists) - saved as `versioned_sidebars/version-<version>-sidebars.json`. - 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`. - Append the new version number to `versions.json`.
## Files ## Files

View file

@ -61,7 +61,7 @@ npm run docusaurus docs:version 1.1.0
When tagging a new version, the document versioning mechanism will: When tagging a new version, the document versioning mechanism will:
- Copy the full `docs/` folder contents into a new `versioned_docs/version-<version>/` folder. - Copy the full `docs/` folder contents into a new `versioned_docs/version-<version>/` folder.
- Create a versioned sidebars file based from your current [sidebar](sidebar.md) configuration (if it exists) - saved as `versioned_sidebars/version-<version>-sidebars.json`. - 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`. - Append the new version number to `versions.json`.
## Files ## Files

View file

@ -61,7 +61,7 @@ npm run docusaurus docs:version 1.1.0
When tagging a new version, the document versioning mechanism will: When tagging a new version, the document versioning mechanism will:
- Copy the full `docs/` folder contents into a new `versioned_docs/version-<version>/` folder. - Copy the full `docs/` folder contents into a new `versioned_docs/version-<version>/` folder.
- Create a versioned sidebars file based from your current [sidebar](sidebar.md) configuration (if it exists) - saved as `versioned_sidebars/version-<version>-sidebars.json`. - 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`. - Append the new version number to `versions.json`.
## Files ## Files

2557
yarn.lock

File diff suppressed because it is too large Load diff