mirror of
https://github.com/facebook/docusaurus.git
synced 2025-07-28 14:08:21 +02:00
feat(v2): polyfill automatically depending on browserslist (#1857)
* feat(v2): polyfill corejs and ie11 compat * use corejs/stable * useBuiltIns => usage instead of entry * chngelo * nits * breaking: withBaseUrl -> useBaseUrl * nits * loose mode for faster perf and smaller bundle
This commit is contained in:
parent
ee936f62b5
commit
abdc647b07
18 changed files with 181 additions and 163 deletions
|
@ -8,6 +8,9 @@
|
||||||
- Fix `swizzle` command not being able to swizzle single js file.
|
- Fix `swizzle` command not being able to swizzle single js file.
|
||||||
- Fix logo URL in footer to be appended with baseUrl automatically.
|
- Fix logo URL in footer to be appended with baseUrl automatically.
|
||||||
- Add the option `--no-open` for `start` command.
|
- Add the option `--no-open` for `start` command.
|
||||||
|
- Set `@babel/env` useBuiltins to `usage`. This will automatically use browserlist and import polyfills required.
|
||||||
|
- Modified TerserWebpackPlugin `terserOptions` for better cross-browser compatibility.
|
||||||
|
- **BREAKING** `withBaseUrl` is renamed to `useBaseUrl` because its a React Hooks. Make sure you import/rename it correctly. Eg: `import useBaseUrl from '@docusaurus/useBaseUrl`;
|
||||||
- Fix potential security vulnerability because we're exposing the directory structure of the host machine.
|
- Fix potential security vulnerability because we're exposing the directory structure of the host machine.
|
||||||
|
|
||||||
## 2.0.0-alpha.27
|
## 2.0.0-alpha.27
|
||||||
|
|
|
@ -10,7 +10,7 @@ import classnames from 'classnames';
|
||||||
import Layout from '@theme/Layout';
|
import Layout from '@theme/Layout';
|
||||||
import Link from '@docusaurus/Link';
|
import Link from '@docusaurus/Link';
|
||||||
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
|
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
|
||||||
import withBaseUrl from '@docusaurus/withBaseUrl';
|
import useBaseUrl from '@docusaurus/useBaseUrl';
|
||||||
import styles from './styles.module.css';
|
import styles from './styles.module.css';
|
||||||
|
|
||||||
const features = [
|
const features = [
|
||||||
|
@ -46,6 +46,21 @@ const features = [
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
function Feature({imageUrl, title, description}) {
|
||||||
|
const imgUrl = useBaseUrl(imageUrl);
|
||||||
|
return (
|
||||||
|
<div className={classnames('col col--4', styles.feature)}>
|
||||||
|
{imgUrl && (
|
||||||
|
<div className="text--center">
|
||||||
|
<img className={styles.featureImage} src={imgUrl} alt={title} />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<h3>{title}</h3>
|
||||||
|
<p>{description}</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function Home() {
|
function Home() {
|
||||||
const context = useDocusaurusContext();
|
const context = useDocusaurusContext();
|
||||||
const {siteConfig = {}} = context;
|
const {siteConfig = {}} = context;
|
||||||
|
@ -63,7 +78,7 @@ function Home() {
|
||||||
'button button--outline button--secondary button--lg',
|
'button button--outline button--secondary button--lg',
|
||||||
styles.getStarted,
|
styles.getStarted,
|
||||||
)}
|
)}
|
||||||
to={withBaseUrl('docs/doc1')}>
|
to={useBaseUrl('docs/doc1')}>
|
||||||
Get Started
|
Get Started
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
|
@ -74,22 +89,8 @@ function Home() {
|
||||||
<section className={styles.features}>
|
<section className={styles.features}>
|
||||||
<div className="container">
|
<div className="container">
|
||||||
<div className="row">
|
<div className="row">
|
||||||
{features.map(({imageUrl, title, description}, idx) => (
|
{features.map((props, idx) => (
|
||||||
<div
|
<Feature key={idx} {...props} />
|
||||||
key={idx}
|
|
||||||
className={classnames('col col--4', styles.feature)}>
|
|
||||||
{imageUrl && (
|
|
||||||
<div className="text--center">
|
|
||||||
<img
|
|
||||||
className={styles.featureImage}
|
|
||||||
src={withBaseUrl(imageUrl)}
|
|
||||||
alt={title}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
<h3>{title}</h3>
|
|
||||||
<p>{description}</p>
|
|
||||||
</div>
|
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -9,7 +9,7 @@ import React from 'react';
|
||||||
|
|
||||||
import Head from '@docusaurus/Head';
|
import Head from '@docusaurus/Head';
|
||||||
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
|
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
|
||||||
import withBaseUrl from '@docusaurus/withBaseUrl';
|
import useBaseUrl from '@docusaurus/useBaseUrl';
|
||||||
import DocPaginator from '@theme/DocPaginator';
|
import DocPaginator from '@theme/DocPaginator';
|
||||||
|
|
||||||
import styles from './styles.module.css';
|
import styles from './styles.module.css';
|
||||||
|
@ -45,6 +45,8 @@ function DocItem(props) {
|
||||||
keywords,
|
keywords,
|
||||||
} = metadata;
|
} = metadata;
|
||||||
|
|
||||||
|
const metaImageUrl = siteUrl + useBaseUrl(metaImage);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Head>
|
<Head>
|
||||||
|
@ -56,18 +58,8 @@ function DocItem(props) {
|
||||||
{keywords && keywords.length && (
|
{keywords && keywords.length && (
|
||||||
<meta name="keywords" content={keywords.join(',')} />
|
<meta name="keywords" content={keywords.join(',')} />
|
||||||
)}
|
)}
|
||||||
{metaImage && (
|
{metaImage && <meta property="og:image" content={metaImageUrl} />}
|
||||||
<meta
|
{metaImage && <meta property="twitter:image" content={metaImageUrl} />}
|
||||||
property="og:image"
|
|
||||||
content={siteUrl + withBaseUrl(metaImage)}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{metaImage && (
|
|
||||||
<meta
|
|
||||||
property="twitter:image"
|
|
||||||
content={siteUrl + withBaseUrl(metaImage)}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{metaImage && (
|
{metaImage && (
|
||||||
<meta name="twitter:image:alt" content={`Image for ${title}`} />
|
<meta name="twitter:image:alt" content={`Image for ${title}`} />
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -10,7 +10,27 @@ import classnames from 'classnames';
|
||||||
|
|
||||||
import Link from '@docusaurus/Link';
|
import Link from '@docusaurus/Link';
|
||||||
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
|
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
|
||||||
import withBaseUrl from '@docusaurus/withBaseUrl';
|
import useBaseUrl from '@docusaurus/useBaseUrl';
|
||||||
|
|
||||||
|
function FooterLink({item}) {
|
||||||
|
const toUrl = useBaseUrl(item.to);
|
||||||
|
return (
|
||||||
|
<Link
|
||||||
|
className="footer__link-item"
|
||||||
|
{...item}
|
||||||
|
{...(item.href
|
||||||
|
? {
|
||||||
|
target: '_blank',
|
||||||
|
rel: 'noopener noreferrer',
|
||||||
|
href: item.href,
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
to: toUrl,
|
||||||
|
})}>
|
||||||
|
{item.label}
|
||||||
|
</Link>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function Footer() {
|
function Footer() {
|
||||||
const context = useDocusaurusContext();
|
const context = useDocusaurusContext();
|
||||||
|
@ -18,12 +38,13 @@ function Footer() {
|
||||||
const {themeConfig = {}} = siteConfig;
|
const {themeConfig = {}} = siteConfig;
|
||||||
const {footer} = themeConfig;
|
const {footer} = themeConfig;
|
||||||
|
|
||||||
|
const {copyright, links = [], logo = {}} = footer || {};
|
||||||
|
const logoUrl = useBaseUrl(logo.src);
|
||||||
|
|
||||||
if (!footer) {
|
if (!footer) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const {copyright, links = [], logo} = footer;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<footer
|
<footer
|
||||||
className={classnames('footer', {
|
className={classnames('footer', {
|
||||||
|
@ -43,20 +64,7 @@ function Footer() {
|
||||||
<ul className="footer__items">
|
<ul className="footer__items">
|
||||||
{linkItem.items.map(item => (
|
{linkItem.items.map(item => (
|
||||||
<li key={item.href || item.to} className="footer__item">
|
<li key={item.href || item.to} className="footer__item">
|
||||||
<Link
|
<FooterLink item={item} />
|
||||||
className="footer__link-item"
|
|
||||||
{...item}
|
|
||||||
{...(item.href
|
|
||||||
? {
|
|
||||||
target: '_blank',
|
|
||||||
rel: 'noopener noreferrer',
|
|
||||||
href: item.href,
|
|
||||||
}
|
|
||||||
: {
|
|
||||||
to: withBaseUrl(item.to),
|
|
||||||
})}>
|
|
||||||
{item.label}
|
|
||||||
</Link>
|
|
||||||
</li>
|
</li>
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
|
@ -69,11 +77,7 @@ function Footer() {
|
||||||
<div className="text--center">
|
<div className="text--center">
|
||||||
{logo && logo.src && (
|
{logo && logo.src && (
|
||||||
<div className="margin-bottom--sm">
|
<div className="margin-bottom--sm">
|
||||||
<img
|
<img className="footer__logo" alt={logo.alt} src={logoUrl} />
|
||||||
className="footer__logo"
|
|
||||||
alt={logo.alt}
|
|
||||||
src={withBaseUrl(logo.src)}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{copyright}
|
{copyright}
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Head from '@docusaurus/Head';
|
import Head from '@docusaurus/Head';
|
||||||
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
|
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
|
||||||
import withBaseUrl from '@docusaurus/withBaseUrl';
|
import useBaseUrl from '@docusaurus/useBaseUrl';
|
||||||
import Navbar from '@theme/Navbar';
|
import Navbar from '@theme/Navbar';
|
||||||
import Footer from '@theme/Footer';
|
import Footer from '@theme/Footer';
|
||||||
|
|
||||||
|
@ -34,6 +34,8 @@ function Layout(props) {
|
||||||
} = props;
|
} = props;
|
||||||
const metaTitle = title || `${defaultTitle} · ${tagline}`;
|
const metaTitle = title || `${defaultTitle} · ${tagline}`;
|
||||||
const metaImage = image || defaultImage;
|
const metaImage = image || defaultImage;
|
||||||
|
const metaImageUrl = siteUrl + useBaseUrl(metaImage);
|
||||||
|
const faviconUrl = useBaseUrl(favicon);
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<Head>
|
<Head>
|
||||||
|
@ -42,7 +44,7 @@ function Layout(props) {
|
||||||
<meta name="viewport" content="width=device-width" />
|
<meta name="viewport" content="width=device-width" />
|
||||||
{metaTitle && <title>{metaTitle}</title>}
|
{metaTitle && <title>{metaTitle}</title>}
|
||||||
{metaTitle && <meta property="og:title" content={metaTitle} />}
|
{metaTitle && <meta property="og:title" content={metaTitle} />}
|
||||||
{favicon && <link rel="shortcut icon" href={withBaseUrl(favicon)} />}
|
{favicon && <link rel="shortcut icon" href={faviconUrl} />}
|
||||||
{description && <meta name="description" content={description} />}
|
{description && <meta name="description" content={description} />}
|
||||||
{description && (
|
{description && (
|
||||||
<meta property="og:description" content={description} />
|
<meta property="og:description" content={description} />
|
||||||
|
@ -50,18 +52,8 @@ function Layout(props) {
|
||||||
{keywords && keywords.length && (
|
{keywords && keywords.length && (
|
||||||
<meta name="keywords" content={keywords.join(',')} />
|
<meta name="keywords" content={keywords.join(',')} />
|
||||||
)}
|
)}
|
||||||
{metaImage && (
|
{metaImage && <meta property="og:image" content={metaImageUrl} />}
|
||||||
<meta
|
{metaImage && <meta property="twitter:image" content={metaImageUrl} />}
|
||||||
property="og:image"
|
|
||||||
content={siteUrl + withBaseUrl(metaImage)}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{metaImage && (
|
|
||||||
<meta
|
|
||||||
property="twitter:image"
|
|
||||||
content={siteUrl + withBaseUrl(metaImage)}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{metaImage && (
|
{metaImage && (
|
||||||
<meta name="twitter:image:alt" content={`Image for ${metaTitle}`} />
|
<meta name="twitter:image:alt" content={`Image for ${metaTitle}`} />
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -11,7 +11,7 @@ import Toggle from 'react-toggle';
|
||||||
import Link from '@docusaurus/Link';
|
import Link from '@docusaurus/Link';
|
||||||
import Head from '@docusaurus/Head';
|
import Head from '@docusaurus/Head';
|
||||||
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
|
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
|
||||||
import withBaseUrl from '@docusaurus/withBaseUrl';
|
import useBaseUrl from '@docusaurus/useBaseUrl';
|
||||||
|
|
||||||
import SearchBar from '@theme/SearchBar';
|
import SearchBar from '@theme/SearchBar';
|
||||||
|
|
||||||
|
@ -20,6 +20,7 @@ import classnames from 'classnames';
|
||||||
import styles from './styles.module.css';
|
import styles from './styles.module.css';
|
||||||
|
|
||||||
function NavLink(props) {
|
function NavLink(props) {
|
||||||
|
const toUrl = useBaseUrl(props.to);
|
||||||
return (
|
return (
|
||||||
<Link
|
<Link
|
||||||
className="navbar__item navbar__link"
|
className="navbar__item navbar__link"
|
||||||
|
@ -32,7 +33,7 @@ function NavLink(props) {
|
||||||
}
|
}
|
||||||
: {
|
: {
|
||||||
activeClassName: 'navbar__link--active',
|
activeClassName: 'navbar__link--active',
|
||||||
to: withBaseUrl(props.to),
|
to: toUrl,
|
||||||
})}>
|
})}>
|
||||||
{props.label}
|
{props.label}
|
||||||
</Link>
|
</Link>
|
||||||
|
@ -54,7 +55,7 @@ function Navbar() {
|
||||||
const {siteConfig = {}} = context;
|
const {siteConfig = {}} = context;
|
||||||
const {baseUrl, themeConfig = {}} = siteConfig;
|
const {baseUrl, themeConfig = {}} = siteConfig;
|
||||||
const {algolia, navbar = {}} = themeConfig;
|
const {algolia, navbar = {}} = themeConfig;
|
||||||
const {title, logo, links = []} = navbar;
|
const {title, logo = {}, links = []} = navbar;
|
||||||
|
|
||||||
const showSidebar = useCallback(() => {
|
const showSidebar = useCallback(() => {
|
||||||
setSidebarShown(true);
|
setSidebarShown(true);
|
||||||
|
@ -82,6 +83,7 @@ function Navbar() {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const logoUrl = useBaseUrl(logo.src);
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<Head>
|
<Head>
|
||||||
|
@ -120,11 +122,7 @@ function Navbar() {
|
||||||
</div>
|
</div>
|
||||||
<Link className="navbar__brand" to={baseUrl}>
|
<Link className="navbar__brand" to={baseUrl}>
|
||||||
{logo != null && (
|
{logo != null && (
|
||||||
<img
|
<img className="navbar__logo" src={logoUrl} alt={logo.alt} />
|
||||||
className="navbar__logo"
|
|
||||||
src={withBaseUrl(logo.src)}
|
|
||||||
alt={logo.alt}
|
|
||||||
/>
|
|
||||||
)}
|
)}
|
||||||
{title != null && (
|
{title != null && (
|
||||||
<strong
|
<strong
|
||||||
|
@ -176,11 +174,7 @@ function Navbar() {
|
||||||
<div className="navbar__sidebar__brand">
|
<div className="navbar__sidebar__brand">
|
||||||
<Link className="navbar__brand" onClick={hideSidebar} to={baseUrl}>
|
<Link className="navbar__brand" onClick={hideSidebar} to={baseUrl}>
|
||||||
{logo != null && (
|
{logo != null && (
|
||||||
<img
|
<img className="navbar__logo" src={logoUrl} alt={logo.alt} />
|
||||||
className="navbar__logo"
|
|
||||||
src={withBaseUrl(logo.src)}
|
|
||||||
alt={logo.alt}
|
|
||||||
/>
|
|
||||||
)}
|
)}
|
||||||
{title != null && <strong>{title}</strong>}
|
{title != null && <strong>{title}</strong>}
|
||||||
</Link>
|
</Link>
|
||||||
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2017-present, Facebook, Inc.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import useBaseUrl from '../useBaseUrl';
|
||||||
|
import useDocusaurusContext from '../useDocusaurusContext';
|
||||||
|
jest.mock('../useDocusaurusContext', () => jest.fn(), {virtual: true});
|
||||||
|
|
||||||
|
const mockedContext = <jest.Mock>useDocusaurusContext;
|
||||||
|
|
||||||
|
describe('useBaseUrl', () => {
|
||||||
|
test('empty base URL', () => {
|
||||||
|
mockedContext.mockImplementation(() => ({
|
||||||
|
siteConfig: {
|
||||||
|
baseUrl: '/',
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
expect(useBaseUrl('hello')).toEqual('/hello');
|
||||||
|
expect(useBaseUrl('/hello')).toEqual('/hello');
|
||||||
|
expect(useBaseUrl('hello/')).toEqual('/hello/');
|
||||||
|
expect(useBaseUrl('/hello/')).toEqual('/hello/');
|
||||||
|
expect(useBaseUrl('hello/byebye')).toEqual('/hello/byebye');
|
||||||
|
expect(useBaseUrl('/hello/byebye')).toEqual('/hello/byebye');
|
||||||
|
expect(useBaseUrl('hello/byebye/')).toEqual('/hello/byebye/');
|
||||||
|
expect(useBaseUrl('/hello/byebye/')).toEqual('/hello/byebye/');
|
||||||
|
expect(useBaseUrl('https://github.com')).toEqual('https://github.com');
|
||||||
|
expect(useBaseUrl('//reactjs.org')).toEqual('//reactjs.org');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('non-empty base URL', () => {
|
||||||
|
mockedContext.mockImplementation(() => ({
|
||||||
|
siteConfig: {
|
||||||
|
baseUrl: '/docusaurus/',
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
expect(useBaseUrl('hello')).toEqual('/docusaurus/hello');
|
||||||
|
expect(useBaseUrl('/hello')).toEqual('/docusaurus/hello');
|
||||||
|
expect(useBaseUrl('hello/')).toEqual('/docusaurus/hello/');
|
||||||
|
expect(useBaseUrl('/hello/')).toEqual('/docusaurus/hello/');
|
||||||
|
expect(useBaseUrl('hello/byebye')).toEqual('/docusaurus/hello/byebye');
|
||||||
|
expect(useBaseUrl('/hello/byebye')).toEqual('/docusaurus/hello/byebye');
|
||||||
|
expect(useBaseUrl('hello/byebye/')).toEqual('/docusaurus/hello/byebye/');
|
||||||
|
expect(useBaseUrl('/hello/byebye/')).toEqual('/docusaurus/hello/byebye/');
|
||||||
|
expect(useBaseUrl('https://github.com')).toEqual('https://github.com');
|
||||||
|
expect(useBaseUrl('//reactjs.org')).toEqual('//reactjs.org');
|
||||||
|
});
|
||||||
|
});
|
|
@ -1,52 +0,0 @@
|
||||||
/**
|
|
||||||
* Copyright (c) 2017-present, Facebook, Inc.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the MIT license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import withBaseUrl from '../withBaseUrl';
|
|
||||||
import useDocusaurusContext from '../useDocusaurusContext';
|
|
||||||
jest.mock('../useDocusaurusContext', () => jest.fn(), {virtual: true});
|
|
||||||
|
|
||||||
const mockedContext = <jest.Mock>useDocusaurusContext;
|
|
||||||
|
|
||||||
describe('withBaseUrl', () => {
|
|
||||||
test('empty base URL', () => {
|
|
||||||
mockedContext.mockImplementation(() => ({
|
|
||||||
siteConfig: {
|
|
||||||
baseUrl: '/',
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
expect(withBaseUrl('hello')).toEqual('/hello');
|
|
||||||
expect(withBaseUrl('/hello')).toEqual('/hello');
|
|
||||||
expect(withBaseUrl('hello/')).toEqual('/hello/');
|
|
||||||
expect(withBaseUrl('/hello/')).toEqual('/hello/');
|
|
||||||
expect(withBaseUrl('hello/byebye')).toEqual('/hello/byebye');
|
|
||||||
expect(withBaseUrl('/hello/byebye')).toEqual('/hello/byebye');
|
|
||||||
expect(withBaseUrl('hello/byebye/')).toEqual('/hello/byebye/');
|
|
||||||
expect(withBaseUrl('/hello/byebye/')).toEqual('/hello/byebye/');
|
|
||||||
expect(withBaseUrl('https://github.com')).toEqual('https://github.com');
|
|
||||||
expect(withBaseUrl('//reactjs.org')).toEqual('//reactjs.org');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('non-empty base URL', () => {
|
|
||||||
mockedContext.mockImplementation(() => ({
|
|
||||||
siteConfig: {
|
|
||||||
baseUrl: '/docusaurus/',
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
expect(withBaseUrl('hello')).toEqual('/docusaurus/hello');
|
|
||||||
expect(withBaseUrl('/hello')).toEqual('/docusaurus/hello');
|
|
||||||
expect(withBaseUrl('hello/')).toEqual('/docusaurus/hello/');
|
|
||||||
expect(withBaseUrl('/hello/')).toEqual('/docusaurus/hello/');
|
|
||||||
expect(withBaseUrl('hello/byebye')).toEqual('/docusaurus/hello/byebye');
|
|
||||||
expect(withBaseUrl('/hello/byebye')).toEqual('/docusaurus/hello/byebye');
|
|
||||||
expect(withBaseUrl('hello/byebye/')).toEqual('/docusaurus/hello/byebye/');
|
|
||||||
expect(withBaseUrl('/hello/byebye/')).toEqual('/docusaurus/hello/byebye/');
|
|
||||||
expect(withBaseUrl('https://github.com')).toEqual('https://github.com');
|
|
||||||
expect(withBaseUrl('//reactjs.org')).toEqual('//reactjs.org');
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -5,7 +5,6 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import * as React from 'react';
|
import React from 'react';
|
||||||
import {DocusaurusContext} from '@docusaurus/types';
|
|
||||||
|
|
||||||
export default React.createContext<DocusaurusContext>({});
|
export default React.createContext({});
|
|
@ -7,10 +7,14 @@
|
||||||
|
|
||||||
import useDocusaurusContext from './useDocusaurusContext';
|
import useDocusaurusContext from './useDocusaurusContext';
|
||||||
|
|
||||||
function withBaseUrl(url: string): string {
|
export default function useBaseUrl(url) {
|
||||||
const {siteConfig} = useDocusaurusContext();
|
const {siteConfig} = useDocusaurusContext();
|
||||||
const {baseUrl = '/'} = siteConfig || {};
|
const {baseUrl = '/'} = siteConfig || {};
|
||||||
|
|
||||||
|
if (!url) {
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
const externalRegex = /^(https?:|\/\/)/;
|
const externalRegex = /^(https?:|\/\/)/;
|
||||||
if (externalRegex.test(url)) {
|
if (externalRegex.test(url)) {
|
||||||
return url;
|
return url;
|
||||||
|
@ -20,5 +24,3 @@ function withBaseUrl(url: string): string {
|
||||||
}
|
}
|
||||||
return baseUrl + url;
|
return baseUrl + url;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default withBaseUrl;
|
|
|
@ -7,9 +7,8 @@
|
||||||
|
|
||||||
import {useContext} from 'react';
|
import {useContext} from 'react';
|
||||||
import context from './context';
|
import context from './context';
|
||||||
import {DocusaurusContext} from '@docusaurus/types';
|
|
||||||
|
|
||||||
function useDocusaurusContext(): DocusaurusContext {
|
function useDocusaurusContext() {
|
||||||
return useContext(context);
|
return useContext(context);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,18 +8,19 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Head from '@docusaurus/Head';
|
import Head from '@docusaurus/Head';
|
||||||
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
|
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
|
||||||
import withBaseUrl from '@docusaurus/withBaseUrl';
|
import useBaseUrl from '@docusaurus/useBaseUrl';
|
||||||
|
|
||||||
function Layout(props) {
|
function Layout(props) {
|
||||||
const context = useDocusaurusContext();
|
const context = useDocusaurusContext();
|
||||||
const {siteConfig = {}} = context;
|
const {siteConfig = {}} = context;
|
||||||
const {favicon, tagline, title: defaultTitle} = siteConfig;
|
const {favicon, tagline, title: defaultTitle} = siteConfig;
|
||||||
const {children, title, description} = props;
|
const {children, title, description} = props;
|
||||||
|
const faviconUrl = useBaseUrl(favicon);
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<Head defaultTitle={`${defaultTitle} · ${tagline}`}>
|
<Head defaultTitle={`${defaultTitle} · ${tagline}`}>
|
||||||
{title && <title>{`${title} · ${tagline}`}</title>}
|
{title && <title>{`${title} · ${tagline}`}</title>}
|
||||||
{favicon && <link rel="shortcut icon" href={withBaseUrl(favicon)} />}
|
{favicon && <link rel="shortcut icon" href={faviconUrl} />}
|
||||||
{description && <meta name="description" content={description} />}
|
{description && <meta name="description" content={description} />}
|
||||||
{description && (
|
{description && (
|
||||||
<meta property="og:description" content={description} />
|
<meta property="og:description" content={description} />
|
||||||
|
|
|
@ -65,10 +65,27 @@ export function createBaseConfig(
|
||||||
parallel: true,
|
parallel: true,
|
||||||
sourceMap: false,
|
sourceMap: false,
|
||||||
terserOptions: {
|
terserOptions: {
|
||||||
ecma: 6,
|
parse: {
|
||||||
mangle: true,
|
// we want uglify-js to parse ecma 8 code. However, we don't want it
|
||||||
|
// to apply any minfication steps that turns valid ecma 5 code
|
||||||
|
// into invalid ecma 5 code. This is why the 'compress' and 'output'
|
||||||
|
// sections only apply transformations that are ecma 5 safe
|
||||||
|
// https://github.com/facebook/create-react-app/pull/4234
|
||||||
|
ecma: 8,
|
||||||
|
},
|
||||||
|
compress: {
|
||||||
|
ecma: 5,
|
||||||
|
warnings: false,
|
||||||
|
},
|
||||||
|
mangle: {
|
||||||
|
safari10: true,
|
||||||
|
},
|
||||||
output: {
|
output: {
|
||||||
|
ecma: 5,
|
||||||
comments: false,
|
comments: false,
|
||||||
|
// Turned on because emoji and regex is not minified properly using default
|
||||||
|
// https://github.com/facebook/create-react-app/issues/2488
|
||||||
|
ascii_only: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -88,7 +88,21 @@ export function getBabelLoader(isServer: boolean, babelOptions?: {}): Loader {
|
||||||
{
|
{
|
||||||
babelrc: false,
|
babelrc: false,
|
||||||
configFile: false,
|
configFile: false,
|
||||||
presets: ['@babel/env', '@babel/react'],
|
presets: [
|
||||||
|
[
|
||||||
|
'@babel/env',
|
||||||
|
{
|
||||||
|
useBuiltIns: 'usage',
|
||||||
|
loose: true,
|
||||||
|
corejs: '2',
|
||||||
|
// Do not transform modules to CJS
|
||||||
|
modules: false,
|
||||||
|
// Exclude transforms that make all code slower
|
||||||
|
exclude: ['transform-typeof-symbol'],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'@babel/react',
|
||||||
|
],
|
||||||
plugins: [
|
plugins: [
|
||||||
isServer ? 'dynamic-import-node' : '@babel/syntax-dynamic-import',
|
isServer ? 'dynamic-import-node' : '@babel/syntax-dynamic-import',
|
||||||
],
|
],
|
||||||
|
|
|
@ -13,23 +13,23 @@ This means that if the site's `baseUrl` is `/`, an image in `/static/img/docusau
|
||||||
|
|
||||||
You can reference assets from the `static` folder in your code. You could use hardcoded absolute paths, i.e. starting with a slash /, but remember to include the `baseUrl` if it is not `/`. However, this will break if you change your `baseUrl` in the config.
|
You can reference assets from the `static` folder in your code. You could use hardcoded absolute paths, i.e. starting with a slash /, but remember to include the `baseUrl` if it is not `/`. However, this will break if you change your `baseUrl` in the config.
|
||||||
|
|
||||||
A better way would be to use the `withBaseUrl` utility function which appends the `baseUrl` to paths for you.
|
A better way would be to use the `useBaseUrl` utility function which appends the `baseUrl` to paths for you.
|
||||||
|
|
||||||
### JSX example
|
### JSX example
|
||||||
|
|
||||||
```jsx
|
```jsx
|
||||||
// MyComponent.js
|
// MyComponent.js
|
||||||
import withBaseUrl from '@docusaurus/withBaseUrl';
|
import useBaseUrl from '@docusaurus/useBaseUrl';
|
||||||
|
|
||||||
<img
|
<img
|
||||||
alt="Docusaurus with Keytar"
|
alt="Docusaurus with Keytar"
|
||||||
src={withBaseUrl('img/docusaurus_keytar.svg')}
|
src={useBaseUrl('img/docusaurus_keytar.svg')}
|
||||||
/>;
|
/>;
|
||||||
```
|
```
|
||||||
|
|
||||||
### Markdown example
|
### Markdown example
|
||||||
|
|
||||||
Thanks to MDX, you can also use `withBaseUrl` utility function in Markdown files! You'd have to use `<img>` tags instead of the Markdown image syntax though. The syntax is exactly the same as in JSX.
|
Thanks to MDX, you can also use `useBaseUrl` utility function in Markdown files! You'd have to use `<img>` tags instead of the Markdown image syntax though. The syntax is exactly the same as in JSX.
|
||||||
|
|
||||||
```txt
|
```txt
|
||||||
// my-doc.mdx
|
// my-doc.mdx
|
||||||
|
@ -38,11 +38,11 @@ id: my-doc
|
||||||
title: My Doc
|
title: My Doc
|
||||||
---
|
---
|
||||||
|
|
||||||
import withBaseUrl from '@docusaurus/withBaseUrl'; // Add to the top of the file below the front matter.
|
import useBaseUrl from '@docusaurus/useBaseUrl'; // Add to the top of the file below the front matter.
|
||||||
|
|
||||||
...
|
...
|
||||||
|
|
||||||
<img alt="Docusaurus with Keytar" src={withBaseUrl('img/docusaurus_keytar.svg')} />;
|
<img alt="Docusaurus with Keytar" src={useBaseUrl('img/docusaurus_keytar.svg')} />;
|
||||||
```
|
```
|
||||||
|
|
||||||
You could also just use Markdown image syntax, but you would have to manually maintain the image paths yourself and isn't recommended.
|
You could also just use Markdown image syntax, but you would have to manually maintain the image paths yourself and isn't recommended.
|
||||||
|
|
|
@ -9,7 +9,7 @@ import React, {useEffect} from 'react';
|
||||||
import Layout from '@theme/Layout';
|
import Layout from '@theme/Layout';
|
||||||
|
|
||||||
import Link from '@docusaurus/Link';
|
import Link from '@docusaurus/Link';
|
||||||
import withBaseUrl from '@docusaurus/withBaseUrl';
|
import useBaseUrl from '@docusaurus/useBaseUrl';
|
||||||
|
|
||||||
function Help() {
|
function Help() {
|
||||||
return (
|
return (
|
||||||
|
@ -27,7 +27,7 @@ function Help() {
|
||||||
<h2>Browse the docs</h2>
|
<h2>Browse the docs</h2>
|
||||||
<p>
|
<p>
|
||||||
Learn more about Docusaurus using the{' '}
|
Learn more about Docusaurus using the{' '}
|
||||||
<Link to={withBaseUrl('docs/introduction')}>
|
<Link to={useBaseUrl('docs/introduction')}>
|
||||||
official documentation
|
official documentation
|
||||||
</Link>
|
</Link>
|
||||||
</p>
|
</p>
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Link from '@docusaurus/Link';
|
import Link from '@docusaurus/Link';
|
||||||
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
|
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
|
||||||
import withBaseUrl from '@docusaurus/withBaseUrl';
|
import useBaseUrl from '@docusaurus/useBaseUrl';
|
||||||
|
|
||||||
import Image from '@theme/IdealImage';
|
import Image from '@theme/IdealImage';
|
||||||
import Layout from '@theme/Layout';
|
import Layout from '@theme/Layout';
|
||||||
|
@ -73,7 +73,7 @@ function Home() {
|
||||||
<img
|
<img
|
||||||
alt="Docusaurus with Keytar"
|
alt="Docusaurus with Keytar"
|
||||||
className={styles.heroLogo}
|
className={styles.heroLogo}
|
||||||
src={withBaseUrl('img/docusaurus_keytar.svg')}
|
src={useBaseUrl('img/docusaurus_keytar.svg')}
|
||||||
/>
|
/>
|
||||||
{siteConfig.title} makes it easy to maintain{' '}
|
{siteConfig.title} makes it easy to maintain{' '}
|
||||||
<span className={styles.heroProjectKeywords}>Open Source</span>{' '}
|
<span className={styles.heroProjectKeywords}>Open Source</span>{' '}
|
||||||
|
@ -82,7 +82,7 @@ function Home() {
|
||||||
<div className={styles.indexCtas}>
|
<div className={styles.indexCtas}>
|
||||||
<Link
|
<Link
|
||||||
className={styles.indexCtasGetStartedButton}
|
className={styles.indexCtasGetStartedButton}
|
||||||
to={withBaseUrl('docs/introduction')}>
|
to={useBaseUrl('docs/introduction')}>
|
||||||
Get Started
|
Get Started
|
||||||
</Link>
|
</Link>
|
||||||
<span className={styles.indexCtasGitHubButton}>
|
<span className={styles.indexCtasGitHubButton}>
|
||||||
|
@ -105,14 +105,14 @@ function Home() {
|
||||||
Docusaurus 2
|
Docusaurus 2
|
||||||
</a>
|
</a>
|
||||||
, contribute to its roadmap by suggesting features or giving feedback{' '}
|
, contribute to its roadmap by suggesting features or giving feedback{' '}
|
||||||
<Link to={withBaseUrl('/feedback')}>here</Link>!
|
<Link to={useBaseUrl('/feedback')}>here</Link>!
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className={classnames(styles.announcement, styles.announcementPrimary)}>
|
className={classnames(styles.announcement, styles.announcementPrimary)}>
|
||||||
<div className={styles.announcementInner}>
|
<div className={styles.announcementInner}>
|
||||||
Coming from v1? Check out our{' '}
|
Coming from v1? Check out our{' '}
|
||||||
<Link to={withBaseUrl('/docs/migrating-from-v1-to-v2')}>
|
<Link to={useBaseUrl('/docs/migrating-from-v1-to-v2')}>
|
||||||
v1 to v2 migration guide
|
v1 to v2 migration guide
|
||||||
</Link>
|
</Link>
|
||||||
.
|
.
|
||||||
|
@ -125,7 +125,7 @@ function Home() {
|
||||||
<img
|
<img
|
||||||
className={styles.featureImage}
|
className={styles.featureImage}
|
||||||
alt="Powered by MDX"
|
alt="Powered by MDX"
|
||||||
src={withBaseUrl('img/undraw_typewriter.svg')}
|
src={useBaseUrl('img/undraw_typewriter.svg')}
|
||||||
/>
|
/>
|
||||||
<h3 className="padding-top--md">Powered by Markdown</h3>
|
<h3 className="padding-top--md">Powered by Markdown</h3>
|
||||||
<p className="padding-horiz--md">
|
<p className="padding-horiz--md">
|
||||||
|
@ -139,7 +139,7 @@ function Home() {
|
||||||
<img
|
<img
|
||||||
alt="Built Using React"
|
alt="Built Using React"
|
||||||
className={styles.featureImage}
|
className={styles.featureImage}
|
||||||
src={withBaseUrl('img/undraw_react.svg')}
|
src={useBaseUrl('img/undraw_react.svg')}
|
||||||
/>
|
/>
|
||||||
<h3 className="padding-top--md">Built Using React</h3>
|
<h3 className="padding-top--md">Built Using React</h3>
|
||||||
<p className="padding-horiz--md">
|
<p className="padding-horiz--md">
|
||||||
|
@ -152,7 +152,7 @@ function Home() {
|
||||||
<img
|
<img
|
||||||
alt="Ready for Translations"
|
alt="Ready for Translations"
|
||||||
className={styles.featureImage}
|
className={styles.featureImage}
|
||||||
src={withBaseUrl('img/undraw_around_the_world.svg')}
|
src={useBaseUrl('img/undraw_around_the_world.svg')}
|
||||||
/>
|
/>
|
||||||
<h3 className="padding-top--md">Ready for Translations</h3>
|
<h3 className="padding-top--md">Ready for Translations</h3>
|
||||||
<p className="padding-horiz--md">
|
<p className="padding-horiz--md">
|
||||||
|
@ -168,7 +168,7 @@ function Home() {
|
||||||
<img
|
<img
|
||||||
alt="Document Versioning"
|
alt="Document Versioning"
|
||||||
className={styles.featureImage}
|
className={styles.featureImage}
|
||||||
src={withBaseUrl('img/undraw_version_control.svg')}
|
src={useBaseUrl('img/undraw_version_control.svg')}
|
||||||
/>
|
/>
|
||||||
<h3 className="padding-top--md">Document Versioning</h3>
|
<h3 className="padding-top--md">Document Versioning</h3>
|
||||||
<p className="padding-horiz--md">
|
<p className="padding-horiz--md">
|
||||||
|
@ -181,7 +181,7 @@ function Home() {
|
||||||
<img
|
<img
|
||||||
alt="Document Search"
|
alt="Document Search"
|
||||||
className={styles.featureImage}
|
className={styles.featureImage}
|
||||||
src={withBaseUrl('img/undraw_algolia.svg')}
|
src={useBaseUrl('img/undraw_algolia.svg')}
|
||||||
/>
|
/>
|
||||||
<h3 className="padding-top--md">Document Search</h3>
|
<h3 className="padding-top--md">Document Search</h3>
|
||||||
<p className="padding-horiz--md">
|
<p className="padding-horiz--md">
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue