From 83a6c6dda622afc7b74656ebd7ee1662e6b06748 Mon Sep 17 00:00:00 2001 From: Aarni Halinen Date: Wed, 8 Jul 2020 18:33:13 +0300 Subject: [PATCH] Fix Styled-components SSR --- package-lock.json | 48 +++++++++++++++++++++++++++++++++++++++++++++ package.json | 3 +++ src/server/index.ts | 20 +++++++++++++++---- 3 files changed, 67 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7147029..2f3c467 100644 --- a/package-lock.json +++ b/package-lock.json @@ -806,6 +806,27 @@ "integrity": "sha512-GRTZLeLJ8ia00ZH8mxMO8t0aC9M1N9bN461Z2eaRurJo6Fpa+utgCwLzI4jQHcrdzuzp5WPN9jRwpsCQ1VhJ5w==", "dev": true }, + "@types/hoist-non-react-statics": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz", + "integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==", + "dev": true, + "requires": { + "@types/react": "*", + "hoist-non-react-statics": "^3.3.0" + }, + "dependencies": { + "hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "dev": true, + "requires": { + "react-is": "^16.7.0" + } + } + } + }, "@types/jest": { "version": "24.0.22", "resolved": "https://registry.npmjs.org/@types/jest/-/jest-24.0.22.tgz", @@ -908,6 +929,15 @@ "@types/react": "*" } }, + "@types/react-native": { + "version": "0.62.17", + "resolved": "https://registry.npmjs.org/@types/react-native/-/react-native-0.62.17.tgz", + "integrity": "sha512-nkWG9oYS0wNiobzY11GOAjG/spV4vCPIbW+u1QIXx+wnQQ4EhkFz6lqqvncO3puXMzwkRhEGawq/bImMReA/vQ==", + "dev": true, + "requires": { + "@types/react": "*" + } + }, "@types/react-router": { "version": "5.1.8", "resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.8.tgz", @@ -929,6 +959,18 @@ "@types/react-router": "*" } }, + "@types/styled-components": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@types/styled-components/-/styled-components-5.1.1.tgz", + "integrity": "sha512-fIjKvDU1LJExBZWEQilHqzfpOK4KUwBsj5zC79lxa94ekz8oDQSBNcayMACBImxIuevF+NbBGL9O/2CQ67Zhig==", + "dev": true, + "requires": { + "@types/hoist-non-react-statics": "*", + "@types/react": "*", + "@types/react-native": "*", + "csstype": "^2.2.0" + } + }, "@types/unist": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.3.tgz", @@ -20488,6 +20530,12 @@ "integrity": "sha512-hSAifV3k+i6lEoCJ2k6R2Z/rp/H3+8sdmcn5NrS3/3kE7+RyZXm9aqvxWqjEXHAd8b0pShatpcdMTvEdvAJltQ==", "dev": true }, + "typescript-plugin-styled-components": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/typescript-plugin-styled-components/-/typescript-plugin-styled-components-1.4.4.tgz", + "integrity": "sha512-w5S5lSpzRFM+61KNNpGtlF46DuTJTyzfWM4g6ic9m189ILEoU3sgoTNHNS2MxQhXsGtQZwAlINKG+Dwy0euwUg==", + "dev": true + }, "uglify-js": { "version": "3.3.28", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.3.28.tgz", diff --git a/package.json b/package.json index 344aaff..ca5c765 100644 --- a/package.json +++ b/package.json @@ -54,12 +54,14 @@ "@types/react-helmet": "6.0.0", "@types/react-jsonschema-form": "1.7.3", "@types/react-router-dom": "5.1.5", + "@types/styled-components": "5.1.1", "@typescript-eslint/eslint-plugin": "2.6.1", "@typescript-eslint/parser": "2.6.1", "awesome-typescript-loader": "5.2.1", "babel-cli": "6.26.0", "babel-core": "6.26.3", "babel-loader": "7.1.5", + "babel-plugin-styled-components": "1.10.7", "babel-preset-env": "1.7.0", "babel-preset-minify": "0.4.3", "babel-preset-react": "6.24.1", @@ -107,6 +109,7 @@ "testcafe-react-selectors": "2.1.0", "tsconfig-paths-webpack-plugin": "3.2.0", "typescript": "3.9.5", + "typescript-plugin-styled-components": "1.4.4", "uglifyjs-webpack-plugin": "1.3.0", "webpack": "4.41.2", "webpack-cdn-plugin": "3.2.0", diff --git a/src/server/index.ts b/src/server/index.ts index 4fa57ab..30a22ea 100644 --- a/src/server/index.ts +++ b/src/server/index.ts @@ -16,14 +16,15 @@ import App from "./App"; import fs from "fs"; import path from "path"; import { StaticContext } from "./StaticContext"; +import { ServerStyleSheet } from "styled-components"; const port = 3000; const server = express(); const indexHtml = fs.readFileSync(path.resolve("./dist/index.html"), "utf-8"); -const html = (body, title, meta) => { +const html = (body, styles, title, meta) => { const withBody = indexHtml.replace("
", `
${body}
`); - const withHead = withBody.replace("", `${title}${meta}`); + const withHead = withBody.replace("", `${title}${meta}${styles}`); return withHead; }; @@ -41,6 +42,9 @@ server.get("*", async (req, res) => { const firstPassRenderResult = renderToString(React.createElement(App, { url: req.url, context })); + // Styled-components Step 1: Create an instance of ServerStyleSheet + const sheet = new ServerStyleSheet(); + const promiseKeys = Object.keys(context.promises); let result: string; if (promiseKeys.length === 0) { @@ -62,13 +66,21 @@ server.get("*", async (req, res) => { }); /* Render a second time with all resolved data. */ - const secondPassRenderResult = renderToString(React.createElement(App, { url: req.url, context })); + // Styled-components Step 2: Retrieve styles from components in the page + const secondPassRenderResult = renderToString( + sheet.collectStyles( + React.createElement(App, { url: req.url, context }) + ) + ); result = secondPassRenderResult; } + // Styled-components Step 3: Extract the styles as