feat(v2): @docusaurus/theme-common (#3775)

* create base @docusaurus/theme-common package + fix Webpack client export aliases issue shadowing other theme-common package

* Move theme-classic/src/utils code to new @docusaurus/theme-common package

* add prettierignore

* fix bad test location for getDocusaurusAliases()
This commit is contained in:
Sébastien Lorber 2020-11-18 16:00:51 +01:00 committed by GitHub
parent 5872bbc735
commit abcd8cefd6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
39 changed files with 176 additions and 32 deletions

View file

@ -23,6 +23,7 @@ packages/docusaurus-plugin-debug/lib/
packages/docusaurus-plugin-sitemap/lib/
packages/docusaurus-plugin-ideal-image/lib/
packages/docusaurus-plugin-ideal-image/copyUntypedFiles.js
packages/docusaurus-theme-common/lib/
packages/docusaurus-theme-classic/lib/
packages/docusaurus-theme-bootstrap/lib/
packages/docusaurus-migrate/lib/

1
.gitignore vendored
View file

@ -27,6 +27,7 @@ packages/docusaurus-plugin-content-pages/lib/
packages/docusaurus-plugin-debug/lib/
packages/docusaurus-plugin-sitemap/lib/
packages/docusaurus-plugin-ideal-image/lib/
packages/docusaurus-theme-common/lib/
packages/docusaurus-theme-classic/lib/
packages/docusaurus-theme-bootstrap/lib/
packages/docusaurus-migrate/lib/

View file

@ -16,5 +16,6 @@ packages/docusaurus-plugin-debug/lib/
packages/docusaurus-plugin-sitemap/lib/
packages/docusaurus-plugin-ideal-image/lib/
packages/docusaurus-migrate/lib/
packages/docusaurus-theme-common/lib/
packages/docusaurus-theme-classic/lib/
__fixtures__

View file

@ -24,6 +24,7 @@
"@docusaurus/plugin-content-blog": "2.0.0-alpha.66",
"@docusaurus/plugin-content-docs": "2.0.0-alpha.66",
"@docusaurus/plugin-content-pages": "2.0.0-alpha.66",
"@docusaurus/theme-common": "2.0.0-alpha.66",
"@docusaurus/types": "2.0.0-alpha.66",
"@docusaurus/utils-validation": "2.0.0-alpha.66",
"@mdx-js/mdx": "^1.6.21",

View file

@ -7,7 +7,7 @@
import React from 'react';
import clsx from 'clsx';
import useThemeConfig from '../../utils/useThemeConfig';
import {useThemeConfig} from '@docusaurus/theme-common';
import useUserPreferencesContext from '@theme/hooks/useUserPreferencesContext';
import styles from './styles.module.css';

View file

@ -14,7 +14,7 @@ import usePrismTheme from '@theme/hooks/usePrismTheme';
import type {Props} from '@theme/CodeBlock';
import styles from './styles.module.css';
import useThemeConfig from '../../utils/useThemeConfig';
import {useThemeConfig} from '@docusaurus/theme-common';
const highlightLinesRangeRegex = /{([\d,-]+)}/;
const getHighlightDirectiveRegex = (

View file

@ -21,7 +21,7 @@ import {matchPath} from '@docusaurus/router';
import clsx from 'clsx';
import styles from './styles.module.css';
import {docVersionSearchTag} from '../../utils/searchUtils';
import {docVersionSearchTag} from '@docusaurus/theme-common';
type DocPageContentProps = {
readonly currentDocRoute: DocumentRoute;

View file

@ -7,8 +7,7 @@
import React, {useState, useCallback, useEffect, useRef} from 'react';
import clsx from 'clsx';
import useThemeConfig from '../../utils/useThemeConfig';
import {isSamePath} from '../../utils';
import {useThemeConfig, isSamePath} from '@docusaurus/theme-common';
import useUserPreferencesContext from '@theme/hooks/useUserPreferencesContext';
import useLockBodyScroll from '@theme/hooks/useLockBodyScroll';
import useWindowSize, {windowSizes} from '@theme/hooks/useWindowSize';

View file

@ -13,7 +13,7 @@ import {
useActiveVersion,
useDocVersionSuggestions,
} from '@theme/hooks/useDocs';
import useDocsPreferredVersion from '../../utils/docsPreferredVersion/useDocsPreferredVersion';
import {useDocsPreferredVersion} from '@docusaurus/theme-common';
const getVersionMainDoc = (version) =>
version.docs.find((doc) => doc.id === version.mainDocId);

View file

@ -9,7 +9,7 @@ import React from 'react';
import clsx from 'clsx';
import Link from '@docusaurus/Link';
import useThemeConfig from '../../utils/useThemeConfig';
import {useThemeConfig} from '@docusaurus/theme-common';
import useBaseUrl from '@docusaurus/useBaseUrl';
import styles from './styles.module.css';

View file

@ -10,7 +10,7 @@
import React from 'react';
import clsx from 'clsx';
import type {HeadingType, Props} from '@theme/Heading';
import useThemeConfig from '../../utils/useThemeConfig';
import {useThemeConfig} from '@docusaurus/theme-common';
import './styles.css';
import styles from './styles.module.css';

View file

@ -11,7 +11,7 @@ import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
import useBaseUrl from '@docusaurus/useBaseUrl';
import type {Props} from '@theme/Layout';
import SearchMetadatas from '@theme/SearchMetadatas';
import {DEFAULT_SEARCH_TAG} from '../../utils/searchUtils';
import {DEFAULT_SEARCH_TAG} from '@docusaurus/theme-common';
export default function LayoutHead(props: Props): JSX.Element {
const {siteConfig} = useDocusaurusContext();

View file

@ -8,7 +8,7 @@
import React from 'react';
import ThemeProvider from '@theme/ThemeProvider';
import UserPreferencesProvider from '@theme/UserPreferencesProvider';
import DocsPreferredVersionContextProvider from '../../utils/docsPreferredVersion/DocsPreferredVersionProvider';
import {DocsPreferredVersionContextProvider} from '@docusaurus/theme-common';
export default function LayoutProviders({children}) {
return (

View file

@ -12,7 +12,7 @@ import Link from '@docusaurus/Link';
import ThemedImage from '@theme/ThemedImage';
import useBaseUrl from '@docusaurus/useBaseUrl';
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
import useThemeConfig from '../../utils/useThemeConfig';
import {useThemeConfig} from '@docusaurus/theme-common';
import isInternalUrl from '@docusaurus/isInternalUrl';
const Logo = (props: Props): JSX.Element => {

View file

@ -11,7 +11,7 @@ import clsx from 'clsx';
import SearchBar from '@theme/SearchBar';
import Toggle from '@theme/Toggle';
import useThemeContext from '@theme/hooks/useThemeContext';
import useThemeConfig from '../../utils/useThemeConfig';
import {useThemeConfig} from '@docusaurus/theme-common';
import useHideableNavbar from '@theme/hooks/useHideableNavbar';
import useLockBodyScroll from '@theme/hooks/useLockBodyScroll';
import useWindowSize, {windowSizes} from '@theme/hooks/useWindowSize';

View file

@ -10,7 +10,7 @@ import clsx from 'clsx';
import Link from '@docusaurus/Link';
import useBaseUrl from '@docusaurus/useBaseUrl';
import {useLocation} from '@docusaurus/router';
import {isSamePath} from '../../utils';
import {isSamePath} from '@docusaurus/theme-common';
import type {
NavLinkProps,
DesktopOrMobileNavBarItemProps,

View file

@ -10,7 +10,7 @@ import DefaultNavbarItem from './DefaultNavbarItem';
import {useLatestVersion, useActiveDocContext} from '@theme/hooks/useDocs';
import clsx from 'clsx';
import type {Props} from '@theme/NavbarItem/DocNavbarItem';
import useDocsPreferredVersion from '../../utils/docsPreferredVersion/useDocsPreferredVersion';
import {useDocsPreferredVersion} from '@docusaurus/theme-common';
export default function DocNavbarItem({
docId,

View file

@ -13,7 +13,7 @@ import {
useActiveDocContext,
} from '@theme/hooks/useDocs';
import type {Props} from '@theme/NavbarItem/DocsVersionDropdownNavbarItem';
import useDocsPreferredVersion from '../../utils/docsPreferredVersion/useDocsPreferredVersion';
import {useDocsPreferredVersion} from '@docusaurus/theme-common';
const getVersionMainDoc = (version) =>
version.docs.find((doc) => doc.id === version.mainDocId);

View file

@ -9,7 +9,7 @@ import React from 'react';
import DefaultNavbarItem from './DefaultNavbarItem';
import {useActiveVersion, useLatestVersion} from '@theme/hooks/useDocs';
import type {Props} from '@theme/NavbarItem/DocsVersionNavbarItem';
import useDocsPreferredVersion from '../../utils/docsPreferredVersion/useDocsPreferredVersion';
import {useDocsPreferredVersion} from '@docusaurus/theme-common';
const getVersionMainDoc = (version) =>
version.docs.find((doc) => doc.id === version.mainDocId);

View file

@ -7,7 +7,7 @@
import React, {ComponentProps} from 'react';
import Toggle from 'react-toggle';
import useThemeConfig from '../../utils/useThemeConfig';
import {useThemeConfig} from '@docusaurus/theme-common';
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
import clsx from 'clsx';

View file

@ -6,7 +6,7 @@
*/
import {useState, useEffect, useCallback} from 'react';
import useThemeConfig from '../../utils/useThemeConfig';
import {useThemeConfig} from '@docusaurus/theme-common';
import type {useAnnouncementBarReturns} from '@theme/hooks/useAnnouncementBar';
const STORAGE_DISMISS_KEY = 'docusaurus.announcement.dismiss';

View file

@ -5,8 +5,11 @@
* LICENSE file in the root directory of this source tree.
*/
import {useAllDocsData, useActivePluginAndVersion} from '@theme/hooks/useDocs';
import {useDocsPreferredVersionByPluginId} from '../../utils/docsPreferredVersion/useDocsPreferredVersion';
import {DEFAULT_SEARCH_TAG, docVersionSearchTag} from '../../utils/searchUtils';
import {
useDocsPreferredVersionByPluginId,
DEFAULT_SEARCH_TAG,
docVersionSearchTag,
} from '@docusaurus/theme-common';
type ContextualSearchFilters = {
language: string;

View file

@ -7,7 +7,7 @@
import defaultTheme from 'prism-react-renderer/themes/palenight';
import useThemeContext from '@theme/hooks/useThemeContext';
import useThemeConfig from '../../utils/useThemeConfig';
import {useThemeConfig} from '@docusaurus/theme-common';
const usePrismTheme = (): typeof defaultTheme => {
const {prism} = useThemeConfig();

View file

@ -9,7 +9,7 @@ import {useState, useCallback, useEffect} from 'react';
import ExecutionEnvironment from '@docusaurus/ExecutionEnvironment';
import type {useThemeReturns} from '@theme/hooks/useTheme';
import useThemeConfig from '../../utils/useThemeConfig';
import {useThemeConfig} from '@docusaurus/theme-common';
const themes = {
light: 'light',

View file

@ -0,0 +1,37 @@
{
"name": "@docusaurus/theme-common",
"version": "2.0.0-alpha.66",
"description": "Common code for Docusaurus themes",
"main": "./lib/index.js",
"types": "./lib/index.d.ts",
"scripts": {
"build": "tsc",
"watch": "tsc --watch"
},
"publishConfig": {
"access": "public"
},
"repository": {
"type": "git",
"url": "https://github.com/facebook/docusaurus.git",
"directory": "packages/docusaurus-theme-common"
},
"license": "MIT",
"dependencies": {
"@docusaurus/core": "2.0.0-alpha.66",
"@docusaurus/plugin-content-blog": "2.0.0-alpha.66",
"@docusaurus/plugin-content-docs": "2.0.0-alpha.66",
"@docusaurus/plugin-content-pages": "2.0.0-alpha.66",
"@docusaurus/types": "2.0.0-alpha.66"
},
"devDependencies": {
"@docusaurus/module-type-aliases": "2.0.0-alpha.66"
},
"peerDependencies": {
"react": "^16.8.4",
"react-dom": "^16.8.4"
},
"engines": {
"node": ">=10.15.1"
}
}

View file

@ -0,0 +1,19 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
export {useThemeConfig, ThemeConfig} from './utils/useThemeConfig';
export {docVersionSearchTag, DEFAULT_SEARCH_TAG} from './utils/searchUtils';
export {isDocsPluginEnabled} from './utils/docsUtils';
export {isSamePath} from './utils/pathUtils';
export {
useDocsPreferredVersion,
useDocsPreferredVersionByPluginId,
} from './utils/docsPreferredVersion/useDocsPreferredVersion';
export {DocsPreferredVersionContextProvider} from './utils/docsPreferredVersion/DocsPreferredVersionProvider';

View file

@ -0,0 +1,13 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/* eslint-disable import/no-duplicates */
/* eslint-disable spaced-comment */
/// <reference types="@docusaurus/module-type-aliases" />
/// <reference types="@docusaurus/plugin-content-blog" />
/// <reference types="@docusaurus/plugin-content-docs" />
/// <reference types="@docusaurus/plugin-content-pages" />

View file

@ -5,7 +5,7 @@
* LICENSE file in the root directory of this source tree.
*/
import {isSamePath} from '../utils';
import {isSamePath} from '../pathUtils';
describe('isSamePath', () => {
test('should be true for compared path without trailing slash', () => {

View file

@ -12,7 +12,7 @@ import React, {
useMemo,
useState,
} from 'react';
import useThemeConfig, {DocsVersionPersistence} from '../useThemeConfig';
import {useThemeConfig, DocsVersionPersistence} from '../useThemeConfig';
import {isDocsPluginEnabled} from '../docsUtils';
import {useAllDocsData} from '@theme/hooks/useDocs';
@ -68,7 +68,7 @@ function readStorageState({
);
const pluginData = allDocsData[pluginId];
const versionExists = pluginData.versions.some(
(version) => version.name === preferredVersionNameUnsafe,
(version: any) => version.name === preferredVersionNameUnsafe,
);
if (versionExists) {
return {preferredVersionName: preferredVersionNameUnsafe};
@ -129,7 +129,7 @@ type DocsPreferredVersionContextValue = ReturnType<typeof useContextValue>;
const Context = createContext<DocsPreferredVersionContextValue | null>(null);
export default function DocsPreferredVersionContextProvider({
export function DocsPreferredVersionContextProvider({
children,
}: {
children: ReactNode;

View file

@ -10,8 +10,10 @@ import {useAllDocsData, useDocsData} from '@theme/hooks/useDocs';
import {DEFAULT_PLUGIN_ID} from '@docusaurus/constants';
// TODO improve typing
// Note, the preferredVersion attribute will always be null before mount
export default function useDocsPreferredVersion(
export function useDocsPreferredVersion(
pluginId: string | undefined = DEFAULT_PLUGIN_ID,
) {
const docsData = useDocsData(pluginId);
@ -20,7 +22,9 @@ export default function useDocsPreferredVersion(
const {preferredVersionName} = state[pluginId];
const preferredVersion = preferredVersionName
? docsData.versions.find((version) => version.name === preferredVersionName)
? docsData.versions.find(
(version: any) => version.name === preferredVersionName,
)
: null;
const savePreferredVersionName = useCallback(
@ -43,7 +47,7 @@ export function useDocsPreferredVersionByPluginId() {
return preferredVersionName
? docsData.versions.find(
(version) => version.name === preferredVersionName,
(version: any) => version.name === preferredVersionName,
)
: null;
}

View file

@ -26,6 +26,6 @@ export type ThemeConfig = {
hideableSidebar: any;
};
export default function useThemeConfig(): ThemeConfig {
export function useThemeConfig(): ThemeConfig {
return useDocusaurusContext().siteConfig.themeConfig as ThemeConfig;
}

View file

@ -0,0 +1,9 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"incremental": true,
"tsBuildInfoFile": "./lib/.tsbuildinfo",
"rootDir": "src",
"outDir": "lib",
}
}

View file

@ -0,0 +1,20 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`getDocusaurusAliases() return appropriate webpack aliases 1`] = `
Object {
"@docusaurus/BrowserOnly": "../../client/exports/BrowserOnly.tsx",
"@docusaurus/ComponentCreator": "../../client/exports/ComponentCreator.tsx",
"@docusaurus/ExecutionEnvironment": "../../client/exports/ExecutionEnvironment.ts",
"@docusaurus/Head": "../../client/exports/Head.tsx",
"@docusaurus/Link": "../../client/exports/Link.tsx",
"@docusaurus/Noop": "../../client/exports/Noop.ts",
"@docusaurus/constants": "../../client/exports/constants.ts",
"@docusaurus/context": "../../client/exports/context.ts",
"@docusaurus/isInternalUrl": "../../client/exports/isInternalUrl.ts",
"@docusaurus/renderRoutes": "../../client/exports/renderRoutes.ts",
"@docusaurus/router": "../../client/exports/router.ts",
"@docusaurus/useBaseUrl": "../../client/exports/useBaseUrl.ts",
"@docusaurus/useDocusaurusContext": "../../client/exports/useDocusaurusContext.ts",
"@docusaurus/useGlobalData": "../../client/exports/useGlobalData.ts",
}
`;

View file

@ -7,7 +7,8 @@
import path from 'path';
import {excludeJS, clientDir} from '../base';
import {excludeJS, clientDir, getDocusaurusAliases} from '../base';
import {mapValues} from 'lodash';
describe('babel transpilation exclude logic', () => {
test('always transpile client dir files', () => {
@ -57,3 +58,14 @@ describe('babel transpilation exclude logic', () => {
});
});
});
describe('getDocusaurusAliases()', () => {
test('return appropriate webpack aliases', () => {
// using relative paths makes tests work everywhere
const relativeDocusaurusAliases = mapValues(
getDocusaurusAliases(),
(aliasValue) => path.relative(__dirname, aliasValue),
);
expect(relativeDocusaurusAliases).toMatchSnapshot();
});
});

View file

@ -36,6 +36,26 @@ export function excludeJS(modulePath: string): boolean {
);
}
export function getDocusaurusAliases() {
const dirPath = path.resolve(__dirname, '../client/exports');
const extensions = ['.js', '.ts', '.tsx'];
const aliases: Record<string, string> = {};
fs.readdirSync(dirPath)
.filter((fileName) => extensions.includes(path.extname(fileName)))
.forEach((fileName) => {
const fileNameWithoutExtension = path.basename(
fileName,
path.extname(fileName),
);
const aliasName = `@docusaurus/${fileNameWithoutExtension}`;
aliases[aliasName] = path.resolve(dirPath, fileName);
});
return aliases;
}
export function createBaseConfig(
props: Props,
isServer: boolean,
@ -77,7 +97,11 @@ export function createBaseConfig(
alias: {
'@site': siteDir,
'@generated': generatedFilesDir,
'@docusaurus': path.resolve(__dirname, '../client/exports'),
// Note: a @docusaurus alias would also catch @docusaurus/theme-common,
// so we use fine-grained aliases instead
// '@docusaurus': path.resolve(__dirname, '../client/exports'),
...getDocusaurusAliases(),
},
// This allows you to set a fallback for where Webpack should look for modules.
// We want `@docusaurus/core` own dependencies/`node_modules` to "win" if there is conflict