From 9a062c08a82ca8d8175fb48c808e06308ed900dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B0=B4=E6=BE=9C?= Date: Thu, 24 Feb 2022 19:57:57 +0800 Subject: [PATCH] feat: render document (#8) * feat: render document * fix: lint * fix: ts lint * chore: update lock info * fix: lint * fix: conflict * fix: conflict Co-authored-by: luhc228 --- examples/basic-project/public/index.html | 12 -------- examples/basic-project/src/document.tsx | 21 ++++++++++++++ packages/build-webpack-config/package.json | 3 +- packages/plugin-app/package.json | 5 ++++ packages/plugin-app/src/index.ts | 33 ++++++++++++++++++++-- packages/plugin-app/src/ssr/build.ts | 18 ++++++++++++ packages/plugin-app/src/ssr/server.tsx | 26 +++++++++++++++++ pnpm-lock.yaml | 7 +++++ 8 files changed, 110 insertions(+), 15 deletions(-) delete mode 100644 examples/basic-project/public/index.html create mode 100644 examples/basic-project/src/document.tsx create mode 100644 packages/plugin-app/src/ssr/build.ts create mode 100644 packages/plugin-app/src/ssr/server.tsx diff --git a/examples/basic-project/public/index.html b/examples/basic-project/public/index.html deleted file mode 100644 index fbbd2c907..000000000 --- a/examples/basic-project/public/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - Vite App - - -
- - - diff --git a/examples/basic-project/src/document.tsx b/examples/basic-project/src/document.tsx new file mode 100644 index 000000000..442ff45c0 --- /dev/null +++ b/examples/basic-project/src/document.tsx @@ -0,0 +1,21 @@ +/* eslint-disable react/self-closing-comp */ +import React from 'react'; + +function Document() { + return ( + + + + + + ICE Demo + + +
+ + + + ); +} + +export default Document; \ No newline at end of file diff --git a/packages/build-webpack-config/package.json b/packages/build-webpack-config/package.json index 9e9946427..1772b64a6 100644 --- a/packages/build-webpack-config/package.json +++ b/packages/build-webpack-config/package.json @@ -11,7 +11,8 @@ "webpack-dev-server": "^4.7.4" }, "devDependencies": { - "webpack": "^5.69.1" + "webpack": "^5.69.1", + "webpack-dev-server": "^4.7.4" }, "files": [ "lib", diff --git a/packages/plugin-app/package.json b/packages/plugin-app/package.json index d2793f398..b0ebd58d2 100644 --- a/packages/plugin-app/package.json +++ b/packages/plugin-app/package.json @@ -16,6 +16,11 @@ "lib" ], "license": "MIT", + "dependencies": { + "esbuild": "^0.14.23", + "react": "^17.0.2", + "react-dom": "^17.0.2" + }, "devDependencies": { "@ice/service": "^1.0.0" } diff --git a/packages/plugin-app/src/index.ts b/packages/plugin-app/src/index.ts index 472e31791..8a6a18506 100644 --- a/packages/plugin-app/src/index.ts +++ b/packages/plugin-app/src/index.ts @@ -1,11 +1,40 @@ import type { FrameworkPlugin } from '@ice/service'; +import { setupRenderServer } from './ssr/server'; +import { buildServerEntry } from './ssr/build'; -const plugin: FrameworkPlugin = ({ registerTask, context }) => { - const { command } = context; +const plugin: FrameworkPlugin = ({ registerTask, context, onHook }) => { + const { command, rootDir } = context; const mode = command === 'start' ? 'development' : 'production'; + // mock routeManifest + const routeManifest = { + '/': '/src/pages/index', + }; + + onHook(`before.${command}.run`, async () => { + // TODO: watch file changes and rebuild + await buildServerEntry({ + rootDir, + }); + }); + registerTask('web', { mode, + middlewares: (middlewares, devServer) => { + if (!devServer) { + throw new Error('webpack-dev-server is not defined'); + } + + middlewares.push({ + name: 'document-render-server', + middleware: setupRenderServer({ + rootDir, + routeManifest, + }), + }); + + return middlewares; + }, }); }; diff --git a/packages/plugin-app/src/ssr/build.ts b/packages/plugin-app/src/ssr/build.ts new file mode 100644 index 000000000..3e7c9921a --- /dev/null +++ b/packages/plugin-app/src/ssr/build.ts @@ -0,0 +1,18 @@ +import * as path from 'path'; +import * as esbuild from 'esbuild'; + +export async function buildServerEntry(options: any): Promise { + const { rootDir } = options; + + const outdir = path.join(rootDir, 'build'); + const document = path.join(rootDir, 'src/document.jsx'); + + // TODO:sync compiler + return esbuild.build({ + outdir, + entryPoints: [document], + bundle: true, + platform: 'node', + external: ['./node_modules/*'], + }); +} \ No newline at end of file diff --git a/packages/plugin-app/src/ssr/server.tsx b/packages/plugin-app/src/ssr/server.tsx new file mode 100644 index 000000000..a1e91ed2a --- /dev/null +++ b/packages/plugin-app/src/ssr/server.tsx @@ -0,0 +1,26 @@ + +import * as path from 'path'; +import * as React from 'react'; +import * as ReactDOMServer from 'react-dom/server'; + +export function setupRenderServer(options: any) { + const { + rootDir, + routeManifest, + } = options; + + return (req, res) => { + if (!routeManifest[req.path]) { + return; + } + + // TODO: disable cache + const document = path.resolve(rootDir, 'build/document.js'); + const Document = require(document).default; + + const html = ReactDOMServer.renderToString(); + + res.setHeader('Content-Type', 'text/html; charset=utf-8'); + res.send(html); + }; +} \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e0e3bf81f..66dac58f2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -177,6 +177,13 @@ importers: packages/plugin-app: specifiers: '@ice/service': ^1.0.0 + esbuild: ^0.14.23 + react: ^17.0.2 + react-dom: ^17.0.2 + dependencies: + esbuild: 0.14.23 + react: 17.0.2 + react-dom: 17.0.2_react@17.0.2 devDependencies: '@ice/service': link:../ice-service