diff --git a/package-lock.json b/package-lock.json index 83d30c6..f837aa0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1479,6 +1479,12 @@ "@types/node": "*" } }, + "@types/history": { + "version": "4.7.2", + "resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.2.tgz", + "integrity": "sha512-ui3WwXmjTaY73fOQ3/m3nnajU/Orhi6cEu5rzX+BrAAJxa3eITXZ5ch9suPqtM03OWhAHhPSyBGCN4UKoxO20Q==", + "dev": true + }, "@types/http-errors": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-1.6.1.tgz", @@ -1585,6 +1591,27 @@ "redux": "^4.0.0" } }, + "@types/react-router": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-4.4.5.tgz", + "integrity": "sha512-12+VOu1+xiC8RPc9yrgHCyLI79VswjtuqeS2gPrMcywH6tkc8rGIUhs4LaL3AJPqo5d+RPnfRpNKiJ7MK2Qhcg==", + "dev": true, + "requires": { + "@types/history": "*", + "@types/react": "*" + } + }, + "@types/react-router-dom": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@types/react-router-dom/-/react-router-dom-4.3.1.tgz", + "integrity": "sha512-GbztJAScOmQ/7RsQfO4cd55RuH1W4g6V1gDW3j4riLlt+8yxYLqqsiMzmyuXBLzdFmDtX/uU2Bpcm0cmudv44A==", + "dev": true, + "requires": { + "@types/history": "*", + "@types/react": "*", + "@types/react-router": "*" + } + }, "@types/serve-static": { "version": "1.13.2", "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.2.tgz", @@ -4134,6 +4161,16 @@ "object-assign": "^4.1.1" } }, + "create-react-context": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/create-react-context/-/create-react-context-0.2.3.tgz", + "integrity": "sha512-CQBmD0+QGgTaxDL3OX1IDXYqjkp2It4RIbcb99jS6AEg27Ga+a9G3JtK6SIu0HBwPLZlmwt9F7UwWA4Bn92Rag==", + "dev": true, + "requires": { + "fbjs": "^0.8.0", + "gud": "^1.0.0" + } + }, "cross-spawn": { "version": "6.0.5", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", @@ -6420,6 +6457,12 @@ "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=", "dev": true }, + "gud": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/gud/-/gud-1.0.0.tgz", + "integrity": "sha512-zGEOVKFM5sVPPrYs7J5/hYEw2Pof8KCyOwyhG8sAF26mCAeUFAcYPu1mwB7hhpIP29zOIBaDqwuHdLp0jvZXjw==", + "dev": true + }, "handlebars": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.1.0.tgz", @@ -6544,6 +6587,20 @@ "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.13.1.tgz", "integrity": "sha512-Sc28JNQNDzaH6PORtRLMvif9RSn1mYuOoX3omVjnb0+HbpPygU2ALBI0R/wsiqCb4/fcp07Gdo8g+fhtFrQl6A==" }, + "history": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/history/-/history-4.9.0.tgz", + "integrity": "sha512-H2DkjCjXf0Op9OAr6nJ56fcRkTSNrUiv41vNJ6IswJjif6wlpZK0BTfFbi7qK9dXLSYZxkq5lBsj3vUjlYBYZA==", + "dev": true, + "requires": { + "@babel/runtime": "^7.1.2", + "loose-envify": "^1.2.0", + "resolve-pathname": "^2.2.0", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0", + "value-equal": "^0.4.0" + } + }, "hmac-drbg": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", @@ -10530,6 +10587,56 @@ "react-is": "^16.6.3" } }, + "react-router": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-4.4.0.tgz", + "integrity": "sha512-qTGsOSF2b02zOsUfcnHjw7muI0Ejx+yA2e4P9qqzB2O+N3Icpca4epViXRgkBIvBjagXBtroxXqH0RJhYDMUbg==", + "dev": true, + "requires": { + "@babel/runtime": "^7.1.2", + "create-react-context": "^0.2.2", + "history": "^4.9.0", + "hoist-non-react-statics": "^3.1.0", + "loose-envify": "^1.3.1", + "path-to-regexp": "^1.7.0", + "prop-types": "^15.6.2", + "react-is": "^16.6.0", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + }, + "path-to-regexp": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.7.0.tgz", + "integrity": "sha1-Wf3g9DW62suhA6hOnTvGTpa5k30=", + "dev": true, + "requires": { + "isarray": "0.0.1" + } + } + } + }, + "react-router-dom": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-4.4.0.tgz", + "integrity": "sha512-r4knbi8lanTGrwoUXFaWALrJZOAl3h9bdFUz4woHgEm7/bYcpBGfnYhPU82xjXrPeJyWF6OmIxpwXjxos30gOQ==", + "dev": true, + "requires": { + "@babel/runtime": "^7.1.2", + "history": "^4.8.0-beta.0", + "loose-envify": "^1.3.1", + "prop-types": "^15.6.2", + "react-router": "^4.4.0", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0" + } + }, "read": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", @@ -10880,6 +10987,12 @@ "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true }, + "resolve-pathname": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-2.2.0.tgz", + "integrity": "sha512-bAFz9ld18RzJfddgrO2e/0S2O81710++chRMUxHjXOYKF6jTAMrUNZrEZ1PvV0zlhfjidm08iRPdTLPno1FuRg==", + "dev": true + }, "resolve-url": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", @@ -12271,6 +12384,18 @@ "process": "~0.11.0" } }, + "tiny-invariant": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.0.3.tgz", + "integrity": "sha512-ytQx8T4DL8PjlX53yYzcIC0WhIZbpR0p1qcYjw2pHu3w6UtgWwFJQ/02cnhOnBBhlFx/edUIfcagCaQSe3KMWg==", + "dev": true + }, + "tiny-warning": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.2.tgz", + "integrity": "sha512-rru86D9CpQRLvsFG5XFdy0KdLAvjdQDyZCsRcuu60WtzFylDM3eAWSxEVz5kzL2Gp544XiUvPbVKtOA/txLi9Q==", + "dev": true + }, "tmp": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", @@ -13247,6 +13372,12 @@ "builtins": "^1.0.3" } }, + "value-equal": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/value-equal/-/value-equal-0.4.0.tgz", + "integrity": "sha512-x+cYdNnaA3CxvMaTX0INdTCN8m8aF2uY9BvEqmxuYp8bL09cs/kWVQPVGcA35fMktdOsP69IgU7wFj/61dJHEw==", + "dev": true + }, "vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", diff --git a/package.json b/package.json index db7eae1..269ad47 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "@types/es6-shim": "^0.31.39", "@types/express": "^4.16.0", "@types/express-session": "^1.15.11", + "@types/history": "^4.7.2", "@types/http-errors": "^1.6.1", "@types/jest": "^23.3.12", "@types/js-yaml": "^3.12.0", @@ -24,6 +25,7 @@ "@types/react": "^16.7.18", "@types/react-dom": "^16.0.11", "@types/react-redux": "^6.0.12", + "@types/react-router-dom": "^4.3.1", "@types/shortid": "0.0.29", "@types/std-mocks": "^1.0.0", "@types/supertest": "^2.0.7", @@ -33,6 +35,7 @@ "browserify": "^16.2.3", "buildfile": "^1.2.20", "bulma": "^0.7.4", + "history": "^4.9.0", "jest": "^24.5.0", "lerna": "^3.13.1", "loose-envify": "^1.4.0", @@ -43,6 +46,7 @@ "react-dom": "^16.7.0", "react-icons": "^3.5.0", "react-redux": "^6.0.0", + "react-router-dom": "^4.4.0", "redux": "^4.0.1", "std-mocks": "^1.0.1", "supertest": "^3.3.0", diff --git a/packages/client/src/renderer/ClientRenderer.tsx b/packages/client/src/renderer/ClientRenderer.tsx index 25621be..74ba835 100644 --- a/packages/client/src/renderer/ClientRenderer.tsx +++ b/packages/client/src/renderer/ClientRenderer.tsx @@ -1,31 +1,35 @@ import React from 'react' import ReactDOM from 'react-dom' import {Action} from 'redux' +import {IClientConfig} from './IClientConfig' import {IRenderer} from './IRenderer' import {IStoreFactory} from './IStoreFactory' import {Provider} from 'react-redux' export interface IClientRendererParams { readonly createStore: IStoreFactory, - readonly RootComponent: React.ComponentType, + readonly RootComponent: React.ComponentType<{config: IClientConfig}>, readonly target?: HTMLElement } export class ClientRenderer implements IRenderer { constructor(readonly params: IClientRendererParams) {} - render(state = (window as any).__PRELOADED_STATE__) { + render( + config = (window as any).__APP_CONFIG__ as IClientConfig, + state = (window as any).__PRELOADED_STATE__, + ) { const { RootComponent, createStore, - target = document.body, + target = document.getElementById('container'), } = this.params if (state) { const store = createStore(state) ReactDOM.hydrate( - + , target, ) @@ -33,7 +37,7 @@ export class ClientRenderer implements IRenderer { const store = createStore() ReactDOM.render( - + , target, ) diff --git a/packages/client/src/renderer/IClientConfig.ts b/packages/client/src/renderer/IClientConfig.ts new file mode 100644 index 0000000..98aa948 --- /dev/null +++ b/packages/client/src/renderer/IClientConfig.ts @@ -0,0 +1,3 @@ +export interface IClientConfig { + readonly baseUrl: string +} diff --git a/packages/client/src/renderer/IRenderer.ts b/packages/client/src/renderer/IRenderer.ts index e353b71..c73529c 100644 --- a/packages/client/src/renderer/IRenderer.ts +++ b/packages/client/src/renderer/IRenderer.ts @@ -1,3 +1,5 @@ +import {IClientConfig} from './IClientConfig' + export interface IRenderer { - render(state?: any): any + render(config: IClientConfig, state?: any): any } diff --git a/packages/client/src/renderer/ServerRenderer.tsx b/packages/client/src/renderer/ServerRenderer.tsx index 4ea7e61..6a9370f 100644 --- a/packages/client/src/renderer/ServerRenderer.tsx +++ b/packages/client/src/renderer/ServerRenderer.tsx @@ -1,5 +1,6 @@ import React from 'react' import {Action} from 'redux' +import {IClientConfig} from './IClientConfig' import {IRenderer} from './IRenderer' import {IStoreFactory} from './IStoreFactory' import {Provider} from 'react-redux' @@ -8,15 +9,15 @@ import {renderToNodeStream} from 'react-dom/server' export class ServerRenderer implements IRenderer { constructor( readonly createStore: IStoreFactory, - readonly RootComponent: React.ComponentType, + readonly RootComponent: React.ComponentType<{config: IClientConfig}>, ) {} - render(state?: any) { + render(config: IClientConfig, state?: any) { const {RootComponent} = this const store = this.createStore(state) const stream = renderToNodeStream( - + , ) return stream diff --git a/packages/client/src/renderer/index.ts b/packages/client/src/renderer/index.ts index 08fc7f1..cb6e9f5 100644 --- a/packages/client/src/renderer/index.ts +++ b/packages/client/src/renderer/index.ts @@ -1,3 +1,4 @@ export * from './ClientRenderer' +export * from './IClientConfig' export * from './IRenderer' export * from './IStoreFactory'