From 07321c73da1a5c26ed7e4797263535c3398494c9 Mon Sep 17 00:00:00 2001 From: Silvio Date: Sat, 17 Feb 2024 18:01:35 -0500 Subject: [PATCH] Switch to Vite (#319) --- .github/workflows/ci.yaml | 4 + development/.eslintrc.json | 2 +- development/client/components/Layout.tsx | 10 - development/client/index.tsx | 3 +- .../client/templates/DjangoDefault.tsx | 2 +- development/client/templates/EditPoll.tsx | 2 +- .../client/templates/FormPlayground.tsx | 2 +- development/client/templates/PollComments.tsx | 2 +- development/client/templates/PollDetail.tsx | 2 +- development/client/templates/PollsIndex.tsx | 2 +- development/client/templates/Results.tsx | 2 +- development/package.json | 1 + development/tsconfig.json | 5 +- package-lock.json | 3424 +++++++++++++---- .../scripts/create-django-app.sh | 2 +- packages/reactivated/package.json | 19 +- packages/reactivated/src/build.client.mts | 188 +- packages/reactivated/src/build.renderer.mts | 97 - packages/reactivated/src/conf.tsx | 24 +- packages/reactivated/src/context.tsx | 28 - .../src/{eslintrc.tsx => eslintrc.cts} | 0 packages/reactivated/src/forms/index.tsx | 2 +- packages/reactivated/src/generator.mts | 126 +- packages/reactivated/src/render.mts | 134 + packages/reactivated/src/renderer.tsx | 196 - packages/reactivated/src/server.mts | 36 + packages/reactivated/src/shared.tsx | 3 + packages/reactivated/src/vite.mts | 101 + reactivated/__init__.py | 141 + reactivated/apps.py | 16 +- reactivated/management/commands/build.py | 51 +- reactivated/processes.py | 80 - reactivated/renderer.py | 41 +- requirements.nix | 2 +- sample/client/App.tsx | 3 + sample/client/Button.tsx | 12 + sample/client/Layout.tsx | 2 + sample/client/index.tsx | 22 +- sample/client/renderer.tsx | 6 + sample/client/styles.css.ts | 2 +- sample/client/templates/HelloWorld.tsx | 2 +- sample/client/templates/Storyboard.tsx | 55 +- sample/package.json | 1 + sample/tsconfig.json | 6 +- sample/vite.config.mts | 7 + scripts/generate_types.py | 11 +- scripts/release.sh | 3 + scripts/script-create-django-app.sh | 4 + website/.eslintrc.json | 2 +- website/client/components/Layout.tsx | 5 - website/client/index.tsx | 3 +- website/client/templates/Documentation.tsx | 2 +- website/client/templates/HomePage.tsx | 2 +- website/package.json | 1 + website/server/docs/api.md | 2 +- website/server/docs/concepts.md | 10 +- website/server/docs/existing-projects.md | 2 +- website/tsconfig.json | 5 +- 58 files changed, 3451 insertions(+), 1469 deletions(-) delete mode 100644 packages/reactivated/src/build.renderer.mts delete mode 100644 packages/reactivated/src/context.tsx rename packages/reactivated/src/{eslintrc.tsx => eslintrc.cts} (100%) create mode 100644 packages/reactivated/src/render.mts delete mode 100644 packages/reactivated/src/renderer.tsx create mode 100644 packages/reactivated/src/server.mts create mode 100644 packages/reactivated/src/shared.tsx create mode 100644 packages/reactivated/src/vite.mts delete mode 100644 reactivated/processes.py create mode 100644 sample/client/App.tsx create mode 100644 sample/client/Button.tsx create mode 100644 sample/client/renderer.tsx create mode 100644 sample/vite.config.mts diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 539004087..e6f133374 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -46,6 +46,9 @@ jobs: nix-shell --command "python manage.py generate_client_assets" nix-shell --command "python manage.py build" nix-shell --command "scripts/test.sh" + - name: Setup tmate session + if: ${{ failure() }} + uses: mxschmitt/action-tmate@v3 website_tests: name: Website tests runs-on: ubuntu-22.04 @@ -56,6 +59,7 @@ jobs: - uses: ./.github/actions/setup - name: Run tests run: | + sed -i '/export {};/d' packages/reactivated/dist/eslintrc.cjs cd website nix-shell --command "python manage.py generate_client_assets" nix-shell --command "scripts/test.sh --all" diff --git a/development/.eslintrc.json b/development/.eslintrc.json index 5c12acfc1..f069b9a3c 100644 --- a/development/.eslintrc.json +++ b/development/.eslintrc.json @@ -1,3 +1,3 @@ { - "extends": ["../node_modules/reactivated/dist/eslintrc.js"] + "extends": ["../node_modules/reactivated/dist/eslintrc.cjs"] } diff --git a/development/client/components/Layout.tsx b/development/client/components/Layout.tsx index b1d1eaa57..5235ea7d6 100644 --- a/development/client/components/Layout.tsx +++ b/development/client/components/Layout.tsx @@ -38,16 +38,6 @@ export const Layout = (props: Props) => { type="text/css" href={`${context.STATIC_URL}admin/css/fonts.css`} /> - - ` + : ``; + + return ` + + + + ${vite} + + ${css} + + ${helmet.base.toString()} + ${helmet.link.toString()} + ${helmet.meta.toString()} + ${helmet.noscript.toString()} + ${helmet.script.toString()} + ${helmet.style.toString()} + ${helmet.title.toString()} + + +
${html}
+ ${js} + +`; +}; + +const defaultConfiguration = { + render: (content) => Promise.resolve(content), +} satisfies Options; + +export type Renderer = (content: JSX.Element) => Promise; + +export const render = async ( + req: Request, + vite: string, + mode: "production" | "development", + entryPoint: string, +) => { + // @ts-ignore + const customConfiguration: {default?: Render} | null = import.meta.glob( + "@client/renderer.tsx", + {eager: true}, + )["/client/renderer.tsx"]; + + const {context, props} = req.body; + const Template = await getTemplate(context); + const helmetContext = {} as {helmet: HelmetServerState}; + + const content = React.createElement( + React.StrictMode, + {}, + React.createElement( + HelmetProvider, + {context: helmetContext}, + React.createElement( + Provider, + {value: context}, + React.createElement(Template, props), + ), + ), + ); + + const html = ReactDOMServer.renderToString( + await (customConfiguration?.default ?? defaultConfiguration.render)(content), + ); + const {helmet} = helmetContext; + + const rendered = renderPage({ + html, + vite, + helmet, + props, + context, + mode, + entryPoint, + }); + + return rendered; +}; diff --git a/packages/reactivated/src/renderer.tsx b/packages/reactivated/src/renderer.tsx deleted file mode 100644 index 212716d58..000000000 --- a/packages/reactivated/src/renderer.tsx +++ /dev/null @@ -1,196 +0,0 @@ -import fs from "fs"; -import http from "http"; -import {compile} from "json-schema-to-typescript"; -import path from "path"; -import React from "react"; -import ReactDOMServer from "react-dom/server"; -import { - FilledContext, - Helmet, - HelmetProvider, - HelmetServerState, -} from "react-helmet-async"; - -import {Options} from "./conf"; -import {Settings} from "./models"; - -// TODO: WHAT DOES THIS NEED TO BE? Even 100k was super fragile and a 10 choice field broke it. -export const BODY_SIZE_LIMIT = "100000000k"; - -export const renderPage = ({ - html, - helmet, - context, - props, -}: { - html: string; - helmet: HelmetServerState; - context: any; - props: any; -}) => { - const scriptNonce = context.request.csp_nonce - ? `nonce="${context.request.csp_nonce}"` - : ""; - return ` - - - - - - ${helmet.base.toString()} - ${helmet.link.toString()} - ${helmet.meta.toString()} - ${helmet.noscript.toString()} - ${helmet.script.toString()} - ${helmet.style.toString()} - ${helmet.title.toString()} - - -
${html}
- -`; -}; - -const PATHS = ["/", "/form/"]; - -type Result = - | { - status: "success"; - rendered: string; - } - | { - status: "error"; - error: any; - }; - -export const render = async ({ - context, - props, -}: { - context: any; - props: any; -}): Promise => { - const defaultConfiguration = { - render: (content) => Promise.resolve(content), - } satisfies Options; - - let customConfiguration: {default?: Options} | null = null; - - try { - customConfiguration = await import( - // @ts-ignore - "_reactivated/conf.mjs" - ); - } catch (error: unknown) {} - - // @ts-ignore - const {Provider, getTemplate} = await import("_reactivated/index.tsx"); - - try { - const Template = getTemplate(context); - const helmetContext = {} as FilledContext; - - const content = ( - - -