diff --git a/packages/docusaurus-types/src/index.d.ts b/packages/docusaurus-types/src/index.d.ts index 28eddd1963..2dbdc89b1c 100644 --- a/packages/docusaurus-types/src/index.d.ts +++ b/packages/docusaurus-types/src/index.d.ts @@ -45,6 +45,7 @@ export interface DocusaurusConfig { export interface DocusaurusContext { siteConfig?: DocusaurusConfig; + isClient?: boolean; } export interface Preset { diff --git a/packages/docusaurus/copyUntypedFiles.js b/packages/docusaurus/copyUntypedFiles.js index 3f814cf099..e5555c5536 100644 --- a/packages/docusaurus/copyUntypedFiles.js +++ b/packages/docusaurus/copyUntypedFiles.js @@ -15,6 +15,6 @@ const srcDir = path.resolve(__dirname, 'src'); const libDir = path.resolve(__dirname, 'lib'); fs.copySync(srcDir, libDir, { filter(filepath) { - return !/__tests__/.test(filepath) && !/\.ts$/.test(filepath); + return !/__tests__/.test(filepath) && !/\.tsx?$/.test(filepath); }, }); diff --git a/packages/docusaurus/package.json b/packages/docusaurus/package.json index e659101a16..deaf509391 100644 --- a/packages/docusaurus/package.json +++ b/packages/docusaurus/package.json @@ -23,7 +23,7 @@ "docusaurus": "bin/docusaurus.js" }, "scripts": { - "tsc": "tsc && node copyUntypedFiles.js" + "tsc": "tsc && tsc -p tsconfig.client.json && node copyUntypedFiles.js" }, "bugs": { "url": "https://github.com/facebook/docusaurus/issues" diff --git a/packages/docusaurus/src/client/App.js b/packages/docusaurus/src/client/App.tsx similarity index 88% rename from packages/docusaurus/src/client/App.js rename to packages/docusaurus/src/client/App.tsx index abf2bae837..40d4f42491 100644 --- a/packages/docusaurus/src/client/App.js +++ b/packages/docusaurus/src/client/App.tsx @@ -9,8 +9,8 @@ import React, {useEffect, useState} from 'react'; import routes from '@generated/routes'; import siteConfig from '@generated/docusaurus.config'; -import renderRoutes from '@docusaurus/renderRoutes'; -import DocusaurusContext from '@docusaurus/context'; +import renderRoutes from './exports/renderRoutes'; +import DocusaurusContext from './exports/context'; import PendingNavigation from './PendingNavigation'; import './client-lifecycles-dispatcher'; diff --git a/packages/docusaurus/src/client/PendingNavigation.js b/packages/docusaurus/src/client/PendingNavigation.tsx similarity index 92% rename from packages/docusaurus/src/client/PendingNavigation.js rename to packages/docusaurus/src/client/PendingNavigation.tsx index f5316d8b64..63f623eadf 100644 --- a/packages/docusaurus/src/client/PendingNavigation.js +++ b/packages/docusaurus/src/client/PendingNavigation.tsx @@ -17,8 +17,20 @@ import 'nprogress/nprogress.css'; nprogress.configure({showSpinner: false}); -class PendingNavigation extends React.Component { - constructor(props) { +interface Props { + routes: any[]; + delay: number; + location: any; +} +interface State { + nextRouteHasLoaded: boolean; +} + +class PendingNavigation extends React.Component { + previousLocation: any; + progressBarTimeout: any; + + constructor(props: Props) { super(props); // previousLocation doesn't affect rendering, hence not stored in state. diff --git a/packages/docusaurus/src/client/__tests__/flat.test.js b/packages/docusaurus/src/client/__tests__/flat.test.ts similarity index 100% rename from packages/docusaurus/src/client/__tests__/flat.test.js rename to packages/docusaurus/src/client/__tests__/flat.test.ts diff --git a/packages/docusaurus/src/client/__tests__/normalizeLocation.test.js b/packages/docusaurus/src/client/__tests__/normalizeLocation.test.ts similarity index 100% rename from packages/docusaurus/src/client/__tests__/normalizeLocation.test.js rename to packages/docusaurus/src/client/__tests__/normalizeLocation.test.ts diff --git a/packages/docusaurus/src/client/client-lifecycles-dispatcher.js b/packages/docusaurus/src/client/client-lifecycles-dispatcher.ts similarity index 87% rename from packages/docusaurus/src/client/client-lifecycles-dispatcher.js rename to packages/docusaurus/src/client/client-lifecycles-dispatcher.ts index 942dd3c2af..376b228664 100644 --- a/packages/docusaurus/src/client/client-lifecycles-dispatcher.js +++ b/packages/docusaurus/src/client/client-lifecycles-dispatcher.ts @@ -16,7 +16,12 @@ function dispatchLifecycleAction(lifecycleAction, ...args) { }); } -function createLifecyclesDispatcher() { +interface Dispatchers { + onRouteUpdate: Function; + onRouteUpdateDelayed: Function; +} + +function createLifecyclesDispatcher(): Dispatchers { // TODO: Not sure whether it's better to declare an explicit object // with all the lifecycles. It's better for typing but quite verbose. // On the other hand, there's some runtime cost generating this object @@ -30,7 +35,7 @@ function createLifecyclesDispatcher() { return lifecycles; }, {}, - ); + ) as Dispatchers; } export default createLifecyclesDispatcher(); diff --git a/packages/docusaurus/src/client/clientEntry.js b/packages/docusaurus/src/client/clientEntry.tsx similarity index 91% rename from packages/docusaurus/src/client/clientEntry.js rename to packages/docusaurus/src/client/clientEntry.tsx index 51e2a2ef3f..ce733a4e7a 100644 --- a/packages/docusaurus/src/client/clientEntry.js +++ b/packages/docusaurus/src/client/clientEntry.tsx @@ -10,11 +10,17 @@ import {hydrate, render} from 'react-dom'; import {BrowserRouter} from 'react-router-dom'; import routes from '@generated/routes'; -import ExecutionEnvironment from '@docusaurus/ExecutionEnvironment'; +import ExecutionEnvironment from './exports/ExecutionEnvironment'; import App from './App'; import preload from './preload'; import docusaurus from './docusaurus'; +declare global { + interface NodeModule { + hot?: any; + } +} + // Client-side render (e.g: running in browser) to become single-page application (SPA). if (ExecutionEnvironment.canUseDOM) { window.docusaurus = docusaurus; diff --git a/packages/docusaurus/src/client/docusaurus.js b/packages/docusaurus/src/client/docusaurus.ts similarity index 95% rename from packages/docusaurus/src/client/docusaurus.js rename to packages/docusaurus/src/client/docusaurus.ts index 17ca22ae77..2bbe88de34 100644 --- a/packages/docusaurus/src/client/docusaurus.js +++ b/packages/docusaurus/src/client/docusaurus.ts @@ -14,6 +14,13 @@ import flat from './flat'; const fetched = {}; const loaded = {}; +declare global { + const __webpack_require__: any; + interface Navigator { + connection: any; + } +} + const isSlowConnection = () => { // If user is on slow or constrained connection. if (`connection` in navigator) { diff --git a/packages/docusaurus/src/client/exports/BrowserOnly.js b/packages/docusaurus/src/client/exports/BrowserOnly.tsx similarity index 84% rename from packages/docusaurus/src/client/exports/BrowserOnly.js rename to packages/docusaurus/src/client/exports/BrowserOnly.tsx index ddae8bb3eb..5c39340b12 100644 --- a/packages/docusaurus/src/client/exports/BrowserOnly.js +++ b/packages/docusaurus/src/client/exports/BrowserOnly.tsx @@ -6,7 +6,7 @@ */ import React from 'react'; -import ExecutionEnvironment from '@docusaurus/ExecutionEnvironment'; +import ExecutionEnvironment from './ExecutionEnvironment'; function BrowserOnly({children}) { return ( diff --git a/packages/docusaurus/src/client/exports/ComponentCreator.js b/packages/docusaurus/src/client/exports/ComponentCreator.tsx similarity index 95% rename from packages/docusaurus/src/client/exports/ComponentCreator.js rename to packages/docusaurus/src/client/exports/ComponentCreator.tsx index 485c86651f..1ee17d0315 100644 --- a/packages/docusaurus/src/client/exports/ComponentCreator.js +++ b/packages/docusaurus/src/client/exports/ComponentCreator.tsx @@ -12,7 +12,7 @@ import routesChunkNames from '@generated/routesChunkNames'; import registry from '@generated/registry'; import flat from '../flat'; -function ComponentCreator(path) { +function ComponentCreator(path: string) { // 404 page if (path === '*') { return Loadable({ @@ -22,8 +22,8 @@ function ComponentCreator(path) { } const chunkNames = routesChunkNames[path]; - const optsModules = []; - const optsWebpack = []; + const optsModules: string[] = []; + const optsWebpack: string[] = []; const optsLoader = {}; /* Prepare opts data that react-loadable needs diff --git a/packages/docusaurus/src/client/exports/ExecutionEnvironment.js b/packages/docusaurus/src/client/exports/ExecutionEnvironment.ts similarity index 91% rename from packages/docusaurus/src/client/exports/ExecutionEnvironment.js rename to packages/docusaurus/src/client/exports/ExecutionEnvironment.ts index 91867c8aa9..9509054616 100644 --- a/packages/docusaurus/src/client/exports/ExecutionEnvironment.js +++ b/packages/docusaurus/src/client/exports/ExecutionEnvironment.ts @@ -15,6 +15,7 @@ const ExecutionEnvironment = { canUseDOM, canUseEventListeners: + // @ts-ignore canUseDOM && !!(window.addEventListener || window.attachEvent), canUseIntersectionObserver: canUseDOM && 'IntersectionObserver' in window, @@ -22,4 +23,4 @@ const ExecutionEnvironment = { canUseViewport: canUseDOM && !!window.screen, }; -module.exports = ExecutionEnvironment; +export default ExecutionEnvironment; diff --git a/packages/docusaurus/src/client/exports/Head.js b/packages/docusaurus/src/client/exports/Head.tsx similarity index 100% rename from packages/docusaurus/src/client/exports/Head.js rename to packages/docusaurus/src/client/exports/Head.tsx diff --git a/packages/docusaurus/src/client/exports/Link.js b/packages/docusaurus/src/client/exports/Link.tsx similarity index 87% rename from packages/docusaurus/src/client/exports/Link.js rename to packages/docusaurus/src/client/exports/Link.tsx index f3a978f7ff..ec970aa43c 100644 --- a/packages/docusaurus/src/client/exports/Link.js +++ b/packages/docusaurus/src/client/exports/Link.tsx @@ -6,11 +6,24 @@ */ import React, {useEffect, useRef} from 'react'; -import {NavLink, Link as RRLink} from 'react-router-dom'; -import isInternalUrl from '@docusaurus/isInternalUrl'; -import ExecutionEnvironment from '@docusaurus/ExecutionEnvironment'; -function Link({isNavLink, ...props}) { +import {NavLink, Link as RRLink} from 'react-router-dom'; +import isInternalUrl from './isInternalUrl'; +import ExecutionEnvironment from './ExecutionEnvironment'; + +declare global { + interface Window { + docusaurus: any; + } +} + +interface Props { + readonly isNavLink?: boolean; + readonly to?: string; + readonly href: string +} + +function Link({isNavLink, ...props}: Props) { const {to, href} = props; const targetLink = to || href; const isInternal = isInternalUrl(targetLink); diff --git a/packages/docusaurus/src/client/exports/Noop.js b/packages/docusaurus/src/client/exports/Noop.ts similarity index 100% rename from packages/docusaurus/src/client/exports/Noop.js rename to packages/docusaurus/src/client/exports/Noop.ts diff --git a/packages/docusaurus/src/client/exports/context.js b/packages/docusaurus/src/client/exports/context.ts similarity index 66% rename from packages/docusaurus/src/client/exports/context.js rename to packages/docusaurus/src/client/exports/context.ts index b979a7f1f7..d5b4f3c5c2 100644 --- a/packages/docusaurus/src/client/exports/context.js +++ b/packages/docusaurus/src/client/exports/context.ts @@ -6,5 +6,6 @@ */ import React from 'react'; +import {DocusaurusContext} from '@docusaurus/types'; -export default React.createContext({}); +export default React.createContext({}); diff --git a/packages/docusaurus/src/client/exports/isInternalUrl.js b/packages/docusaurus/src/client/exports/isInternalUrl.ts similarity index 80% rename from packages/docusaurus/src/client/exports/isInternalUrl.js rename to packages/docusaurus/src/client/exports/isInternalUrl.ts index 9e7acfc818..c68ce38be6 100644 --- a/packages/docusaurus/src/client/exports/isInternalUrl.js +++ b/packages/docusaurus/src/client/exports/isInternalUrl.ts @@ -5,6 +5,6 @@ * LICENSE file in the root directory of this source tree. */ -export default function isInternalUrl(url) { +export default function isInternalUrl(url: string): boolean { return /^(https?:|\/\/|mailto:|tel:)/.test(url) === false; } diff --git a/packages/docusaurus/src/client/exports/renderRoutes.js b/packages/docusaurus/src/client/exports/renderRoutes.ts similarity index 100% rename from packages/docusaurus/src/client/exports/renderRoutes.js rename to packages/docusaurus/src/client/exports/renderRoutes.ts diff --git a/packages/docusaurus/src/client/exports/router.js b/packages/docusaurus/src/client/exports/router.ts similarity index 100% rename from packages/docusaurus/src/client/exports/router.js rename to packages/docusaurus/src/client/exports/router.ts diff --git a/packages/docusaurus/src/client/exports/useBaseUrl.js b/packages/docusaurus/src/client/exports/useBaseUrl.ts similarity index 90% rename from packages/docusaurus/src/client/exports/useBaseUrl.js rename to packages/docusaurus/src/client/exports/useBaseUrl.ts index aed661096b..a27d87813c 100644 --- a/packages/docusaurus/src/client/exports/useBaseUrl.js +++ b/packages/docusaurus/src/client/exports/useBaseUrl.ts @@ -7,7 +7,7 @@ import useDocusaurusContext from './useDocusaurusContext'; -export default function useBaseUrl(url) { +export default function useBaseUrl(url: string): string { const {siteConfig} = useDocusaurusContext(); const {baseUrl = '/'} = siteConfig || {}; diff --git a/packages/docusaurus/src/client/exports/useDocusaurusContext.js b/packages/docusaurus/src/client/exports/useDocusaurusContext.ts similarity index 100% rename from packages/docusaurus/src/client/exports/useDocusaurusContext.js rename to packages/docusaurus/src/client/exports/useDocusaurusContext.ts diff --git a/packages/docusaurus/src/client/flat.js b/packages/docusaurus/src/client/flat.ts similarity index 94% rename from packages/docusaurus/src/client/flat.js rename to packages/docusaurus/src/client/flat.ts index 04173df589..b1f320b3ab 100644 --- a/packages/docusaurus/src/client/flat.js +++ b/packages/docusaurus/src/client/flat.ts @@ -9,7 +9,7 @@ function flat(target) { const delimiter = '.'; const output = {}; - function step(object, prev) { + function step(object, prev?: string) { Object.keys(object).forEach((key) => { const value = object[key]; const type = typeof value; diff --git a/packages/docusaurus/src/client/normalizeLocation.js b/packages/docusaurus/src/client/normalizeLocation.ts similarity index 100% rename from packages/docusaurus/src/client/normalizeLocation.js rename to packages/docusaurus/src/client/normalizeLocation.ts diff --git a/packages/docusaurus/src/client/prefetch.js b/packages/docusaurus/src/client/prefetch.ts similarity index 100% rename from packages/docusaurus/src/client/prefetch.js rename to packages/docusaurus/src/client/prefetch.ts diff --git a/packages/docusaurus/src/client/preload.js b/packages/docusaurus/src/client/preload.ts similarity index 100% rename from packages/docusaurus/src/client/preload.js rename to packages/docusaurus/src/client/preload.ts diff --git a/packages/docusaurus/src/client/serverEntry.js b/packages/docusaurus/src/client/serverEntry.js index 5cb7be8d57..b700e41aa6 100644 --- a/packages/docusaurus/src/client/serverEntry.js +++ b/packages/docusaurus/src/client/serverEntry.js @@ -18,7 +18,9 @@ import path from 'path'; import fs from 'fs-extra'; import routes from '@generated/routes'; import packageJson from '../../package.json'; +// eslint-disable-next-line import/no-unresolved import preload from './preload'; +// eslint-disable-next-line import/no-unresolved import App from './App'; import ssrTemplate from './templates/ssr.html.template'; diff --git a/packages/docusaurus/src/client/types.d.ts b/packages/docusaurus/src/client/types.d.ts new file mode 100644 index 0000000000..4d019518ae --- /dev/null +++ b/packages/docusaurus/src/client/types.d.ts @@ -0,0 +1,43 @@ +/** + * 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. + */ + +declare module '@generated/client-modules' { + const clientModules: readonly any[]; + export default clientModules; +} + +declare module '@generated/docusaurus.config' { + const config: any; + export default config; +} + +declare module '@generated/registry' { + const registry: { + readonly [key: string]: [() => Promise, string, string]; + }; + export default registry; +} + +declare module '@generated/routes' { + type Route = { + readonly path: string; + readonly component: any; + readonly exact?: boolean; + }; + const routes: Route[]; + export default routes; +} + +declare module '@generated/routesChunkNames' { + const routesChunkNames: any; + export default routesChunkNames; +} + +declare module '@theme/*' { + const component: any; + export default component; +} diff --git a/packages/docusaurus/tsconfig.client.json b/packages/docusaurus/tsconfig.client.json new file mode 100644 index 0000000000..713d7753e9 --- /dev/null +++ b/packages/docusaurus/tsconfig.client.json @@ -0,0 +1,13 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "incremental": true, + "lib": ["DOM"], + "module": "esnext", + "tsBuildInfoFile": "./lib/client/.tsbuildinfo", + "outDir": "lib/client", + "noImplicitAny": false, + "jsx": "react", + }, + "include": ["src/client"] +} diff --git a/packages/docusaurus/tsconfig.json b/packages/docusaurus/tsconfig.json index ef724a2c34..5276f6f4d1 100644 --- a/packages/docusaurus/tsconfig.json +++ b/packages/docusaurus/tsconfig.json @@ -2,10 +2,12 @@ "extends": "../../tsconfig.json", "compilerOptions": { "incremental": true, + "lib": ["DOM"], "tsBuildInfoFile": "./lib/.tsbuildinfo", "rootDir": "src", "outDir": "lib", "noImplicitAny": false, "jsx": "react", }, + "exclude": ["node_modules", "**/__tests__/**/*", "**/lib/**/*", "src/client"] }