diff --git a/packages/docusaurus-plugin-content-blog/package.json b/packages/docusaurus-plugin-content-blog/package.json index e192dd068f73..3ad5c940ecbc 100644 --- a/packages/docusaurus-plugin-content-blog/package.json +++ b/packages/docusaurus-plugin-content-blog/package.json @@ -16,6 +16,11 @@ "loader-utils": "^1.2.3" }, "peerDependencies": { - "@docusaurus/core": "^2.0.0" + "@docusaurus/core": "^2.0.0", + "react": "^16.8.4", + "react-dom": "^16.8.4" + }, + "engines": { + "node": ">=8" } } diff --git a/packages/docusaurus-plugin-content-blog/src/index.js b/packages/docusaurus-plugin-content-blog/src/index.js index 511607f6595f..827c18a56cce 100644 --- a/packages/docusaurus-plugin-content-blog/src/index.js +++ b/packages/docusaurus-plugin-content-blog/src/index.js @@ -158,6 +158,22 @@ class DocusaurusPluginContentBlog { configureWebpack(config, isServer, {getBabelLoader, getCacheLoader}) { return { + resolve: { + alias: { + '@theme/BlogListPage': path.resolve( + __dirname, + './theme/BlogListPage', + ), + '@theme/BlogPostItem': path.resolve( + __dirname, + './theme/BlogPostItem', + ), + '@theme/BlogPostPage': path.resolve( + __dirname, + './theme/BlogPostPage', + ), + }, + }, module: { rules: [ { diff --git a/packages/docusaurus/lib/default-theme/BlogListPage/index.js b/packages/docusaurus-plugin-content-blog/src/theme/BlogListPage/index.js similarity index 95% rename from packages/docusaurus/lib/default-theme/BlogListPage/index.js rename to packages/docusaurus-plugin-content-blog/src/theme/BlogListPage/index.js index 608b9ec782fb..813c6d1f1530 100644 --- a/packages/docusaurus/lib/default-theme/BlogListPage/index.js +++ b/packages/docusaurus-plugin-content-blog/src/theme/BlogListPage/index.js @@ -8,7 +8,7 @@ import React from 'react'; import Layout from '@theme/Layout'; // eslint-disable-line -import BlogPostItem from '../BlogPostItem'; +import BlogPostItem from '@theme/BlogPostItem'; function BlogListPage(props) { const { diff --git a/packages/docusaurus/lib/default-theme/BlogPostItem/index.js b/packages/docusaurus-plugin-content-blog/src/theme/BlogPostItem/index.js similarity index 100% rename from packages/docusaurus/lib/default-theme/BlogPostItem/index.js rename to packages/docusaurus-plugin-content-blog/src/theme/BlogPostItem/index.js diff --git a/packages/docusaurus/lib/default-theme/BlogPostPage/index.js b/packages/docusaurus-plugin-content-blog/src/theme/BlogPostPage/index.js similarity index 94% rename from packages/docusaurus/lib/default-theme/BlogPostPage/index.js rename to packages/docusaurus-plugin-content-blog/src/theme/BlogPostPage/index.js index 60c304dd5f5f..1659927d92dc 100644 --- a/packages/docusaurus/lib/default-theme/BlogPostPage/index.js +++ b/packages/docusaurus-plugin-content-blog/src/theme/BlogPostPage/index.js @@ -8,7 +8,7 @@ import React from 'react'; import Layout from '@theme/Layout'; // eslint-disable-line -import BlogPostItem from '../BlogPostItem'; +import BlogPostItem from '@theme/BlogPostItem'; function BlogPostPage(props) { const {content: BlogPostContents, metadata} = props; diff --git a/packages/docusaurus-plugin-content-docs/package.json b/packages/docusaurus-plugin-content-docs/package.json index a4d81000debc..2b5523e7f726 100644 --- a/packages/docusaurus-plugin-content-docs/package.json +++ b/packages/docusaurus-plugin-content-docs/package.json @@ -18,6 +18,12 @@ "loader-utils": "^1.2.3" }, "peerDependencies": { - "@docusaurus/core": "^2.0.0" + "@docusaurus/core": "^2.0.0", + "react": "^16.8.4", + "react-dom": "^16.8.4", + "react-router-config": "^5.0.0" + }, + "engines": { + "node": ">=8" } } diff --git a/packages/docusaurus-plugin-content-docs/src/index.js b/packages/docusaurus-plugin-content-docs/src/index.js index 59854501b93d..e4f457dd411e 100644 --- a/packages/docusaurus-plugin-content-docs/src/index.js +++ b/packages/docusaurus-plugin-content-docs/src/index.js @@ -153,6 +153,17 @@ class DocusaurusPluginContentDocs { configureWebpack(config, isServer, {getBabelLoader, getCacheLoader}) { return { + resolve: { + alias: { + '@theme/DocItem': path.resolve(__dirname, './theme/DocItem'), + '@theme/DocPage': path.resolve(__dirname, './theme/DocPage'), + '@theme/DocPaginator': path.resolve( + __dirname, + './theme/DocPaginator', + ), + '@theme/DocSidebar': path.resolve(__dirname, './theme/DocSidebar'), + }, + }, module: { rules: [ { diff --git a/packages/docusaurus/lib/default-theme/DocItem/index.js b/packages/docusaurus-plugin-content-docs/src/theme/DocItem/index.js similarity index 97% rename from packages/docusaurus/lib/default-theme/DocItem/index.js rename to packages/docusaurus-plugin-content-docs/src/theme/DocItem/index.js index 85041692ece3..fe0800bb3b11 100644 --- a/packages/docusaurus/lib/default-theme/DocItem/index.js +++ b/packages/docusaurus-plugin-content-docs/src/theme/DocItem/index.js @@ -9,7 +9,7 @@ import React from 'react'; import Head from '@docusaurus/Head'; -import DocPaginator from '../DocPaginator'; +import DocPaginator from '@theme/DocPaginator'; import styles from './styles.module.css'; diff --git a/packages/docusaurus/lib/default-theme/DocItem/styles.module.css b/packages/docusaurus-plugin-content-docs/src/theme/DocItem/styles.module.css similarity index 100% rename from packages/docusaurus/lib/default-theme/DocItem/styles.module.css rename to packages/docusaurus-plugin-content-docs/src/theme/DocItem/styles.module.css diff --git a/packages/docusaurus/lib/default-theme/DocPage/index.js b/packages/docusaurus-plugin-content-docs/src/theme/DocPage/index.js similarity index 94% rename from packages/docusaurus/lib/default-theme/DocPage/index.js rename to packages/docusaurus-plugin-content-docs/src/theme/DocPage/index.js index 8f1e9893f40b..b205455b13b0 100644 --- a/packages/docusaurus/lib/default-theme/DocPage/index.js +++ b/packages/docusaurus-plugin-content-docs/src/theme/DocPage/index.js @@ -10,7 +10,7 @@ import {renderRoutes} from 'react-router-config'; import Layout from '@theme/Layout'; // eslint-disable-line -import DocSidebar from '../DocSidebar'; +import DocSidebar from '@theme/DocSidebar'; function DocPage(props) { const {route, docsMetadata, location} = props; diff --git a/packages/docusaurus/lib/default-theme/DocPaginator/index.js b/packages/docusaurus-plugin-content-docs/src/theme/DocPaginator/index.js similarity index 100% rename from packages/docusaurus/lib/default-theme/DocPaginator/index.js rename to packages/docusaurus-plugin-content-docs/src/theme/DocPaginator/index.js diff --git a/packages/docusaurus/lib/default-theme/DocSidebar/index.js b/packages/docusaurus-plugin-content-docs/src/theme/DocSidebar/index.js similarity index 100% rename from packages/docusaurus/lib/default-theme/DocSidebar/index.js rename to packages/docusaurus-plugin-content-docs/src/theme/DocSidebar/index.js diff --git a/packages/docusaurus/lib/default-theme/DocSidebar/styles.css b/packages/docusaurus-plugin-content-docs/src/theme/DocSidebar/styles.css similarity index 100% rename from packages/docusaurus/lib/default-theme/DocSidebar/styles.css rename to packages/docusaurus-plugin-content-docs/src/theme/DocSidebar/styles.css diff --git a/packages/docusaurus-plugin-content-pages/package.json b/packages/docusaurus-plugin-content-pages/package.json index 73d755bab89a..88c1fca258e7 100644 --- a/packages/docusaurus-plugin-content-pages/package.json +++ b/packages/docusaurus-plugin-content-pages/package.json @@ -12,6 +12,11 @@ "globby": "^9.1.0" }, "peerDependencies": { - "@docusaurus/core": "^2.0.0" + "@docusaurus/core": "^2.0.0", + "react": "^16.8.4", + "react-dom": "^16.8.4" + }, + "engines": { + "node": ">=8" } } diff --git a/packages/docusaurus-preset-classic/src/index.js b/packages/docusaurus-preset-classic/src/index.js index 04cbece645c2..6aba831a2aa1 100644 --- a/packages/docusaurus-preset-classic/src/index.js +++ b/packages/docusaurus-preset-classic/src/index.js @@ -7,6 +7,11 @@ module.exports = function preset(context, opts = {}) { return { + themes: [ + { + name: '@docusaurus/theme-classic', + }, + ], plugins: [ { name: '@docusaurus/plugin-content-docs', diff --git a/packages/docusaurus-theme-classic/package.json b/packages/docusaurus-theme-classic/package.json new file mode 100644 index 000000000000..12fef6df98fa --- /dev/null +++ b/packages/docusaurus-theme-classic/package.json @@ -0,0 +1,21 @@ +{ + "name": "@docusaurus/theme-classic", + "version": "2.0.0-alpha.13", + "description": "Classic theme for Docusaurus", + "main": "src/index.js", + "publishConfig": { + "access": "public" + }, + "license": "MIT", + "dependencies": { + "docsearch.js": "^2.5.2" + }, + "peerDependencies": { + "@docusaurus/core": "^2.0.0", + "react": "^16.8.4", + "react-dom": "^16.8.4" + }, + "engines": { + "node": ">=8" + } +} diff --git a/packages/docusaurus-theme-classic/src/index.js b/packages/docusaurus-theme-classic/src/index.js new file mode 100644 index 000000000000..d01193d835f5 --- /dev/null +++ b/packages/docusaurus-theme-classic/src/index.js @@ -0,0 +1,36 @@ +/** + * 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. + */ + +const path = require('path'); + +const DEFAULT_OPTIONS = {}; + +class DocusaurusThemeDefault { + constructor(context, opts) { + this.options = {...DEFAULT_OPTIONS, ...opts}; + this.context = context; + } + + getName() { + return 'docusaurus-theme-classic'; + } + + configureWebpack() { + return { + resolve: { + alias: { + '@theme/Footer': path.resolve(__dirname, './theme/Footer'), + '@theme/Navbar': path.resolve(__dirname, './theme/Navbar'), + '@theme/NotFound': path.resolve(__dirname, './theme/NotFound'), + '@theme/Search': path.resolve(__dirname, './theme/Search'), + }, + }, + }; + } +} + +module.exports = DocusaurusThemeDefault; diff --git a/packages/docusaurus/lib/default-theme/Footer/index.js b/packages/docusaurus-theme-classic/src/theme/Footer/index.js similarity index 100% rename from packages/docusaurus/lib/default-theme/Footer/index.js rename to packages/docusaurus-theme-classic/src/theme/Footer/index.js diff --git a/packages/docusaurus/lib/default-theme/Layout/index.js b/packages/docusaurus-theme-classic/src/theme/Layout/index.js similarity index 100% rename from packages/docusaurus/lib/default-theme/Layout/index.js rename to packages/docusaurus-theme-classic/src/theme/Layout/index.js diff --git a/packages/docusaurus/lib/default-theme/Layout/styles.css b/packages/docusaurus-theme-classic/src/theme/Layout/styles.css similarity index 100% rename from packages/docusaurus/lib/default-theme/Layout/styles.css rename to packages/docusaurus-theme-classic/src/theme/Layout/styles.css diff --git a/packages/docusaurus/lib/default-theme/Navbar/index.js b/packages/docusaurus-theme-classic/src/theme/Navbar/index.js similarity index 100% rename from packages/docusaurus/lib/default-theme/Navbar/index.js rename to packages/docusaurus-theme-classic/src/theme/Navbar/index.js diff --git a/packages/docusaurus/lib/default-theme/NotFound.js b/packages/docusaurus-theme-classic/src/theme/NotFound.js similarity index 100% rename from packages/docusaurus/lib/default-theme/NotFound.js rename to packages/docusaurus-theme-classic/src/theme/NotFound.js diff --git a/packages/docusaurus/lib/default-theme/Search/index.js b/packages/docusaurus-theme-classic/src/theme/Search/index.js similarity index 100% rename from packages/docusaurus/lib/default-theme/Search/index.js rename to packages/docusaurus-theme-classic/src/theme/Search/index.js diff --git a/packages/docusaurus/lib/default-theme/Search/styles.css b/packages/docusaurus-theme-classic/src/theme/Search/styles.css similarity index 100% rename from packages/docusaurus/lib/default-theme/Search/styles.css rename to packages/docusaurus-theme-classic/src/theme/Search/styles.css diff --git a/packages/docusaurus/lib/client/theme-fallback/Layout/index.js b/packages/docusaurus/lib/client/theme-fallback/Layout/index.js new file mode 100644 index 000000000000..fdcb856e1b0f --- /dev/null +++ b/packages/docusaurus/lib/client/theme-fallback/Layout/index.js @@ -0,0 +1,28 @@ +/** + * 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 React from 'react'; +import Head from '@docusaurus/Head'; // eslint-disable-line +import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; // eslint-disable-line + +function Layout(props) { + const context = useDocusaurusContext(); + const {siteConfig = {}} = context; + const {baseUrl, favicon, tagline, title: defaultTitle} = siteConfig; + const {children, title} = props; + return ( + + + {title && {`${title} · ${tagline}`}} + {favicon && } + + {children} + + ); +} + +export default Layout; diff --git a/packages/docusaurus/lib/client/theme-fallback/Loading/index.js b/packages/docusaurus/lib/client/theme-fallback/Loading/index.js new file mode 100644 index 000000000000..2460dc1b4c25 --- /dev/null +++ b/packages/docusaurus/lib/client/theme-fallback/Loading/index.js @@ -0,0 +1,110 @@ +/** + * 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 React from 'react'; + +export default props => { + if (props.error) { + console.warn(props.error); + return
Error
; + } + + if (props.pastDelay) { + return ( +
+ + + + + + + + + + + + + + + + + +
+ ); + } + + return null; +}; diff --git a/packages/docusaurus/lib/client/theme-fallback/NotFound/index.js b/packages/docusaurus/lib/client/theme-fallback/NotFound/index.js new file mode 100644 index 000000000000..3e9ff74b35b0 --- /dev/null +++ b/packages/docusaurus/lib/client/theme-fallback/NotFound/index.js @@ -0,0 +1,28 @@ +/** + * 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 React from 'react'; +import Layout from '@theme/Layout'; + +function NotFound() { + return ( + +
+

Oops, page not found

+
+
+ ); +} + +export default NotFound; diff --git a/packages/docusaurus/lib/commands/build.js b/packages/docusaurus/lib/commands/build.js index 71d16e822582..78a494bd6e49 100644 --- a/packages/docusaurus/lib/commands/build.js +++ b/packages/docusaurus/lib/commands/build.js @@ -84,7 +84,7 @@ module.exports = async function build(siteDir, cliOptions = {}) { ); }); - // Run webpack to build js bundle (client) and static html files (server) !! + // Run webpack to build JS bundle (client) and static html files (server). await compile([clientConfig, serverConfig]); // Remove server.bundle.js because it is useless diff --git a/packages/docusaurus/lib/default-theme/Loading/index.js b/packages/docusaurus/lib/default-theme/Loading/index.js deleted file mode 100644 index e430c572cb9a..000000000000 --- a/packages/docusaurus/lib/default-theme/Loading/index.js +++ /dev/null @@ -1,28 +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 React from 'react'; - -import styles from './styles.module.css'; - -export default props => { - if (props.error) { - console.warn(props.error); - return
Error
; - } - - if (props.pastDelay) { - return ( -
-

Please wait a moment

-
-
- ); - } - - return null; -}; diff --git a/packages/docusaurus/lib/default-theme/Loading/styles.module.css b/packages/docusaurus/lib/default-theme/Loading/styles.module.css deleted file mode 100644 index f2712c389f23..000000000000 --- a/packages/docusaurus/lib/default-theme/Loading/styles.module.css +++ /dev/null @@ -1,30 +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. - */ - -.loader { - padding: 20px; - text-align: center; -} - -.loaderSpinning { - width: 49px; - height: 49px; - margin: 0 auto; - border: 5px solid #ccc; - border-radius: 50%; - border-top: 5px solid #1d4d8b; - animation: loader-spin infinite 1s linear; -} - -@keyframes loader-spin { - from { - transform: rotate(0deg); - } - to { - transform: rotate(360deg); - } -} diff --git a/packages/docusaurus/lib/server/index.js b/packages/docusaurus/lib/server/index.js index e2b283cbaebe..f3a2c8d61fdb 100644 --- a/packages/docusaurus/lib/server/index.js +++ b/packages/docusaurus/lib/server/index.js @@ -31,10 +31,18 @@ module.exports = async function load(siteDir, cliOptions = {}) { const context = {siteDir, generatedFilesDir, siteConfig, cliOptions}; // Process presets. - const presetPlugins = loadPresets(context); + const {plugins: presetPlugins, themes: presetThemes} = loadPresets(context); + + // Process plugins and themes. Themes are also plugins, but they run after all + // the explicit plugins because they may override the resolve.alias(es) + // defined by the plugins. + const pluginConfigs = [ + ...presetPlugins, + ...(siteConfig.plugins || []), + ...presetThemes, + ...(siteConfig.themes || []), + ]; - // Process plugins. - const pluginConfigs = [...presetPlugins, ...siteConfig.plugins]; const {plugins, pluginsRouteConfigs} = await loadPlugins({ pluginConfigs, context, @@ -43,8 +51,18 @@ module.exports = async function load(siteDir, cliOptions = {}) { const outDir = path.resolve(siteDir, 'build'); const {baseUrl} = siteConfig; - // Resolve theme. TBD (Experimental) - const themePath = loadTheme(siteDir); + // Resolve custom theme override aliases. + const themeAliases = await loadTheme(siteDir); + // Make a fake plugin to resolve user's theme overrides. + if (themeAliases != null) { + plugins.push({ + configureWebpack: () => ({ + resolve: { + alias: themeAliases, + }, + }), + }); + } // Routing const { @@ -81,7 +99,6 @@ ${Object.keys(registry) siteConfig, siteDir, outDir, - themePath, baseUrl, generatedFilesDir, routesPaths, diff --git a/packages/docusaurus/lib/server/load/__tests__/__fixtures__/preset-qux.js b/packages/docusaurus/lib/server/load/__tests__/__fixtures__/preset-qux.js new file mode 100644 index 000000000000..27ef476447d2 --- /dev/null +++ b/packages/docusaurus/lib/server/load/__tests__/__fixtures__/preset-qux.js @@ -0,0 +1,16 @@ +module.exports = function preset(context, opts = {}) { + return { + themes: [ + { + name: '@docusaurus/theme-classic', + options: opts.test, + }, + ], + plugins: [ + { + name: '@docusaurus/plugin-test', + options: opts.test, + }, + ], + }; +}; diff --git a/packages/docusaurus/lib/server/load/__tests__/presets.test.js b/packages/docusaurus/lib/server/load/__tests__/presets.test.js index 93c3dedfd89a..52eeb4536706 100644 --- a/packages/docusaurus/lib/server/load/__tests__/presets.test.js +++ b/packages/docusaurus/lib/server/load/__tests__/presets.test.js @@ -13,7 +13,12 @@ import loadPresets from '../presets'; describe('loadPresets', () => { test('no presets', () => { const presets = loadPresets({siteConfig: {presets: []}}); - expect(presets).toEqual([]); + expect(presets).toMatchInlineSnapshot(` +Object { + "plugins": Array [], + "themes": Array [], +} +`); }); test('string form', () => { @@ -23,16 +28,19 @@ describe('loadPresets', () => { }, }); expect(presets).toMatchInlineSnapshot(` -Array [ - Object { - "name": "@docusaurus/plugin-content-docs", - "options": undefined, - }, - Object { - "name": "@docusaurus/plugin-content-blog", - "options": undefined, - }, -] +Object { + "plugins": Array [ + Object { + "name": "@docusaurus/plugin-content-docs", + "options": undefined, + }, + Object { + "name": "@docusaurus/plugin-content-blog", + "options": undefined, + }, + ], + "themes": Array [], +} `); }); @@ -46,24 +54,27 @@ Array [ }, }); expect(presets).toMatchInlineSnapshot(` -Array [ - Object { - "name": "@docusaurus/plugin-content-docs", - "options": undefined, - }, - Object { - "name": "@docusaurus/plugin-content-blog", - "options": undefined, - }, - Object { - "name": "@docusaurus/plugin-content-pages", - "options": undefined, - }, - Object { - "name": "@docusaurus/plugin-sitemap", - "options": undefined, - }, -] +Object { + "plugins": Array [ + Object { + "name": "@docusaurus/plugin-content-docs", + "options": undefined, + }, + Object { + "name": "@docusaurus/plugin-content-blog", + "options": undefined, + }, + Object { + "name": "@docusaurus/plugin-content-pages", + "options": undefined, + }, + Object { + "name": "@docusaurus/plugin-sitemap", + "options": undefined, + }, + ], + "themes": Array [], +} `); }); @@ -74,16 +85,19 @@ Array [ }, }); expect(presets).toMatchInlineSnapshot(` -Array [ - Object { - "name": "@docusaurus/plugin-content-docs", - "options": undefined, - }, - Object { - "name": "@docusaurus/plugin-content-blog", - "options": undefined, - }, -] +Object { + "plugins": Array [ + Object { + "name": "@docusaurus/plugin-content-docs", + "options": undefined, + }, + Object { + "name": "@docusaurus/plugin-content-blog", + "options": undefined, + }, + ], + "themes": Array [], +} `); }); @@ -99,18 +113,21 @@ Array [ }, }); expect(presets).toMatchInlineSnapshot(` -Array [ - Object { - "name": "@docusaurus/plugin-content-docs", - "options": Object { - "path": "../", - }, - }, - Object { - "name": "@docusaurus/plugin-content-blog", - "options": undefined, - }, -] +Object { + "plugins": Array [ + Object { + "name": "@docusaurus/plugin-content-docs", + "options": Object { + "path": "../", + }, + }, + Object { + "name": "@docusaurus/plugin-content-blog", + "options": undefined, + }, + ], + "themes": Array [], +} `); }); @@ -130,28 +147,31 @@ Array [ }, }); expect(presets).toMatchInlineSnapshot(` -Array [ - Object { - "name": "@docusaurus/plugin-content-docs", - "options": Object { - "path": "../", - }, - }, - Object { - "name": "@docusaurus/plugin-content-blog", - "options": undefined, - }, - Object { - "name": "@docusaurus/plugin-content-pages", - "options": Object { - "path": "../", - }, - }, - Object { - "name": "@docusaurus/plugin-sitemap", - "options": undefined, - }, -] +Object { + "plugins": Array [ + Object { + "name": "@docusaurus/plugin-content-docs", + "options": Object { + "path": "../", + }, + }, + Object { + "name": "@docusaurus/plugin-content-blog", + "options": undefined, + }, + Object { + "name": "@docusaurus/plugin-content-pages", + "options": Object { + "path": "../", + }, + }, + Object { + "name": "@docusaurus/plugin-sitemap", + "options": undefined, + }, + ], + "themes": Array [], +} `); }); @@ -168,26 +188,78 @@ Array [ }, }); expect(presets).toMatchInlineSnapshot(` -Array [ - Object { - "name": "@docusaurus/plugin-content-docs", - "options": Object { - "path": "../", - }, - }, - Object { - "name": "@docusaurus/plugin-content-blog", - "options": undefined, - }, - Object { - "name": "@docusaurus/plugin-content-pages", - "options": undefined, - }, - Object { - "name": "@docusaurus/plugin-sitemap", - "options": undefined, - }, -] +Object { + "plugins": Array [ + Object { + "name": "@docusaurus/plugin-content-docs", + "options": Object { + "path": "../", + }, + }, + Object { + "name": "@docusaurus/plugin-content-blog", + "options": undefined, + }, + Object { + "name": "@docusaurus/plugin-content-pages", + "options": undefined, + }, + Object { + "name": "@docusaurus/plugin-sitemap", + "options": undefined, + }, + ], + "themes": Array [], +} +`); + }); + + test('mixed form with themes', () => { + const presets = loadPresets({ + siteConfig: { + presets: [ + [ + path.join(__dirname, '__fixtures__/preset-bar.js'), + {docs: {path: '../'}}, + ], + path.join(__dirname, '__fixtures__/preset-foo.js'), + path.join(__dirname, '__fixtures__/preset-qux.js'), + ], + }, + }); + expect(presets).toMatchInlineSnapshot(` +Object { + "plugins": Array [ + Object { + "name": "@docusaurus/plugin-content-docs", + "options": Object { + "path": "../", + }, + }, + Object { + "name": "@docusaurus/plugin-content-blog", + "options": undefined, + }, + Object { + "name": "@docusaurus/plugin-content-pages", + "options": undefined, + }, + Object { + "name": "@docusaurus/plugin-sitemap", + "options": undefined, + }, + Object { + "name": "@docusaurus/plugin-test", + "options": undefined, + }, + ], + "themes": Array [ + Object { + "name": "@docusaurus/theme-classic", + "options": undefined, + }, + ], +} `); }); }); diff --git a/packages/docusaurus/lib/server/load/presets.js b/packages/docusaurus/lib/server/load/presets.js index 8e40f12f4756..9a3c8b93229e 100644 --- a/packages/docusaurus/lib/server/load/presets.js +++ b/packages/docusaurus/lib/server/load/presets.js @@ -7,29 +7,28 @@ const importFresh = require('import-fresh'); const _ = require('lodash'); -const fs = require('fs-extra'); module.exports = function loadPresets(context) { const presets = context.siteConfig.presets || []; - return _.flatten( - presets.map(presetItem => { - let presetModule; - let presetOptions = {}; - if (typeof presetItem === 'string') { - presetModule = presetItem; - } else if (Array.isArray(presetItem)) { - [presetModule, presetOptions] = presetItem; - } + const plugins = []; + const themes = []; - let preset; - if (presetModule && fs.existsSync(presetModule)) { - // Local preset. - preset = importFresh(presetModule); - } else { - // From npm. - preset = importFresh(presetModule); - } - return preset(context, presetOptions).plugins; - }), - ); + presets.forEach(presetItem => { + let presetModule; + let presetOptions = {}; + if (typeof presetItem === 'string') { + presetModule = presetItem; + } else if (Array.isArray(presetItem)) { + [presetModule, presetOptions] = presetItem; + } + + const preset = importFresh(presetModule); + plugins.push(preset(context, presetOptions).plugins); + themes.push(preset(context, presetOptions).themes); + }); + + return { + plugins: _.compact(_.flatten(plugins)), + themes: _.compact(_.flatten(themes)), + }; }; diff --git a/packages/docusaurus/lib/server/load/theme.js b/packages/docusaurus/lib/server/load/theme.js index e229a230e34b..010feb35fb94 100644 --- a/packages/docusaurus/lib/server/load/theme.js +++ b/packages/docusaurus/lib/server/load/theme.js @@ -5,25 +5,32 @@ * LICENSE file in the root directory of this source tree. */ +const globby = require('globby'); const fs = require('fs-extra'); const path = require('path'); +const {fileToPath, posixPath, normalizeUrl} = require('@docusaurus/utils'); -module.exports = function loadConfig(siteDir) { - const customThemePath = path.resolve(siteDir, 'theme'); - const themePath = fs.existsSync(customThemePath) - ? customThemePath - : path.resolve(__dirname, '../../default-theme'); +module.exports = async function loadTheme(siteDir) { + const themePath = path.resolve(siteDir, 'theme'); + if (!fs.existsSync(themePath)) { + return null; + } - const requiredComponents = ['Loading', 'NotFound']; - requiredComponents.forEach(component => { - try { - require.resolve(path.join(themePath, component)); - } catch (e) { - throw new Error( - `Failed to load ${themePath}/${component}. It does not exist.`, - ); - } + const themeComponentFiles = await globby(['**/*.{js,jsx}'], { + cwd: themePath, }); - return themePath; + const alias = {}; + await Promise.all( + themeComponentFiles.map(async relativeSource => { + const filePath = path.join(themePath, relativeSource); + const fileName = fileToPath(relativeSource); + const aliasName = posixPath( + normalizeUrl(['@theme', fileName]).replace(/\/$/, ''), + ); + alias[aliasName] = filePath; + }), + ); + + return alias; }; diff --git a/packages/docusaurus/lib/webpack/base.js b/packages/docusaurus/lib/webpack/base.js index a9cebebd153c..f579f67b2e47 100644 --- a/packages/docusaurus/lib/webpack/base.js +++ b/packages/docusaurus/lib/webpack/base.js @@ -18,7 +18,6 @@ const CSS_MODULE_REGEX = /\.module\.css$/; module.exports = function createBaseConfig(props, isServer) { const { outDir, - themePath, siteDir, baseUrl, generatedFilesDir, @@ -26,6 +25,7 @@ module.exports = function createBaseConfig(props, isServer) { } = props; const isProd = process.env.NODE_ENV === 'production'; + const themeFallback = path.resolve(__dirname, '../client/theme-fallback'); return { mode: isProd ? 'production' : 'development', output: { @@ -42,10 +42,14 @@ module.exports = function createBaseConfig(props, isServer) { resolve: { symlinks: true, alias: { + // https://stackoverflow.com/a/55433680/6072730 ejs: 'ejs/ejs.min.js', - '@theme': themePath, + // These alias can be overriden in plugins. However, these components are essential + // (e.g: react-loadable requires Loading component) so we alias it here first as fallback. + '@theme/Layout': path.join(themeFallback, 'Layout'), + '@theme/Loading': path.join(themeFallback, 'Loading'), + '@theme/NotFound': path.join(themeFallback, 'NotFound'), '@site': siteDir, - '@build': outDir, '@generated': generatedFilesDir, '@docusaurus': path.resolve(__dirname, '../client/exports'), }, diff --git a/packages/docusaurus/package.json b/packages/docusaurus/package.json index 4f5199cb1121..636215ccee3a 100644 --- a/packages/docusaurus/package.json +++ b/packages/docusaurus/package.json @@ -45,7 +45,6 @@ "clean-webpack-plugin": "^2.0.1", "commander": "^2.16.0", "css-loader": "^1.0.0", - "docsearch.js": "^2.5.2", "ejs": "^2.6.1", "envinfo": "^7.2.0", "express": "^4.16.4", diff --git a/website/pages/index.js b/website/pages/index.js index e4aca3fbe35b..63659df4fe24 100644 --- a/website/pages/index.js +++ b/website/pages/index.js @@ -66,7 +66,7 @@ function Home() { // TODO: (wrapper function) API so that user won't need to concatenate url manually const feedbackUrl = `${siteConfig.baseUrl}feedback/`; - const gettingStartedUrl = `${siteConfig.baseUrl}docs/installation`; + const gettingStartedUrl = `${siteConfig.baseUrl}docs/introduction`; useEffect(() => { // Prefetch feedback pages & getting started pages