diff --git a/custom.d.ts b/custom.d.ts index 0154cc79..4fbe6022 100644 --- a/custom.d.ts +++ b/custom.d.ts @@ -13,7 +13,7 @@ declare module '*.css' { export default content; } -declare var __DEV__: boolean; +declare var __REDOC_DEV__: boolean; declare var __REDOC_VERSION__: string; declare var __REDOC_REVISION__: string; diff --git a/demo/ssr/index.ts b/demo/ssr/index.ts index 5baeb48e..836af8a4 100644 --- a/demo/ssr/index.ts +++ b/demo/ssr/index.ts @@ -18,7 +18,7 @@ const server = http.createServer(async (request, response) => { fs.createReadStream('bundles/redoc.standalone.js', 'utf8').pipe(response); } else if (request.url === '/') { const spec = yaml.load(readFileSync(resolve(__dirname, '../openapi.yaml'))); - let store = await createStore(spec, '', { nativeScrollbars: true }); + let store = await createStore(spec, 'path/to/spec.yaml'); const sheet = new ServerStyleSheet(); @@ -37,26 +37,21 @@ const server = http.createServer(async (request, response) => { margin: 0; } - - ${css} -
${html}
- + +
${html}
`; - response.writeHead(200); + response.writeHead(200, { 'Content-Length': res.length }); response.write(res); response.end(); } else { diff --git a/src/__tests__/ssr.test.tsx b/src/__tests__/ssr.test.tsx index 0947fba4..e6c141e0 100644 --- a/src/__tests__/ssr.test.tsx +++ b/src/__tests__/ssr.test.tsx @@ -8,13 +8,13 @@ import { resolve } from 'path'; describe('SSR', () => { it('should render in SSR mode', async () => { - (global as any).__DEV__ = true; + (global as any).__REDOC_DEV__ = true; const spec = yaml.load(readFileSync(resolve(__dirname, '../../demo/openapi.yaml'))); const store = await createStore(spec, ''); expect(() => { renderToString(); }).not.toThrow(); - delete (global as any).__DEV__; + delete (global as any).__REDOC_DEV__; }); }); diff --git a/src/services/AppStore.ts b/src/services/AppStore.ts index 81031cc0..b213166b 100644 --- a/src/services/AppStore.ts +++ b/src/services/AppStore.ts @@ -9,7 +9,7 @@ import { RedocNormalizedOptions, RedocRawOptions } from './RedocNormalizedOption import { ScrollService } from './ScrollService'; import { SearchStore } from './SearchStore'; -interface StoreData { +export interface StoreState { menu: { activeItemIdx: number; }; @@ -36,7 +36,7 @@ export class AppStore { * **SUPER HACKY AND NOT OPTIMAL IMPLEMENTATION** */ // TODO: - static fromJS(state: StoreData): AppStore { + static fromJS(state: StoreState): AppStore { const inst = new AppStore(state.spec.data, state.spec.url, state.options, false); inst.menu.activeItemIdx = state.menu.activeItemIdx || 0; inst.menu.activate(inst.menu.flatItems[inst.menu.activeItemIdx]); @@ -114,7 +114,7 @@ export class AppStore { * **SUPER HACKY AND NOT OPTIMAL IMPLEMENTATION** */ // TODO: - async toJS(): Promise { + async toJS(): Promise { return { menu: { activeItemIdx: this.menu.activeItemIdx, diff --git a/src/services/OpenAPIParser.ts b/src/services/OpenAPIParser.ts index b03c7139..d4a676df 100644 --- a/src/services/OpenAPIParser.ts +++ b/src/services/OpenAPIParser.ts @@ -122,7 +122,7 @@ export class OpenAPIParser { * resets visited enpoints. should be run after */ resetVisited() { - if (__DEV__) { + if (__REDOC_DEV__) { // check in dev mode for (const k in this._refCounter._counter) { if (this._refCounter._counter[k] > 0) { diff --git a/src/standalone.tsx b/src/standalone.tsx index a9df0c5a..43482154 100644 --- a/src/standalone.tsx +++ b/src/standalone.tsx @@ -1,10 +1,12 @@ import * as React from 'react'; -import { render } from 'react-dom'; +import { render, hydrate as hydrateComponent } from 'react-dom'; -import { RedocStandalone } from './components/RedocStandalone'; +import { RedocStandalone, Redoc } from './components/'; +import { AppStore, StoreState } from './services/AppStore'; import { querySelector } from './utils/dom'; +import { debugTime, debugTimeEnd } from './utils/debug'; -export { Redoc, AppStore } from './index'; +export { Redoc, AppStore } from '.'; export const version = __REDOC_VERSION__; export const revision = __REDOC_REVISION__; @@ -35,6 +37,7 @@ export function init( specOrSpecUrl: string | any, options: any = {}, element: Element | null = querySelector('redoc'), + callback?: () => void, ) { if (element === null) { throw new Error('"element" argument is not provided and tag is not found on the page'); @@ -60,9 +63,24 @@ export function init( ['Loading...'], ), element, + callback, ); } +export function hydrate( + state: StoreState, + element: Element | null = querySelector('redoc'), + callback?: () => void, +) { + debugTime('Redoc create store'); + const store = AppStore.fromJS(state); + debugTimeEnd('Redoc create store'); + + debugTime('Redoc hydrate'); + hydrateComponent(, element, callback); + debugTimeEnd('Redoc hydrate'); +} + /** * autoinit ReDoc if tag is found on the page with "spec-url" attr */ diff --git a/src/utils/debug.ts b/src/utils/debug.ts new file mode 100644 index 00000000..c577ed64 --- /dev/null +++ b/src/utils/debug.ts @@ -0,0 +1,11 @@ +export function debugTime(label: string) { + if (__REDOC_DEV__) { + console.time(label); + } +} + +export function debugTimeEnd(label: string) { + if (__REDOC_DEV__) { + console.timeEnd(label); + } +} diff --git a/src/utils/index.ts b/src/utils/index.ts index 6c29d963..21bbc5fa 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -7,3 +7,4 @@ export * from './highlight'; export * from './loadAndBundleSpec'; export * from './dom'; export * from './decorators'; +export * from './debug'; diff --git a/webpack.config.ts b/webpack.config.ts index c1924f21..29f55b3a 100644 --- a/webpack.config.ts +++ b/webpack.config.ts @@ -108,7 +108,7 @@ export default env => { 'process.env.NODE_ENV': env.prod ? '"production"' : '"development"', __REDOC_VERSION__: VERSION, __REDOC_REVISION__: REVISION, - __DEV__: env.prod ? 'false' : 'true', + __REDOC_DEV__: env.prod ? 'false' : 'true', }), new webpack.NamedModulesPlugin(), ],