diff --git a/.eslintignore b/.eslintignore
index 6d9160dd1a53..9a985afaa818 100644
--- a/.eslintignore
+++ b/.eslintignore
@@ -26,6 +26,7 @@ packages/docusaurus-plugin-ideal-image/copyUntypedFiles.js
packages/docusaurus-theme-classic/lib/
packages/docusaurus-theme-bootstrap/lib/
packages/docusaurus-migrate/lib/
+packages/docusaurus-theme-common/lib/
packages/docusaurus-1.x/.eslintrc.js
packages/docusaurus-init/templates/facebook/.eslintrc.js
diff --git a/.gitignore b/.gitignore
index a3b7f0a61726..404575d8adca 100644
--- a/.gitignore
+++ b/.gitignore
@@ -30,6 +30,7 @@ packages/docusaurus-plugin-ideal-image/lib/
packages/docusaurus-theme-classic/lib/
packages/docusaurus-theme-bootstrap/lib/
packages/docusaurus-migrate/lib/
+packages/docusaurus-theme-common/lib/
website/netlifyDeployPreview
!website/netlifyDeployPreview/index.html
diff --git a/.prettierignore b/.prettierignore
index 05dc4d5f5396..02f90a78f8d7 100644
--- a/.prettierignore
+++ b/.prettierignore
@@ -17,4 +17,5 @@ packages/docusaurus-plugin-sitemap/lib/
packages/docusaurus-plugin-ideal-image/lib/
packages/docusaurus-migrate/lib/
packages/docusaurus-theme-classic/lib/
+packages/docusaurus-theme-common/lib/
__fixtures__
diff --git a/packages/docusaurus-theme-classic/package.json b/packages/docusaurus-theme-classic/package.json
index 53023bc34b45..c0a81d500825 100644
--- a/packages/docusaurus-theme-classic/package.json
+++ b/packages/docusaurus-theme-classic/package.json
@@ -25,6 +25,7 @@
"@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",
+ "@docusaurus/theme-common": "2.0.0-alpha.66",
"@docusaurus/utils-validation": "2.0.0-alpha.66",
"@mdx-js/mdx": "^1.6.21",
"@mdx-js/react": "^1.6.21",
diff --git a/packages/docusaurus-theme-classic/src/index.js b/packages/docusaurus-theme-classic/src/index.js
index ff0d71749fff..37f4e2f8387e 100644
--- a/packages/docusaurus-theme-classic/src/index.js
+++ b/packages/docusaurus-theme-classic/src/index.js
@@ -144,3 +144,5 @@ const swizzleAllowedComponents = [
module.exports.getSwizzleComponentList = () => swizzleAllowedComponents;
module.exports.validateThemeConfig = validateThemeConfig;
+
+module.exports.getBaseTheme = () => '@docusaurus/theme-common';
diff --git a/packages/docusaurus-theme-classic/src/theme/AnnouncementBar/index.tsx b/packages/docusaurus-theme-classic/src/theme/AnnouncementBar/index.tsx
index 95b147b94e20..4ae61a159934 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 '@theme-utils/useThemeConfig';
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 5b0284abd33a..02aff5606bd9 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 '@theme-utils/useThemeConfig';
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 7a5e08d08e68..2594a82dade8 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 '@theme-utils/searchUtils';
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 9cf9f9f3011f..0316fe9412fa 100644
--- a/packages/docusaurus-theme-classic/src/theme/DocSidebar/index.tsx
+++ b/packages/docusaurus-theme-classic/src/theme/DocSidebar/index.tsx
@@ -8,8 +8,8 @@
import React, {useState, useCallback, useEffect, useRef} from 'react';
import clsx from 'clsx';
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
-import useThemeConfig from '../../utils/useThemeConfig';
-import {isSamePath} from '../../utils';
+import useThemeConfig from '@theme-utils/useThemeConfig';
+import {isSamePath} from '@theme-utils';
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 81f171f1f468..d23a2fac880a 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 '@theme-utils/docsPreferredVersion/useDocsPreferredVersion';
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 5cb11111cdfb..fd6c1a9344e9 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 '@theme-utils/useThemeConfig';
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 9d4b1d4cb4ca..50fa2a48111c 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 '@theme-utils/useThemeConfig';
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 da5bf3aefb7f..cec6064cdc9d 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 '@theme-utils/searchUtils';
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 b592d4f90e0e..2b28dfd6414d 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 '@theme-utils/docsPreferredVersion/DocsPreferredVersionProvider';
export default function LayoutProviders({children}) {
return (
diff --git a/packages/docusaurus-theme-classic/src/theme/Navbar/index.tsx b/packages/docusaurus-theme-classic/src/theme/Navbar/index.tsx
index 89addc41ebe7..1e965224d528 100644
--- a/packages/docusaurus-theme-classic/src/theme/Navbar/index.tsx
+++ b/packages/docusaurus-theme-classic/src/theme/Navbar/index.tsx
@@ -13,7 +13,7 @@ import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
import SearchBar from '@theme/SearchBar';
import Toggle from '@theme/Toggle';
import useThemeContext from '@theme/hooks/useThemeContext';
-import useThemeConfig from '../../utils/useThemeConfig';
+import useThemeConfig from '@theme-utils/useThemeConfig';
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 2ba2a7e495bf..aaea8773cc58 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 '@theme-utils';
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 90b73d560a40..69ff3c90a3ae 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 '@theme-utils/docsPreferredVersion/useDocsPreferredVersion';
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 858abdeb65eb..c509f190ed15 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 '@theme-utils/docsPreferredVersion/useDocsPreferredVersion';
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 bab774760eca..b85de509da0f 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 '@theme-utils/docsPreferredVersion/useDocsPreferredVersion';
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 07eea1e64fa5..31573322b6fb 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 '@theme-utils/useThemeConfig';
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 2ad3762963fe..b4ea99b41593 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 '@theme-utils/useThemeConfig';
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 e15473d6c79f..8e380ad8d2d8 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} from '@theme-utils/docsPreferredVersion/useDocsPreferredVersion';
+import {
+ DEFAULT_SEARCH_TAG,
+ docVersionSearchTag,
+} from '@theme-utils/searchUtils';
type ContextualSearchFilters = {
language: string;
diff --git a/packages/docusaurus-theme-classic/src/theme/hooks/useLogo.ts b/packages/docusaurus-theme-classic/src/theme/hooks/useLogo.ts
index 5181ba34a47d..1570898887ce 100644
--- a/packages/docusaurus-theme-classic/src/theme/hooks/useLogo.ts
+++ b/packages/docusaurus-theme-classic/src/theme/hooks/useLogo.ts
@@ -9,7 +9,7 @@ import useThemeContext from '@theme/hooks/useThemeContext';
import useBaseUrl from '@docusaurus/useBaseUrl';
import isInternalUrl from '@docusaurus/isInternalUrl';
import type {LogoLinkProps, useLogoReturns} from '@theme/hooks/useLogo';
-import useThemeConfig from '../../utils/useThemeConfig';
+import useThemeConfig from '@theme-utils/useThemeConfig';
const useLogo = (): useLogoReturns => {
const {
diff --git a/packages/docusaurus-theme-classic/src/theme/hooks/usePrismTheme.ts b/packages/docusaurus-theme-classic/src/theme/hooks/usePrismTheme.ts
index e8287d3cd9e3..ac73d8a9351a 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 '@theme-utils/useThemeConfig';
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 74265b0eac31..c106da7baa89 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 '@theme-utils/useThemeConfig';
const themes = {
light: 'light',
diff --git a/packages/docusaurus-theme-classic/src/types.d.ts b/packages/docusaurus-theme-classic/src/types.d.ts
index 3087612c349f..d318f0e87ce6 100644
--- a/packages/docusaurus-theme-classic/src/types.d.ts
+++ b/packages/docusaurus-theme-classic/src/types.d.ts
@@ -11,6 +11,7 @@
///
///
///
+///
declare module '@theme/AnnouncementBar' {
const AnnouncementBar: () => JSX.Element | null;
diff --git a/packages/docusaurus-theme-common/README.md b/packages/docusaurus-theme-common/README.md
new file mode 100644
index 000000000000..eb6a53624782
--- /dev/null
+++ b/packages/docusaurus-theme-common/README.md
@@ -0,0 +1,3 @@
+# Docusaurus Theme Common
+
+The common parts of Docusaurus themes.
diff --git a/packages/docusaurus-theme-common/babel.config.js b/packages/docusaurus-theme-common/babel.config.js
new file mode 100644
index 000000000000..a6b570f38777
--- /dev/null
+++ b/packages/docusaurus-theme-common/babel.config.js
@@ -0,0 +1,10 @@
+/**
+ * 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.
+ */
+
+module.exports = {
+ presets: [['@babel/preset-typescript', {isTSX: true, allExtensions: true}]],
+};
diff --git a/packages/docusaurus-theme-common/package.json b/packages/docusaurus-theme-common/package.json
new file mode 100644
index 000000000000..07280a206193
--- /dev/null
+++ b/packages/docusaurus-theme-common/package.json
@@ -0,0 +1,35 @@
+{
+ "name": "@docusaurus/theme-common",
+ "version": "2.0.0-alpha.66",
+ "description": "Common parts for Docusaurus themes",
+ "main": "src/index.js",
+ "types": "src/types.d.ts",
+ "publishConfig": {
+ "access": "public"
+ },
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/facebook/docusaurus.git",
+ "directory": "packages/docusaurus-theme-common"
+ },
+ "license": "MIT",
+ "scripts": {
+ "build": "tsc --noEmit && yarn babel && yarn prettier",
+ "watch": "yarn babel --watch",
+ "babel": "babel src -d lib --extensions \".tsx,.ts\" --ignore \"**/*.d.ts\" --copy-files",
+ "prettier": "prettier --config ../../.prettierrc --write \"**/*.{js,ts}\""
+ },
+ "dependencies": {
+ "@docusaurus/core": "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-classic/src/__tests__/utils.test.js b/packages/docusaurus-theme-common/src/__tests__/utils.test.js
similarity index 100%
rename from packages/docusaurus-theme-classic/src/__tests__/utils.test.js
rename to packages/docusaurus-theme-common/src/__tests__/utils.test.js
diff --git a/packages/docusaurus-theme-common/src/index.js b/packages/docusaurus-theme-common/src/index.js
new file mode 100644
index 000000000000..6110fff166e3
--- /dev/null
+++ b/packages/docusaurus-theme-common/src/index.js
@@ -0,0 +1,32 @@
+/**
+ * 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.
+ */
+
+const path = require('path');
+
+module.exports = function () {
+ return {
+ name: 'docusaurus-theme-common',
+
+ getThemePath() {
+ return path.join(__dirname, '..', 'lib', 'theme');
+ },
+
+ getTypeScriptThemePath() {
+ return path.resolve(__dirname, './theme');
+ },
+
+ configureWebpack() {
+ return {
+ resolve: {
+ alias: {
+ '@theme-utils': path.resolve(__dirname, 'utils'),
+ },
+ },
+ };
+ },
+ };
+};
diff --git a/packages/docusaurus-theme-classic/src/theme/hooks/useDocs.ts b/packages/docusaurus-theme-common/src/theme/hooks/useDocs.ts
similarity index 100%
rename from packages/docusaurus-theme-classic/src/theme/hooks/useDocs.ts
rename to packages/docusaurus-theme-common/src/theme/hooks/useDocs.ts
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 000000000000..6c1dc10a666d
--- /dev/null
+++ b/packages/docusaurus-theme-common/src/types.d.ts
@@ -0,0 +1,14 @@
+/**
+ * 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 */
+///
+
+declare module '@theme-utils';
+
+declare module '@theme-utils/*';
diff --git a/packages/docusaurus-theme-classic/src/utils/docsPreferredVersion/DocsPreferredVersionProvider.tsx b/packages/docusaurus-theme-common/src/utils/docsPreferredVersion/DocsPreferredVersionProvider.tsx
similarity index 100%
rename from packages/docusaurus-theme-classic/src/utils/docsPreferredVersion/DocsPreferredVersionProvider.tsx
rename to packages/docusaurus-theme-common/src/utils/docsPreferredVersion/DocsPreferredVersionProvider.tsx
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 100%
rename from packages/docusaurus-theme-classic/src/utils/docsPreferredVersion/useDocsPreferredVersion.ts
rename to packages/docusaurus-theme-common/src/utils/docsPreferredVersion/useDocsPreferredVersion.ts
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/index.ts
similarity index 100%
rename from packages/docusaurus-theme-classic/src/utils/index.ts
rename to packages/docusaurus-theme-common/src/utils/index.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 100%
rename from packages/docusaurus-theme-classic/src/utils/useThemeConfig.ts
rename to packages/docusaurus-theme-common/src/utils/useThemeConfig.ts
diff --git a/packages/docusaurus-theme-common/tsconfig.json b/packages/docusaurus-theme-common/tsconfig.json
new file mode 100644
index 000000000000..a27160e60158
--- /dev/null
+++ b/packages/docusaurus-theme-common/tsconfig.json
@@ -0,0 +1,12 @@
+{
+ "extends": "../../tsconfig.json",
+ "compilerOptions": {
+ "lib": ["DOM"],
+ "module": "esnext",
+ "noEmit": true,
+ "noImplicitAny": false,
+ "jsx": "react",
+ "baseUrl": "src"
+ },
+ "include": ["src/"]
+}
diff --git a/packages/docusaurus/src/server/index.ts b/packages/docusaurus/src/server/index.ts
index bcd2c84843a3..9a142afbe8fc 100644
--- a/packages/docusaurus/src/server/index.ts
+++ b/packages/docusaurus/src/server/index.ts
@@ -31,6 +31,7 @@ import {loadHtmlTags} from './html-tags';
import {getPackageJsonVersion} from './versions';
import {handleDuplicateRoutes} from './duplicateRoutes';
import chalk from 'chalk';
+import importFresh from 'import-fresh';
export function loadContext(
siteDir: string,
@@ -58,14 +59,32 @@ export function loadContext(
export function loadPluginConfigs(context: LoadContext): PluginConfig[] {
const {plugins: presetPlugins, themes: presetThemes} = loadPresets(context);
- const {siteConfig} = context;
- return [
+ const {
+ siteConfig: {plugins: sitePlugins = [], themes: siteThemes = []},
+ } = context;
+ const baseThemes = (themeConfigs) => {
+ return themeConfigs.reduce((themes, themeConfig) => {
+ const themePluginImport =
+ themeConfig instanceof Array ? themeConfig[0] : themeConfig;
+ const themePlugin: any = importFresh(themePluginImport);
+
+ if (typeof themePlugin.getBaseTheme === 'function') {
+ themes.push(themePlugin.getBaseTheme());
+ }
+
+ return themes;
+ }, []);
+ };
+
+ const pluginConfigs = [
...presetPlugins,
- ...presetThemes,
+ ...baseThemes(presetThemes).concat(presetThemes),
// Site config should be the highest priority.
- ...(siteConfig.plugins || []),
- ...(siteConfig.themes || []),
+ ...sitePlugins,
+ ...baseThemes(siteThemes).concat(siteThemes),
];
+
+ return pluginConfigs;
}
export async function load(