mirror of
https://github.com/facebook/docusaurus.git
synced 2025-06-06 21:03:47 +02:00
refactor(v2): Convert docusaurus-core to TypeScript (#2578)
* refactor(v2): Convert docusaurus-core to TypeScript * Update types.d.ts Co-authored-by: Yangshun Tay <tay.yang.shun@gmail.com>
This commit is contained in:
parent
f6267dc52c
commit
5f487f3b02
30 changed files with 128 additions and 22 deletions
1
packages/docusaurus-types/src/index.d.ts
vendored
1
packages/docusaurus-types/src/index.d.ts
vendored
|
@ -45,6 +45,7 @@ export interface DocusaurusConfig {
|
||||||
|
|
||||||
export interface DocusaurusContext {
|
export interface DocusaurusContext {
|
||||||
siteConfig?: DocusaurusConfig;
|
siteConfig?: DocusaurusConfig;
|
||||||
|
isClient?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Preset {
|
export interface Preset {
|
||||||
|
|
|
@ -15,6 +15,6 @@ const srcDir = path.resolve(__dirname, 'src');
|
||||||
const libDir = path.resolve(__dirname, 'lib');
|
const libDir = path.resolve(__dirname, 'lib');
|
||||||
fs.copySync(srcDir, libDir, {
|
fs.copySync(srcDir, libDir, {
|
||||||
filter(filepath) {
|
filter(filepath) {
|
||||||
return !/__tests__/.test(filepath) && !/\.ts$/.test(filepath);
|
return !/__tests__/.test(filepath) && !/\.tsx?$/.test(filepath);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
"docusaurus": "bin/docusaurus.js"
|
"docusaurus": "bin/docusaurus.js"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"tsc": "tsc && node copyUntypedFiles.js"
|
"tsc": "tsc && tsc -p tsconfig.client.json && node copyUntypedFiles.js"
|
||||||
},
|
},
|
||||||
"bugs": {
|
"bugs": {
|
||||||
"url": "https://github.com/facebook/docusaurus/issues"
|
"url": "https://github.com/facebook/docusaurus/issues"
|
||||||
|
|
|
@ -9,8 +9,8 @@ import React, {useEffect, useState} from 'react';
|
||||||
|
|
||||||
import routes from '@generated/routes';
|
import routes from '@generated/routes';
|
||||||
import siteConfig from '@generated/docusaurus.config';
|
import siteConfig from '@generated/docusaurus.config';
|
||||||
import renderRoutes from '@docusaurus/renderRoutes';
|
import renderRoutes from './exports/renderRoutes';
|
||||||
import DocusaurusContext from '@docusaurus/context';
|
import DocusaurusContext from './exports/context';
|
||||||
import PendingNavigation from './PendingNavigation';
|
import PendingNavigation from './PendingNavigation';
|
||||||
|
|
||||||
import './client-lifecycles-dispatcher';
|
import './client-lifecycles-dispatcher';
|
|
@ -17,8 +17,20 @@ import 'nprogress/nprogress.css';
|
||||||
|
|
||||||
nprogress.configure({showSpinner: false});
|
nprogress.configure({showSpinner: false});
|
||||||
|
|
||||||
class PendingNavigation extends React.Component {
|
interface Props {
|
||||||
constructor(props) {
|
routes: any[];
|
||||||
|
delay: number;
|
||||||
|
location: any;
|
||||||
|
}
|
||||||
|
interface State {
|
||||||
|
nextRouteHasLoaded: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
class PendingNavigation extends React.Component<Props, State> {
|
||||||
|
previousLocation: any;
|
||||||
|
progressBarTimeout: any;
|
||||||
|
|
||||||
|
constructor(props: Props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
// previousLocation doesn't affect rendering, hence not stored in state.
|
// previousLocation doesn't affect rendering, hence not stored in state.
|
|
@ -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
|
// TODO: Not sure whether it's better to declare an explicit object
|
||||||
// with all the lifecycles. It's better for typing but quite verbose.
|
// with all the lifecycles. It's better for typing but quite verbose.
|
||||||
// On the other hand, there's some runtime cost generating this object
|
// On the other hand, there's some runtime cost generating this object
|
||||||
|
@ -30,7 +35,7 @@ function createLifecyclesDispatcher() {
|
||||||
return lifecycles;
|
return lifecycles;
|
||||||
},
|
},
|
||||||
{},
|
{},
|
||||||
);
|
) as Dispatchers;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default createLifecyclesDispatcher();
|
export default createLifecyclesDispatcher();
|
|
@ -10,11 +10,17 @@ import {hydrate, render} from 'react-dom';
|
||||||
import {BrowserRouter} from 'react-router-dom';
|
import {BrowserRouter} from 'react-router-dom';
|
||||||
|
|
||||||
import routes from '@generated/routes';
|
import routes from '@generated/routes';
|
||||||
import ExecutionEnvironment from '@docusaurus/ExecutionEnvironment';
|
import ExecutionEnvironment from './exports/ExecutionEnvironment';
|
||||||
import App from './App';
|
import App from './App';
|
||||||
import preload from './preload';
|
import preload from './preload';
|
||||||
import docusaurus from './docusaurus';
|
import docusaurus from './docusaurus';
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface NodeModule {
|
||||||
|
hot?: any;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Client-side render (e.g: running in browser) to become single-page application (SPA).
|
// Client-side render (e.g: running in browser) to become single-page application (SPA).
|
||||||
if (ExecutionEnvironment.canUseDOM) {
|
if (ExecutionEnvironment.canUseDOM) {
|
||||||
window.docusaurus = docusaurus;
|
window.docusaurus = docusaurus;
|
|
@ -14,6 +14,13 @@ import flat from './flat';
|
||||||
const fetched = {};
|
const fetched = {};
|
||||||
const loaded = {};
|
const loaded = {};
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
const __webpack_require__: any;
|
||||||
|
interface Navigator {
|
||||||
|
connection: any;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const isSlowConnection = () => {
|
const isSlowConnection = () => {
|
||||||
// If user is on slow or constrained connection.
|
// If user is on slow or constrained connection.
|
||||||
if (`connection` in navigator) {
|
if (`connection` in navigator) {
|
|
@ -6,7 +6,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import ExecutionEnvironment from '@docusaurus/ExecutionEnvironment';
|
import ExecutionEnvironment from './ExecutionEnvironment';
|
||||||
|
|
||||||
function BrowserOnly({children}) {
|
function BrowserOnly({children}) {
|
||||||
return (
|
return (
|
|
@ -12,7 +12,7 @@ import routesChunkNames from '@generated/routesChunkNames';
|
||||||
import registry from '@generated/registry';
|
import registry from '@generated/registry';
|
||||||
import flat from '../flat';
|
import flat from '../flat';
|
||||||
|
|
||||||
function ComponentCreator(path) {
|
function ComponentCreator(path: string) {
|
||||||
// 404 page
|
// 404 page
|
||||||
if (path === '*') {
|
if (path === '*') {
|
||||||
return Loadable({
|
return Loadable({
|
||||||
|
@ -22,8 +22,8 @@ function ComponentCreator(path) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const chunkNames = routesChunkNames[path];
|
const chunkNames = routesChunkNames[path];
|
||||||
const optsModules = [];
|
const optsModules: string[] = [];
|
||||||
const optsWebpack = [];
|
const optsWebpack: string[] = [];
|
||||||
const optsLoader = {};
|
const optsLoader = {};
|
||||||
|
|
||||||
/* Prepare opts data that react-loadable needs
|
/* Prepare opts data that react-loadable needs
|
|
@ -15,6 +15,7 @@ const ExecutionEnvironment = {
|
||||||
canUseDOM,
|
canUseDOM,
|
||||||
|
|
||||||
canUseEventListeners:
|
canUseEventListeners:
|
||||||
|
// @ts-ignore
|
||||||
canUseDOM && !!(window.addEventListener || window.attachEvent),
|
canUseDOM && !!(window.addEventListener || window.attachEvent),
|
||||||
|
|
||||||
canUseIntersectionObserver: canUseDOM && 'IntersectionObserver' in window,
|
canUseIntersectionObserver: canUseDOM && 'IntersectionObserver' in window,
|
||||||
|
@ -22,4 +23,4 @@ const ExecutionEnvironment = {
|
||||||
canUseViewport: canUseDOM && !!window.screen,
|
canUseViewport: canUseDOM && !!window.screen,
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = ExecutionEnvironment;
|
export default ExecutionEnvironment;
|
|
@ -6,11 +6,24 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, {useEffect, useRef} from 'react';
|
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 {to, href} = props;
|
||||||
const targetLink = to || href;
|
const targetLink = to || href;
|
||||||
const isInternal = isInternalUrl(targetLink);
|
const isInternal = isInternalUrl(targetLink);
|
|
@ -6,5 +6,6 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import {DocusaurusContext} from '@docusaurus/types';
|
||||||
|
|
||||||
export default React.createContext({});
|
export default React.createContext<DocusaurusContext>({});
|
|
@ -5,6 +5,6 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* 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;
|
return /^(https?:|\/\/|mailto:|tel:)/.test(url) === false;
|
||||||
}
|
}
|
|
@ -7,7 +7,7 @@
|
||||||
|
|
||||||
import useDocusaurusContext from './useDocusaurusContext';
|
import useDocusaurusContext from './useDocusaurusContext';
|
||||||
|
|
||||||
export default function useBaseUrl(url) {
|
export default function useBaseUrl(url: string): string {
|
||||||
const {siteConfig} = useDocusaurusContext();
|
const {siteConfig} = useDocusaurusContext();
|
||||||
const {baseUrl = '/'} = siteConfig || {};
|
const {baseUrl = '/'} = siteConfig || {};
|
||||||
|
|
|
@ -9,7 +9,7 @@ function flat(target) {
|
||||||
const delimiter = '.';
|
const delimiter = '.';
|
||||||
const output = {};
|
const output = {};
|
||||||
|
|
||||||
function step(object, prev) {
|
function step(object, prev?: string) {
|
||||||
Object.keys(object).forEach((key) => {
|
Object.keys(object).forEach((key) => {
|
||||||
const value = object[key];
|
const value = object[key];
|
||||||
const type = typeof value;
|
const type = typeof value;
|
|
@ -18,7 +18,9 @@ import path from 'path';
|
||||||
import fs from 'fs-extra';
|
import fs from 'fs-extra';
|
||||||
import routes from '@generated/routes';
|
import routes from '@generated/routes';
|
||||||
import packageJson from '../../package.json';
|
import packageJson from '../../package.json';
|
||||||
|
// eslint-disable-next-line import/no-unresolved
|
||||||
import preload from './preload';
|
import preload from './preload';
|
||||||
|
// eslint-disable-next-line import/no-unresolved
|
||||||
import App from './App';
|
import App from './App';
|
||||||
import ssrTemplate from './templates/ssr.html.template';
|
import ssrTemplate from './templates/ssr.html.template';
|
||||||
|
|
||||||
|
|
43
packages/docusaurus/src/client/types.d.ts
vendored
Normal file
43
packages/docusaurus/src/client/types.d.ts
vendored
Normal file
|
@ -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<any>, 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;
|
||||||
|
}
|
13
packages/docusaurus/tsconfig.client.json
Normal file
13
packages/docusaurus/tsconfig.client.json
Normal file
|
@ -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"]
|
||||||
|
}
|
|
@ -2,10 +2,12 @@
|
||||||
"extends": "../../tsconfig.json",
|
"extends": "../../tsconfig.json",
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"incremental": true,
|
"incremental": true,
|
||||||
|
"lib": ["DOM"],
|
||||||
"tsBuildInfoFile": "./lib/.tsbuildinfo",
|
"tsBuildInfoFile": "./lib/.tsbuildinfo",
|
||||||
"rootDir": "src",
|
"rootDir": "src",
|
||||||
"outDir": "lib",
|
"outDir": "lib",
|
||||||
"noImplicitAny": false,
|
"noImplicitAny": false,
|
||||||
"jsx": "react",
|
"jsx": "react",
|
||||||
},
|
},
|
||||||
|
"exclude": ["node_modules", "**/__tests__/**/*", "**/lib/**/*", "src/client"]
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue