diff --git a/.eslintignore b/.eslintignore
index 571c30d88c..49cbc607f6 100644
--- a/.eslintignore
+++ b/.eslintignore
@@ -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/
diff --git a/.gitignore b/.gitignore
index a3b7f0a617..08f8d64c8d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -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/
diff --git a/.prettierignore b/.prettierignore
index 05dc4d5f53..4611baf9c5 100644
--- a/.prettierignore
+++ b/.prettierignore
@@ -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__
diff --git a/packages/docusaurus-theme-classic/package.json b/packages/docusaurus-theme-classic/package.json
index 53023bc34b..4d1ef9af39 100644
--- a/packages/docusaurus-theme-classic/package.json
+++ b/packages/docusaurus-theme-classic/package.json
@@ -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",
diff --git a/packages/docusaurus-theme-classic/src/theme/AnnouncementBar/index.tsx b/packages/docusaurus-theme-classic/src/theme/AnnouncementBar/index.tsx
index 95b147b94e..85a6ffc115 100644
--- a/packages/docusaurus-theme-classic/src/theme/AnnouncementBar/index.tsx
+++ b/packages/docusaurus-theme-classic/src/theme/AnnouncementBar/index.tsx
@@ -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';
diff --git a/packages/docusaurus-theme-classic/src/theme/CodeBlock/index.tsx b/packages/docusaurus-theme-classic/src/theme/CodeBlock/index.tsx
index 22c5cb52b5..561896209f 100644
--- a/packages/docusaurus-theme-classic/src/theme/CodeBlock/index.tsx
+++ b/packages/docusaurus-theme-classic/src/theme/CodeBlock/index.tsx
@@ -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 = (
diff --git a/packages/docusaurus-theme-classic/src/theme/DocPage/index.tsx b/packages/docusaurus-theme-classic/src/theme/DocPage/index.tsx
index 461cc93291..4979c9af09 100644
--- a/packages/docusaurus-theme-classic/src/theme/DocPage/index.tsx
+++ b/packages/docusaurus-theme-classic/src/theme/DocPage/index.tsx
@@ -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;
diff --git a/packages/docusaurus-theme-classic/src/theme/DocSidebar/index.tsx b/packages/docusaurus-theme-classic/src/theme/DocSidebar/index.tsx
index 5ce32d0255..fa7a51b830 100644
--- a/packages/docusaurus-theme-classic/src/theme/DocSidebar/index.tsx
+++ b/packages/docusaurus-theme-classic/src/theme/DocSidebar/index.tsx
@@ -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';
diff --git a/packages/docusaurus-theme-classic/src/theme/DocVersionSuggestions/index.tsx b/packages/docusaurus-theme-classic/src/theme/DocVersionSuggestions/index.tsx
index 81f171f1f4..cef5d48e6e 100644
--- a/packages/docusaurus-theme-classic/src/theme/DocVersionSuggestions/index.tsx
+++ b/packages/docusaurus-theme-classic/src/theme/DocVersionSuggestions/index.tsx
@@ -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);
diff --git a/packages/docusaurus-theme-classic/src/theme/Footer/index.tsx b/packages/docusaurus-theme-classic/src/theme/Footer/index.tsx
index 5cb11111cd..b1bc6b3a58 100644
--- a/packages/docusaurus-theme-classic/src/theme/Footer/index.tsx
+++ b/packages/docusaurus-theme-classic/src/theme/Footer/index.tsx
@@ -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';
diff --git a/packages/docusaurus-theme-classic/src/theme/Heading/index.tsx b/packages/docusaurus-theme-classic/src/theme/Heading/index.tsx
index d699be9f8b..a4599329d6 100644
--- a/packages/docusaurus-theme-classic/src/theme/Heading/index.tsx
+++ b/packages/docusaurus-theme-classic/src/theme/Heading/index.tsx
@@ -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';
diff --git a/packages/docusaurus-theme-classic/src/theme/LayoutHead/index.tsx b/packages/docusaurus-theme-classic/src/theme/LayoutHead/index.tsx
index da5bf3aefb..7a25c3b05b 100644
--- a/packages/docusaurus-theme-classic/src/theme/LayoutHead/index.tsx
+++ b/packages/docusaurus-theme-classic/src/theme/LayoutHead/index.tsx
@@ -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();
diff --git a/packages/docusaurus-theme-classic/src/theme/LayoutProviders/index.tsx b/packages/docusaurus-theme-classic/src/theme/LayoutProviders/index.tsx
index b592d4f90e..710cfb0218 100644
--- a/packages/docusaurus-theme-classic/src/theme/LayoutProviders/index.tsx
+++ b/packages/docusaurus-theme-classic/src/theme/LayoutProviders/index.tsx
@@ -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 (
diff --git a/packages/docusaurus-theme-classic/src/theme/Logo/index.tsx b/packages/docusaurus-theme-classic/src/theme/Logo/index.tsx
index 0033dd00d3..e6f94a6786 100644
--- a/packages/docusaurus-theme-classic/src/theme/Logo/index.tsx
+++ b/packages/docusaurus-theme-classic/src/theme/Logo/index.tsx
@@ -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 => {
diff --git a/packages/docusaurus-theme-classic/src/theme/Navbar/index.tsx b/packages/docusaurus-theme-classic/src/theme/Navbar/index.tsx
index e05fe70e81..cef3b688d3 100644
--- a/packages/docusaurus-theme-classic/src/theme/Navbar/index.tsx
+++ b/packages/docusaurus-theme-classic/src/theme/Navbar/index.tsx
@@ -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';
diff --git a/packages/docusaurus-theme-classic/src/theme/NavbarItem/DefaultNavbarItem.tsx b/packages/docusaurus-theme-classic/src/theme/NavbarItem/DefaultNavbarItem.tsx
index 2ba2a7e495..9d40bdbbde 100644
--- a/packages/docusaurus-theme-classic/src/theme/NavbarItem/DefaultNavbarItem.tsx
+++ b/packages/docusaurus-theme-classic/src/theme/NavbarItem/DefaultNavbarItem.tsx
@@ -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,
diff --git a/packages/docusaurus-theme-classic/src/theme/NavbarItem/DocNavbarItem.tsx b/packages/docusaurus-theme-classic/src/theme/NavbarItem/DocNavbarItem.tsx
index 90b73d560a..acba6486c3 100644
--- a/packages/docusaurus-theme-classic/src/theme/NavbarItem/DocNavbarItem.tsx
+++ b/packages/docusaurus-theme-classic/src/theme/NavbarItem/DocNavbarItem.tsx
@@ -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,
diff --git a/packages/docusaurus-theme-classic/src/theme/NavbarItem/DocsVersionDropdownNavbarItem.tsx b/packages/docusaurus-theme-classic/src/theme/NavbarItem/DocsVersionDropdownNavbarItem.tsx
index 858abdeb65..52fa4e23ca 100644
--- a/packages/docusaurus-theme-classic/src/theme/NavbarItem/DocsVersionDropdownNavbarItem.tsx
+++ b/packages/docusaurus-theme-classic/src/theme/NavbarItem/DocsVersionDropdownNavbarItem.tsx
@@ -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);
diff --git a/packages/docusaurus-theme-classic/src/theme/NavbarItem/DocsVersionNavbarItem.tsx b/packages/docusaurus-theme-classic/src/theme/NavbarItem/DocsVersionNavbarItem.tsx
index bab774760e..f2a4b88b76 100644
--- a/packages/docusaurus-theme-classic/src/theme/NavbarItem/DocsVersionNavbarItem.tsx
+++ b/packages/docusaurus-theme-classic/src/theme/NavbarItem/DocsVersionNavbarItem.tsx
@@ -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);
diff --git a/packages/docusaurus-theme-classic/src/theme/Toggle/index.tsx b/packages/docusaurus-theme-classic/src/theme/Toggle/index.tsx
index 07eea1e64f..06e119fdec 100644
--- a/packages/docusaurus-theme-classic/src/theme/Toggle/index.tsx
+++ b/packages/docusaurus-theme-classic/src/theme/Toggle/index.tsx
@@ -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';
diff --git a/packages/docusaurus-theme-classic/src/theme/hooks/useAnnouncementBar.ts b/packages/docusaurus-theme-classic/src/theme/hooks/useAnnouncementBar.ts
index 2ad3762963..75feb58dfe 100644
--- a/packages/docusaurus-theme-classic/src/theme/hooks/useAnnouncementBar.ts
+++ b/packages/docusaurus-theme-classic/src/theme/hooks/useAnnouncementBar.ts
@@ -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';
diff --git a/packages/docusaurus-theme-classic/src/theme/hooks/useContextualSearchFilters.ts b/packages/docusaurus-theme-classic/src/theme/hooks/useContextualSearchFilters.ts
index e15473d6c7..dccdbc2402 100644
--- a/packages/docusaurus-theme-classic/src/theme/hooks/useContextualSearchFilters.ts
+++ b/packages/docusaurus-theme-classic/src/theme/hooks/useContextualSearchFilters.ts
@@ -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;
diff --git a/packages/docusaurus-theme-classic/src/theme/hooks/usePrismTheme.ts b/packages/docusaurus-theme-classic/src/theme/hooks/usePrismTheme.ts
index e8287d3cd9..36d80a0538 100644
--- a/packages/docusaurus-theme-classic/src/theme/hooks/usePrismTheme.ts
+++ b/packages/docusaurus-theme-classic/src/theme/hooks/usePrismTheme.ts
@@ -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();
diff --git a/packages/docusaurus-theme-classic/src/theme/hooks/useTheme.ts b/packages/docusaurus-theme-classic/src/theme/hooks/useTheme.ts
index 74265b0eac..aa2669a6d4 100644
--- a/packages/docusaurus-theme-classic/src/theme/hooks/useTheme.ts
+++ b/packages/docusaurus-theme-classic/src/theme/hooks/useTheme.ts
@@ -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',
diff --git a/packages/docusaurus-theme-common/package.json b/packages/docusaurus-theme-common/package.json
new file mode 100644
index 0000000000..6050e83531
--- /dev/null
+++ b/packages/docusaurus-theme-common/package.json
@@ -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"
+ }
+}
diff --git a/packages/docusaurus-theme-common/src/index.ts b/packages/docusaurus-theme-common/src/index.ts
new file mode 100644
index 0000000000..84c003e241
--- /dev/null
+++ b/packages/docusaurus-theme-common/src/index.ts
@@ -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';
diff --git a/packages/docusaurus-theme-common/src/types.d.ts b/packages/docusaurus-theme-common/src/types.d.ts
new file mode 100644
index 0000000000..d62d2918c4
--- /dev/null
+++ b/packages/docusaurus-theme-common/src/types.d.ts
@@ -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 */
+///
+///
+///
+///
diff --git a/packages/docusaurus-theme-classic/src/__tests__/utils.test.js b/packages/docusaurus-theme-common/src/utils/__tests__/pathUtils.test.ts
similarity index 96%
rename from packages/docusaurus-theme-classic/src/__tests__/utils.test.js
rename to packages/docusaurus-theme-common/src/utils/__tests__/pathUtils.test.ts
index bdae0c5259..71d88b7d9a 100644
--- a/packages/docusaurus-theme-classic/src/__tests__/utils.test.js
+++ b/packages/docusaurus-theme-common/src/utils/__tests__/pathUtils.test.ts
@@ -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', () => {
diff --git a/packages/docusaurus-theme-classic/src/utils/docsPreferredVersion/DocsPreferredVersionProvider.tsx b/packages/docusaurus-theme-common/src/utils/docsPreferredVersion/DocsPreferredVersionProvider.tsx
similarity index 96%
rename from packages/docusaurus-theme-classic/src/utils/docsPreferredVersion/DocsPreferredVersionProvider.tsx
rename to packages/docusaurus-theme-common/src/utils/docsPreferredVersion/DocsPreferredVersionProvider.tsx
index f98d7030ef..f34215e498 100644
--- a/packages/docusaurus-theme-classic/src/utils/docsPreferredVersion/DocsPreferredVersionProvider.tsx
+++ b/packages/docusaurus-theme-common/src/utils/docsPreferredVersion/DocsPreferredVersionProvider.tsx
@@ -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;
const Context = createContext(null);
-export default function DocsPreferredVersionContextProvider({
+export function DocsPreferredVersionContextProvider({
children,
}: {
children: ReactNode;
diff --git a/packages/docusaurus-theme-classic/src/utils/docsPreferredVersion/DocsPreferredVersionStorage.ts b/packages/docusaurus-theme-common/src/utils/docsPreferredVersion/DocsPreferredVersionStorage.ts
similarity index 100%
rename from packages/docusaurus-theme-classic/src/utils/docsPreferredVersion/DocsPreferredVersionStorage.ts
rename to packages/docusaurus-theme-common/src/utils/docsPreferredVersion/DocsPreferredVersionStorage.ts
diff --git a/packages/docusaurus-theme-classic/src/utils/docsPreferredVersion/useDocsPreferredVersion.ts b/packages/docusaurus-theme-common/src/utils/docsPreferredVersion/useDocsPreferredVersion.ts
similarity index 87%
rename from packages/docusaurus-theme-classic/src/utils/docsPreferredVersion/useDocsPreferredVersion.ts
rename to packages/docusaurus-theme-common/src/utils/docsPreferredVersion/useDocsPreferredVersion.ts
index 6708c782b1..c9df4cbc8c 100644
--- a/packages/docusaurus-theme-classic/src/utils/docsPreferredVersion/useDocsPreferredVersion.ts
+++ b/packages/docusaurus-theme-common/src/utils/docsPreferredVersion/useDocsPreferredVersion.ts
@@ -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;
}
diff --git a/packages/docusaurus-theme-classic/src/utils/docsUtils.ts b/packages/docusaurus-theme-common/src/utils/docsUtils.ts
similarity index 100%
rename from packages/docusaurus-theme-classic/src/utils/docsUtils.ts
rename to packages/docusaurus-theme-common/src/utils/docsUtils.ts
diff --git a/packages/docusaurus-theme-classic/src/utils/index.ts b/packages/docusaurus-theme-common/src/utils/pathUtils.ts
similarity index 100%
rename from packages/docusaurus-theme-classic/src/utils/index.ts
rename to packages/docusaurus-theme-common/src/utils/pathUtils.ts
diff --git a/packages/docusaurus-theme-classic/src/utils/searchUtils.ts b/packages/docusaurus-theme-common/src/utils/searchUtils.ts
similarity index 100%
rename from packages/docusaurus-theme-classic/src/utils/searchUtils.ts
rename to packages/docusaurus-theme-common/src/utils/searchUtils.ts
diff --git a/packages/docusaurus-theme-classic/src/utils/useThemeConfig.ts b/packages/docusaurus-theme-common/src/utils/useThemeConfig.ts
similarity index 93%
rename from packages/docusaurus-theme-classic/src/utils/useThemeConfig.ts
rename to packages/docusaurus-theme-common/src/utils/useThemeConfig.ts
index 00d775aafa..b03ab20401 100644
--- a/packages/docusaurus-theme-classic/src/utils/useThemeConfig.ts
+++ b/packages/docusaurus-theme-common/src/utils/useThemeConfig.ts
@@ -26,6 +26,6 @@ export type ThemeConfig = {
hideableSidebar: any;
};
-export default function useThemeConfig(): ThemeConfig {
+export function useThemeConfig(): ThemeConfig {
return useDocusaurusContext().siteConfig.themeConfig as ThemeConfig;
}
diff --git a/packages/docusaurus-theme-common/tsconfig.json b/packages/docusaurus-theme-common/tsconfig.json
new file mode 100644
index 0000000000..f50aa9ee6d
--- /dev/null
+++ b/packages/docusaurus-theme-common/tsconfig.json
@@ -0,0 +1,9 @@
+{
+ "extends": "../../tsconfig.json",
+ "compilerOptions": {
+ "incremental": true,
+ "tsBuildInfoFile": "./lib/.tsbuildinfo",
+ "rootDir": "src",
+ "outDir": "lib",
+ }
+}
diff --git a/packages/docusaurus/src/webpack/__tests__/__snapshots__/base.test.ts.snap b/packages/docusaurus/src/webpack/__tests__/__snapshots__/base.test.ts.snap
new file mode 100644
index 0000000000..f17a59672e
--- /dev/null
+++ b/packages/docusaurus/src/webpack/__tests__/__snapshots__/base.test.ts.snap
@@ -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",
+}
+`;
diff --git a/packages/docusaurus/src/webpack/__tests__/base.test.ts b/packages/docusaurus/src/webpack/__tests__/base.test.ts
index 07ce4ead6d..43ead9104f 100644
--- a/packages/docusaurus/src/webpack/__tests__/base.test.ts
+++ b/packages/docusaurus/src/webpack/__tests__/base.test.ts
@@ -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();
+ });
+});
diff --git a/packages/docusaurus/src/webpack/base.ts b/packages/docusaurus/src/webpack/base.ts
index 74d356fed4..bc18a5e0ee 100644
--- a/packages/docusaurus/src/webpack/base.ts
+++ b/packages/docusaurus/src/webpack/base.ts
@@ -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 = {};
+
+ 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