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:
Sam Zhou 2020-04-12 14:05:46 -04:00 committed by GitHub
parent f6267dc52c
commit 5f487f3b02
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
30 changed files with 128 additions and 22 deletions

View file

@ -45,6 +45,7 @@ export interface DocusaurusConfig {
export interface DocusaurusContext {
siteConfig?: DocusaurusConfig;
isClient?: boolean;
}
export interface Preset {

View file

@ -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);
},
});

View file

@ -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"

View file

@ -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';

View file

@ -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<Props, State> {
previousLocation: any;
progressBarTimeout: any;
constructor(props: Props) {
super(props);
// previousLocation doesn't affect rendering, hence not stored in state.

View file

@ -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();

View file

@ -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;

View file

@ -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) {

View file

@ -6,7 +6,7 @@
*/
import React from 'react';
import ExecutionEnvironment from '@docusaurus/ExecutionEnvironment';
import ExecutionEnvironment from './ExecutionEnvironment';
function BrowserOnly({children}) {
return (

View file

@ -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

View file

@ -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;

View file

@ -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);

View file

@ -6,5 +6,6 @@
*/
import React from 'react';
import {DocusaurusContext} from '@docusaurus/types';
export default React.createContext({});
export default React.createContext<DocusaurusContext>({});

View file

@ -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;
}

View file

@ -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 || {};

View file

@ -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;

View file

@ -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';

View 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;
}

View 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"]
}

View file

@ -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"]
}