From ce00d18f769e24b3e93ca5f436a73266b4965db4 Mon Sep 17 00:00:00 2001 From: "shuilan.cj" Date: Thu, 31 Aug 2023 16:24:49 +0800 Subject: [PATCH 01/17] feat: rsc poc --- examples/with-rsc/ice.config.mts | 5 + examples/with-rsc/package.json | 22 ++ examples/with-rsc/src/app.tsx | 7 + examples/with-rsc/src/components/Comments.tsx | 35 +++ .../src/components/Counter.client.tsx | 16 ++ .../src/components/EditButton.client.tsx | 23 ++ examples/with-rsc/src/components/Footer.tsx | 29 ++ .../with-rsc/src/components/index.module.css | 45 ++++ examples/with-rsc/src/document.tsx | 22 ++ examples/with-rsc/src/pages/index.module.css | 45 ++++ examples/with-rsc/src/pages/index.tsx | 20 ++ examples/with-rsc/src/pages/layout.tsx | 12 + examples/with-rsc/src/typings.d.ts | 1 + examples/with-rsc/tsconfig.json | 32 +++ packages/ice/package.json | 10 +- .../src/bundler/webpack/getWebpackConfig.ts | 4 + packages/ice/src/esbuild/rscServerRegister.ts | 27 ++ packages/ice/src/service/serverCompiler.ts | 2 + .../ice/templates/core/clientEntry.tsx.ejs | 46 ++++ .../ice/templates/core/entry.server.ts.ejs | 2 + packages/runtime/package.json | 10 +- packages/runtime/src/index.ts | 5 + .../src/reactFlightWebpackReference.ts | 248 ++++++++++++++++++ packages/runtime/src/routes.tsx | 14 +- packages/runtime/src/runServerApp.tsx | 51 +++- packages/webpack-config/src/index.ts | 2 +- pnpm-lock.yaml | 145 ++++++++-- 27 files changed, 831 insertions(+), 49 deletions(-) create mode 100644 examples/with-rsc/ice.config.mts create mode 100644 examples/with-rsc/package.json create mode 100644 examples/with-rsc/src/app.tsx create mode 100644 examples/with-rsc/src/components/Comments.tsx create mode 100644 examples/with-rsc/src/components/Counter.client.tsx create mode 100644 examples/with-rsc/src/components/EditButton.client.tsx create mode 100644 examples/with-rsc/src/components/Footer.tsx create mode 100644 examples/with-rsc/src/components/index.module.css create mode 100644 examples/with-rsc/src/document.tsx create mode 100644 examples/with-rsc/src/pages/index.module.css create mode 100644 examples/with-rsc/src/pages/index.tsx create mode 100644 examples/with-rsc/src/pages/layout.tsx create mode 100644 examples/with-rsc/src/typings.d.ts create mode 100644 examples/with-rsc/tsconfig.json create mode 100644 packages/ice/src/esbuild/rscServerRegister.ts create mode 100644 packages/ice/templates/core/clientEntry.tsx.ejs create mode 100644 packages/runtime/src/reactFlightWebpackReference.ts diff --git a/examples/with-rsc/ice.config.mts b/examples/with-rsc/ice.config.mts new file mode 100644 index 0000000000..02208a54f6 --- /dev/null +++ b/examples/with-rsc/ice.config.mts @@ -0,0 +1,5 @@ +import { defineConfig } from '@ice/app'; + +export default defineConfig({ + ssr: true, +}); diff --git a/examples/with-rsc/package.json b/examples/with-rsc/package.json new file mode 100644 index 0000000000..beb168ce04 --- /dev/null +++ b/examples/with-rsc/package.json @@ -0,0 +1,22 @@ +{ + "name": "with-server-component", + "version": "1.0.0", + "scripts": { + "start": "ice start", + "build": "ice build" + }, + "description": "ICE example with server-component", + "author": "ICE Team", + "license": "MIT", + "dependencies": { + "@ice/app": "workspace:*", + "@ice/runtime": "workspace:*", + "react": "18.3.0-next-3ba7add60-20221201", + "react-dom": "18.3.0-next-855b77c9b-20230202", + "react-server-dom-webpack": "18.3.0-next-855b77c9b-20230202" + }, + "devDependencies": { + "@types/react": "^18.0.17", + "@types/react-dom": "^18.0.6" + } +} diff --git a/examples/with-rsc/src/app.tsx b/examples/with-rsc/src/app.tsx new file mode 100644 index 0000000000..1ceb78f306 --- /dev/null +++ b/examples/with-rsc/src/app.tsx @@ -0,0 +1,7 @@ +import { defineAppConfig } from 'ice'; + +export default defineAppConfig({ + app: { + rootId: 'app', + }, +}); diff --git a/examples/with-rsc/src/components/Comments.tsx b/examples/with-rsc/src/components/Comments.tsx new file mode 100644 index 0000000000..97f3cab4c5 --- /dev/null +++ b/examples/with-rsc/src/components/Comments.tsx @@ -0,0 +1,35 @@ +import { useSuspenseData, withSuspense } from 'ice'; + +function Comments() { + const comments = useSuspenseData(getData); + + console.log('Render: Comments'); + + return ( +
+ {comments.map((comment, i) => ( +

+ {comment} +

+ ))} +
+ ); +} + +export default withSuspense(Comments); + +const fakeData = [ + "Wait, it doesn't wait for React to load?", + 'How does this even work?', + 'I like marshmallows', +]; + +async function getData() { + console.log('load comments'); + + await new Promise((resolve) => { + setTimeout(() => resolve(null), 3000); + }); + + return fakeData; +} \ No newline at end of file diff --git a/examples/with-rsc/src/components/Counter.client.tsx b/examples/with-rsc/src/components/Counter.client.tsx new file mode 100644 index 0000000000..384eece061 --- /dev/null +++ b/examples/with-rsc/src/components/Counter.client.tsx @@ -0,0 +1,16 @@ +import { useState } from 'react'; +import styles from './index.module.css'; + +export default function Counter() { + const [count, setCount] = useState(0); + + function updateCount() { + setCount(count + 1); + } + + return ( + + ); +} \ No newline at end of file diff --git a/examples/with-rsc/src/components/EditButton.client.tsx b/examples/with-rsc/src/components/EditButton.client.tsx new file mode 100644 index 0000000000..1c19168703 --- /dev/null +++ b/examples/with-rsc/src/components/EditButton.client.tsx @@ -0,0 +1,23 @@ +import { useTransition } from 'react'; + +export default function EditButton({ noteId, children }) { + const [isPending, startTransition] = useTransition(); + const isDraft = noteId == null; + return ( + + ); +} diff --git a/examples/with-rsc/src/components/Footer.tsx b/examples/with-rsc/src/components/Footer.tsx new file mode 100644 index 0000000000..27ceace7ba --- /dev/null +++ b/examples/with-rsc/src/components/Footer.tsx @@ -0,0 +1,29 @@ +import { useSuspenseData, withSuspense } from 'ice'; + +function Footer() { + const data = useSuspenseData(getData); + + console.log('Render: Footer'); + + return ( +
+

{data.title}

+
+ ); +} + +export default withSuspense(Footer); + +const fakeData = { + title: 'Thanks for reading!', +}; + +async function getData() { + console.log('load footer'); + + await new Promise((resolve) => { + setTimeout(() => resolve(null), 2000); + }); + + return fakeData; +} \ No newline at end of file diff --git a/examples/with-rsc/src/components/index.module.css b/examples/with-rsc/src/components/index.module.css new file mode 100644 index 0000000000..d11aa6a0b6 --- /dev/null +++ b/examples/with-rsc/src/components/index.module.css @@ -0,0 +1,45 @@ +.app { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + height: 100vh; +} + +.app > header { + display: flex; + flex-direction: column; + align-items: center; +} + +.app > header > img { + width: 120px; +} + +.app > header > p { + margin: 20px 0; + text-align: center; + font-size: 2.6rem; +} + +.app > main { + display: flex; + flex-direction: column; + margin: 20px 0 10px; + font-size: 0.9rem; +} + +.link { + font-size: 1.2rem; + color: var(--primary); +} + +.button { + outline: none; + border: none; + border-radius: 8px; + padding: 10px 35px; + background: var(--primary); + box-shadow: 0 5px 10px 0 #ddd; + font-size: calc(10px + 2vmin); +} diff --git a/examples/with-rsc/src/document.tsx b/examples/with-rsc/src/document.tsx new file mode 100644 index 0000000000..195d21a7f1 --- /dev/null +++ b/examples/with-rsc/src/document.tsx @@ -0,0 +1,22 @@ +import { Meta, Title, Links, Main, Scripts } from 'ice'; + +function Document() { + return ( + + + + + + + + <Links /> + </head> + <body> + <Main /> + <Scripts async /> + </body> + </html> + ); +} + +export default Document; diff --git a/examples/with-rsc/src/pages/index.module.css b/examples/with-rsc/src/pages/index.module.css new file mode 100644 index 0000000000..d11aa6a0b6 --- /dev/null +++ b/examples/with-rsc/src/pages/index.module.css @@ -0,0 +1,45 @@ +.app { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + height: 100vh; +} + +.app > header { + display: flex; + flex-direction: column; + align-items: center; +} + +.app > header > img { + width: 120px; +} + +.app > header > p { + margin: 20px 0; + text-align: center; + font-size: 2.6rem; +} + +.app > main { + display: flex; + flex-direction: column; + margin: 20px 0 10px; + font-size: 0.9rem; +} + +.link { + font-size: 1.2rem; + color: var(--primary); +} + +.button { + outline: none; + border: none; + border-radius: 8px; + padding: 10px 35px; + background: var(--primary); + box-shadow: 0 5px 10px 0 #ddd; + font-size: calc(10px + 2vmin); +} diff --git a/examples/with-rsc/src/pages/index.tsx b/examples/with-rsc/src/pages/index.tsx new file mode 100644 index 0000000000..40144ed28b --- /dev/null +++ b/examples/with-rsc/src/pages/index.tsx @@ -0,0 +1,20 @@ +import { useState } from 'react'; +import styles from './index.module.css'; +// import Comments from '@/components/Comments'; +// import Footer from '@/components/Footer'; +import EditButton from '@/components/EditButton.client'; +import Counter from '@/components/Counter.client'; + +export default function Home() { + console.log('Render: Index'); + + return ( + <div> + <h2>Home Page</h2> + <Counter /> + <EditButton noteId="editButton"> + hello world + </EditButton> + </div> + ); +} diff --git a/examples/with-rsc/src/pages/layout.tsx b/examples/with-rsc/src/pages/layout.tsx new file mode 100644 index 0000000000..6456f4b6e3 --- /dev/null +++ b/examples/with-rsc/src/pages/layout.tsx @@ -0,0 +1,12 @@ +import { Outlet } from 'ice'; + +export default function Layout() { + console.log('Render: Layout'); + + return ( + <div> + <h1>Suspense App</h1> + <Outlet /> + </div> + ); +} \ No newline at end of file diff --git a/examples/with-rsc/src/typings.d.ts b/examples/with-rsc/src/typings.d.ts new file mode 100644 index 0000000000..1a48695046 --- /dev/null +++ b/examples/with-rsc/src/typings.d.ts @@ -0,0 +1 @@ +/// <reference types="@ice/app/types" /> \ No newline at end of file diff --git a/examples/with-rsc/tsconfig.json b/examples/with-rsc/tsconfig.json new file mode 100644 index 0000000000..e41a1f451f --- /dev/null +++ b/examples/with-rsc/tsconfig.json @@ -0,0 +1,32 @@ +{ + "compileOnSave": false, + "buildOnSave": false, + "compilerOptions": { + "baseUrl": ".", + "outDir": "build", + "module": "esnext", + "target": "esnext", + "jsx": "react-jsx", + "moduleResolution": "node", + "allowSyntheticDefaultImports": true, + "lib": ["es6", "dom"], + "sourceMap": true, + "allowJs": true, + "rootDir": "./", + "forceConsistentCasingInFileNames": true, + "noImplicitReturns": true, + "noImplicitThis": true, + "noImplicitAny": false, + "importHelpers": true, + "strictNullChecks": true, + "suppressImplicitAnyIndexErrors": true, + "noUnusedLocals": true, + "skipLibCheck": true, + "paths": { + "@/*": ["./src/*"], + "ice": [".ice"] + } + }, + "include": ["src", ".ice", "ice.config.*"], + "exclude": ["build", "public"] +} \ No newline at end of file diff --git a/packages/ice/package.json b/packages/ice/package.json index cc00fab358..941eb3ee8b 100644 --- a/packages/ice/package.json +++ b/packages/ice/package.json @@ -82,18 +82,20 @@ "chokidar": "^3.5.3", "esbuild": "^0.17.16", "jest": "^29.0.2", - "react": "^18.2.0", + "react": "18.3.0-next-3ba7add60-20221201", "react-router": "6.14.2", "sass": "^1.50.0", "unplugin": "^0.9.0", "webpack": "^5.88.0", "webpack-dev-server": "^4.7.4", "@rspack/core": "0.3.0", - "@rspack/dev-server": "0.3.0" + "@rspack/dev-server": "0.3.0", + "react-server-dom-webpack": "18.3.0-next-855b77c9b-20230202" }, "peerDependencies": { - "react": ">=18.0.0", - "react-dom": ">=18.0.0" + "react": "18.3.0-next-3ba7add60-20221201", + "react-dom": "18.3.0-next-855b77c9b-20230202", + "react-server-dom-webpack": "18.3.0-next-855b77c9b-20230202" }, "publishConfig": { "access": "public" diff --git a/packages/ice/src/bundler/webpack/getWebpackConfig.ts b/packages/ice/src/bundler/webpack/getWebpackConfig.ts index d45402f19d..bda1b4e2a0 100644 --- a/packages/ice/src/bundler/webpack/getWebpackConfig.ts +++ b/packages/ice/src/bundler/webpack/getWebpackConfig.ts @@ -1,7 +1,9 @@ +import path from 'path'; import webpack from '@ice/bundles/compiled/webpack/index.js'; import lodash from '@ice/bundles/compiled/lodash/index.js'; import { getWebpackConfig as getDefaultWebpackConfig } from '@ice/webpack-config'; import type { Configuration } from 'webpack'; +import ReactServerWebpackPlugin from 'react-server-dom-webpack/plugin'; import { getExpandedEnvs } from '../../utils/runtimeEnv.js'; import { getRouteExportConfig } from '../../service/config.js'; import { getFileHash } from '../../utils/hash.js'; @@ -117,6 +119,8 @@ const getWebpackConfig: GetWebpackConfig = async (context, options) => { // Add spinner for webpack task. webpackConfig.plugins.push(getSpinnerPlugin(spinner)); + webpackConfig.plugins.push(new ReactServerWebpackPlugin({ isServer: false, dist: path.join(rootDir, '.ice') })); + return webpackConfig; }); diff --git a/packages/ice/src/esbuild/rscServerRegister.ts b/packages/ice/src/esbuild/rscServerRegister.ts new file mode 100644 index 0000000000..da039253da --- /dev/null +++ b/packages/ice/src/esbuild/rscServerRegister.ts @@ -0,0 +1,27 @@ +import url from 'url'; +import type { Plugin, PluginBuild } from 'esbuild'; + +const rscServerRegister = (): Plugin => { + return { + name: 'rsc-server-register', + setup: async (build: PluginBuild) => { + build.onLoad({ filter: /\/src\/.*\.client\.(js|ts|jsx|tsx)$/ }, async (args) => { // /src\/.*\ + const { path } = args; + const loader = path.endsWith('.tsx') || path.endsWith('.ts') ? 'tsx' : 'jsx'; + const moduleId: string = url.pathToFileURL(path).href; + let source = 'import {createClientModuleProxy} from \'@ice/runtime\';'; + source += transformContent(moduleId); + return { contents: source, loader }; + }); + }, + }; +}; + +function transformContent(moduleId: string) { + const content = `\ + const comp = createClientModuleProxy('${moduleId}'); + export default comp`; + return content; +} + +export default rscServerRegister; \ No newline at end of file diff --git a/packages/ice/src/service/serverCompiler.ts b/packages/ice/src/service/serverCompiler.ts index 2118de2302..f4d5301cb8 100644 --- a/packages/ice/src/service/serverCompiler.ts +++ b/packages/ice/src/service/serverCompiler.ts @@ -23,6 +23,7 @@ import formatPath from '../utils/formatPath.js'; import { createLogger } from '../utils/logger.js'; import { getExpandedEnvs } from '../utils/runtimeEnv.js'; import getCSSModuleIdent from '../utils/getCSSModuleIdent.js'; +import rscServerRegister from '../esbuild/rscServerRegister.js'; import { scanImports } from './analyze.js'; import type { PreBundleDepsMetaData } from './preBundleDeps.js'; import preBundleDeps from './preBundleDeps.js'; @@ -197,6 +198,7 @@ export function createServerCompiler(options: Options) { externals: server.externals, }), server?.ignores && ignorePlugin(server.ignores), + rscServerRegister(), cssModulesPlugin({ extract: false, generateLocalIdentName: function (name: string, fileName: string) { diff --git a/packages/ice/templates/core/clientEntry.tsx.ejs b/packages/ice/templates/core/clientEntry.tsx.ejs new file mode 100644 index 0000000000..762701b86d --- /dev/null +++ b/packages/ice/templates/core/clientEntry.tsx.ejs @@ -0,0 +1,46 @@ +<% if (importCoreJs) { -%>import 'core-js';<% } %> +import { createElement, Fragment } from 'react'; +import { getAppConfig } from '<%- iceRuntimePath %>'; +import { commons, statics } from './runtimeModules'; +import * as app from '@/app'; +<%- runtimeOptions.imports %> +<% if(dataLoaderImport.imports) {-%><%-dataLoaderImport.imports%><% } -%> +const getRouterBasename = () => { + const appConfig = getAppConfig(app); + return appConfig?.router?.basename ?? <%- basename %> ?? ''; +} +// Add react fragment for split chunks of app. +// Otherwise chunk of route component will pack @ice/jsx-runtime and depend on framework bundle. + +import React, { Suspense, use } from 'react'; +import * as ReactDOM from 'react-dom/client'; +import { createFromFetch } from 'react-server-dom-webpack/client'; + +async function runRSCApp() { + function Message({ response }) { + const body = use(response); + return <div>{body}</div>; + } + + function App({ response }) { + return ( + <Suspense fallback={<h1>Loading...</h1>}> + <Message response={response} /> + </Suspense> + ); + } + + const response = createFromFetch( + fetch('/?body'), + ); + + const container = document.getElementById('app'); + const root = ReactDOM.createRoot(container); + root.render(<App response={response} />); +} + +const render = (customOptions = {}) => { + return runRSCApp(); +}; + +<%- entryCode %> diff --git a/packages/ice/templates/core/entry.server.ts.ejs b/packages/ice/templates/core/entry.server.ts.ejs index 48b7a4eb0f..9228a68d83 100644 --- a/packages/ice/templates/core/entry.server.ts.ejs +++ b/packages/ice/templates/core/entry.server.ts.ejs @@ -9,6 +9,7 @@ import type { RenderMode, DistType } from '@ice/runtime'; import type { RenderToPipeableStreamOptions } from 'react-dom/server'; // @ts-ignore import assetsManifest from 'virtual:assets-manifest.json'; +import clientManifest from './react-client-manifest.json'; import createRoutes from './routes'; import routesConfig from './routes-config.bundle.mjs'; <% if(dataLoaderImport.imports) {-%><%-dataLoaderImport.imports%><% } -%> @@ -89,6 +90,7 @@ function mergeOptions(options) { basename: basename || getRouterBasename(), renderMode, routesConfig, + clientManifest, runtimeOptions: { <% if (runtimeOptions.exports) { -%> <%- runtimeOptions.exports %> diff --git a/packages/runtime/package.json b/packages/runtime/package.json index 22c0e1ea88..7117864692 100644 --- a/packages/runtime/package.json +++ b/packages/runtime/package.json @@ -39,8 +39,9 @@ "devDependencies": { "@types/react": "^18.0.8", "@types/react-dom": "^18.0.3", - "react": "^18.0.0", - "react-dom": "^18.0.0", + "react": "18.3.0-next-3ba7add60-20221201", + "react-server-dom-webpack": "18.3.0-next-855b77c9b-20230202", + "react-dom": "18.3.0-next-855b77c9b-20230202", "regenerator-runtime": "^0.13.9", "@remix-run/web-fetch": "^4.3.3" }, @@ -61,8 +62,9 @@ "source-map": "^0.7.4" }, "peerDependencies": { - "react": "^18.1.0", - "react-dom": "^18.1.0" + "react": "18.3.0-next-3ba7add60-20221201", + "react-dom": "18.3.0-next-855b77c9b-20230202", + "react-server-dom-webpack": "18.3.0-next-855b77c9b-20230202" }, "publishConfig": { "access": "public" diff --git a/packages/runtime/src/index.ts b/packages/runtime/src/index.ts index 67c46b42b4..cf36649bb0 100644 --- a/packages/runtime/src/index.ts +++ b/packages/runtime/src/index.ts @@ -26,6 +26,8 @@ import type { RunClientAppOptions, CreateRoutes } from './runClientApp.js'; import { useAppContext as useInternalAppContext, useAppData, AppContextProvider } from './AppContext.js'; import { getAppData } from './appData.js'; import { useData, useConfig } from './RouteContext.js'; +// import runRSCApp from './runRSCApp.js'; +import { createClientModuleProxy } from './reactFlightWebpackReference.js'; import { Meta, Title, @@ -133,6 +135,9 @@ export { createRouteLoader, WrapRouteComponent, RouteErrorComponent, + + // runRSCApp, + createClientModuleProxy, }; export type { diff --git a/packages/runtime/src/reactFlightWebpackReference.ts b/packages/runtime/src/reactFlightWebpackReference.ts new file mode 100644 index 0000000000..b1bf3be61e --- /dev/null +++ b/packages/runtime/src/reactFlightWebpackReference.ts @@ -0,0 +1,248 @@ +/* eslint-disable no-negated-condition */ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +// Modified from https://github.com/facebook/react/blob/main/packages/react-server-dom-webpack/src/ReactFlightWebpackNodeRegister.js + +let CLIENT_REFERENCE = Symbol.for('react.client.reference'); +let PROMISE_PROTOTYPE = Promise.prototype; +let deepProxyHandlers = { + get: function (target, name, receiver) { + switch (name) { + // These names are read by the Flight runtime if you end up using the exports object. + case '$$typeof': + // These names are a little too common. We should probably have a way to + // have the Flight runtime extract the inner target instead. + return target.$$typeof; + + case 'filepath': + return target.filepath; + + case 'name': + return target.name; + + case 'async': + return target.async; + // We need to special case this because createElement reads it if we pass this + // reference. + + case 'defaultProps': + return undefined; + // Avoid this attempting to be serialized. + + case 'toJSON': + return undefined; + + case Symbol.toPrimitive: + // $FlowFixMe[prop-missing] + return Object.prototype[Symbol.toPrimitive]; + + case 'Provider': + throw new Error('Cannot render a Client Context Provider on the Server. ' + 'Instead, you can export a Client Component wrapper ' + 'that itself renders a Client Context Provider.'); + } + + let expression; + + switch (target.name) { + case '': + expression = String(name); + break; + + case '*': + expression = String(name); + break; + + default: + expression = `${String(target.name)}.${String(name)}`; + } + + throw new Error(`Cannot access ${expression} on the server. ` + 'You cannot dot into a client module from a server component. ' + 'You can only pass the imported name through.'); + }, + set: function () { + throw new Error('Cannot assign to a client module from a server module.'); + }, +}; +const proxyHandlers = { + get: function (target, name, receiver) { + switch (name) { + // These names are read by the Flight runtime if you end up using the exports object. + case '$$typeof': + // These names are a little too common. We should probably have a way to + // have the Flight runtime extract the inner target instead. + return target.$$typeof; + + case 'filepath': + return target.filepath; + + case 'name': + return target.name; + + case 'async': + return target.async; + // We need to special case this because createElement reads it if we pass this + // reference. + + case 'defaultProps': + return undefined; + // Avoid this attempting to be serialized. + + case 'toJSON': + return undefined; + + case Symbol.toPrimitive: + // $FlowFixMe[prop-missing] + return Object.prototype[Symbol.toPrimitive]; + + case '__esModule': + // Something is conditionally checking which export to use. We'll pretend to be + // an ESM compat module but then we'll check again on the client. + const moduleId = target.filepath; + target.default = Object.defineProperties(() => { + throw new Error(`Attempted to call the default export of ${moduleId} from the server` + 'but it\'s on the client. It\'s not possible to invoke a client function from ' + 'the server, it can only be rendered as a Component or passed to props of a' + 'Client Component.'); + }, { + // This a placeholder value that tells the client to conditionally use the + // whole object or just the default export. + name: { + value: '', + }, + $$typeof: { + value: CLIENT_REFERENCE, + }, + filepath: { + value: target.filepath, + }, + async: { + value: target.async, + }, + }); + return true; + + case 'then': + if (target.then) { + // Use a cached value + return target.then; + } + + if (!target.async) { + // If this module is expected to return a Promise (such as an AsyncModule) then + // we should resolve that with a client reference that unwraps the Promise on + // the client. + let clientReference = Object.defineProperties({}, { + // Represents the whole Module object instead of a particular import. + name: { + value: '*', + }, + $$typeof: { + value: CLIENT_REFERENCE, + }, + filepath: { + value: target.filepath, + }, + async: { + value: true, + }, + }); + const proxy = new Proxy(clientReference, proxyHandlers); // Treat this as a resolved Promise for React's use() + + target.status = 'fulfilled'; + target.value = proxy; // $FlowFixMe[missing-local-annot] + + const then = target.then = Object.defineProperties((resolve, reject) => { + // Expose to React. + return Promise.resolve( // $FlowFixMe[incompatible-call] found when upgrading Flow + resolve(proxy)); + }, // If this is not used as a Promise but is treated as a reference to a `.then` + // export then we should treat it as a reference to that name. + { + name: { + value: 'then', + }, + $$typeof: { + value: CLIENT_REFERENCE, + }, + filepath: { + value: target.filepath, + }, + async: { + value: false, + }, + }); + return then; + } else { + // Since typeof .then === 'function' is a feature test we'd continue recursing + // indefinitely if we return a function. Instead, we return an object reference + // if we check further. + return undefined; + } + } + + let cachedReference = target[name]; + + if (!cachedReference) { + let reference = Object.defineProperties(() => { + throw new Error( + `Attempted to call ${String(name)}() from the server but ${String(name)} is on the client. ` + 'It\'s not possible to invoke a client function from the server, it can ' + 'only be rendered as a Component or passed to props of a Client Component.'); + }, { + name: { + value: name, + }, + $$typeof: { + value: CLIENT_REFERENCE, + }, + filepath: { + value: target.filepath, + }, + async: { + value: target.async, + }, + }); + cachedReference = target[name] = new Proxy(reference, deepProxyHandlers); + } + + return cachedReference; + }, + getPrototypeOf: function (target) { + // Pretend to be a Promise in case anyone asks. + return PROMISE_PROTOTYPE; + }, + set: function () { + throw new Error('Cannot assign to a client module from a server module.'); + }, +}; // $FlowFixMe[prop-missing] found when upgrading Flow + + +export function createClientModuleProxy(moduleId: string) { + // const clientReference = Object.defineProperties( + // {}, + // { + // $$typeof: { value: CLIENT_REFERENCE }, + // // Represents the whole Module object instead of a particular import. + // $$id: { value: moduleId }, + // $$async: { value: false }, + // }, + // ); + // var moduleId = url.pathToFileURL(path).href; + let clientReference = Object.defineProperties({}, { + // Represents the whole Module object instead of a particular import. + name: { + value: '', + }, + $$typeof: { + value: CLIENT_REFERENCE, + }, + filepath: { + value: moduleId, + }, + async: { + value: false, + }, + }); // $FlowFixMe[incompatible-call] found when upgrading Flow + + const pxy = new Proxy(clientReference, proxyHandlers); + console.log('proxy', pxy); + return pxy; // new Proxy(clientReference, proxyHandlers) +} \ No newline at end of file diff --git a/packages/runtime/src/routes.tsx b/packages/runtime/src/routes.tsx index 0ab6f54c7b..0a54146791 100644 --- a/packages/runtime/src/routes.tsx +++ b/packages/runtime/src/routes.tsx @@ -59,12 +59,14 @@ export function WrapRouteComponent(options: { routeExports: ComponentModule; }) { const { routeId, isLayout, routeExports } = options; - const { RouteWrappers } = useAppContext(); - return ( - <RouteWrapper routeExports={routeExports} id={routeId} isLayout={isLayout} wrappers={RouteWrappers}> - <routeExports.default /> - </RouteWrapper> - ); + + return <routeExports.default />; + // const { RouteWrappers } = useAppContext(); + // return ( + // <RouteWrapper routeExports={routeExports} id={routeId} isLayout={isLayout} wrappers={RouteWrappers}> + // <routeExports.default /> + // </RouteWrapper> + // ); } export function RouteComponent({ id }: { id: string }) { diff --git a/packages/runtime/src/runServerApp.tsx b/packages/runtime/src/runServerApp.tsx index 56a80a4f60..cbd7d619fe 100644 --- a/packages/runtime/src/runServerApp.tsx +++ b/packages/runtime/src/runServerApp.tsx @@ -4,6 +4,7 @@ import * as ReactDOMServer from 'react-dom/server'; import { parsePath } from 'history'; import type { Location } from 'history'; import type { RenderToPipeableStreamOptions } from 'react-dom/server'; +import { renderToPipeableStream } from 'react-server-dom-webpack/server.node'; import type { AppContext, RouteItem, ServerContext, AppExport, AssetsManifest, @@ -53,6 +54,7 @@ interface RenderOptions { prependCode?: string; serverData?: any; streamOptions?: RenderToPipeableStreamOptions; + clientManifest: any; } interface Piper { @@ -271,6 +273,10 @@ async function doRender(serverContext: ServerContext, renderOptions: RenderOptio } } + if (req.url.indexOf('?') === -1) { + return renderDocument({ matches: [], routes, renderOptions }); + } + // HashRouter loads route modules by the CSR. if (appConfig?.router?.type === 'hash') { return renderDocument({ matches: [], routes, renderOptions }); @@ -381,22 +387,41 @@ async function renderServerEntry( location, }; - const documentContext = { - main: ( - <AppRouter routes={routes} routerContext={routerContext} /> - ), - }; + const Page = await matches[1].route.lazy(); + // @ts-expect-error + const PageComponent = Page.Component; + const element = ( - <AppContextProvider value={appContext}> - <AppRuntimeProvider> - <DocumentContextProvider value={documentContext}> - <Document pagePath={routePath} /> - </DocumentContextProvider> - </AppRuntimeProvider> - </AppContextProvider> + <div> + <PageComponent /> + </div> + ); + + // const documentContext = { + // main: ( + // <AppRouter routes={routes} routerContext={routerContext} /> + // ), + // }; + // const element = ( + // <AppContextProvider value={appContext}> + // <AppRuntimeProvider> + // <DocumentContextProvider value={documentContext}> + // <Document pagePath={routePath} /> + // </DocumentContextProvider> + // </AppRuntimeProvider> + // </AppContextProvider> + // ); + + const moduleMap = { + clientManifest: renderOptions.clientManifest, + }; + + const { pipe } = renderToPipeableStream( + element, + moduleMap, ); - const pipe = renderToNodeStream(element); + // const pipe = renderToNodeStream(element); const fallback = () => { return renderDocument({ matches, routePath, renderOptions, routes, downgrade: true }); diff --git a/packages/webpack-config/src/index.ts b/packages/webpack-config/src/index.ts index fe9b9d2081..04ddcfb7be 100644 --- a/packages/webpack-config/src/index.ts +++ b/packages/webpack-config/src/index.ts @@ -48,7 +48,7 @@ function getEntry(rootDir: string, runtimeTmpDir: string) { })[0]; if (!entryFile) { // use generated file in template directory - entryFile = path.join(rootDir, runtimeTmpDir, 'entry.client.tsx'); + entryFile = path.join(rootDir, runtimeTmpDir, 'clientEntry.tsx'); } // const dataLoaderFile = path.join(rootDir, '.ice/data-loader.ts'); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index be4e8223cf..db5e530b55 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -770,6 +770,25 @@ importers: '@types/react': 18.0.28 '@types/react-dom': 18.0.11 + examples/with-rsc: + specifiers: + '@ice/app': workspace:* + '@ice/runtime': workspace:* + '@types/react': ^18.0.17 + '@types/react-dom': ^18.0.6 + react: 18.3.0-next-3ba7add60-20221201 + react-dom: 18.3.0-next-855b77c9b-20230202 + react-server-dom-webpack: 18.3.0-next-855b77c9b-20230202 + dependencies: + '@ice/app': link:../../packages/ice + '@ice/runtime': link:../../packages/runtime + react: 18.3.0-next-3ba7add60-20221201 + react-dom: 18.3.0-next-855b77c9b-20230202_osgg5tsgainv67oqv2d3ptcxsm + react-server-dom-webpack: 18.3.0-next-855b77c9b-20230202_rinjvadhybif4dwgmiuj7eb2ee + devDependencies: + '@types/react': 18.0.34 + '@types/react-dom': 18.0.11 + examples/with-ssg: specifiers: '@ice/app': workspace:* @@ -1134,8 +1153,9 @@ importers: mrmime: ^1.0.0 open: ^8.4.0 path-to-regexp: ^6.2.0 - react: ^18.2.0 + react: 18.3.0-next-3ba7add60-20221201 react-router: 6.14.2 + react-server-dom-webpack: 18.3.0-next-855b77c9b-20230202 regenerator-runtime: ^0.13.0 resolve.exports: ^1.1.0 sass: ^1.50.0 @@ -1193,8 +1213,9 @@ importers: chokidar: 3.5.3 esbuild: 0.17.16 jest: 29.5.0 - react: 18.2.0 - react-router: 6.14.2_react@18.2.0 + react: 18.3.0-next-3ba7add60-20221201 + react-router: 6.14.2_osgg5tsgainv67oqv2d3ptcxsm + react-server-dom-webpack: 18.3.0-next-855b77c9b-20230202_eaktsl3pcltpekt37vdcusnisq sass: 1.50.0 unplugin: 0.9.5_4yjf5voakpkrj4qbnm3gtqjbli webpack: 5.88.2_esbuild@0.17.16 @@ -1591,9 +1612,10 @@ importers: fs-extra: ^10.0.0 history: ^5.3.0 htmlparser2: ^8.0.1 - react: ^18.0.0 - react-dom: ^18.0.0 + react: 18.3.0-next-3ba7add60-20221201 + react-dom: 18.3.0-next-855b77c9b-20230202 react-router-dom: 6.14.2 + react-server-dom-webpack: 18.3.0-next-855b77c9b-20230202 regenerator-runtime: ^0.13.9 semver: ^7.4.0 source-map: ^0.7.4 @@ -1605,15 +1627,16 @@ importers: fs-extra: 10.1.0 history: 5.3.0 htmlparser2: 8.0.1 - react-router-dom: 6.14.2_biqbaboplfbrettd7655fr4n2y + react-router-dom: 6.14.2_rinjvadhybif4dwgmiuj7eb2ee semver: 7.4.0 source-map: 0.7.4 devDependencies: '@remix-run/web-fetch': 4.3.3 '@types/react': 18.0.28 '@types/react-dom': 18.0.11 - react: 18.2.0 - react-dom: 18.2.0_react@18.2.0 + react: 18.3.0-next-3ba7add60-20221201 + react-dom: 18.3.0-next-855b77c9b-20230202_osgg5tsgainv67oqv2d3ptcxsm + react-server-dom-webpack: 18.3.0-next-855b77c9b-20230202_rinjvadhybif4dwgmiuj7eb2ee regenerator-runtime: 0.13.11 packages/shared: @@ -7455,6 +7478,7 @@ packages: cpu: [arm64] os: [darwin] requiresBuild: true + dev: false optional: true /@swc/core-darwin-x64/1.3.32: @@ -7472,6 +7496,7 @@ packages: cpu: [x64] os: [darwin] requiresBuild: true + dev: false optional: true /@swc/core-linux-arm-gnueabihf/1.3.32: @@ -7489,6 +7514,7 @@ packages: cpu: [arm] os: [linux] requiresBuild: true + dev: false optional: true /@swc/core-linux-arm64-gnu/1.3.32: @@ -7506,6 +7532,7 @@ packages: cpu: [arm64] os: [linux] requiresBuild: true + dev: false optional: true /@swc/core-linux-arm64-musl/1.3.32: @@ -7523,6 +7550,7 @@ packages: cpu: [arm64] os: [linux] requiresBuild: true + dev: false optional: true /@swc/core-linux-x64-gnu/1.3.32: @@ -7540,6 +7568,7 @@ packages: cpu: [x64] os: [linux] requiresBuild: true + dev: false optional: true /@swc/core-linux-x64-musl/1.3.32: @@ -7557,6 +7586,7 @@ packages: cpu: [x64] os: [linux] requiresBuild: true + dev: false optional: true /@swc/core-win32-arm64-msvc/1.3.32: @@ -7574,6 +7604,7 @@ packages: cpu: [arm64] os: [win32] requiresBuild: true + dev: false optional: true /@swc/core-win32-ia32-msvc/1.3.32: @@ -7591,6 +7622,7 @@ packages: cpu: [ia32] os: [win32] requiresBuild: true + dev: false optional: true /@swc/core-win32-x64-msvc/1.3.32: @@ -7608,6 +7640,7 @@ packages: cpu: [x64] os: [win32] requiresBuild: true + dev: false optional: true /@swc/core/1.3.32: @@ -7649,6 +7682,7 @@ packages: '@swc/core-win32-arm64-msvc': 1.3.80 '@swc/core-win32-ia32-msvc': 1.3.80 '@swc/core-win32-x64-msvc': 1.3.80 + dev: false /@swc/helpers/0.4.14: resolution: {integrity: sha512-4C7nX/dvpzB7za4Ql9K81xK3HPxCpHMgwTZVyf+9JQ6VUbn9jjZVN7/Nkdz/Ugzs2CSjqnL/UPXroiVBVHUWUw==} @@ -7663,6 +7697,7 @@ packages: /@swc/types/0.1.4: resolution: {integrity: sha512-z/G02d+59gyyUb7KYhKi9jOhicek6QD2oMaotUyG+lUkybpXoV49dY9bj7Ah5Q+y7knK2jU67UTX9FyfGzaxQg==} + dev: false /@szmarczak/http-timer/1.1.2: resolution: {integrity: sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==} @@ -8129,6 +8164,7 @@ packages: '@types/prop-types': 15.7.5 '@types/scheduler': 0.16.2 csstype: 3.1.1 + dev: true /@types/react/18.0.28: resolution: {integrity: sha512-RD0ivG1kEztNBdoAK7lekI9M+azSnitIn85h4iOiaLjaTrMjzslhaqCGaI4IyCJ1RljWiLCEu4jyrLLgqxBTew==} @@ -8713,6 +8749,11 @@ packages: resolution: {integrity: sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==} engines: {node: '>=0.4.0'} + /acorn/6.4.2: + resolution: {integrity: sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==} + engines: {node: '>=0.4.0'} + hasBin: true + /acorn/7.4.1: resolution: {integrity: sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==} engines: {node: '>=0.4.0'} @@ -10397,8 +10438,8 @@ packages: engines: {node: '>=10'} hasBin: true dependencies: - JSONStream: 1.3.5 is-text-path: 1.0.1 + JSONStream: 1.3.5 lodash: 4.17.21 meow: 8.1.2 split2: 3.2.2 @@ -10428,6 +10469,7 @@ packages: resolution: {integrity: sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==} dependencies: is-what: 3.14.1 + dev: false /copy-text-to-clipboard/3.0.1: resolution: {integrity: sha512-rvVsHrpFcL4F2P8ihsoLdFHmd404+CMg71S756oRSeQgqk51U3kicGdnvfkrxva0xXH92SjGS62B0XIJsbh+9Q==} @@ -11633,6 +11675,7 @@ packages: requiresBuild: true dependencies: prr: 1.0.1 + dev: false optional: true /error-ex/1.3.2: @@ -14006,6 +14049,7 @@ packages: engines: {node: '>=0.10.0'} hasBin: true requiresBuild: true + dev: false optional: true /image-size/1.0.2: @@ -14519,6 +14563,7 @@ packages: /is-what/3.14.1: resolution: {integrity: sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==} + dev: false /is-whitespace-character/1.0.4: resolution: {integrity: sha512-SDweEzfIZM0SJV0EUga669UTKlmL0Pq8Lno0QDQsPnvECB3IM2aP0gdx5TrU0A01MAPfViaZiI2V1QMZLaKK5w==} @@ -15800,6 +15845,7 @@ packages: source-map: 0.6.1 transitivePeerDependencies: - supports-color + dev: false /leven/3.1.0: resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} @@ -16103,6 +16149,7 @@ packages: dependencies: pify: 4.0.1 semver: 5.7.1 + dev: false optional: true /make-dir/3.1.0: @@ -16498,6 +16545,7 @@ packages: sax: 1.2.4 transitivePeerDependencies: - supports-color + dev: false optional: true /negotiator/0.6.3: @@ -16950,6 +16998,7 @@ packages: /parse-node-version/1.0.1: resolution: {integrity: sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==} engines: {node: '>= 0.10'} + dev: false /parse-numeric-range/1.3.0: resolution: {integrity: sha512-twN+njEipszzlMJd4ONUYgSfZPDxgHhT9Ahed5uTigpQn90FggW4SA/AIPq/6a149fTbE9qBEcSwE3FAEp6wQQ==} @@ -18591,6 +18640,7 @@ packages: nanoid: 3.3.4 picocolors: 1.0.0 source-map-js: 1.0.2 + dev: false /postcss/8.4.21: resolution: {integrity: sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==} @@ -18748,6 +18798,7 @@ packages: /prr/1.0.1: resolution: {integrity: sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==} + dev: false optional: true /pseudomap/1.0.2: @@ -19888,12 +19939,6 @@ packages: /react-dev-utils/12.0.1_rggdtlzfqxxwxudp3onsqdyocm: resolution: {integrity: sha512-84Ivxmr17KjUupyqzFode6xKhjwuEJDROWKJy/BthkL7Wn6NJ8h4WE6k/exAv6ImS+0oZLRRW5j/aINMHyeGeQ==} engines: {node: '>=14'} - peerDependencies: - typescript: '>=2.7' - webpack: '>=4' - peerDependenciesMeta: - typescript: - optional: true dependencies: '@babel/code-frame': 7.18.6 address: 1.2.2 @@ -19924,7 +19969,9 @@ packages: transitivePeerDependencies: - eslint - supports-color + - typescript - vue-template-compiler + - webpack /react-dom/17.0.2_react@17.0.2: resolution: {integrity: sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==} @@ -19935,6 +19982,7 @@ packages: object-assign: 4.1.1 react: 17.0.2 scheduler: 0.20.2 + dev: false /react-dom/18.2.0_react@18.2.0: resolution: {integrity: sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==} @@ -19945,6 +19993,15 @@ packages: react: 18.2.0 scheduler: 0.23.0 + /react-dom/18.3.0-next-855b77c9b-20230202_osgg5tsgainv67oqv2d3ptcxsm: + resolution: {integrity: sha512-5IiFiBrNR6HzFoeMI07ELTmtmd6gui8HsReLXrKwZlpuzMXlLAOWlCEaYSF+kCZNmRAoognUh+LUQJ31TaR4WA==} + peerDependencies: + react: 18.3.0-next-855b77c9b-20230202 + dependencies: + loose-envify: 1.4.0 + react: 18.3.0-next-3ba7add60-20221201 + scheduler: 0.24.0-next-855b77c9b-20230202 + /react-error-overlay/6.0.11: resolution: {integrity: sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg==} @@ -20095,7 +20152,7 @@ packages: tiny-invariant: 1.3.1 tiny-warning: 1.0.3 - /react-router-dom/6.14.2_biqbaboplfbrettd7655fr4n2y: + /react-router-dom/6.14.2_rinjvadhybif4dwgmiuj7eb2ee: resolution: {integrity: sha512-5pWX0jdKR48XFZBuJqHosX3AAHjRAzygouMTyimnBPOLdY3WjzUSKhus2FVMihUFWzeLebDgr4r8UeQFAct7Bg==} engines: {node: '>=14'} peerDependencies: @@ -20103,9 +20160,9 @@ packages: react-dom: '>=16.8' dependencies: '@remix-run/router': 1.7.2 - react: 18.2.0 - react-dom: 18.2.0_react@18.2.0 - react-router: 6.14.2_react@18.2.0 + react: 18.3.0-next-3ba7add60-20221201 + react-dom: 18.3.0-next-855b77c9b-20230202_osgg5tsgainv67oqv2d3ptcxsm + react-router: 6.14.2_osgg5tsgainv67oqv2d3ptcxsm dev: false /react-router/5.3.4_react@17.0.2: @@ -20124,14 +20181,43 @@ packages: tiny-invariant: 1.3.1 tiny-warning: 1.0.3 - /react-router/6.14.2_react@18.2.0: + /react-router/6.14.2_osgg5tsgainv67oqv2d3ptcxsm: resolution: {integrity: sha512-09Zss2dE2z+T1D03IheqAFtK4UzQyX8nFPWx6jkwdYzGLXd5ie06A6ezS2fO6zJfEb/SpG6UocN2O1hfD+2urQ==} engines: {node: '>=14'} peerDependencies: react: '>=16.8' dependencies: '@remix-run/router': 1.7.2 - react: 18.2.0 + react: 18.3.0-next-3ba7add60-20221201 + + /react-server-dom-webpack/18.3.0-next-855b77c9b-20230202_eaktsl3pcltpekt37vdcusnisq: + resolution: {integrity: sha512-bjqFXHpl/ZFaP7gPebLjGkGy4dGaxRF88rjCinYULOPyxLIVTXmiZyQE6wdA6+zeqRZbFllIF2CJAnDSDAIUww==} + engines: {node: '>=0.10.0'} + peerDependencies: + react: 18.3.0-next-855b77c9b-20230202 + react-dom: 18.3.0-next-855b77c9b-20230202 + webpack: ^5.59.0 + dependencies: + acorn: 6.4.2 + loose-envify: 1.4.0 + neo-async: 2.6.2 + react: 18.3.0-next-3ba7add60-20221201 + webpack: 5.88.2_esbuild@0.17.16 + dev: true + + /react-server-dom-webpack/18.3.0-next-855b77c9b-20230202_rinjvadhybif4dwgmiuj7eb2ee: + resolution: {integrity: sha512-bjqFXHpl/ZFaP7gPebLjGkGy4dGaxRF88rjCinYULOPyxLIVTXmiZyQE6wdA6+zeqRZbFllIF2CJAnDSDAIUww==} + engines: {node: '>=0.10.0'} + peerDependencies: + react: 18.3.0-next-855b77c9b-20230202 + react-dom: 18.3.0-next-855b77c9b-20230202 + webpack: ^5.59.0 + dependencies: + acorn: 6.4.2 + loose-envify: 1.4.0 + neo-async: 2.6.2 + react: 18.3.0-next-3ba7add60-20221201 + react-dom: 18.3.0-next-855b77c9b-20230202_osgg5tsgainv67oqv2d3ptcxsm /react-textarea-autosize/8.4.0_h7fc2el62uaa77gho3xhys6ola: resolution: {integrity: sha512-YrTFaEHLgJsi8sJVYHBzYn+mkP3prGkmP2DKb/tm0t7CLJY5t1Rxix8070LAKb0wby7bl/lf2EeHkuMihMZMwQ==} @@ -20167,6 +20253,7 @@ packages: dependencies: loose-envify: 1.4.0 object-assign: 4.1.1 + dev: false /react/18.2.0: resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==} @@ -20174,6 +20261,12 @@ packages: dependencies: loose-envify: 1.4.0 + /react/18.3.0-next-3ba7add60-20221201: + resolution: {integrity: sha512-/hwADSpnz/GeDEljbg7Z2mF2MaYw7V1CsdbGvvhCUse4RvaRueHjcH7B/jbik8wRll3rxBPlomt15rSjIMjEJQ==} + engines: {node: '>=0.10.0'} + dependencies: + loose-envify: 1.4.0 + /read-cache/1.0.0: resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==} dependencies: @@ -20791,6 +20884,7 @@ packages: dependencies: loose-envify: 1.4.0 object-assign: 4.1.1 + dev: false /scheduler/0.21.0: resolution: {integrity: sha512-1r87x5fz9MXqswA2ERLo0EbOAU74DpIUO090gIasYTqlVoJeMcl+Z1Rg7WHz+qtPujhS/hGIt9kxZOYBV3faRQ==} @@ -20803,6 +20897,11 @@ packages: dependencies: loose-envify: 1.4.0 + /scheduler/0.24.0-next-855b77c9b-20230202: + resolution: {integrity: sha512-uZWTxDVYVxc1XmqDM1TtxUKI2WMMXzyjw03iLgMDtoEuUMZq8rwBB8Ue+kX8axrVDwC3lN1dzd5P3G+5rZCnKw==} + dependencies: + loose-envify: 1.4.0 + /schema-utils/2.7.0: resolution: {integrity: sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A==} engines: {node: '>= 8.9.0'} @@ -21865,6 +21964,7 @@ packages: serialize-javascript: 6.0.1 terser: 5.14.2 webpack: 5.76.0_yt3h3qjhcnsf3663codtuni62a + dev: false /terser-webpack-plugin/5.3.5_muqrkd6dqvsxxmw22vfpzybwpe: resolution: {integrity: sha512-AOEDLDxD2zylUGf/wxHxklEkOe2/r+seuyOWujejFrIxHf11brA1/dWQNIgXa1c6/Wkxgu7zvv0JhOWfc2ELEA==} @@ -22014,6 +22114,7 @@ packages: serialize-javascript: 6.0.1 terser: 5.16.5 webpack: 5.88.2_yt3h3qjhcnsf3663codtuni62a + dev: true /terser-webpack-plugin/5.3.7_webpack@5.88.2: resolution: {integrity: sha512-AfKwIktyP7Cu50xNjXF/6Qb5lBNzYaWpU6YfoX3uZicTx0zTy0stDDCsvjDapKsSDvOeWo5MEq4TmdBy2cNoHw==} @@ -23664,6 +23765,7 @@ packages: - '@swc/core' - esbuild - uglify-js + dev: false /webpack/5.86.0_esbuild@0.17.16: resolution: {integrity: sha512-3BOvworZ8SO/D4GVP+GoRC3fVeg5MO4vzmq8TJJEkdmopxyazGDxN8ClqN12uzrZW9Tv8EED8v5VSb6Sqyi0pg==} @@ -23822,6 +23924,7 @@ packages: - '@swc/core' - esbuild - uglify-js + dev: true /webpackbar/5.0.2_webpack@5.88.2: resolution: {integrity: sha512-BmFJo7veBDgQzfWXl/wwYXr/VFus0614qZ8i9znqcl9fnEdiVkdbi0TedLQ6xAK92HZHDJ0QmyQ0fmuZPAgCYQ==} From 475b118b2b77870bc3d0d0552e1e991750745fbb Mon Sep 17 00:00:00 2001 From: "shuilan.cj" <shuilan.cj@taobao.com> Date: Fri, 1 Sep 2023 16:33:28 +0800 Subject: [PATCH 02/17] refactor: update react version --- examples/with-rsc/package.json | 6 +- .../src/components/Counter.client.tsx | 1 + .../src/components/EditButton.client.tsx | 1 + packages/ice/package.json | 8 +- .../src/bundler/webpack/getWebpackConfig.ts | 8 +- packages/ice/src/esbuild/assets.ts | 16 + packages/ice/src/esbuild/rscServerRegister.ts | 4 +- packages/ice/src/plugins/web/task.ts | 1 + .../ice/src/webpack/ServerCompilerPlugin.ts | 4 + .../ice/templates/core/clientEntry.tsx.ejs | 29 +- .../ice/templates/core/entry.server.ts.ejs | 2 +- packages/runtime/package.json | 12 +- packages/runtime/src/index.ts | 6 +- .../src/reactFlightWebpackReference.ts | 248 --------- packages/runtime/src/runRSCApp.tsx | 28 + packages/runtime/src/runServerApp.tsx | 6 +- pnpm-lock.yaml | 490 ++++++++++++++---- 17 files changed, 474 insertions(+), 396 deletions(-) delete mode 100644 packages/runtime/src/reactFlightWebpackReference.ts create mode 100644 packages/runtime/src/runRSCApp.tsx diff --git a/examples/with-rsc/package.json b/examples/with-rsc/package.json index beb168ce04..7786e40cb1 100644 --- a/examples/with-rsc/package.json +++ b/examples/with-rsc/package.json @@ -11,9 +11,9 @@ "dependencies": { "@ice/app": "workspace:*", "@ice/runtime": "workspace:*", - "react": "18.3.0-next-3ba7add60-20221201", - "react-dom": "18.3.0-next-855b77c9b-20230202", - "react-server-dom-webpack": "18.3.0-next-855b77c9b-20230202" + "react": "18.3.0-canary-dd480ef92-20230822", + "react-dom": "18.3.0-canary-dd480ef92-20230822", + "react-server-dom-webpack": "18.3.0-canary-dd480ef92-20230822" }, "devDependencies": { "@types/react": "^18.0.17", diff --git a/examples/with-rsc/src/components/Counter.client.tsx b/examples/with-rsc/src/components/Counter.client.tsx index 384eece061..d4c233afdd 100644 --- a/examples/with-rsc/src/components/Counter.client.tsx +++ b/examples/with-rsc/src/components/Counter.client.tsx @@ -1,3 +1,4 @@ +'use client'; import { useState } from 'react'; import styles from './index.module.css'; diff --git a/examples/with-rsc/src/components/EditButton.client.tsx b/examples/with-rsc/src/components/EditButton.client.tsx index 1c19168703..4a9fd16add 100644 --- a/examples/with-rsc/src/components/EditButton.client.tsx +++ b/examples/with-rsc/src/components/EditButton.client.tsx @@ -1,3 +1,4 @@ +'use client'; import { useTransition } from 'react'; export default function EditButton({ noteId, children }) { diff --git a/packages/ice/package.json b/packages/ice/package.json index 941eb3ee8b..573a98d72d 100644 --- a/packages/ice/package.json +++ b/packages/ice/package.json @@ -90,12 +90,12 @@ "webpack-dev-server": "^4.7.4", "@rspack/core": "0.3.0", "@rspack/dev-server": "0.3.0", - "react-server-dom-webpack": "18.3.0-next-855b77c9b-20230202" + "react-server-dom-webpack": "18.3.0-canary-dd480ef92-20230822" }, "peerDependencies": { - "react": "18.3.0-next-3ba7add60-20221201", - "react-dom": "18.3.0-next-855b77c9b-20230202", - "react-server-dom-webpack": "18.3.0-next-855b77c9b-20230202" + "react": "18.3.0-canary-dd480ef92-20230822", + "react-dom": "18.3.0-canary-dd480ef92-20230822", + "react-server-dom-webpack": "18.3.0-canary-dd480ef92-20230822" }, "publishConfig": { "access": "public" diff --git a/packages/ice/src/bundler/webpack/getWebpackConfig.ts b/packages/ice/src/bundler/webpack/getWebpackConfig.ts index bda1b4e2a0..62a28501c6 100644 --- a/packages/ice/src/bundler/webpack/getWebpackConfig.ts +++ b/packages/ice/src/bundler/webpack/getWebpackConfig.ts @@ -119,7 +119,13 @@ const getWebpackConfig: GetWebpackConfig = async (context, options) => { // Add spinner for webpack task. webpackConfig.plugins.push(getSpinnerPlugin(spinner)); - webpackConfig.plugins.push(new ReactServerWebpackPlugin({ isServer: false, dist: path.join(rootDir, '.ice') })); + webpackConfig.plugins.push(new ReactServerWebpackPlugin({ isServer: false, +clientReferences: [{ + directory: path.join(rootDir, 'src'), + recursive: true, + include: /\.(js|ts|jsx|tsx)$/, + exclude: /types.ts|.d.ts/, + }] })); return webpackConfig; }); diff --git a/packages/ice/src/esbuild/assets.ts b/packages/ice/src/esbuild/assets.ts index 1290eb8f21..8c0e18d280 100644 --- a/packages/ice/src/esbuild/assets.ts +++ b/packages/ice/src/esbuild/assets.ts @@ -40,6 +40,7 @@ const ASSETS_RE = new RegExp(`\\.(${ASSET_TYPES.join('|')})(\\?.*)?$`); interface CompilationInfo { assetsManifest?: AssetsManifest; + rscManifest?: any; } const createAssetsPlugin = (compilationInfo: CompilationInfo | (() => CompilationInfo), rootDir: string) => ({ @@ -60,6 +61,21 @@ const createAssetsPlugin = (compilationInfo: CompilationInfo | (() => Compilatio loader: 'json', }; }); + build.onResolve({ filter: /react-client-manifest.json$/ }, (args) => { + if (args.path === 'virtual:react-client-manifest.json') { + return { + path: args.path, + namespace: 'react-client-manifest', + }; + } + }); + build.onLoad({ filter: /.*/, namespace: 'react-client-manifest' }, () => { + const manifest = typeof compilationInfo === 'function' ? compilationInfo() : compilationInfo; + return { + contents: JSON.stringify(manifest?.rscManifest || ''), + loader: 'json', + }; + }); build.onLoad({ filter: ASSETS_RE }, async (args) => { const manifest = typeof compilationInfo === 'function' ? compilationInfo() : compilationInfo; if (args.suffix == '?raw') { diff --git a/packages/ice/src/esbuild/rscServerRegister.ts b/packages/ice/src/esbuild/rscServerRegister.ts index da039253da..ff90045b6d 100644 --- a/packages/ice/src/esbuild/rscServerRegister.ts +++ b/packages/ice/src/esbuild/rscServerRegister.ts @@ -9,7 +9,7 @@ const rscServerRegister = (): Plugin => { const { path } = args; const loader = path.endsWith('.tsx') || path.endsWith('.ts') ? 'tsx' : 'jsx'; const moduleId: string = url.pathToFileURL(path).href; - let source = 'import {createClientModuleProxy} from \'@ice/runtime\';'; + let source = 'const Server: any = require(\'react-server-dom-webpack/server.node\');const createClientModuleProxy = Server.createClientModuleProxy;'; source += transformContent(moduleId); return { contents: source, loader }; }); @@ -20,7 +20,7 @@ const rscServerRegister = (): Plugin => { function transformContent(moduleId: string) { const content = `\ const comp = createClientModuleProxy('${moduleId}'); - export default comp`; + module.exports = comp`; return content; } diff --git a/packages/ice/src/plugins/web/task.ts b/packages/ice/src/plugins/web/task.ts index 5b792793a6..9e0c4d5a00 100644 --- a/packages/ice/src/plugins/web/task.ts +++ b/packages/ice/src/plugins/web/task.ts @@ -31,6 +31,7 @@ const getWebTask = ({ rootDir, command, userConfig }): Config => { '@swc/helpers': path.dirname(require.resolve('@swc/helpers/package.json')), 'universal-env': envReplacement, '@uni/env': envReplacement, + 'react-server-dom-webpack/client': require.resolve('react-server-dom-webpack/client.browser'), }, swcOptions: { removeExportExprs, diff --git a/packages/ice/src/webpack/ServerCompilerPlugin.ts b/packages/ice/src/webpack/ServerCompilerPlugin.ts index 42711e4118..aeeca3bda7 100644 --- a/packages/ice/src/webpack/ServerCompilerPlugin.ts +++ b/packages/ice/src/webpack/ServerCompilerPlugin.ts @@ -41,6 +41,10 @@ export default class ServerCompilerPlugin { // Option of compilationInfo need to be object, while it may changed during multi-time compilation. this.compilerOptions.compilationInfo.assetsManifest = JSON.parse(compilation.assets['assets-manifest.json'].source().toString()); + + // @ts-ignore + this.compilerOptions.compilationInfo.rscManifest = + JSON.parse(compilation.assets['react-client-manifest.json']?.source()?.toString()); } // For first time, we create a new task. // The next time, we use incremental build so do not create task again. diff --git a/packages/ice/templates/core/clientEntry.tsx.ejs b/packages/ice/templates/core/clientEntry.tsx.ejs index 762701b86d..ea55d772ed 100644 --- a/packages/ice/templates/core/clientEntry.tsx.ejs +++ b/packages/ice/templates/core/clientEntry.tsx.ejs @@ -1,6 +1,6 @@ <% if (importCoreJs) { -%>import 'core-js';<% } %> import { createElement, Fragment } from 'react'; -import { getAppConfig } from '<%- iceRuntimePath %>'; +import { runRSCApp, getAppConfig } from '<%- iceRuntimePath %>'; import { commons, statics } from './runtimeModules'; import * as app from '@/app'; <%- runtimeOptions.imports %> @@ -12,33 +12,6 @@ const getRouterBasename = () => { // Add react fragment for split chunks of app. // Otherwise chunk of route component will pack @ice/jsx-runtime and depend on framework bundle. -import React, { Suspense, use } from 'react'; -import * as ReactDOM from 'react-dom/client'; -import { createFromFetch } from 'react-server-dom-webpack/client'; - -async function runRSCApp() { - function Message({ response }) { - const body = use(response); - return <div>{body}</div>; - } - - function App({ response }) { - return ( - <Suspense fallback={<h1>Loading...</h1>}> - <Message response={response} /> - </Suspense> - ); - } - - const response = createFromFetch( - fetch('/?body'), - ); - - const container = document.getElementById('app'); - const root = ReactDOM.createRoot(container); - root.render(<App response={response} />); -} - const render = (customOptions = {}) => { return runRSCApp(); }; diff --git a/packages/ice/templates/core/entry.server.ts.ejs b/packages/ice/templates/core/entry.server.ts.ejs index 9228a68d83..3777253023 100644 --- a/packages/ice/templates/core/entry.server.ts.ejs +++ b/packages/ice/templates/core/entry.server.ts.ejs @@ -9,7 +9,7 @@ import type { RenderMode, DistType } from '@ice/runtime'; import type { RenderToPipeableStreamOptions } from 'react-dom/server'; // @ts-ignore import assetsManifest from 'virtual:assets-manifest.json'; -import clientManifest from './react-client-manifest.json'; +import clientManifest from 'virtual:react-client-manifest.json'; import createRoutes from './routes'; import routesConfig from './routes-config.bundle.mjs'; <% if(dataLoaderImport.imports) {-%><%-dataLoaderImport.imports%><% } -%> diff --git a/packages/runtime/package.json b/packages/runtime/package.json index 7117864692..877771124f 100644 --- a/packages/runtime/package.json +++ b/packages/runtime/package.json @@ -39,9 +39,9 @@ "devDependencies": { "@types/react": "^18.0.8", "@types/react-dom": "^18.0.3", - "react": "18.3.0-next-3ba7add60-20221201", - "react-server-dom-webpack": "18.3.0-next-855b77c9b-20230202", - "react-dom": "18.3.0-next-855b77c9b-20230202", + "react": "18.3.0-canary-dd480ef92-20230822", + "react-server-dom-webpack": "18.3.0-canary-dd480ef92-20230822", + "react-dom": "18.3.0-canary-dd480ef92-20230822", "regenerator-runtime": "^0.13.9", "@remix-run/web-fetch": "^4.3.3" }, @@ -62,9 +62,9 @@ "source-map": "^0.7.4" }, "peerDependencies": { - "react": "18.3.0-next-3ba7add60-20221201", - "react-dom": "18.3.0-next-855b77c9b-20230202", - "react-server-dom-webpack": "18.3.0-next-855b77c9b-20230202" + "react": "18.3.0-canary-dd480ef92-20230822", + "react-dom": "18.3.0-canary-dd480ef92-20230822", + "react-server-dom-webpack": "18.3.0-canary-dd480ef92-20230822" }, "publishConfig": { "access": "public" diff --git a/packages/runtime/src/index.ts b/packages/runtime/src/index.ts index cf36649bb0..bbb87ca693 100644 --- a/packages/runtime/src/index.ts +++ b/packages/runtime/src/index.ts @@ -26,8 +26,7 @@ import type { RunClientAppOptions, CreateRoutes } from './runClientApp.js'; import { useAppContext as useInternalAppContext, useAppData, AppContextProvider } from './AppContext.js'; import { getAppData } from './appData.js'; import { useData, useConfig } from './RouteContext.js'; -// import runRSCApp from './runRSCApp.js'; -import { createClientModuleProxy } from './reactFlightWebpackReference.js'; +import runRSCApp from './runRSCApp.js'; import { Meta, Title, @@ -136,8 +135,7 @@ export { WrapRouteComponent, RouteErrorComponent, - // runRSCApp, - createClientModuleProxy, + runRSCApp, }; export type { diff --git a/packages/runtime/src/reactFlightWebpackReference.ts b/packages/runtime/src/reactFlightWebpackReference.ts deleted file mode 100644 index b1bf3be61e..0000000000 --- a/packages/runtime/src/reactFlightWebpackReference.ts +++ /dev/null @@ -1,248 +0,0 @@ -/* eslint-disable no-negated-condition */ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -// Modified from https://github.com/facebook/react/blob/main/packages/react-server-dom-webpack/src/ReactFlightWebpackNodeRegister.js - -let CLIENT_REFERENCE = Symbol.for('react.client.reference'); -let PROMISE_PROTOTYPE = Promise.prototype; -let deepProxyHandlers = { - get: function (target, name, receiver) { - switch (name) { - // These names are read by the Flight runtime if you end up using the exports object. - case '$$typeof': - // These names are a little too common. We should probably have a way to - // have the Flight runtime extract the inner target instead. - return target.$$typeof; - - case 'filepath': - return target.filepath; - - case 'name': - return target.name; - - case 'async': - return target.async; - // We need to special case this because createElement reads it if we pass this - // reference. - - case 'defaultProps': - return undefined; - // Avoid this attempting to be serialized. - - case 'toJSON': - return undefined; - - case Symbol.toPrimitive: - // $FlowFixMe[prop-missing] - return Object.prototype[Symbol.toPrimitive]; - - case 'Provider': - throw new Error('Cannot render a Client Context Provider on the Server. ' + 'Instead, you can export a Client Component wrapper ' + 'that itself renders a Client Context Provider.'); - } - - let expression; - - switch (target.name) { - case '': - expression = String(name); - break; - - case '*': - expression = String(name); - break; - - default: - expression = `${String(target.name)}.${String(name)}`; - } - - throw new Error(`Cannot access ${expression} on the server. ` + 'You cannot dot into a client module from a server component. ' + 'You can only pass the imported name through.'); - }, - set: function () { - throw new Error('Cannot assign to a client module from a server module.'); - }, -}; -const proxyHandlers = { - get: function (target, name, receiver) { - switch (name) { - // These names are read by the Flight runtime if you end up using the exports object. - case '$$typeof': - // These names are a little too common. We should probably have a way to - // have the Flight runtime extract the inner target instead. - return target.$$typeof; - - case 'filepath': - return target.filepath; - - case 'name': - return target.name; - - case 'async': - return target.async; - // We need to special case this because createElement reads it if we pass this - // reference. - - case 'defaultProps': - return undefined; - // Avoid this attempting to be serialized. - - case 'toJSON': - return undefined; - - case Symbol.toPrimitive: - // $FlowFixMe[prop-missing] - return Object.prototype[Symbol.toPrimitive]; - - case '__esModule': - // Something is conditionally checking which export to use. We'll pretend to be - // an ESM compat module but then we'll check again on the client. - const moduleId = target.filepath; - target.default = Object.defineProperties(() => { - throw new Error(`Attempted to call the default export of ${moduleId} from the server` + 'but it\'s on the client. It\'s not possible to invoke a client function from ' + 'the server, it can only be rendered as a Component or passed to props of a' + 'Client Component.'); - }, { - // This a placeholder value that tells the client to conditionally use the - // whole object or just the default export. - name: { - value: '', - }, - $$typeof: { - value: CLIENT_REFERENCE, - }, - filepath: { - value: target.filepath, - }, - async: { - value: target.async, - }, - }); - return true; - - case 'then': - if (target.then) { - // Use a cached value - return target.then; - } - - if (!target.async) { - // If this module is expected to return a Promise (such as an AsyncModule) then - // we should resolve that with a client reference that unwraps the Promise on - // the client. - let clientReference = Object.defineProperties({}, { - // Represents the whole Module object instead of a particular import. - name: { - value: '*', - }, - $$typeof: { - value: CLIENT_REFERENCE, - }, - filepath: { - value: target.filepath, - }, - async: { - value: true, - }, - }); - const proxy = new Proxy(clientReference, proxyHandlers); // Treat this as a resolved Promise for React's use() - - target.status = 'fulfilled'; - target.value = proxy; // $FlowFixMe[missing-local-annot] - - const then = target.then = Object.defineProperties((resolve, reject) => { - // Expose to React. - return Promise.resolve( // $FlowFixMe[incompatible-call] found when upgrading Flow - resolve(proxy)); - }, // If this is not used as a Promise but is treated as a reference to a `.then` - // export then we should treat it as a reference to that name. - { - name: { - value: 'then', - }, - $$typeof: { - value: CLIENT_REFERENCE, - }, - filepath: { - value: target.filepath, - }, - async: { - value: false, - }, - }); - return then; - } else { - // Since typeof .then === 'function' is a feature test we'd continue recursing - // indefinitely if we return a function. Instead, we return an object reference - // if we check further. - return undefined; - } - } - - let cachedReference = target[name]; - - if (!cachedReference) { - let reference = Object.defineProperties(() => { - throw new Error( - `Attempted to call ${String(name)}() from the server but ${String(name)} is on the client. ` + 'It\'s not possible to invoke a client function from the server, it can ' + 'only be rendered as a Component or passed to props of a Client Component.'); - }, { - name: { - value: name, - }, - $$typeof: { - value: CLIENT_REFERENCE, - }, - filepath: { - value: target.filepath, - }, - async: { - value: target.async, - }, - }); - cachedReference = target[name] = new Proxy(reference, deepProxyHandlers); - } - - return cachedReference; - }, - getPrototypeOf: function (target) { - // Pretend to be a Promise in case anyone asks. - return PROMISE_PROTOTYPE; - }, - set: function () { - throw new Error('Cannot assign to a client module from a server module.'); - }, -}; // $FlowFixMe[prop-missing] found when upgrading Flow - - -export function createClientModuleProxy(moduleId: string) { - // const clientReference = Object.defineProperties( - // {}, - // { - // $$typeof: { value: CLIENT_REFERENCE }, - // // Represents the whole Module object instead of a particular import. - // $$id: { value: moduleId }, - // $$async: { value: false }, - // }, - // ); - // var moduleId = url.pathToFileURL(path).href; - let clientReference = Object.defineProperties({}, { - // Represents the whole Module object instead of a particular import. - name: { - value: '', - }, - $$typeof: { - value: CLIENT_REFERENCE, - }, - filepath: { - value: moduleId, - }, - async: { - value: false, - }, - }); // $FlowFixMe[incompatible-call] found when upgrading Flow - - const pxy = new Proxy(clientReference, proxyHandlers); - console.log('proxy', pxy); - return pxy; // new Proxy(clientReference, proxyHandlers) -} \ No newline at end of file diff --git a/packages/runtime/src/runRSCApp.tsx b/packages/runtime/src/runRSCApp.tsx new file mode 100644 index 0000000000..b12e956fa7 --- /dev/null +++ b/packages/runtime/src/runRSCApp.tsx @@ -0,0 +1,28 @@ +// @ts-ignore +import React, { Suspense, use } from 'react'; +import * as ReactDOM from 'react-dom/client'; +import pkg from 'react-server-dom-webpack/client'; +const { createFromFetch } = pkg; + +export default async function runRSCApp() { + function Message({ response }) { + const body = use(response); + return <div>{body}</div>; + } + + function App({ response }) { + return ( + <Suspense fallback={<h1>Loading...</h1>}> + <Message response={response} /> + </Suspense> + ); + } + + const response = createFromFetch( + fetch('/?body'), + ); + + const container = document.getElementById('app'); + const root = ReactDOM.createRoot(container); + root.render(<App response={response} />); +} \ No newline at end of file diff --git a/packages/runtime/src/runServerApp.tsx b/packages/runtime/src/runServerApp.tsx index cbd7d619fe..3c3d8cd9a1 100644 --- a/packages/runtime/src/runServerApp.tsx +++ b/packages/runtime/src/runServerApp.tsx @@ -412,13 +412,11 @@ async function renderServerEntry( // </AppContextProvider> // ); - const moduleMap = { - clientManifest: renderOptions.clientManifest, - }; + // console.log(moduleMap); const { pipe } = renderToPipeableStream( element, - moduleMap, + renderOptions.clientManifest, ); // const pipe = renderToNodeStream(element); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index db5e530b55..c5beb157f0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -776,15 +776,15 @@ importers: '@ice/runtime': workspace:* '@types/react': ^18.0.17 '@types/react-dom': ^18.0.6 - react: 18.3.0-next-3ba7add60-20221201 - react-dom: 18.3.0-next-855b77c9b-20230202 - react-server-dom-webpack: 18.3.0-next-855b77c9b-20230202 + react: 18.3.0-canary-dd480ef92-20230822 + react-dom: 18.3.0-canary-dd480ef92-20230822 + react-server-dom-webpack: 18.3.0-canary-dd480ef92-20230822 dependencies: '@ice/app': link:../../packages/ice '@ice/runtime': link:../../packages/runtime - react: 18.3.0-next-3ba7add60-20221201 - react-dom: 18.3.0-next-855b77c9b-20230202_osgg5tsgainv67oqv2d3ptcxsm - react-server-dom-webpack: 18.3.0-next-855b77c9b-20230202_rinjvadhybif4dwgmiuj7eb2ee + react: 18.3.0-canary-dd480ef92-20230822 + react-dom: 18.3.0-canary-dd480ef92-20230822_hhgf3bgmselb7o32scmuz3hjam + react-server-dom-webpack: 18.3.0-canary-dd480ef92-20230822_i5uyhljmd6xc2xkotszrmzynhy devDependencies: '@types/react': 18.0.34 '@types/react-dom': 18.0.11 @@ -1155,7 +1155,7 @@ importers: path-to-regexp: ^6.2.0 react: 18.3.0-next-3ba7add60-20221201 react-router: 6.14.2 - react-server-dom-webpack: 18.3.0-next-855b77c9b-20230202 + react-server-dom-webpack: 18.3.0-canary-dd480ef92-20230822 regenerator-runtime: ^0.13.0 resolve.exports: ^1.1.0 sass: ^1.50.0 @@ -1170,7 +1170,7 @@ importers: '@ice/bundles': link:../bundles '@ice/route-manifest': link:../route-manifest '@ice/rspack-config': link:../rspack-config - '@ice/runtime': link:../runtime + '@ice/runtime': 1.2.8_osgg5tsgainv67oqv2d3ptcxsm '@ice/shared-config': link:../shared-config '@ice/webpack-config': link:../webpack-config '@swc/helpers': 0.5.1 @@ -1215,7 +1215,7 @@ importers: jest: 29.5.0 react: 18.3.0-next-3ba7add60-20221201 react-router: 6.14.2_osgg5tsgainv67oqv2d3ptcxsm - react-server-dom-webpack: 18.3.0-next-855b77c9b-20230202_eaktsl3pcltpekt37vdcusnisq + react-server-dom-webpack: 18.3.0-canary-dd480ef92-20230822_eaktsl3pcltpekt37vdcusnisq sass: 1.50.0 unplugin: 0.9.5_4yjf5voakpkrj4qbnm3gtqjbli webpack: 5.88.2_esbuild@0.17.16 @@ -1275,7 +1275,7 @@ importers: react: ^18.1.0 react-dom: ^18.1.0 dependencies: - '@ice/runtime': link:../runtime + '@ice/runtime': 1.2.8_biqbaboplfbrettd7655fr4n2y '@ice/shared': link:../shared miniapp-history: 0.1.7 devDependencies: @@ -1302,7 +1302,7 @@ importers: regenerator-runtime: ^0.13.9 devDependencies: '@ice/app': link:../ice - '@ice/runtime': link:../runtime + '@ice/runtime': 1.2.8 '@types/react': 18.0.28 '@types/react-dom': 18.0.11 regenerator-runtime: 0.13.11 @@ -1317,7 +1317,7 @@ importers: '@ice/cache-canvas': link:../cache-canvas devDependencies: '@ice/app': link:../ice - '@ice/runtime': link:../runtime + '@ice/runtime': 1.2.8 webpack: 5.88.2 packages/plugin-css-assets-local: @@ -1382,7 +1382,7 @@ importers: '@ice/stark-app': 1.5.0 devDependencies: '@ice/app': link:../ice - '@ice/runtime': link:../runtime + '@ice/runtime': 1.2.8 '@types/react': 18.0.28 '@types/react-dom': 18.0.11 @@ -1445,7 +1445,7 @@ importers: sax: 1.2.4 devDependencies: '@ice/app': link:../ice - '@ice/runtime': link:../runtime + '@ice/runtime': 1.2.8 webpack: 5.88.2 packages/plugin-moment-locales: @@ -1526,7 +1526,7 @@ importers: axios: 0.27.2 devDependencies: '@ice/app': link:../ice - '@ice/runtime': link:../runtime + '@ice/runtime': 1.2.8 '@types/react': 18.0.28 '@types/react-dom': 18.0.11 regenerator-runtime: 0.13.11 @@ -1612,10 +1612,10 @@ importers: fs-extra: ^10.0.0 history: ^5.3.0 htmlparser2: ^8.0.1 - react: 18.3.0-next-3ba7add60-20221201 - react-dom: 18.3.0-next-855b77c9b-20230202 + react: 18.3.0-canary-dd480ef92-20230822 + react-dom: 18.3.0-canary-dd480ef92-20230822 react-router-dom: 6.14.2 - react-server-dom-webpack: 18.3.0-next-855b77c9b-20230202 + react-server-dom-webpack: 18.3.0-canary-dd480ef92-20230822 regenerator-runtime: ^0.13.9 semver: ^7.4.0 source-map: ^0.7.4 @@ -1627,16 +1627,16 @@ importers: fs-extra: 10.1.0 history: 5.3.0 htmlparser2: 8.0.1 - react-router-dom: 6.14.2_rinjvadhybif4dwgmiuj7eb2ee + react-router-dom: 6.14.2_i5uyhljmd6xc2xkotszrmzynhy semver: 7.4.0 source-map: 0.7.4 devDependencies: '@remix-run/web-fetch': 4.3.3 '@types/react': 18.0.28 '@types/react-dom': 18.0.11 - react: 18.3.0-next-3ba7add60-20221201 - react-dom: 18.3.0-next-855b77c9b-20230202_osgg5tsgainv67oqv2d3ptcxsm - react-server-dom-webpack: 18.3.0-next-855b77c9b-20230202_rinjvadhybif4dwgmiuj7eb2ee + react: 18.3.0-canary-dd480ef92-20230822 + react-dom: 18.3.0-canary-dd480ef92-20230822_hhgf3bgmselb7o32scmuz3hjam + react-server-dom-webpack: 18.3.0-canary-dd480ef92-20230822_i5uyhljmd6xc2xkotszrmzynhy regenerator-runtime: 0.13.11 packages/shared: @@ -1701,7 +1701,7 @@ importers: dependencies: consola: 2.15.3 devDependencies: - '@ice/webpack-config': link:../webpack-config + '@ice/webpack-config': 1.1.1_webpack@5.88.2 webpack: 5.88.2 website: @@ -5463,13 +5463,54 @@ packages: resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==} dev: true + /@ice/bundles/0.1.15_webpack@5.88.2: + resolution: {integrity: sha512-T8d/bY/1GeFl7zif6eaxITwyEiAzb7f5rN+vpjh6Bu5QdiQbPPuixWwySyl9qO6Dl36ERXrNh6ylJpLt3i6EZA==} + dependencies: + '@ice/css-modules-hash': 0.0.6 + '@ice/swc-plugin-keep-export': 0.2.0 + '@ice/swc-plugin-node-transform': 0.2.0 + '@ice/swc-plugin-remove-export': 0.2.0 + '@rspack/core': 0.3.0_webpack@5.88.2 + '@rspack/dev-server': 0.3.0_bioma5hrmjqlc63rjodddzwoma + '@swc/core': 1.3.80 + ansi-html-community: 0.0.8 + caniuse-lite: 1.0.30001462 + chokidar: 3.5.3 + core-js: 3.32.0 + core-js-pure: 3.29.0 + error-stack-parser: 2.1.4 + esbuild: 0.17.16 + events: 3.3.0 + html-entities: 2.3.3 + jest-worker: 27.5.1 + less: 4.1.2 + postcss: 8.4.12 + react-refresh: 0.14.0 + sass: 1.50.0 + transitivePeerDependencies: + - '@swc/helpers' + - '@types/express' + - '@types/webpack' + - bufferutil + - debug + - sockjs-client + - supports-color + - type-fest + - uglify-js + - utf-8-validate + - webpack + - webpack-cli + - webpack-dev-server + - webpack-hot-middleware + - webpack-plugin-serve + dev: true + /@ice/css-modules-hash-darwin-arm64/0.0.6: resolution: {integrity: sha512-5QWZl3+biY5U/kRhymH+6X/kAk3Imvkqu9QpV+LTDxhoXEkdhzZd2sCO5ZNfrsODFuHy78iKzh6gEweADPwYkQ==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] requiresBuild: true - dev: false optional: true /@ice/css-modules-hash-darwin-universal/0.0.6: @@ -5477,7 +5518,6 @@ packages: engines: {node: '>= 10'} os: [darwin] requiresBuild: true - dev: false optional: true /@ice/css-modules-hash-darwin-x64/0.0.6: @@ -5486,7 +5526,6 @@ packages: cpu: [x64] os: [darwin] requiresBuild: true - dev: false optional: true /@ice/css-modules-hash-linux-x64-gnu/0.0.6: @@ -5495,7 +5534,6 @@ packages: cpu: [x64] os: [linux] requiresBuild: true - dev: false optional: true /@ice/css-modules-hash-linux-x64-musl/0.0.6: @@ -5504,7 +5542,6 @@ packages: cpu: [x64] os: [linux] requiresBuild: true - dev: false optional: true /@ice/css-modules-hash-win32-arm64-msvc/0.0.6: @@ -5513,7 +5550,6 @@ packages: cpu: [arm64] os: [win32] requiresBuild: true - dev: false optional: true /@ice/css-modules-hash-win32-x64-msvc/0.0.6: @@ -5522,7 +5558,6 @@ packages: cpu: [x64] os: [win32] requiresBuild: true - dev: false optional: true /@ice/css-modules-hash/0.0.6: @@ -5536,6 +5571,31 @@ packages: '@ice/css-modules-hash-linux-x64-musl': 0.0.6 '@ice/css-modules-hash-win32-arm64-msvc': 0.0.6 '@ice/css-modules-hash-win32-x64-msvc': 0.0.6 + + /@ice/jsx-runtime/0.2.1: + resolution: {integrity: sha512-X+IMfhmrfAFSA1Kh0fCr3+xJKRR048uljfB8zBIzoQyEf8MEkifUHtoS8UXQPp8fjyPCyt1hKXzAvz+LTLgO5g==} + peerDependencies: + react: ^16 || ^17 || ^18 + dependencies: + style-unit: 3.0.5 + dev: true + + /@ice/jsx-runtime/0.2.1_osgg5tsgainv67oqv2d3ptcxsm: + resolution: {integrity: sha512-X+IMfhmrfAFSA1Kh0fCr3+xJKRR048uljfB8zBIzoQyEf8MEkifUHtoS8UXQPp8fjyPCyt1hKXzAvz+LTLgO5g==} + peerDependencies: + react: ^16 || ^17 || ^18 + dependencies: + react: 18.3.0-next-3ba7add60-20221201 + style-unit: 3.0.5 + dev: false + + /@ice/jsx-runtime/0.2.1_react@18.2.0: + resolution: {integrity: sha512-X+IMfhmrfAFSA1Kh0fCr3+xJKRR048uljfB8zBIzoQyEf8MEkifUHtoS8UXQPp8fjyPCyt1hKXzAvz+LTLgO5g==} + peerDependencies: + react: ^16 || ^17 || ^18 + dependencies: + react: 18.2.0 + style-unit: 3.0.5 dev: false /@ice/pkg/1.5.5: @@ -5580,10 +5640,103 @@ packages: - supports-color dev: true + /@ice/runtime/1.2.8: + resolution: {integrity: sha512-9gscJwsLKij4YowQ1RdVQK3YTKu6v4e2uC3b8kOnB19/dQESHuwCntpoleVf2TvGP8d3SikkUB2OVkizXT4Ijg==} + requiresBuild: true + peerDependencies: + react: ^18.1.0 + react-dom: ^18.1.0 + dependencies: + '@ice/jsx-runtime': 0.2.1 + '@ice/shared': 1.0.1 + '@remix-run/router': 1.7.2 + abortcontroller-polyfill: 1.7.5 + ejs: 3.1.8 + fs-extra: 10.1.0 + history: 5.3.0 + htmlparser2: 8.0.1 + react-router-dom: 6.14.2 + semver: 7.4.0 + source-map: 0.7.4 + dev: true + + /@ice/runtime/1.2.8_biqbaboplfbrettd7655fr4n2y: + resolution: {integrity: sha512-9gscJwsLKij4YowQ1RdVQK3YTKu6v4e2uC3b8kOnB19/dQESHuwCntpoleVf2TvGP8d3SikkUB2OVkizXT4Ijg==} + requiresBuild: true + peerDependencies: + react: ^18.1.0 + react-dom: ^18.1.0 + dependencies: + '@ice/jsx-runtime': 0.2.1_react@18.2.0 + '@ice/shared': 1.0.1 + '@remix-run/router': 1.7.2 + abortcontroller-polyfill: 1.7.5 + ejs: 3.1.8 + fs-extra: 10.1.0 + history: 5.3.0 + htmlparser2: 8.0.1 + react: 18.2.0 + react-dom: 18.2.0_react@18.2.0 + react-router-dom: 6.14.2_biqbaboplfbrettd7655fr4n2y + semver: 7.4.0 + source-map: 0.7.4 + dev: false + + /@ice/runtime/1.2.8_osgg5tsgainv67oqv2d3ptcxsm: + resolution: {integrity: sha512-9gscJwsLKij4YowQ1RdVQK3YTKu6v4e2uC3b8kOnB19/dQESHuwCntpoleVf2TvGP8d3SikkUB2OVkizXT4Ijg==} + requiresBuild: true + peerDependencies: + react: ^18.1.0 + react-dom: ^18.1.0 + dependencies: + '@ice/jsx-runtime': 0.2.1_osgg5tsgainv67oqv2d3ptcxsm + '@ice/shared': 1.0.1 + '@remix-run/router': 1.7.2 + abortcontroller-polyfill: 1.7.5 + ejs: 3.1.8 + fs-extra: 10.1.0 + history: 5.3.0 + htmlparser2: 8.0.1 + react: 18.3.0-next-3ba7add60-20221201 + react-router-dom: 6.14.2_osgg5tsgainv67oqv2d3ptcxsm + semver: 7.4.0 + source-map: 0.7.4 + dev: false + /@ice/sandbox/1.1.4: resolution: {integrity: sha512-MEVF0Ze3McKDutnFiUAhUoc+WwOFxITVBgSSHmbGpKtWbXJX9kUVlx3VsEVJvdqU3O1kiBNx6zE1sFMjKPRTIQ==} dev: false + /@ice/shared-config/1.0.2_webpack@5.88.2: + resolution: {integrity: sha512-ZGoCr8HXrn5TGX7xU+7nNKIkEz4NXt1l7VIcQoBaElOXn4BL5btiiKdAjZQ5f1zEb5Q25g7/SP/Z52/SzgSvUw==} + dependencies: + '@ice/bundles': 0.1.15_webpack@5.88.2 + '@rollup/pluginutils': 4.2.1 + browserslist: 4.21.5 + consola: 2.15.3 + fast-glob: 3.3.0 + process: 0.11.10 + transitivePeerDependencies: + - '@swc/helpers' + - '@types/express' + - '@types/webpack' + - bufferutil + - debug + - sockjs-client + - supports-color + - type-fest + - uglify-js + - utf-8-validate + - webpack + - webpack-cli + - webpack-dev-server + - webpack-hot-middleware + - webpack-plugin-serve + dev: true + + /@ice/shared/1.0.1: + resolution: {integrity: sha512-nZJpHIx6dpjuAYhaVMzYsLiIPSGMXcHvf2e7qbqDCYJSQ/fAYYy3m2VIVw8dQ25QswvWi/c5Vg7SR6MJEVHzpA==} + /@ice/stark-app/1.5.0: resolution: {integrity: sha512-9fuCri48eZj6TnfPkCju4vVLhGurz+mt6lFx4JQFHhnRBQ5MuiBqRZg5F/3vdnJ7dAYQJlCXmHlQtBHok82z+g==} dev: false @@ -5618,15 +5771,37 @@ packages: /@ice/swc-plugin-keep-export/0.2.0: resolution: {integrity: sha512-N3tg4BOV78jZSR/9CypJf5YzHxrNi40dNlUAwFjf7nr9pzMvVlo9bZM0I/A9l6J9vMff/5mgtkW5+JiMYdyjig==} - dev: false /@ice/swc-plugin-node-transform/0.2.0: resolution: {integrity: sha512-06NtOUGVAUKP1eQXGMkaIZpNl9d5RK6SB6xQJsMY/DIso8WnwymyN7hmoFXPzX0eFkhmQEc7jzJ7NDBXaXRqWQ==} - dev: false /@ice/swc-plugin-remove-export/0.2.0: resolution: {integrity: sha512-kmyrCMtuEsS7J3rpENT5qUhhbuu3eldsN1WpJjtXX4rgogJ1+QmnAPjnhB0SWzr0/b5ArGfz83O6M+5NNGRd+A==} - dev: false + + /@ice/webpack-config/1.1.1_webpack@5.88.2: + resolution: {integrity: sha512-B6THHyrjLLVwgC5fquNdczV0KdPu9kXKmuIUv5HCGglqGWY/CaypSA/Ns0uaDFaRyQQR3ZwzPocmG14239VmpQ==} + dependencies: + '@ice/bundles': 0.1.15_webpack@5.88.2 + '@ice/shared-config': 1.0.2_webpack@5.88.2 + fast-glob: 3.3.0 + process: 0.11.10 + transitivePeerDependencies: + - '@swc/helpers' + - '@types/express' + - '@types/webpack' + - bufferutil + - debug + - sockjs-client + - supports-color + - type-fest + - uglify-js + - utf-8-validate + - webpack + - webpack-cli + - webpack-dev-server + - webpack-hot-middleware + - webpack-plugin-serve + dev: true /@iceworks/generate-project/2.0.2: resolution: {integrity: sha512-t7/uHl5kM71o+xyR+FnaPsgyFqhFQm89TdqPahM4Kv/ubdKDknFVUYLio1khMDGY8Ops0ahn/+KM+gFnHEKSQw==} @@ -6393,7 +6568,6 @@ packages: source-map: 0.7.4 webpack: 5.76.0_yt3h3qjhcnsf3663codtuni62a webpack-dev-server: 4.13.1_webpack@5.76.0 - dev: false /@pmmmwh/react-refresh-webpack-plugin/0.5.10_p44l2xjftguod6ctnkuod3jp7e: resolution: {integrity: sha512-j0Ya0hCFZPd4x40qLzbhGsh9TMtdb+CJQiso+WxLOPNasohq9cc5SNUcwsZaRH6++Xh91Xkm/xHCkuIiIu0LUA==} @@ -6512,6 +6686,45 @@ packages: webpack-dev-server: 4.11.1_webpack@5.88.2 dev: true + /@pmmmwh/react-refresh-webpack-plugin/0.5.10_wrxi7ct7dz7g7lwv6srrq7wgqy: + resolution: {integrity: sha512-j0Ya0hCFZPd4x40qLzbhGsh9TMtdb+CJQiso+WxLOPNasohq9cc5SNUcwsZaRH6++Xh91Xkm/xHCkuIiIu0LUA==} + engines: {node: '>= 10.13'} + peerDependencies: + '@types/webpack': 4.x || 5.x + react-refresh: '>=0.10.0 <1.0.0' + sockjs-client: ^1.4.0 + type-fest: '>=0.17.0 <4.0.0' + webpack: '>=4.43.0 <6.0.0' + webpack-dev-server: 3.x || 4.x + webpack-hot-middleware: 2.x + webpack-plugin-serve: 0.x || 1.x + peerDependenciesMeta: + '@types/webpack': + optional: true + sockjs-client: + optional: true + type-fest: + optional: true + webpack-dev-server: + optional: true + webpack-hot-middleware: + optional: true + webpack-plugin-serve: + optional: true + dependencies: + ansi-html-community: 0.0.8 + common-path-prefix: 3.0.0 + core-js-pure: 3.29.0 + error-stack-parser: 2.1.4 + find-up: 5.0.0 + html-entities: 2.3.3 + loader-utils: 2.0.4 + react-refresh: 0.14.0 + schema-utils: 3.1.1 + source-map: 0.7.4 + webpack: 5.88.2 + dev: true + /@pmmmwh/react-refresh-webpack-plugin/0.5.10_ynqbgb5bmgbvx2am6mt2h3lxsq: resolution: {integrity: sha512-j0Ya0hCFZPd4x40qLzbhGsh9TMtdb+CJQiso+WxLOPNasohq9cc5SNUcwsZaRH6++Xh91Xkm/xHCkuIiIu0LUA==} engines: {node: '>= 10.13'} @@ -6965,6 +7178,35 @@ packages: - webpack-plugin-serve dev: true + /@rspack/core/0.3.0_webpack@5.88.2: + resolution: {integrity: sha512-YltE0AQimUMOSTIFuDP+BW2GoJsabrig/GmgCR1eDWlVeKlmGJ6wd2GdYjmW5TWdH6FBQPQ3YfU8GOB4XWsvgQ==} + dependencies: + '@rspack/binding': 0.3.0 + '@rspack/dev-client': 0.3.0_wrxi7ct7dz7g7lwv6srrq7wgqy + '@swc/helpers': 0.5.1 + browserslist: 4.21.5 + compare-versions: 6.0.0-rc.1 + enhanced-resolve: 5.12.0 + graceful-fs: 4.2.10 + neo-async: 2.6.2 + react-refresh: 0.14.0 + schema-utils: 4.0.0 + tapable: 2.2.1 + util: 0.12.5 + watchpack: 2.4.0 + webpack-sources: 3.2.3 + zod: 3.21.4 + zod-validation-error: 1.2.0_zod@3.21.4 + transitivePeerDependencies: + - '@types/webpack' + - sockjs-client + - type-fest + - webpack + - webpack-dev-server + - webpack-hot-middleware + - webpack-plugin-serve + dev: true + /@rspack/core/0.3.0_zur76qpjdwubwowmoyfe2ntqhe: resolution: {integrity: sha512-YltE0AQimUMOSTIFuDP+BW2GoJsabrig/GmgCR1eDWlVeKlmGJ6wd2GdYjmW5TWdH6FBQPQ3YfU8GOB4XWsvgQ==} dependencies: @@ -7012,7 +7254,6 @@ packages: - webpack-dev-server - webpack-hot-middleware - webpack-plugin-serve - dev: false /@rspack/dev-client/0.3.0_p44l2xjftguod6ctnkuod3jp7e: resolution: {integrity: sha512-nttTUBVctbh9auvPq91ThmjNDcBLj3kfLDjM/O1jBYA3xTz9MNsTN3rInLOb4S2fWEsSBLz7CVsNLP7LWtUecA==} @@ -7073,6 +7314,26 @@ packages: - webpack-plugin-serve dev: true + /@rspack/dev-client/0.3.0_wrxi7ct7dz7g7lwv6srrq7wgqy: + resolution: {integrity: sha512-nttTUBVctbh9auvPq91ThmjNDcBLj3kfLDjM/O1jBYA3xTz9MNsTN3rInLOb4S2fWEsSBLz7CVsNLP7LWtUecA==} + peerDependencies: + react-refresh: '>=0.10.0 <1.0.0' + peerDependenciesMeta: + react-refresh: + optional: true + dependencies: + '@pmmmwh/react-refresh-webpack-plugin': 0.5.10_wrxi7ct7dz7g7lwv6srrq7wgqy + react-refresh: 0.14.0 + transitivePeerDependencies: + - '@types/webpack' + - sockjs-client + - type-fest + - webpack + - webpack-dev-server + - webpack-hot-middleware + - webpack-plugin-serve + dev: true + /@rspack/dev-client/0.3.0_ynqbgb5bmgbvx2am6mt2h3lxsq: resolution: {integrity: sha512-nttTUBVctbh9auvPq91ThmjNDcBLj3kfLDjM/O1jBYA3xTz9MNsTN3rInLOb4S2fWEsSBLz7CVsNLP7LWtUecA==} peerDependencies: @@ -7125,7 +7386,6 @@ packages: - webpack-cli - webpack-hot-middleware - webpack-plugin-serve - dev: false /@rspack/dev-server/0.3.0_saarlyqjwgcwik7cbeuxgtrvdm: resolution: {integrity: sha512-aKY1mUP1PdOWXDvxpUA14mEE7p+IFYnU67i7cAUh361z2/v5KbCTngt521ly8H1LqJv3SJIoEXqSqNc8c62Dsg==} @@ -7478,7 +7738,6 @@ packages: cpu: [arm64] os: [darwin] requiresBuild: true - dev: false optional: true /@swc/core-darwin-x64/1.3.32: @@ -7496,7 +7755,6 @@ packages: cpu: [x64] os: [darwin] requiresBuild: true - dev: false optional: true /@swc/core-linux-arm-gnueabihf/1.3.32: @@ -7514,7 +7772,6 @@ packages: cpu: [arm] os: [linux] requiresBuild: true - dev: false optional: true /@swc/core-linux-arm64-gnu/1.3.32: @@ -7532,7 +7789,6 @@ packages: cpu: [arm64] os: [linux] requiresBuild: true - dev: false optional: true /@swc/core-linux-arm64-musl/1.3.32: @@ -7550,7 +7806,6 @@ packages: cpu: [arm64] os: [linux] requiresBuild: true - dev: false optional: true /@swc/core-linux-x64-gnu/1.3.32: @@ -7568,7 +7823,6 @@ packages: cpu: [x64] os: [linux] requiresBuild: true - dev: false optional: true /@swc/core-linux-x64-musl/1.3.32: @@ -7586,7 +7840,6 @@ packages: cpu: [x64] os: [linux] requiresBuild: true - dev: false optional: true /@swc/core-win32-arm64-msvc/1.3.32: @@ -7604,7 +7857,6 @@ packages: cpu: [arm64] os: [win32] requiresBuild: true - dev: false optional: true /@swc/core-win32-ia32-msvc/1.3.32: @@ -7622,7 +7874,6 @@ packages: cpu: [ia32] os: [win32] requiresBuild: true - dev: false optional: true /@swc/core-win32-x64-msvc/1.3.32: @@ -7640,7 +7891,6 @@ packages: cpu: [x64] os: [win32] requiresBuild: true - dev: false optional: true /@swc/core/1.3.32: @@ -7682,7 +7932,6 @@ packages: '@swc/core-win32-arm64-msvc': 1.3.80 '@swc/core-win32-ia32-msvc': 1.3.80 '@swc/core-win32-x64-msvc': 1.3.80 - dev: false /@swc/helpers/0.4.14: resolution: {integrity: sha512-4C7nX/dvpzB7za4Ql9K81xK3HPxCpHMgwTZVyf+9JQ6VUbn9jjZVN7/Nkdz/Ugzs2CSjqnL/UPXroiVBVHUWUw==} @@ -7697,7 +7946,6 @@ packages: /@swc/types/0.1.4: resolution: {integrity: sha512-z/G02d+59gyyUb7KYhKi9jOhicek6QD2oMaotUyG+lUkybpXoV49dY9bj7Ah5Q+y7knK2jU67UTX9FyfGzaxQg==} - dev: false /@szmarczak/http-timer/1.1.2: resolution: {integrity: sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==} @@ -8423,7 +8671,6 @@ packages: /@uni/env/1.1.0: resolution: {integrity: sha512-2GVgUzxIaO2vGElXEuc45+I7L6Jbw8inLDDFuC0K4htjKtPmYywKSE6oDhvmdAXb4GCOH8hmxECYtAh1rjsgoQ==} - dev: false /@use-gesture/core/10.2.20: resolution: {integrity: sha512-4lFhHc8so4yIHkBEs641DnEsBxPyhJ5GEjB4PURFDH4p/FcZriH6w99knZgI63zN/MBFfylMyb8+PDuj6RIXKQ==} @@ -8697,7 +8944,6 @@ packages: /abortcontroller-polyfill/1.7.5: resolution: {integrity: sha512-JMJ5soJWP18htbbxJjG7bG6yuI6pRhgJ0scHHTfkUjf6wjP912xZWvM+A4sJK3gqd9E8fcPbDnOefbA9Th/FIQ==} - dev: false /accept-language-parser/1.5.0: resolution: {integrity: sha512-QhyTbMLYo0BBGg1aWbeMG4ekWtds/31BrEU+DONOg/7ax23vxpL03Pb7/zBmha2v7vdD3AyzZVWBVGEZxKOXWw==} @@ -8732,6 +8978,12 @@ packages: acorn: 8.8.2 dev: true + /acorn-loose/8.3.0: + resolution: {integrity: sha512-75lAs9H19ldmW+fAbyqHdjgdCrz0pWGXKmnqFoh8PyVd1L2RIb4RzYrSjmopeqv3E1G3/Pimu6GgLlrGbrkF7w==} + engines: {node: '>=0.4.0'} + dependencies: + acorn: 8.8.2 + /acorn-node/1.8.2: resolution: {integrity: sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==} dependencies: @@ -8749,11 +9001,6 @@ packages: resolution: {integrity: sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==} engines: {node: '>=0.4.0'} - /acorn/6.4.2: - resolution: {integrity: sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==} - engines: {node: '>=0.4.0'} - hasBin: true - /acorn/7.4.1: resolution: {integrity: sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==} engines: {node: '>=0.4.0'} @@ -9265,7 +9512,6 @@ packages: /async/3.2.4: resolution: {integrity: sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==} - dev: false /asynckit/0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} @@ -10469,7 +10715,6 @@ packages: resolution: {integrity: sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==} dependencies: is-what: 3.14.1 - dev: false /copy-text-to-clipboard/3.0.1: resolution: {integrity: sha512-rvVsHrpFcL4F2P8ihsoLdFHmd404+CMg71S756oRSeQgqk51U3kicGdnvfkrxva0xXH92SjGS62B0XIJsbh+9Q==} @@ -11596,7 +11841,6 @@ packages: hasBin: true dependencies: jake: 10.8.5 - dev: false /electron-to-chromium/1.4.322: resolution: {integrity: sha512-KovjizNC9XB7dno/2GjxX8VS0SlfPpCjtyoKft+bCO+UfD8bFy16hY4Sh9s0h9BDxbRH2U0zX5VBjpM1LTcNlg==} @@ -11675,7 +11919,6 @@ packages: requiresBuild: true dependencies: prr: 1.0.1 - dev: false optional: true /error-ex/1.3.2: @@ -12972,7 +13215,6 @@ packages: resolution: {integrity: sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==} dependencies: minimatch: 5.1.6 - dev: false /filesize/8.0.7: resolution: {integrity: sha512-pjmC+bkIF8XI7fWaH8KxHcZL3DPybs1roSKP4rKDvy20tAWwIObE4+JIseG2byfGKhud5ZnM4YSGKBz7Sh0ndQ==} @@ -14049,7 +14291,6 @@ packages: engines: {node: '>=0.10.0'} hasBin: true requiresBuild: true - dev: false optional: true /image-size/1.0.2: @@ -14563,7 +14804,6 @@ packages: /is-what/3.14.1: resolution: {integrity: sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==} - dev: false /is-whitespace-character/1.0.4: resolution: {integrity: sha512-SDweEzfIZM0SJV0EUga669UTKlmL0Pq8Lno0QDQsPnvECB3IM2aP0gdx5TrU0A01MAPfViaZiI2V1QMZLaKK5w==} @@ -14661,7 +14901,6 @@ packages: chalk: 4.1.2 filelist: 1.0.4 minimatch: 3.1.2 - dev: false /jest-changed-files/28.1.3: resolution: {integrity: sha512-esaOfUWJXk2nfZt9SPyC8gA1kNfdKLkQWyzsMlqq8msYSlNKfmZxfRgZn4Cd4MGVUF+7v6dBs0d5TOAKa7iIiA==} @@ -15845,7 +16084,6 @@ packages: source-map: 0.6.1 transitivePeerDependencies: - supports-color - dev: false /leven/3.1.0: resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} @@ -16149,7 +16387,6 @@ packages: dependencies: pify: 4.0.1 semver: 5.7.1 - dev: false optional: true /make-dir/3.1.0: @@ -16545,7 +16782,6 @@ packages: sax: 1.2.4 transitivePeerDependencies: - supports-color - dev: false optional: true /negotiator/0.6.3: @@ -16998,7 +17234,6 @@ packages: /parse-node-version/1.0.1: resolution: {integrity: sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==} engines: {node: '>= 0.10'} - dev: false /parse-numeric-range/1.3.0: resolution: {integrity: sha512-twN+njEipszzlMJd4ONUYgSfZPDxgHhT9Ahed5uTigpQn90FggW4SA/AIPq/6a149fTbE9qBEcSwE3FAEp6wQQ==} @@ -18640,7 +18875,6 @@ packages: nanoid: 3.3.4 picocolors: 1.0.0 source-map-js: 1.0.2 - dev: false /postcss/8.4.21: resolution: {integrity: sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==} @@ -18744,7 +18978,6 @@ packages: /process/0.11.10: resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} engines: {node: '>= 0.6.0'} - dev: false /progress/2.0.3: resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==} @@ -18798,7 +19031,6 @@ packages: /prr/1.0.1: resolution: {integrity: sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==} - dev: false optional: true /pseudomap/1.0.2: @@ -19993,14 +20225,14 @@ packages: react: 18.2.0 scheduler: 0.23.0 - /react-dom/18.3.0-next-855b77c9b-20230202_osgg5tsgainv67oqv2d3ptcxsm: - resolution: {integrity: sha512-5IiFiBrNR6HzFoeMI07ELTmtmd6gui8HsReLXrKwZlpuzMXlLAOWlCEaYSF+kCZNmRAoognUh+LUQJ31TaR4WA==} + /react-dom/18.3.0-canary-dd480ef92-20230822_hhgf3bgmselb7o32scmuz3hjam: + resolution: {integrity: sha512-xAUst7w1A+Cupsv8x9pT/hZ8VmkA4UwZixUVMiay2keN9oRY8f0xvQTcwXgFgOH6wqgsoT2KPpmm6Yf8QMik5g==} peerDependencies: - react: 18.3.0-next-855b77c9b-20230202 + react: 18.3.0-canary-dd480ef92-20230822 dependencies: loose-envify: 1.4.0 - react: 18.3.0-next-3ba7add60-20221201 - scheduler: 0.24.0-next-855b77c9b-20230202 + react: 18.3.0-canary-dd480ef92-20230822 + scheduler: 0.24.0-canary-dd480ef92-20230822 /react-error-overlay/6.0.11: resolution: {integrity: sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg==} @@ -20152,7 +20384,44 @@ packages: tiny-invariant: 1.3.1 tiny-warning: 1.0.3 - /react-router-dom/6.14.2_rinjvadhybif4dwgmiuj7eb2ee: + /react-router-dom/6.14.2: + resolution: {integrity: sha512-5pWX0jdKR48XFZBuJqHosX3AAHjRAzygouMTyimnBPOLdY3WjzUSKhus2FVMihUFWzeLebDgr4r8UeQFAct7Bg==} + engines: {node: '>=14'} + peerDependencies: + react: '>=16.8' + react-dom: '>=16.8' + dependencies: + '@remix-run/router': 1.7.2 + react-router: 6.14.2 + dev: true + + /react-router-dom/6.14.2_biqbaboplfbrettd7655fr4n2y: + resolution: {integrity: sha512-5pWX0jdKR48XFZBuJqHosX3AAHjRAzygouMTyimnBPOLdY3WjzUSKhus2FVMihUFWzeLebDgr4r8UeQFAct7Bg==} + engines: {node: '>=14'} + peerDependencies: + react: '>=16.8' + react-dom: '>=16.8' + dependencies: + '@remix-run/router': 1.7.2 + react: 18.2.0 + react-dom: 18.2.0_react@18.2.0 + react-router: 6.14.2_react@18.2.0 + dev: false + + /react-router-dom/6.14.2_i5uyhljmd6xc2xkotszrmzynhy: + resolution: {integrity: sha512-5pWX0jdKR48XFZBuJqHosX3AAHjRAzygouMTyimnBPOLdY3WjzUSKhus2FVMihUFWzeLebDgr4r8UeQFAct7Bg==} + engines: {node: '>=14'} + peerDependencies: + react: '>=16.8' + react-dom: '>=16.8' + dependencies: + '@remix-run/router': 1.7.2 + react: 18.3.0-canary-dd480ef92-20230822 + react-dom: 18.3.0-canary-dd480ef92-20230822_hhgf3bgmselb7o32scmuz3hjam + react-router: 6.14.2_hhgf3bgmselb7o32scmuz3hjam + dev: false + + /react-router-dom/6.14.2_osgg5tsgainv67oqv2d3ptcxsm: resolution: {integrity: sha512-5pWX0jdKR48XFZBuJqHosX3AAHjRAzygouMTyimnBPOLdY3WjzUSKhus2FVMihUFWzeLebDgr4r8UeQFAct7Bg==} engines: {node: '>=14'} peerDependencies: @@ -20161,7 +20430,6 @@ packages: dependencies: '@remix-run/router': 1.7.2 react: 18.3.0-next-3ba7add60-20221201 - react-dom: 18.3.0-next-855b77c9b-20230202_osgg5tsgainv67oqv2d3ptcxsm react-router: 6.14.2_osgg5tsgainv67oqv2d3ptcxsm dev: false @@ -20181,6 +20449,25 @@ packages: tiny-invariant: 1.3.1 tiny-warning: 1.0.3 + /react-router/6.14.2: + resolution: {integrity: sha512-09Zss2dE2z+T1D03IheqAFtK4UzQyX8nFPWx6jkwdYzGLXd5ie06A6ezS2fO6zJfEb/SpG6UocN2O1hfD+2urQ==} + engines: {node: '>=14'} + peerDependencies: + react: '>=16.8' + dependencies: + '@remix-run/router': 1.7.2 + dev: true + + /react-router/6.14.2_hhgf3bgmselb7o32scmuz3hjam: + resolution: {integrity: sha512-09Zss2dE2z+T1D03IheqAFtK4UzQyX8nFPWx6jkwdYzGLXd5ie06A6ezS2fO6zJfEb/SpG6UocN2O1hfD+2urQ==} + engines: {node: '>=14'} + peerDependencies: + react: '>=16.8' + dependencies: + '@remix-run/router': 1.7.2 + react: 18.3.0-canary-dd480ef92-20230822 + dev: false + /react-router/6.14.2_osgg5tsgainv67oqv2d3ptcxsm: resolution: {integrity: sha512-09Zss2dE2z+T1D03IheqAFtK4UzQyX8nFPWx6jkwdYzGLXd5ie06A6ezS2fO6zJfEb/SpG6UocN2O1hfD+2urQ==} engines: {node: '>=14'} @@ -20190,34 +20477,44 @@ packages: '@remix-run/router': 1.7.2 react: 18.3.0-next-3ba7add60-20221201 - /react-server-dom-webpack/18.3.0-next-855b77c9b-20230202_eaktsl3pcltpekt37vdcusnisq: - resolution: {integrity: sha512-bjqFXHpl/ZFaP7gPebLjGkGy4dGaxRF88rjCinYULOPyxLIVTXmiZyQE6wdA6+zeqRZbFllIF2CJAnDSDAIUww==} + /react-router/6.14.2_react@18.2.0: + resolution: {integrity: sha512-09Zss2dE2z+T1D03IheqAFtK4UzQyX8nFPWx6jkwdYzGLXd5ie06A6ezS2fO6zJfEb/SpG6UocN2O1hfD+2urQ==} + engines: {node: '>=14'} + peerDependencies: + react: '>=16.8' + dependencies: + '@remix-run/router': 1.7.2 + react: 18.2.0 + dev: false + + /react-server-dom-webpack/18.3.0-canary-dd480ef92-20230822_eaktsl3pcltpekt37vdcusnisq: + resolution: {integrity: sha512-vBIBAkrOMrqZZGKgjSY9ly82YgZrmQgK4OOMBfMD5ZpAl58eifQFF18ZtVYNX9sLdPPi4MrizYfGjMaS9fP2VQ==} engines: {node: '>=0.10.0'} peerDependencies: - react: 18.3.0-next-855b77c9b-20230202 - react-dom: 18.3.0-next-855b77c9b-20230202 + react: 18.3.0-canary-dd480ef92-20230822 + react-dom: 18.3.0-canary-dd480ef92-20230822 webpack: ^5.59.0 dependencies: - acorn: 6.4.2 + acorn-loose: 8.3.0 loose-envify: 1.4.0 neo-async: 2.6.2 react: 18.3.0-next-3ba7add60-20221201 webpack: 5.88.2_esbuild@0.17.16 dev: true - /react-server-dom-webpack/18.3.0-next-855b77c9b-20230202_rinjvadhybif4dwgmiuj7eb2ee: - resolution: {integrity: sha512-bjqFXHpl/ZFaP7gPebLjGkGy4dGaxRF88rjCinYULOPyxLIVTXmiZyQE6wdA6+zeqRZbFllIF2CJAnDSDAIUww==} + /react-server-dom-webpack/18.3.0-canary-dd480ef92-20230822_i5uyhljmd6xc2xkotszrmzynhy: + resolution: {integrity: sha512-vBIBAkrOMrqZZGKgjSY9ly82YgZrmQgK4OOMBfMD5ZpAl58eifQFF18ZtVYNX9sLdPPi4MrizYfGjMaS9fP2VQ==} engines: {node: '>=0.10.0'} peerDependencies: - react: 18.3.0-next-855b77c9b-20230202 - react-dom: 18.3.0-next-855b77c9b-20230202 + react: 18.3.0-canary-dd480ef92-20230822 + react-dom: 18.3.0-canary-dd480ef92-20230822 webpack: ^5.59.0 dependencies: - acorn: 6.4.2 + acorn-loose: 8.3.0 loose-envify: 1.4.0 neo-async: 2.6.2 - react: 18.3.0-next-3ba7add60-20221201 - react-dom: 18.3.0-next-855b77c9b-20230202_osgg5tsgainv67oqv2d3ptcxsm + react: 18.3.0-canary-dd480ef92-20230822 + react-dom: 18.3.0-canary-dd480ef92-20230822_hhgf3bgmselb7o32scmuz3hjam /react-textarea-autosize/8.4.0_h7fc2el62uaa77gho3xhys6ola: resolution: {integrity: sha512-YrTFaEHLgJsi8sJVYHBzYn+mkP3prGkmP2DKb/tm0t7CLJY5t1Rxix8070LAKb0wby7bl/lf2EeHkuMihMZMwQ==} @@ -20261,11 +20558,18 @@ packages: dependencies: loose-envify: 1.4.0 + /react/18.3.0-canary-dd480ef92-20230822: + resolution: {integrity: sha512-12tBLcvl+cSvREyeKgGfv7k9R22nxNIjIaExcPTYtPCEoefaagzuW8v3jFFSgZNw/XGg57bivIQVkj8ImVvnvg==} + engines: {node: '>=0.10.0'} + dependencies: + loose-envify: 1.4.0 + /react/18.3.0-next-3ba7add60-20221201: resolution: {integrity: sha512-/hwADSpnz/GeDEljbg7Z2mF2MaYw7V1CsdbGvvhCUse4RvaRueHjcH7B/jbik8wRll3rxBPlomt15rSjIMjEJQ==} engines: {node: '>=0.10.0'} dependencies: loose-envify: 1.4.0 + dev: true /read-cache/1.0.0: resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==} @@ -20897,8 +21201,8 @@ packages: dependencies: loose-envify: 1.4.0 - /scheduler/0.24.0-next-855b77c9b-20230202: - resolution: {integrity: sha512-uZWTxDVYVxc1XmqDM1TtxUKI2WMMXzyjw03iLgMDtoEuUMZq8rwBB8Ue+kX8axrVDwC3lN1dzd5P3G+5rZCnKw==} + /scheduler/0.24.0-canary-dd480ef92-20230822: + resolution: {integrity: sha512-6hp1jChwe5RNdfVyA8rXw28CdPh7/hVGALqjwNwpaVrTM0SdPHy0Hes6Rqon1c9qKfUrQFhds+C+0fNMgy9hRw==} dependencies: loose-envify: 1.4.0 @@ -21640,7 +21944,6 @@ packages: dependencies: '@babel/runtime': 7.21.0 universal-env: 3.3.3 - dev: false /stylehacks/5.1.1_postcss@8.4.12: resolution: {integrity: sha512-sBpcd5Hx7G6seo7b1LkpttvTz7ikD0LlH5RmdcBNb6fFR0Fl7LQwHDFr300q4cwUqi+IYrFGmsIHieMBfnN/Bw==} @@ -21964,7 +22267,6 @@ packages: serialize-javascript: 6.0.1 terser: 5.14.2 webpack: 5.76.0_yt3h3qjhcnsf3663codtuni62a - dev: false /terser-webpack-plugin/5.3.5_muqrkd6dqvsxxmw22vfpzybwpe: resolution: {integrity: sha512-AOEDLDxD2zylUGf/wxHxklEkOe2/r+seuyOWujejFrIxHf11brA1/dWQNIgXa1c6/Wkxgu7zvv0JhOWfc2ELEA==} @@ -22708,7 +23010,6 @@ packages: engines: {npm: '>=3.0.0'} dependencies: '@uni/env': 1.1.0 - dev: false /universalify/0.1.2: resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} @@ -23765,7 +24066,6 @@ packages: - '@swc/core' - esbuild - uglify-js - dev: false /webpack/5.86.0_esbuild@0.17.16: resolution: {integrity: sha512-3BOvworZ8SO/D4GVP+GoRC3fVeg5MO4vzmq8TJJEkdmopxyazGDxN8ClqN12uzrZW9Tv8EED8v5VSb6Sqyi0pg==} From ae2d17e42905ef7cec9697fb8240a66ad9631641 Mon Sep 17 00:00:00 2001 From: "shuilan.cj" <shuilan.cj@taobao.com> Date: Mon, 4 Sep 2023 16:48:26 +0800 Subject: [PATCH 03/17] fix: conflict --- packages/runtime/src/runServerApp.tsx | 3 +- pnpm-lock.yaml | 391 ++++---------------------- 2 files changed, 56 insertions(+), 338 deletions(-) diff --git a/packages/runtime/src/runServerApp.tsx b/packages/runtime/src/runServerApp.tsx index 4a69e1fcde..fc5f7c4244 100644 --- a/packages/runtime/src/runServerApp.tsx +++ b/packages/runtime/src/runServerApp.tsx @@ -3,7 +3,6 @@ import * as React from 'react'; import type { RenderToPipeableStreamOptions } from 'react-dom/server'; import * as ReactDOMServer from 'react-dom/server'; import type { Location } from 'history'; -import type { RenderToPipeableStreamOptions } from 'react-dom/server'; import { renderToPipeableStream } from 'react-server-dom-webpack/server.node'; import { parsePath } from 'history'; import { isFunction } from '@ice/shared'; @@ -291,7 +290,7 @@ async function doRender(serverContext: ServerContext, renderOptions: RenderOptio } if (req.url.indexOf('?') === -1) { - return renderDocument({ matches: [], routes, renderOptions }); + return renderDocument({ matches: [], routes, renderOptions, documentData }); } // HashRouter loads route modules by the CSR. diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1d62bd9d07..4d4d180b71 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1170,7 +1170,7 @@ importers: '@ice/bundles': link:../bundles '@ice/route-manifest': link:../route-manifest '@ice/rspack-config': link:../rspack-config - '@ice/runtime': 1.2.8_osgg5tsgainv67oqv2d3ptcxsm + '@ice/runtime': link:../runtime '@ice/shared-config': link:../shared-config '@ice/webpack-config': link:../webpack-config '@swc/helpers': 0.5.1 @@ -1275,7 +1275,7 @@ importers: react: ^18.1.0 react-dom: ^18.1.0 dependencies: - '@ice/runtime': 1.2.8_biqbaboplfbrettd7655fr4n2y + '@ice/runtime': link:../runtime '@ice/shared': link:../shared miniapp-history: 0.1.7 devDependencies: @@ -1302,7 +1302,7 @@ importers: regenerator-runtime: ^0.13.9 devDependencies: '@ice/app': link:../ice - '@ice/runtime': 1.2.8 + '@ice/runtime': link:../runtime '@types/react': 18.0.28 '@types/react-dom': 18.0.11 regenerator-runtime: 0.13.11 @@ -1317,7 +1317,7 @@ importers: '@ice/cache-canvas': link:../cache-canvas devDependencies: '@ice/app': link:../ice - '@ice/runtime': 1.2.8 + '@ice/runtime': link:../runtime webpack: 5.88.2 packages/plugin-css-assets-local: @@ -1382,7 +1382,7 @@ importers: '@ice/stark-app': 1.5.0 devDependencies: '@ice/app': link:../ice - '@ice/runtime': 1.2.8 + '@ice/runtime': link:../runtime '@types/react': 18.0.28 '@types/react-dom': 18.0.11 @@ -1445,7 +1445,7 @@ importers: sax: 1.2.4 devDependencies: '@ice/app': link:../ice - '@ice/runtime': 1.2.8 + '@ice/runtime': link:../runtime webpack: 5.88.2 packages/plugin-moment-locales: @@ -1526,7 +1526,7 @@ importers: axios: 0.27.2 devDependencies: '@ice/app': link:../ice - '@ice/runtime': 1.2.8 + '@ice/runtime': link:../runtime '@types/react': 18.0.28 '@types/react-dom': 18.0.11 regenerator-runtime: 0.13.11 @@ -1703,7 +1703,7 @@ importers: dependencies: consola: 2.15.3 devDependencies: - '@ice/webpack-config': 1.1.1_webpack@5.88.2 + '@ice/webpack-config': link:../webpack-config webpack: 5.88.2 website: @@ -5465,54 +5465,13 @@ packages: resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==} dev: true - /@ice/bundles/0.1.15_webpack@5.88.2: - resolution: {integrity: sha512-T8d/bY/1GeFl7zif6eaxITwyEiAzb7f5rN+vpjh6Bu5QdiQbPPuixWwySyl9qO6Dl36ERXrNh6ylJpLt3i6EZA==} - dependencies: - '@ice/css-modules-hash': 0.0.6 - '@ice/swc-plugin-keep-export': 0.2.0 - '@ice/swc-plugin-node-transform': 0.2.0 - '@ice/swc-plugin-remove-export': 0.2.0 - '@rspack/core': 0.3.0_webpack@5.88.2 - '@rspack/dev-server': 0.3.0_bioma5hrmjqlc63rjodddzwoma - '@swc/core': 1.3.80 - ansi-html-community: 0.0.8 - caniuse-lite: 1.0.30001462 - chokidar: 3.5.3 - core-js: 3.32.0 - core-js-pure: 3.29.0 - error-stack-parser: 2.1.4 - esbuild: 0.17.16 - events: 3.3.0 - html-entities: 2.3.3 - jest-worker: 27.5.1 - less: 4.1.2 - postcss: 8.4.12 - react-refresh: 0.14.0 - sass: 1.50.0 - transitivePeerDependencies: - - '@swc/helpers' - - '@types/express' - - '@types/webpack' - - bufferutil - - debug - - sockjs-client - - supports-color - - type-fest - - uglify-js - - utf-8-validate - - webpack - - webpack-cli - - webpack-dev-server - - webpack-hot-middleware - - webpack-plugin-serve - dev: true - /@ice/css-modules-hash-darwin-arm64/0.0.6: resolution: {integrity: sha512-5QWZl3+biY5U/kRhymH+6X/kAk3Imvkqu9QpV+LTDxhoXEkdhzZd2sCO5ZNfrsODFuHy78iKzh6gEweADPwYkQ==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] requiresBuild: true + dev: false optional: true /@ice/css-modules-hash-darwin-universal/0.0.6: @@ -5520,6 +5479,7 @@ packages: engines: {node: '>= 10'} os: [darwin] requiresBuild: true + dev: false optional: true /@ice/css-modules-hash-darwin-x64/0.0.6: @@ -5528,6 +5488,7 @@ packages: cpu: [x64] os: [darwin] requiresBuild: true + dev: false optional: true /@ice/css-modules-hash-linux-x64-gnu/0.0.6: @@ -5536,6 +5497,7 @@ packages: cpu: [x64] os: [linux] requiresBuild: true + dev: false optional: true /@ice/css-modules-hash-linux-x64-musl/0.0.6: @@ -5544,6 +5506,7 @@ packages: cpu: [x64] os: [linux] requiresBuild: true + dev: false optional: true /@ice/css-modules-hash-win32-arm64-msvc/0.0.6: @@ -5552,6 +5515,7 @@ packages: cpu: [arm64] os: [win32] requiresBuild: true + dev: false optional: true /@ice/css-modules-hash-win32-x64-msvc/0.0.6: @@ -5560,6 +5524,7 @@ packages: cpu: [x64] os: [win32] requiresBuild: true + dev: false optional: true /@ice/css-modules-hash/0.0.6: @@ -5573,31 +5538,6 @@ packages: '@ice/css-modules-hash-linux-x64-musl': 0.0.6 '@ice/css-modules-hash-win32-arm64-msvc': 0.0.6 '@ice/css-modules-hash-win32-x64-msvc': 0.0.6 - - /@ice/jsx-runtime/0.2.1: - resolution: {integrity: sha512-X+IMfhmrfAFSA1Kh0fCr3+xJKRR048uljfB8zBIzoQyEf8MEkifUHtoS8UXQPp8fjyPCyt1hKXzAvz+LTLgO5g==} - peerDependencies: - react: ^16 || ^17 || ^18 - dependencies: - style-unit: 3.0.5 - dev: true - - /@ice/jsx-runtime/0.2.1_osgg5tsgainv67oqv2d3ptcxsm: - resolution: {integrity: sha512-X+IMfhmrfAFSA1Kh0fCr3+xJKRR048uljfB8zBIzoQyEf8MEkifUHtoS8UXQPp8fjyPCyt1hKXzAvz+LTLgO5g==} - peerDependencies: - react: ^16 || ^17 || ^18 - dependencies: - react: 18.3.0-next-3ba7add60-20221201 - style-unit: 3.0.5 - dev: false - - /@ice/jsx-runtime/0.2.1_react@18.2.0: - resolution: {integrity: sha512-X+IMfhmrfAFSA1Kh0fCr3+xJKRR048uljfB8zBIzoQyEf8MEkifUHtoS8UXQPp8fjyPCyt1hKXzAvz+LTLgO5g==} - peerDependencies: - react: ^16 || ^17 || ^18 - dependencies: - react: 18.2.0 - style-unit: 3.0.5 dev: false /@ice/pkg/1.5.5: @@ -5642,103 +5582,10 @@ packages: - supports-color dev: true - /@ice/runtime/1.2.8: - resolution: {integrity: sha512-9gscJwsLKij4YowQ1RdVQK3YTKu6v4e2uC3b8kOnB19/dQESHuwCntpoleVf2TvGP8d3SikkUB2OVkizXT4Ijg==} - requiresBuild: true - peerDependencies: - react: ^18.1.0 - react-dom: ^18.1.0 - dependencies: - '@ice/jsx-runtime': 0.2.1 - '@ice/shared': 1.0.1 - '@remix-run/router': 1.7.2 - abortcontroller-polyfill: 1.7.5 - ejs: 3.1.8 - fs-extra: 10.1.0 - history: 5.3.0 - htmlparser2: 8.0.1 - react-router-dom: 6.14.2 - semver: 7.4.0 - source-map: 0.7.4 - dev: true - - /@ice/runtime/1.2.8_biqbaboplfbrettd7655fr4n2y: - resolution: {integrity: sha512-9gscJwsLKij4YowQ1RdVQK3YTKu6v4e2uC3b8kOnB19/dQESHuwCntpoleVf2TvGP8d3SikkUB2OVkizXT4Ijg==} - requiresBuild: true - peerDependencies: - react: ^18.1.0 - react-dom: ^18.1.0 - dependencies: - '@ice/jsx-runtime': 0.2.1_react@18.2.0 - '@ice/shared': 1.0.1 - '@remix-run/router': 1.7.2 - abortcontroller-polyfill: 1.7.5 - ejs: 3.1.8 - fs-extra: 10.1.0 - history: 5.3.0 - htmlparser2: 8.0.1 - react: 18.2.0 - react-dom: 18.2.0_react@18.2.0 - react-router-dom: 6.14.2_biqbaboplfbrettd7655fr4n2y - semver: 7.4.0 - source-map: 0.7.4 - dev: false - - /@ice/runtime/1.2.8_osgg5tsgainv67oqv2d3ptcxsm: - resolution: {integrity: sha512-9gscJwsLKij4YowQ1RdVQK3YTKu6v4e2uC3b8kOnB19/dQESHuwCntpoleVf2TvGP8d3SikkUB2OVkizXT4Ijg==} - requiresBuild: true - peerDependencies: - react: ^18.1.0 - react-dom: ^18.1.0 - dependencies: - '@ice/jsx-runtime': 0.2.1_osgg5tsgainv67oqv2d3ptcxsm - '@ice/shared': 1.0.1 - '@remix-run/router': 1.7.2 - abortcontroller-polyfill: 1.7.5 - ejs: 3.1.8 - fs-extra: 10.1.0 - history: 5.3.0 - htmlparser2: 8.0.1 - react: 18.3.0-next-3ba7add60-20221201 - react-router-dom: 6.14.2_osgg5tsgainv67oqv2d3ptcxsm - semver: 7.4.0 - source-map: 0.7.4 - dev: false - /@ice/sandbox/1.1.4: resolution: {integrity: sha512-MEVF0Ze3McKDutnFiUAhUoc+WwOFxITVBgSSHmbGpKtWbXJX9kUVlx3VsEVJvdqU3O1kiBNx6zE1sFMjKPRTIQ==} dev: false - /@ice/shared-config/1.0.2_webpack@5.88.2: - resolution: {integrity: sha512-ZGoCr8HXrn5TGX7xU+7nNKIkEz4NXt1l7VIcQoBaElOXn4BL5btiiKdAjZQ5f1zEb5Q25g7/SP/Z52/SzgSvUw==} - dependencies: - '@ice/bundles': 0.1.15_webpack@5.88.2 - '@rollup/pluginutils': 4.2.1 - browserslist: 4.21.5 - consola: 2.15.3 - fast-glob: 3.3.0 - process: 0.11.10 - transitivePeerDependencies: - - '@swc/helpers' - - '@types/express' - - '@types/webpack' - - bufferutil - - debug - - sockjs-client - - supports-color - - type-fest - - uglify-js - - utf-8-validate - - webpack - - webpack-cli - - webpack-dev-server - - webpack-hot-middleware - - webpack-plugin-serve - dev: true - - /@ice/shared/1.0.1: - resolution: {integrity: sha512-nZJpHIx6dpjuAYhaVMzYsLiIPSGMXcHvf2e7qbqDCYJSQ/fAYYy3m2VIVw8dQ25QswvWi/c5Vg7SR6MJEVHzpA==} - /@ice/stark-app/1.5.0: resolution: {integrity: sha512-9fuCri48eZj6TnfPkCju4vVLhGurz+mt6lFx4JQFHhnRBQ5MuiBqRZg5F/3vdnJ7dAYQJlCXmHlQtBHok82z+g==} dev: false @@ -5773,37 +5620,15 @@ packages: /@ice/swc-plugin-keep-export/0.2.0: resolution: {integrity: sha512-N3tg4BOV78jZSR/9CypJf5YzHxrNi40dNlUAwFjf7nr9pzMvVlo9bZM0I/A9l6J9vMff/5mgtkW5+JiMYdyjig==} + dev: false /@ice/swc-plugin-node-transform/0.2.0: resolution: {integrity: sha512-06NtOUGVAUKP1eQXGMkaIZpNl9d5RK6SB6xQJsMY/DIso8WnwymyN7hmoFXPzX0eFkhmQEc7jzJ7NDBXaXRqWQ==} + dev: false /@ice/swc-plugin-remove-export/0.2.0: resolution: {integrity: sha512-kmyrCMtuEsS7J3rpENT5qUhhbuu3eldsN1WpJjtXX4rgogJ1+QmnAPjnhB0SWzr0/b5ArGfz83O6M+5NNGRd+A==} - - /@ice/webpack-config/1.1.1_webpack@5.88.2: - resolution: {integrity: sha512-B6THHyrjLLVwgC5fquNdczV0KdPu9kXKmuIUv5HCGglqGWY/CaypSA/Ns0uaDFaRyQQR3ZwzPocmG14239VmpQ==} - dependencies: - '@ice/bundles': 0.1.15_webpack@5.88.2 - '@ice/shared-config': 1.0.2_webpack@5.88.2 - fast-glob: 3.3.0 - process: 0.11.10 - transitivePeerDependencies: - - '@swc/helpers' - - '@types/express' - - '@types/webpack' - - bufferutil - - debug - - sockjs-client - - supports-color - - type-fest - - uglify-js - - utf-8-validate - - webpack - - webpack-cli - - webpack-dev-server - - webpack-hot-middleware - - webpack-plugin-serve - dev: true + dev: false /@iceworks/generate-project/2.0.2: resolution: {integrity: sha512-t7/uHl5kM71o+xyR+FnaPsgyFqhFQm89TdqPahM4Kv/ubdKDknFVUYLio1khMDGY8Ops0ahn/+KM+gFnHEKSQw==} @@ -6570,6 +6395,7 @@ packages: source-map: 0.7.4 webpack: 5.76.0_yt3h3qjhcnsf3663codtuni62a webpack-dev-server: 4.13.1_webpack@5.76.0 + dev: false /@pmmmwh/react-refresh-webpack-plugin/0.5.10_p44l2xjftguod6ctnkuod3jp7e: resolution: {integrity: sha512-j0Ya0hCFZPd4x40qLzbhGsh9TMtdb+CJQiso+WxLOPNasohq9cc5SNUcwsZaRH6++Xh91Xkm/xHCkuIiIu0LUA==} @@ -6688,45 +6514,6 @@ packages: webpack-dev-server: 4.11.1_webpack@5.88.2 dev: true - /@pmmmwh/react-refresh-webpack-plugin/0.5.10_wrxi7ct7dz7g7lwv6srrq7wgqy: - resolution: {integrity: sha512-j0Ya0hCFZPd4x40qLzbhGsh9TMtdb+CJQiso+WxLOPNasohq9cc5SNUcwsZaRH6++Xh91Xkm/xHCkuIiIu0LUA==} - engines: {node: '>= 10.13'} - peerDependencies: - '@types/webpack': 4.x || 5.x - react-refresh: '>=0.10.0 <1.0.0' - sockjs-client: ^1.4.0 - type-fest: '>=0.17.0 <4.0.0' - webpack: '>=4.43.0 <6.0.0' - webpack-dev-server: 3.x || 4.x - webpack-hot-middleware: 2.x - webpack-plugin-serve: 0.x || 1.x - peerDependenciesMeta: - '@types/webpack': - optional: true - sockjs-client: - optional: true - type-fest: - optional: true - webpack-dev-server: - optional: true - webpack-hot-middleware: - optional: true - webpack-plugin-serve: - optional: true - dependencies: - ansi-html-community: 0.0.8 - common-path-prefix: 3.0.0 - core-js-pure: 3.29.0 - error-stack-parser: 2.1.4 - find-up: 5.0.0 - html-entities: 2.3.3 - loader-utils: 2.0.4 - react-refresh: 0.14.0 - schema-utils: 3.1.1 - source-map: 0.7.4 - webpack: 5.88.2 - dev: true - /@pmmmwh/react-refresh-webpack-plugin/0.5.10_ynqbgb5bmgbvx2am6mt2h3lxsq: resolution: {integrity: sha512-j0Ya0hCFZPd4x40qLzbhGsh9TMtdb+CJQiso+WxLOPNasohq9cc5SNUcwsZaRH6++Xh91Xkm/xHCkuIiIu0LUA==} engines: {node: '>= 10.13'} @@ -7180,35 +6967,6 @@ packages: - webpack-plugin-serve dev: true - /@rspack/core/0.3.0_webpack@5.88.2: - resolution: {integrity: sha512-YltE0AQimUMOSTIFuDP+BW2GoJsabrig/GmgCR1eDWlVeKlmGJ6wd2GdYjmW5TWdH6FBQPQ3YfU8GOB4XWsvgQ==} - dependencies: - '@rspack/binding': 0.3.0 - '@rspack/dev-client': 0.3.0_wrxi7ct7dz7g7lwv6srrq7wgqy - '@swc/helpers': 0.5.1 - browserslist: 4.21.5 - compare-versions: 6.0.0-rc.1 - enhanced-resolve: 5.12.0 - graceful-fs: 4.2.10 - neo-async: 2.6.2 - react-refresh: 0.14.0 - schema-utils: 4.0.0 - tapable: 2.2.1 - util: 0.12.5 - watchpack: 2.4.0 - webpack-sources: 3.2.3 - zod: 3.21.4 - zod-validation-error: 1.2.0_zod@3.21.4 - transitivePeerDependencies: - - '@types/webpack' - - sockjs-client - - type-fest - - webpack - - webpack-dev-server - - webpack-hot-middleware - - webpack-plugin-serve - dev: true - /@rspack/core/0.3.0_zur76qpjdwubwowmoyfe2ntqhe: resolution: {integrity: sha512-YltE0AQimUMOSTIFuDP+BW2GoJsabrig/GmgCR1eDWlVeKlmGJ6wd2GdYjmW5TWdH6FBQPQ3YfU8GOB4XWsvgQ==} dependencies: @@ -7256,6 +7014,7 @@ packages: - webpack-dev-server - webpack-hot-middleware - webpack-plugin-serve + dev: false /@rspack/dev-client/0.3.0_p44l2xjftguod6ctnkuod3jp7e: resolution: {integrity: sha512-nttTUBVctbh9auvPq91ThmjNDcBLj3kfLDjM/O1jBYA3xTz9MNsTN3rInLOb4S2fWEsSBLz7CVsNLP7LWtUecA==} @@ -7316,26 +7075,6 @@ packages: - webpack-plugin-serve dev: true - /@rspack/dev-client/0.3.0_wrxi7ct7dz7g7lwv6srrq7wgqy: - resolution: {integrity: sha512-nttTUBVctbh9auvPq91ThmjNDcBLj3kfLDjM/O1jBYA3xTz9MNsTN3rInLOb4S2fWEsSBLz7CVsNLP7LWtUecA==} - peerDependencies: - react-refresh: '>=0.10.0 <1.0.0' - peerDependenciesMeta: - react-refresh: - optional: true - dependencies: - '@pmmmwh/react-refresh-webpack-plugin': 0.5.10_wrxi7ct7dz7g7lwv6srrq7wgqy - react-refresh: 0.14.0 - transitivePeerDependencies: - - '@types/webpack' - - sockjs-client - - type-fest - - webpack - - webpack-dev-server - - webpack-hot-middleware - - webpack-plugin-serve - dev: true - /@rspack/dev-client/0.3.0_ynqbgb5bmgbvx2am6mt2h3lxsq: resolution: {integrity: sha512-nttTUBVctbh9auvPq91ThmjNDcBLj3kfLDjM/O1jBYA3xTz9MNsTN3rInLOb4S2fWEsSBLz7CVsNLP7LWtUecA==} peerDependencies: @@ -7388,6 +7127,7 @@ packages: - webpack-cli - webpack-hot-middleware - webpack-plugin-serve + dev: false /@rspack/dev-server/0.3.0_saarlyqjwgcwik7cbeuxgtrvdm: resolution: {integrity: sha512-aKY1mUP1PdOWXDvxpUA14mEE7p+IFYnU67i7cAUh361z2/v5KbCTngt521ly8H1LqJv3SJIoEXqSqNc8c62Dsg==} @@ -7740,6 +7480,7 @@ packages: cpu: [arm64] os: [darwin] requiresBuild: true + dev: false optional: true /@swc/core-darwin-x64/1.3.32: @@ -7757,6 +7498,7 @@ packages: cpu: [x64] os: [darwin] requiresBuild: true + dev: false optional: true /@swc/core-linux-arm-gnueabihf/1.3.32: @@ -7774,6 +7516,7 @@ packages: cpu: [arm] os: [linux] requiresBuild: true + dev: false optional: true /@swc/core-linux-arm64-gnu/1.3.32: @@ -7791,6 +7534,7 @@ packages: cpu: [arm64] os: [linux] requiresBuild: true + dev: false optional: true /@swc/core-linux-arm64-musl/1.3.32: @@ -7808,6 +7552,7 @@ packages: cpu: [arm64] os: [linux] requiresBuild: true + dev: false optional: true /@swc/core-linux-x64-gnu/1.3.32: @@ -7825,6 +7570,7 @@ packages: cpu: [x64] os: [linux] requiresBuild: true + dev: false optional: true /@swc/core-linux-x64-musl/1.3.32: @@ -7842,6 +7588,7 @@ packages: cpu: [x64] os: [linux] requiresBuild: true + dev: false optional: true /@swc/core-win32-arm64-msvc/1.3.32: @@ -7859,6 +7606,7 @@ packages: cpu: [arm64] os: [win32] requiresBuild: true + dev: false optional: true /@swc/core-win32-ia32-msvc/1.3.32: @@ -7876,6 +7624,7 @@ packages: cpu: [ia32] os: [win32] requiresBuild: true + dev: false optional: true /@swc/core-win32-x64-msvc/1.3.32: @@ -7893,6 +7642,7 @@ packages: cpu: [x64] os: [win32] requiresBuild: true + dev: false optional: true /@swc/core/1.3.32: @@ -7934,6 +7684,7 @@ packages: '@swc/core-win32-arm64-msvc': 1.3.80 '@swc/core-win32-ia32-msvc': 1.3.80 '@swc/core-win32-x64-msvc': 1.3.80 + dev: false /@swc/helpers/0.4.14: resolution: {integrity: sha512-4C7nX/dvpzB7za4Ql9K81xK3HPxCpHMgwTZVyf+9JQ6VUbn9jjZVN7/Nkdz/Ugzs2CSjqnL/UPXroiVBVHUWUw==} @@ -7948,6 +7699,7 @@ packages: /@swc/types/0.1.4: resolution: {integrity: sha512-z/G02d+59gyyUb7KYhKi9jOhicek6QD2oMaotUyG+lUkybpXoV49dY9bj7Ah5Q+y7knK2jU67UTX9FyfGzaxQg==} + dev: false /@szmarczak/http-timer/1.1.2: resolution: {integrity: sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==} @@ -8673,6 +8425,7 @@ packages: /@uni/env/1.1.0: resolution: {integrity: sha512-2GVgUzxIaO2vGElXEuc45+I7L6Jbw8inLDDFuC0K4htjKtPmYywKSE6oDhvmdAXb4GCOH8hmxECYtAh1rjsgoQ==} + dev: false /@use-gesture/core/10.2.20: resolution: {integrity: sha512-4lFhHc8so4yIHkBEs641DnEsBxPyhJ5GEjB4PURFDH4p/FcZriH6w99knZgI63zN/MBFfylMyb8+PDuj6RIXKQ==} @@ -8946,6 +8699,7 @@ packages: /abortcontroller-polyfill/1.7.5: resolution: {integrity: sha512-JMJ5soJWP18htbbxJjG7bG6yuI6pRhgJ0scHHTfkUjf6wjP912xZWvM+A4sJK3gqd9E8fcPbDnOefbA9Th/FIQ==} + dev: false /accept-language-parser/1.5.0: resolution: {integrity: sha512-QhyTbMLYo0BBGg1aWbeMG4ekWtds/31BrEU+DONOg/7ax23vxpL03Pb7/zBmha2v7vdD3AyzZVWBVGEZxKOXWw==} @@ -9514,6 +9268,7 @@ packages: /async/3.2.4: resolution: {integrity: sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==} + dev: false /asynckit/0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} @@ -10717,6 +10472,7 @@ packages: resolution: {integrity: sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==} dependencies: is-what: 3.14.1 + dev: false /copy-text-to-clipboard/3.0.1: resolution: {integrity: sha512-rvVsHrpFcL4F2P8ihsoLdFHmd404+CMg71S756oRSeQgqk51U3kicGdnvfkrxva0xXH92SjGS62B0XIJsbh+9Q==} @@ -11843,6 +11599,7 @@ packages: hasBin: true dependencies: jake: 10.8.5 + dev: false /electron-to-chromium/1.4.322: resolution: {integrity: sha512-KovjizNC9XB7dno/2GjxX8VS0SlfPpCjtyoKft+bCO+UfD8bFy16hY4Sh9s0h9BDxbRH2U0zX5VBjpM1LTcNlg==} @@ -11921,6 +11678,7 @@ packages: requiresBuild: true dependencies: prr: 1.0.1 + dev: false optional: true /error-ex/1.3.2: @@ -13217,6 +12975,7 @@ packages: resolution: {integrity: sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==} dependencies: minimatch: 5.1.6 + dev: false /filesize/8.0.7: resolution: {integrity: sha512-pjmC+bkIF8XI7fWaH8KxHcZL3DPybs1roSKP4rKDvy20tAWwIObE4+JIseG2byfGKhud5ZnM4YSGKBz7Sh0ndQ==} @@ -14293,6 +14052,7 @@ packages: engines: {node: '>=0.10.0'} hasBin: true requiresBuild: true + dev: false optional: true /image-size/1.0.2: @@ -14806,6 +14566,7 @@ packages: /is-what/3.14.1: resolution: {integrity: sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==} + dev: false /is-whitespace-character/1.0.4: resolution: {integrity: sha512-SDweEzfIZM0SJV0EUga669UTKlmL0Pq8Lno0QDQsPnvECB3IM2aP0gdx5TrU0A01MAPfViaZiI2V1QMZLaKK5w==} @@ -14903,6 +14664,7 @@ packages: chalk: 4.1.2 filelist: 1.0.4 minimatch: 3.1.2 + dev: false /jest-changed-files/28.1.3: resolution: {integrity: sha512-esaOfUWJXk2nfZt9SPyC8gA1kNfdKLkQWyzsMlqq8msYSlNKfmZxfRgZn4Cd4MGVUF+7v6dBs0d5TOAKa7iIiA==} @@ -16086,6 +15848,7 @@ packages: source-map: 0.6.1 transitivePeerDependencies: - supports-color + dev: false /leven/3.1.0: resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} @@ -16389,6 +16152,7 @@ packages: dependencies: pify: 4.0.1 semver: 5.7.1 + dev: false optional: true /make-dir/3.1.0: @@ -16784,6 +16548,7 @@ packages: sax: 1.2.4 transitivePeerDependencies: - supports-color + dev: false optional: true /negotiator/0.6.3: @@ -17236,6 +17001,7 @@ packages: /parse-node-version/1.0.1: resolution: {integrity: sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==} engines: {node: '>= 0.10'} + dev: false /parse-numeric-range/1.3.0: resolution: {integrity: sha512-twN+njEipszzlMJd4ONUYgSfZPDxgHhT9Ahed5uTigpQn90FggW4SA/AIPq/6a149fTbE9qBEcSwE3FAEp6wQQ==} @@ -18877,6 +18643,7 @@ packages: nanoid: 3.3.4 picocolors: 1.0.0 source-map-js: 1.0.2 + dev: false /postcss/8.4.21: resolution: {integrity: sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==} @@ -18980,6 +18747,7 @@ packages: /process/0.11.10: resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} engines: {node: '>= 0.6.0'} + dev: false /progress/2.0.3: resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==} @@ -19033,6 +18801,7 @@ packages: /prr/1.0.1: resolution: {integrity: sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==} + dev: false optional: true /pseudomap/1.0.2: @@ -20386,30 +20155,6 @@ packages: tiny-invariant: 1.3.1 tiny-warning: 1.0.3 - /react-router-dom/6.14.2: - resolution: {integrity: sha512-5pWX0jdKR48XFZBuJqHosX3AAHjRAzygouMTyimnBPOLdY3WjzUSKhus2FVMihUFWzeLebDgr4r8UeQFAct7Bg==} - engines: {node: '>=14'} - peerDependencies: - react: '>=16.8' - react-dom: '>=16.8' - dependencies: - '@remix-run/router': 1.7.2 - react-router: 6.14.2 - dev: true - - /react-router-dom/6.14.2_biqbaboplfbrettd7655fr4n2y: - resolution: {integrity: sha512-5pWX0jdKR48XFZBuJqHosX3AAHjRAzygouMTyimnBPOLdY3WjzUSKhus2FVMihUFWzeLebDgr4r8UeQFAct7Bg==} - engines: {node: '>=14'} - peerDependencies: - react: '>=16.8' - react-dom: '>=16.8' - dependencies: - '@remix-run/router': 1.7.2 - react: 18.2.0 - react-dom: 18.2.0_react@18.2.0 - react-router: 6.14.2_react@18.2.0 - dev: false - /react-router-dom/6.14.2_i5uyhljmd6xc2xkotszrmzynhy: resolution: {integrity: sha512-5pWX0jdKR48XFZBuJqHosX3AAHjRAzygouMTyimnBPOLdY3WjzUSKhus2FVMihUFWzeLebDgr4r8UeQFAct7Bg==} engines: {node: '>=14'} @@ -20423,18 +20168,6 @@ packages: react-router: 6.14.2_hhgf3bgmselb7o32scmuz3hjam dev: false - /react-router-dom/6.14.2_osgg5tsgainv67oqv2d3ptcxsm: - resolution: {integrity: sha512-5pWX0jdKR48XFZBuJqHosX3AAHjRAzygouMTyimnBPOLdY3WjzUSKhus2FVMihUFWzeLebDgr4r8UeQFAct7Bg==} - engines: {node: '>=14'} - peerDependencies: - react: '>=16.8' - react-dom: '>=16.8' - dependencies: - '@remix-run/router': 1.7.2 - react: 18.3.0-next-3ba7add60-20221201 - react-router: 6.14.2_osgg5tsgainv67oqv2d3ptcxsm - dev: false - /react-router/5.3.4_react@17.0.2: resolution: {integrity: sha512-Ys9K+ppnJah3QuaRiLxk+jDWOR1MekYQrlytiXxC1RyfbdsZkS5pvKAzCCr031xHixZwpnsYNT5xysdFHQaYsA==} peerDependencies: @@ -20451,15 +20184,6 @@ packages: tiny-invariant: 1.3.1 tiny-warning: 1.0.3 - /react-router/6.14.2: - resolution: {integrity: sha512-09Zss2dE2z+T1D03IheqAFtK4UzQyX8nFPWx6jkwdYzGLXd5ie06A6ezS2fO6zJfEb/SpG6UocN2O1hfD+2urQ==} - engines: {node: '>=14'} - peerDependencies: - react: '>=16.8' - dependencies: - '@remix-run/router': 1.7.2 - dev: true - /react-router/6.14.2_hhgf3bgmselb7o32scmuz3hjam: resolution: {integrity: sha512-09Zss2dE2z+T1D03IheqAFtK4UzQyX8nFPWx6jkwdYzGLXd5ie06A6ezS2fO6zJfEb/SpG6UocN2O1hfD+2urQ==} engines: {node: '>=14'} @@ -20478,16 +20202,7 @@ packages: dependencies: '@remix-run/router': 1.7.2 react: 18.3.0-next-3ba7add60-20221201 - - /react-router/6.14.2_react@18.2.0: - resolution: {integrity: sha512-09Zss2dE2z+T1D03IheqAFtK4UzQyX8nFPWx6jkwdYzGLXd5ie06A6ezS2fO6zJfEb/SpG6UocN2O1hfD+2urQ==} - engines: {node: '>=14'} - peerDependencies: - react: '>=16.8' - dependencies: - '@remix-run/router': 1.7.2 - react: 18.2.0 - dev: false + dev: true /react-server-dom-webpack/18.3.0-canary-dd480ef92-20230822_eaktsl3pcltpekt37vdcusnisq: resolution: {integrity: sha512-vBIBAkrOMrqZZGKgjSY9ly82YgZrmQgK4OOMBfMD5ZpAl58eifQFF18ZtVYNX9sLdPPi4MrizYfGjMaS9fP2VQ==} @@ -21946,6 +21661,7 @@ packages: dependencies: '@babel/runtime': 7.21.0 universal-env: 3.3.3 + dev: false /stylehacks/5.1.1_postcss@8.4.12: resolution: {integrity: sha512-sBpcd5Hx7G6seo7b1LkpttvTz7ikD0LlH5RmdcBNb6fFR0Fl7LQwHDFr300q4cwUqi+IYrFGmsIHieMBfnN/Bw==} @@ -22269,6 +21985,7 @@ packages: serialize-javascript: 6.0.1 terser: 5.14.2 webpack: 5.76.0_yt3h3qjhcnsf3663codtuni62a + dev: false /terser-webpack-plugin/5.3.5_muqrkd6dqvsxxmw22vfpzybwpe: resolution: {integrity: sha512-AOEDLDxD2zylUGf/wxHxklEkOe2/r+seuyOWujejFrIxHf11brA1/dWQNIgXa1c6/Wkxgu7zvv0JhOWfc2ELEA==} @@ -23012,6 +22729,7 @@ packages: engines: {npm: '>=3.0.0'} dependencies: '@uni/env': 1.1.0 + dev: false /universalify/0.1.2: resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} @@ -24068,6 +23786,7 @@ packages: - '@swc/core' - esbuild - uglify-js + dev: false /webpack/5.86.0_esbuild@0.17.16: resolution: {integrity: sha512-3BOvworZ8SO/D4GVP+GoRC3fVeg5MO4vzmq8TJJEkdmopxyazGDxN8ClqN12uzrZW9Tv8EED8v5VSb6Sqyi0pg==} From d28ddd271e3ce9b1c672b649695bbe0028b86cd2 Mon Sep 17 00:00:00 2001 From: ClarkXia <xiawenwu41@gmail.com> Date: Thu, 7 Sep 2023 10:13:00 +0800 Subject: [PATCH 04/17] feat: bundle canary version of react (#6518) * feat: bundle canary version of react * fix: bundle dependencies * fix: add switch for rsc * fix: compat with rsc plugin * fix: server logic --- examples/with-rsc/ice.config.mts | 6 + examples/with-rsc/package.json | 5 +- packages/bundles/package.json | 10 +- packages/bundles/scripts/tasks.ts | 136 ++++++++++++++++++ packages/ice/package.json | 10 +- .../src/bundler/webpack/getWebpackConfig.ts | 21 +-- packages/ice/src/config.ts | 5 + packages/ice/src/createService.ts | 1 + packages/ice/src/plugins/web/config.ts | 17 +++ packages/ice/src/plugins/web/task.ts | 7 +- packages/ice/src/service/serverCompiler.ts | 19 ++- packages/ice/src/types/userConfig.ts | 4 + .../ice/src/webpack/ServerCompilerPlugin.ts | 8 +- .../ice/templates/core/entry.server.ts.ejs | 4 + packages/runtime/package.json | 11 +- packages/runtime/src/routes.tsx | 13 +- packages/runtime/src/runRSCApp.tsx | 7 +- packages/runtime/src/runServerApp.tsx | 70 ++++----- packages/shared-config/src/types.ts | 2 +- packages/webpack-config/src/index.ts | 2 +- pnpm-lock.yaml | 136 +++++++----------- 21 files changed, 331 insertions(+), 163 deletions(-) create mode 100644 packages/ice/src/plugins/web/config.ts diff --git a/examples/with-rsc/ice.config.mts b/examples/with-rsc/ice.config.mts index 02208a54f6..845f8921f4 100644 --- a/examples/with-rsc/ice.config.mts +++ b/examples/with-rsc/ice.config.mts @@ -2,4 +2,10 @@ import { defineConfig } from '@ice/app'; export default defineConfig({ ssr: true, + // TODO: support esm format and resolve runtime dependencies to compiled dependencies. + server: { + bundle: true, + format: 'cjs', + }, + rsc: true, }); diff --git a/examples/with-rsc/package.json b/examples/with-rsc/package.json index 7786e40cb1..76c4d522de 100644 --- a/examples/with-rsc/package.json +++ b/examples/with-rsc/package.json @@ -11,9 +11,8 @@ "dependencies": { "@ice/app": "workspace:*", "@ice/runtime": "workspace:*", - "react": "18.3.0-canary-dd480ef92-20230822", - "react-dom": "18.3.0-canary-dd480ef92-20230822", - "react-server-dom-webpack": "18.3.0-canary-dd480ef92-20230822" + "react": "^18.2.0", + "react-dom": "^18.2.0" }, "devDependencies": { "@types/react": "^18.0.17", diff --git a/packages/bundles/package.json b/packages/bundles/package.json index 44fead21d2..69a6f01d7f 100644 --- a/packages/bundles/package.json +++ b/packages/bundles/package.json @@ -35,7 +35,9 @@ "error-stack-parser": "^2.0.6", "@rspack/core": "0.3.0", "@rspack/dev-server": "0.3.0", - "@ice/css-modules-hash": "0.0.6" + "@ice/css-modules-hash": "0.0.6", + "acorn-loose": "^8.3.0", + "neo-async": "^2.6.1" }, "devDependencies": { "@types/less": "^3.0.3", @@ -97,7 +99,11 @@ "loader-utils": "^2.0.0", "source-map": "0.8.0-beta.0", "find-up": "5.0.0", - "common-path-prefix": "3.0.0" + "common-path-prefix": "3.0.0", + "react-builtin": "npm:react@18.3.0-canary-dd480ef92-20230822", + "react-dom-builtin": "npm:react-dom@18.3.0-canary-dd480ef92-20230822", + "react-server-dom-webpack": "18.3.0-canary-dd480ef92-20230822", + "scheduler-builtin": "npm:scheduler@0.24.0-canary-dd480ef92-20230822" }, "publishConfig": { "access": "public", diff --git a/packages/bundles/scripts/tasks.ts b/packages/bundles/scripts/tasks.ts index 48dee28bf7..bceb7d2f02 100644 --- a/packages/bundles/scripts/tasks.ts +++ b/packages/bundles/scripts/tasks.ts @@ -22,6 +22,53 @@ export const taskExternals = { esbuild: 'esbuild', }; +// Override the `react`, `react-dom` and `scheduler`'s package names to avoid +// "The name `react` was looked up in the Haste module map" warnings. +function overridePackageName(source: string, channel: string) { + const json = JSON.parse(source); + json.name = `${json.name}-${channel}`; + return JSON.stringify( + { + name: json.name, + main: json.main, + exports: json.exports, + dependencies: json.dependencies, + peerDependencies: json.peerDependencies, + browser: json.browser, + }, + null, + 2, + ); +} + +interface CopyModulesOptions { + loaders?: { test: RegExp; handler: (code: string, id: string) => string }[]; + channel?: string; + ignore?: string[]; +} + +function copyModules(rules: string[], packageName: string, option?: CopyModulesOptions) { + const { channel, ignore, loaders } = option || {}; + const pkgDir = path.join(__dirname, `../node_modules/${packageName}${channel ? `-${channel}` : ''}`); + const targetDir = path.join(__dirname, `../compiled/${packageName}`); + const filePaths = globbySync(rules, { cwd: pkgDir, ignore: ignore ?? ['node_modules'] }); + filePaths.forEach((filePath) => { + fs.ensureDirSync(path.join(targetDir, path.dirname(filePath))); + const sourcePath = path.join(pkgDir, filePath); + const targetPath = path.join(targetDir, filePath); + // Only deal with js files. + if (loaders) { + const loader = loaders.find(({ test }) => test.test(filePath)); + if (loader) { + const fileContent = fs.readFileSync(sourcePath, 'utf8'); + fs.writeFileSync(targetPath, loader.handler(fileContent, filePath)); + return; + } + } + fs.copyFileSync(sourcePath, targetPath); + }); +} + const commonDeps = ['terser', 'tapable', 'cssnano', 'terser-webpack-plugin', 'webpack', 'schema-utils', 'lodash', 'postcss-preset-env', 'loader-utils', 'find-up', 'common-path-prefix', 'magic-string']; @@ -204,6 +251,95 @@ const tasks = [ fs.copySync(path.join(__dirname, '../webpack/packages'), targetPath); }, }, + { + pkgName: 'react', + skipCompile: true, + declaration: false, + patch: () => { + copyModules( + ['*.{json,js}', 'cjs/**/*.js', 'LICENSE'], + 'react', + { + channel: 'builtin', + loaders: [ + { test: /package.json$/, handler: (source) => overridePackageName(source, 'builtin') }, + { test: /\.js$/, handler: (source) => replaceDeps(source, ['scheduler']) }, + ], + }, + ); + }, + }, + { + pkgName: 'react-dom', + skipCompile: true, + declaration: false, + patch: () => { + copyModules( + ['*.{json,js}', 'cjs/**/*.js', 'LICENSE'], + 'react-dom', + { + channel: 'builtin', + loaders: [ + { test: /package.json$/, handler: (source) => overridePackageName(source, 'builtin') }, + { test: /\.js$/, handler: (source) => replaceDeps(source, ['scheduler', 'react']) }, + ], + // Ignore unused files. + ignore: [ + 'node_modules', + 'static.js', + 'static.node.js', + 'static.browser.js', + 'unstable_testing.js', + 'test-utils.js', + 'server.bun.js', + 'cjs/react-dom-server.bun.development.js', + 'cjs/react-dom-server.bun.production.min.js', + 'cjs/react-dom-test-utils.development.js', + 'cjs/react-dom-test-utils.production.min.js', + 'unstable_server-external-runtime.js', + ], + }, + ); + }, + }, + { + pkgName: 'react-server-dom-webpack', + skipCompile: true, + patch: () => { + copyModules( + ['*.{json,js}', 'cjs/**/*.js', 'LICENSE'], + 'react-server-dom-webpack', + { + loaders: [ + { test: /package.json$/, +handler: (source) => { + const json = JSON.parse(source); + // Compatible with both esm and cjs. + json.exports['./plugin.js'] = './plugin.js'; + return JSON.stringify(json, null, 2); + } }, + ], + }, + ); + }, + }, + { + pkgName: 'scheduler', + skipCompile: true, + declaration: false, + patch: () => { + copyModules( + ['*.{json,js}', 'cjs/**/*.js', 'LICENSE'], + 'scheduler', + { + channel: 'builtin', + loaders: [ + { test: /package.json$/, handler: (source) => overridePackageName(source, 'builtin') }, + ], + }, + ); + }, + }, ]; export default tasks; diff --git a/packages/ice/package.json b/packages/ice/package.json index 0dc5bb8e04..b876a13868 100644 --- a/packages/ice/package.json +++ b/packages/ice/package.json @@ -82,20 +82,18 @@ "chokidar": "^3.5.3", "esbuild": "^0.17.16", "jest": "^29.0.2", - "react": "18.3.0-next-3ba7add60-20221201", + "react": "^18.2.0", "react-router": "6.14.2", "sass": "^1.50.0", "unplugin": "^0.9.0", "webpack": "^5.88.0", "webpack-dev-server": "^4.7.4", "@rspack/core": "0.3.0", - "@rspack/dev-server": "0.3.0", - "react-server-dom-webpack": "18.3.0-canary-dd480ef92-20230822" + "@rspack/dev-server": "0.3.0" }, "peerDependencies": { - "react": "18.3.0-canary-dd480ef92-20230822", - "react-dom": "18.3.0-canary-dd480ef92-20230822", - "react-server-dom-webpack": "18.3.0-canary-dd480ef92-20230822" + "react": ">=18.0.0", + "react-dom": ">=18.0.0" }, "publishConfig": { "access": "public" diff --git a/packages/ice/src/bundler/webpack/getWebpackConfig.ts b/packages/ice/src/bundler/webpack/getWebpackConfig.ts index 62a28501c6..03e5d9116b 100644 --- a/packages/ice/src/bundler/webpack/getWebpackConfig.ts +++ b/packages/ice/src/bundler/webpack/getWebpackConfig.ts @@ -3,7 +3,7 @@ import webpack from '@ice/bundles/compiled/webpack/index.js'; import lodash from '@ice/bundles/compiled/lodash/index.js'; import { getWebpackConfig as getDefaultWebpackConfig } from '@ice/webpack-config'; import type { Configuration } from 'webpack'; -import ReactServerWebpackPlugin from 'react-server-dom-webpack/plugin'; +import ReactServerWebpackPlugin from '@ice/bundles/compiled/react-server-dom-webpack/plugin.js'; import { getExpandedEnvs } from '../../utils/runtimeEnv.js'; import { getRouteExportConfig } from '../../service/config.js'; import { getFileHash } from '../../utils/hash.js'; @@ -118,14 +118,17 @@ const getWebpackConfig: GetWebpackConfig = async (context, options) => { } // Add spinner for webpack task. webpackConfig.plugins.push(getSpinnerPlugin(spinner)); - - webpackConfig.plugins.push(new ReactServerWebpackPlugin({ isServer: false, -clientReferences: [{ - directory: path.join(rootDir, 'src'), - recursive: true, - include: /\.(js|ts|jsx|tsx)$/, - exclude: /types.ts|.d.ts/, - }] })); + if (userConfig.rsc) { + webpackConfig.plugins.push(new ReactServerWebpackPlugin({ + isServer: false, + clientReferences: [{ + directory: path.join(rootDir, 'src'), + recursive: true, + include: /\.(js|ts|jsx|tsx)$/, + exclude: /types.ts|.d.ts/, + }], + })); + } return webpackConfig; }); diff --git a/packages/ice/src/config.ts b/packages/ice/src/config.ts index 4db01cee1c..43c78efbb9 100644 --- a/packages/ice/src/config.ts +++ b/packages/ice/src/config.ts @@ -126,6 +126,11 @@ const userConfig = [ validation: 'boolean', defaultValue: true, }, + { + name: 'rsc', + validation: 'boolean', + defaultValue: false, + }, { name: 'ssr', validation: 'boolean', diff --git a/packages/ice/src/createService.ts b/packages/ice/src/createService.ts index c94cba07bf..9dd2fecbf9 100644 --- a/packages/ice/src/createService.ts +++ b/packages/ice/src/createService.ts @@ -270,6 +270,7 @@ async function createService({ rootDir, command, commandArgs }: CreateServiceOpt dataLoader: userConfig.dataLoader, routeImports, routeDefinition, + rsc: userConfig.rsc, }); dataCache.set('routes', JSON.stringify(routesInfo)); dataCache.set('hasExportAppData', hasExportAppData ? 'true' : ''); diff --git a/packages/ice/src/plugins/web/config.ts b/packages/ice/src/plugins/web/config.ts new file mode 100644 index 0000000000..9b44cbfe53 --- /dev/null +++ b/packages/ice/src/plugins/web/config.ts @@ -0,0 +1,17 @@ +export function createRSCAliases() { + const alias: Record<string, string> = { + react$: '@ice/bundles/compiled/react', + 'react-dom$': '@ice/bundles/compiled/react-dom', + 'react/jsx-runtime$': '@ice/bundles/compiled/react/jsx-runtime', + 'react/jsx-dev-runtime$': '@ice/bundles/compiled/react/jsx-dev-runtime', + 'react-dom/client$': '@ice/bundles/compiled/react-dom/client', + 'react-dom/server$': '@ice/bundles/compiled/react-dom/server', + 'react-dom/server.edge$': '@ice/bundles/compiled/react-dom/server.edge', + 'react-dom/server.browser$': '@ice/bundles/compiled/react-dom/server.browser', + 'react-server-dom-webpack/client$': '@ice/bundles/compiled/react-server-dom-webpack/client', + 'react-server-dom-webpack/client.edge$': '@ice/bundles/compiled/react-server-dom-webpack/client.edge', + 'react-server-dom-webpack/server.edge$': '@ice/bundles/compiled/react-server-dom-webpack/server.edge', + 'react-server-dom-webpack/server.node$': '@ice/bundles/compiled/react-server-dom-webpack/server.node', + }; + return alias; +} diff --git a/packages/ice/src/plugins/web/task.ts b/packages/ice/src/plugins/web/task.ts index 9e0c4d5a00..f52a09c00f 100644 --- a/packages/ice/src/plugins/web/task.ts +++ b/packages/ice/src/plugins/web/task.ts @@ -2,6 +2,7 @@ import * as path from 'path'; import { createRequire } from 'module'; import type { Config } from '@ice/shared-config/types'; import { CACHE_DIR, RUNTIME_TMP_DIR, WEB } from '../../constant.js'; +import { createRSCAliases } from './config.js'; const require = createRequire(import.meta.url); const getWebTask = ({ rootDir, command, userConfig }): Config => { @@ -31,7 +32,7 @@ const getWebTask = ({ rootDir, command, userConfig }): Config => { '@swc/helpers': path.dirname(require.resolve('@swc/helpers/package.json')), 'universal-env': envReplacement, '@uni/env': envReplacement, - 'react-server-dom-webpack/client': require.resolve('react-server-dom-webpack/client.browser'), + ...(userConfig.rsc ? createRSCAliases() : {}), }, swcOptions: { removeExportExprs, @@ -43,6 +44,10 @@ const getWebTask = ({ rootDir, command, userConfig }): Config => { useDevServer: true, useDataLoader: true, target: WEB, + ...(userConfig.rsc ? { + // TODO: temporary solution for rsc. + entry: { main: [path.join(rootDir, RUNTIME_TMP_DIR, 'clientEntry.tsx')] }, + } : {}), }; }; diff --git a/packages/ice/src/service/serverCompiler.ts b/packages/ice/src/service/serverCompiler.ts index f4d5301cb8..f20160b4ca 100644 --- a/packages/ice/src/service/serverCompiler.ts +++ b/packages/ice/src/service/serverCompiler.ts @@ -95,6 +95,23 @@ export const getRuntimeDefination = ( return define; }; +function formatAlias(alias: Record<string, string | boolean>) { + const aliasMap: Record<string, string> = {}; + for (const key in alias) { + const value = alias[key]; + // Esbuild only receive string type of alias. + if (typeof value === 'string') { + if (key.endsWith('$')) { + // Esbuild do not support alias ends with $. + aliasMap[key.replace(/\$$/, '')] = value; + } else { + aliasMap[key] = value; + } + } + } + return aliasMap; +} + export function createServerCompiler(options: Options) { const { task, rootDir, command, speedup, server, syntaxFeatures, getRoutesFile } = options; const externals = task.config?.externals || {}; @@ -170,7 +187,7 @@ export function createServerCompiler(options: Options) { bundle: true, format, target: 'node12.20.0', - alias, + alias: formatAlias(alias), // enable JSX syntax in .js files by default for compatible with migrate project // while it is not recommended loader: { '.js': 'jsx' }, diff --git a/packages/ice/src/types/userConfig.ts b/packages/ice/src/types/userConfig.ts index bbf2435c21..c48c1de3f0 100644 --- a/packages/ice/src/types/userConfig.ts +++ b/packages/ice/src/types/userConfig.ts @@ -189,6 +189,10 @@ export interface UserConfig { * @see https://v3.ice.work/docs/guide/basic/config#ssg */ ssg?: boolean; + /** + * A switch for RSC (React Server Component) support. + */ + rsc?: boolean; /** * config for server bundle * @see https://v3.ice.work/docs/guide/basic/config#server diff --git a/packages/ice/src/webpack/ServerCompilerPlugin.ts b/packages/ice/src/webpack/ServerCompilerPlugin.ts index aeeca3bda7..4579f4fdef 100644 --- a/packages/ice/src/webpack/ServerCompilerPlugin.ts +++ b/packages/ice/src/webpack/ServerCompilerPlugin.ts @@ -42,9 +42,11 @@ export default class ServerCompilerPlugin { this.compilerOptions.compilationInfo.assetsManifest = JSON.parse(compilation.assets['assets-manifest.json'].source().toString()); - // @ts-ignore - this.compilerOptions.compilationInfo.rscManifest = - JSON.parse(compilation.assets['react-client-manifest.json']?.source()?.toString()); + if (compilation.assets?.['react-client-manifest.json']) { + // @ts-ignore + this.compilerOptions.compilationInfo.rscManifest = + JSON.parse(compilation.assets['react-client-manifest.json']?.source()?.toString()); + } } // For first time, we create a new task. // The next time, we use incremental build so do not create task again. diff --git a/packages/ice/templates/core/entry.server.ts.ejs b/packages/ice/templates/core/entry.server.ts.ejs index 2b56b86e58..6383067a33 100644 --- a/packages/ice/templates/core/entry.server.ts.ejs +++ b/packages/ice/templates/core/entry.server.ts.ejs @@ -9,7 +9,9 @@ import type { RenderMode, DistType } from '@ice/runtime'; import type { RenderToPipeableStreamOptions } from 'react-dom/server'; // @ts-ignore import assetsManifest from 'virtual:assets-manifest.json'; +<% if(rsc) {-%> import clientManifest from 'virtual:react-client-manifest.json'; +<% }-%> import createRoutes from './routes'; import routesConfig from './routes-config.bundle.mjs'; <% if(dataLoaderImport.imports) {-%><%-dataLoaderImport.imports%><% } -%> @@ -91,7 +93,9 @@ function mergeOptions(options) { basename: basename || getRouterBasename(), renderMode, routesConfig, + <% if(rsc) {-%> clientManifest, + <% }-%> runtimeOptions: { <% if (runtimeOptions.exports) { -%> <%- runtimeOptions.exports %> diff --git a/packages/runtime/package.json b/packages/runtime/package.json index 4981b0fc70..649a663c0b 100644 --- a/packages/runtime/package.json +++ b/packages/runtime/package.json @@ -39,9 +39,9 @@ "devDependencies": { "@types/react": "^18.0.8", "@types/react-dom": "^18.0.3", - "react": "18.3.0-canary-dd480ef92-20230822", - "react-server-dom-webpack": "18.3.0-canary-dd480ef92-20230822", - "react-dom": "18.3.0-canary-dd480ef92-20230822", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-server-dom-webpack": "canary", "regenerator-runtime": "^0.13.9", "@remix-run/web-fetch": "^4.3.3" }, @@ -63,9 +63,8 @@ "source-map": "^0.7.4" }, "peerDependencies": { - "react": "18.3.0-canary-dd480ef92-20230822", - "react-dom": "18.3.0-canary-dd480ef92-20230822", - "react-server-dom-webpack": "18.3.0-canary-dd480ef92-20230822" + "react": "^18.2.0", + "react-dom": "^18.2.0" }, "publishConfig": { "access": "public" diff --git a/packages/runtime/src/routes.tsx b/packages/runtime/src/routes.tsx index 0a54146791..6c2fde77bc 100644 --- a/packages/runtime/src/routes.tsx +++ b/packages/runtime/src/routes.tsx @@ -60,13 +60,12 @@ export function WrapRouteComponent(options: { }) { const { routeId, isLayout, routeExports } = options; - return <routeExports.default />; - // const { RouteWrappers } = useAppContext(); - // return ( - // <RouteWrapper routeExports={routeExports} id={routeId} isLayout={isLayout} wrappers={RouteWrappers}> - // <routeExports.default /> - // </RouteWrapper> - // ); + const { RouteWrappers } = useAppContext() || {}; + return ( + <RouteWrapper routeExports={routeExports} id={routeId} isLayout={isLayout} wrappers={RouteWrappers}> + <routeExports.default /> + </RouteWrapper> + ); } export function RouteComponent({ id }: { id: string }) { diff --git a/packages/runtime/src/runRSCApp.tsx b/packages/runtime/src/runRSCApp.tsx index b12e956fa7..8f47500949 100644 --- a/packages/runtime/src/runRSCApp.tsx +++ b/packages/runtime/src/runRSCApp.tsx @@ -1,8 +1,9 @@ -// @ts-ignore -import React, { Suspense, use } from 'react'; +import * as React from 'react'; import * as ReactDOM from 'react-dom/client'; import pkg from 'react-server-dom-webpack/client'; const { createFromFetch } = pkg; +// @ts-ignore +const { Suspense, use } = React; export default async function runRSCApp() { function Message({ response }) { @@ -25,4 +26,4 @@ export default async function runRSCApp() { const container = document.getElementById('app'); const root = ReactDOM.createRoot(container); root.render(<App response={response} />); -} \ No newline at end of file +} diff --git a/packages/runtime/src/runServerApp.tsx b/packages/runtime/src/runServerApp.tsx index fc5f7c4244..c0c6ee6bf0 100644 --- a/packages/runtime/src/runServerApp.tsx +++ b/packages/runtime/src/runServerApp.tsx @@ -289,10 +289,6 @@ async function doRender(serverContext: ServerContext, renderOptions: RenderOptio } } - if (req.url.indexOf('?') === -1) { - return renderDocument({ matches: [], routes, renderOptions, documentData }); - } - // HashRouter loads route modules by the CSR. if (appConfig?.router?.type === 'hash') { return renderDocument({ matches: [], routes, renderOptions, documentData }); @@ -403,39 +399,35 @@ async function renderServerEntry( location, }; - const Page = await matches[1].route.lazy(); - // @ts-expect-error - const PageComponent = Page.Component; + let element: JSX.Element; - const element = ( - <div> - <PageComponent /> - </div> - ); + if (renderOptions.clientManifest) { + const Page = await matches[1].route.lazy(); + // @ts-expect-error + const PageComponent = Page.Component; - // const documentContext = { - // main: ( - // <AppRouter routes={routes} routerContext={routerContext} /> - // ), - // }; - // const element = ( - // <AppContextProvider value={appContext}> - // <AppRuntimeProvider> - // <DocumentContextProvider value={documentContext}> - // <Document pagePath={routePath} /> - // </DocumentContextProvider> - // </AppRuntimeProvider> - // </AppContextProvider> - // ); - - // console.log(moduleMap); - - const { pipe } = renderToPipeableStream( - element, - renderOptions.clientManifest, - ); + element = ( + <div> + <PageComponent /> + </div> + ); + } else { + const documentContext = { + main: ( + <AppRouter routes={routes} routerContext={routerContext} /> + ), + }; - // const pipe = renderToNodeStream(element); + element = ( + <AppContextProvider value={appContext}> + <AppRuntimeProvider> + <DocumentContextProvider value={documentContext}> + <Document pagePath={routePath} /> + </DocumentContextProvider> + </AppRuntimeProvider> + </AppContextProvider> + ); + } const fallback = () => { return renderDocument({ @@ -447,7 +439,15 @@ async function renderServerEntry( documentData: appContext.documentData, }); }; - + let pipe: NodeWritablePiper; + if (renderOptions.clientManifest) { + pipe = renderToPipeableStream( + element, + renderOptions.clientManifest, + ).pipe; + } else { + pipe = renderToNodeStream(element); + } return { value: { pipe, diff --git a/packages/shared-config/src/types.ts b/packages/shared-config/src/types.ts index 70dc995e34..cb0eb7390f 100644 --- a/packages/shared-config/src/types.ts +++ b/packages/shared-config/src/types.ts @@ -146,7 +146,7 @@ export interface Config { redirectImports?: ImportDeclaration[]; entry?: { - [key: string]: string; + [key: string]: string | string[]; }; splitChunks?: boolean | 'vendors' | 'chunks' | 'page-vendors' | webpack.Configuration['optimization']['splitChunks']; diff --git a/packages/webpack-config/src/index.ts b/packages/webpack-config/src/index.ts index 04ddcfb7be..fe9b9d2081 100644 --- a/packages/webpack-config/src/index.ts +++ b/packages/webpack-config/src/index.ts @@ -48,7 +48,7 @@ function getEntry(rootDir: string, runtimeTmpDir: string) { })[0]; if (!entryFile) { // use generated file in template directory - entryFile = path.join(rootDir, runtimeTmpDir, 'clientEntry.tsx'); + entryFile = path.join(rootDir, runtimeTmpDir, 'entry.client.tsx'); } // const dataLoaderFile = path.join(rootDir, '.ice/data-loader.ts'); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4d4d180b71..d8152e9135 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -776,15 +776,13 @@ importers: '@ice/runtime': workspace:* '@types/react': ^18.0.17 '@types/react-dom': ^18.0.6 - react: 18.3.0-canary-dd480ef92-20230822 - react-dom: 18.3.0-canary-dd480ef92-20230822 - react-server-dom-webpack: 18.3.0-canary-dd480ef92-20230822 + react: ^18.2.0 + react-dom: ^18.2.0 dependencies: '@ice/app': link:../../packages/ice '@ice/runtime': link:../../packages/runtime - react: 18.3.0-canary-dd480ef92-20230822 - react-dom: 18.3.0-canary-dd480ef92-20230822_hhgf3bgmselb7o32scmuz3hjam - react-server-dom-webpack: 18.3.0-canary-dd480ef92-20230822_i5uyhljmd6xc2xkotszrmzynhy + react: 18.2.0 + react-dom: 18.2.0_react@18.2.0 devDependencies: '@types/react': 18.0.34 '@types/react-dom': 18.0.11 @@ -928,6 +926,7 @@ importers: '@types/less': ^3.0.3 '@types/lodash': ^4.14.181 '@types/webpack-bundle-analyzer': ^4.4.1 + acorn-loose: ^8.3.0 ansi-html-community: ^0.0.8 bonjour-service: ^1.0.13 cacache: 17.0.4 @@ -967,6 +966,7 @@ importers: lodash: 4.17.21 magic-string: 0.27.0 mini-css-extract-plugin: 2.6.1 + neo-async: ^2.6.1 open: ^8.0.9 ora: 5.4.1 p-retry: ^4.5.0 @@ -977,10 +977,14 @@ importers: postcss-nested: 5.0.6 postcss-plugin-rpx2vw: 1.0.0 postcss-preset-env: 7.4.3 + react-builtin: npm:react@18.3.0-canary-dd480ef92-20230822 + react-dom-builtin: npm:react-dom@18.3.0-canary-dd480ef92-20230822 react-refresh: 0.14.0 + react-server-dom-webpack: 18.3.0-canary-dd480ef92-20230822 rimraf: ^3.0.2 sass: 1.50.0 sass-loader: 12.6.0 + scheduler-builtin: npm:scheduler@0.24.0-canary-dd480ef92-20230822 schema-utils: ^4.0.0 selfsigned: ^2.0.1 serve-index: ^1.9.1 @@ -1006,6 +1010,7 @@ importers: '@rspack/core': 0.3.0_zur76qpjdwubwowmoyfe2ntqhe '@rspack/dev-server': 0.3.0_bioma5hrmjqlc63rjodddzwoma '@swc/core': 1.3.80 + acorn-loose: 8.3.0 ansi-html-community: 0.0.8 caniuse-lite: 1.0.30001462 chokidar: 3.5.3 @@ -1017,6 +1022,7 @@ importers: html-entities: 2.3.3 jest-worker: 27.5.1 less: 4.1.2 + neo-async: 2.6.2 postcss: 8.4.12 react-refresh: 0.14.0 sass: 1.50.0 @@ -1062,8 +1068,12 @@ importers: postcss-nested: 5.0.6_postcss@8.4.12 postcss-plugin-rpx2vw: 1.0.0_postcss@8.4.12 postcss-preset-env: 7.4.3_postcss@8.4.12 + react-builtin: /react/18.3.0-canary-dd480ef92-20230822 + react-dom-builtin: /react-dom/18.3.0-canary-dd480ef92-20230822 + react-server-dom-webpack: 18.3.0-canary-dd480ef92-20230822_webpack@5.88.2 rimraf: 3.0.2 sass-loader: 12.6.0_sass@1.50.0+webpack@5.88.2 + scheduler-builtin: /scheduler/0.24.0-canary-dd480ef92-20230822 schema-utils: 4.0.0 selfsigned: 2.1.1 serve-index: 1.9.1 @@ -1153,9 +1163,8 @@ importers: mrmime: ^1.0.0 open: ^8.4.0 path-to-regexp: ^6.2.0 - react: 18.3.0-next-3ba7add60-20221201 + react: ^18.2.0 react-router: 6.14.2 - react-server-dom-webpack: 18.3.0-canary-dd480ef92-20230822 regenerator-runtime: ^0.13.0 resolve.exports: ^1.1.0 sass: ^1.50.0 @@ -1213,9 +1222,8 @@ importers: chokidar: 3.5.3 esbuild: 0.17.16 jest: 29.5.0 - react: 18.3.0-next-3ba7add60-20221201 - react-router: 6.14.2_osgg5tsgainv67oqv2d3ptcxsm - react-server-dom-webpack: 18.3.0-canary-dd480ef92-20230822_eaktsl3pcltpekt37vdcusnisq + react: 18.2.0 + react-router: 6.14.2_react@18.2.0 sass: 1.50.0 unplugin: 0.9.5_4yjf5voakpkrj4qbnm3gtqjbli webpack: 5.88.2_esbuild@0.17.16 @@ -1613,10 +1621,10 @@ importers: fs-extra: ^10.0.0 history: ^5.3.0 htmlparser2: ^8.0.1 - react: 18.3.0-canary-dd480ef92-20230822 - react-dom: 18.3.0-canary-dd480ef92-20230822 + react: ^18.2.0 + react-dom: ^18.2.0 react-router-dom: 6.14.2 - react-server-dom-webpack: 18.3.0-canary-dd480ef92-20230822 + react-server-dom-webpack: canary regenerator-runtime: ^0.13.9 semver: ^7.4.0 source-map: ^0.7.4 @@ -1629,16 +1637,16 @@ importers: fs-extra: 10.1.0 history: 5.3.0 htmlparser2: 8.0.1 - react-router-dom: 6.14.2_i5uyhljmd6xc2xkotszrmzynhy + react-router-dom: 6.14.2_biqbaboplfbrettd7655fr4n2y semver: 7.4.0 source-map: 0.7.4 devDependencies: '@remix-run/web-fetch': 4.3.3 '@types/react': 18.0.28 '@types/react-dom': 18.0.11 - react: 18.3.0-canary-dd480ef92-20230822 - react-dom: 18.3.0-canary-dd480ef92-20230822_hhgf3bgmselb7o32scmuz3hjam - react-server-dom-webpack: 18.3.0-canary-dd480ef92-20230822_i5uyhljmd6xc2xkotszrmzynhy + react: 18.2.0 + react-dom: 18.2.0_react@18.2.0 + react-server-dom-webpack: 18.3.0-canary-9b4f847d9-20230901_biqbaboplfbrettd7655fr4n2y regenerator-runtime: 0.13.11 packages/shared: @@ -7480,7 +7488,6 @@ packages: cpu: [arm64] os: [darwin] requiresBuild: true - dev: false optional: true /@swc/core-darwin-x64/1.3.32: @@ -7498,7 +7505,6 @@ packages: cpu: [x64] os: [darwin] requiresBuild: true - dev: false optional: true /@swc/core-linux-arm-gnueabihf/1.3.32: @@ -7516,7 +7522,6 @@ packages: cpu: [arm] os: [linux] requiresBuild: true - dev: false optional: true /@swc/core-linux-arm64-gnu/1.3.32: @@ -7534,7 +7539,6 @@ packages: cpu: [arm64] os: [linux] requiresBuild: true - dev: false optional: true /@swc/core-linux-arm64-musl/1.3.32: @@ -7552,7 +7556,6 @@ packages: cpu: [arm64] os: [linux] requiresBuild: true - dev: false optional: true /@swc/core-linux-x64-gnu/1.3.32: @@ -7570,7 +7573,6 @@ packages: cpu: [x64] os: [linux] requiresBuild: true - dev: false optional: true /@swc/core-linux-x64-musl/1.3.32: @@ -7588,7 +7590,6 @@ packages: cpu: [x64] os: [linux] requiresBuild: true - dev: false optional: true /@swc/core-win32-arm64-msvc/1.3.32: @@ -7606,7 +7607,6 @@ packages: cpu: [arm64] os: [win32] requiresBuild: true - dev: false optional: true /@swc/core-win32-ia32-msvc/1.3.32: @@ -7624,7 +7624,6 @@ packages: cpu: [ia32] os: [win32] requiresBuild: true - dev: false optional: true /@swc/core-win32-x64-msvc/1.3.32: @@ -7642,7 +7641,6 @@ packages: cpu: [x64] os: [win32] requiresBuild: true - dev: false optional: true /@swc/core/1.3.32: @@ -7684,7 +7682,6 @@ packages: '@swc/core-win32-arm64-msvc': 1.3.80 '@swc/core-win32-ia32-msvc': 1.3.80 '@swc/core-win32-x64-msvc': 1.3.80 - dev: false /@swc/helpers/0.4.14: resolution: {integrity: sha512-4C7nX/dvpzB7za4Ql9K81xK3HPxCpHMgwTZVyf+9JQ6VUbn9jjZVN7/Nkdz/Ugzs2CSjqnL/UPXroiVBVHUWUw==} @@ -7699,7 +7696,6 @@ packages: /@swc/types/0.1.4: resolution: {integrity: sha512-z/G02d+59gyyUb7KYhKi9jOhicek6QD2oMaotUyG+lUkybpXoV49dY9bj7Ah5Q+y7knK2jU67UTX9FyfGzaxQg==} - dev: false /@szmarczak/http-timer/1.1.2: resolution: {integrity: sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==} @@ -8166,7 +8162,6 @@ packages: '@types/prop-types': 15.7.5 '@types/scheduler': 0.16.2 csstype: 3.1.1 - dev: true /@types/react/18.0.28: resolution: {integrity: sha512-RD0ivG1kEztNBdoAK7lekI9M+azSnitIn85h4iOiaLjaTrMjzslhaqCGaI4IyCJ1RljWiLCEu4jyrLLgqxBTew==} @@ -10441,8 +10436,8 @@ packages: engines: {node: '>=10'} hasBin: true dependencies: - is-text-path: 1.0.1 JSONStream: 1.3.5 + is-text-path: 1.0.1 lodash: 4.17.21 meow: 8.1.2 split2: 3.2.2 @@ -10472,7 +10467,6 @@ packages: resolution: {integrity: sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==} dependencies: is-what: 3.14.1 - dev: false /copy-text-to-clipboard/3.0.1: resolution: {integrity: sha512-rvVsHrpFcL4F2P8ihsoLdFHmd404+CMg71S756oRSeQgqk51U3kicGdnvfkrxva0xXH92SjGS62B0XIJsbh+9Q==} @@ -11678,7 +11672,6 @@ packages: requiresBuild: true dependencies: prr: 1.0.1 - dev: false optional: true /error-ex/1.3.2: @@ -14052,7 +14045,6 @@ packages: engines: {node: '>=0.10.0'} hasBin: true requiresBuild: true - dev: false optional: true /image-size/1.0.2: @@ -14566,7 +14558,6 @@ packages: /is-what/3.14.1: resolution: {integrity: sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==} - dev: false /is-whitespace-character/1.0.4: resolution: {integrity: sha512-SDweEzfIZM0SJV0EUga669UTKlmL0Pq8Lno0QDQsPnvECB3IM2aP0gdx5TrU0A01MAPfViaZiI2V1QMZLaKK5w==} @@ -15848,7 +15839,6 @@ packages: source-map: 0.6.1 transitivePeerDependencies: - supports-color - dev: false /leven/3.1.0: resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} @@ -16152,7 +16142,6 @@ packages: dependencies: pify: 4.0.1 semver: 5.7.1 - dev: false optional: true /make-dir/3.1.0: @@ -16548,7 +16537,6 @@ packages: sax: 1.2.4 transitivePeerDependencies: - supports-color - dev: false optional: true /negotiator/0.6.3: @@ -17001,7 +16989,6 @@ packages: /parse-node-version/1.0.1: resolution: {integrity: sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==} engines: {node: '>= 0.10'} - dev: false /parse-numeric-range/1.3.0: resolution: {integrity: sha512-twN+njEipszzlMJd4ONUYgSfZPDxgHhT9Ahed5uTigpQn90FggW4SA/AIPq/6a149fTbE9qBEcSwE3FAEp6wQQ==} @@ -18643,7 +18630,6 @@ packages: nanoid: 3.3.4 picocolors: 1.0.0 source-map-js: 1.0.2 - dev: false /postcss/8.4.21: resolution: {integrity: sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==} @@ -18801,7 +18787,6 @@ packages: /prr/1.0.1: resolution: {integrity: sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==} - dev: false optional: true /pseudomap/1.0.2: @@ -19942,6 +19927,12 @@ packages: /react-dev-utils/12.0.1_rggdtlzfqxxwxudp3onsqdyocm: resolution: {integrity: sha512-84Ivxmr17KjUupyqzFode6xKhjwuEJDROWKJy/BthkL7Wn6NJ8h4WE6k/exAv6ImS+0oZLRRW5j/aINMHyeGeQ==} engines: {node: '>=14'} + peerDependencies: + typescript: '>=2.7' + webpack: '>=4' + peerDependenciesMeta: + typescript: + optional: true dependencies: '@babel/code-frame': 7.18.6 address: 1.2.2 @@ -19972,9 +19963,7 @@ packages: transitivePeerDependencies: - eslint - supports-color - - typescript - vue-template-compiler - - webpack /react-dom/17.0.2_react@17.0.2: resolution: {integrity: sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==} @@ -19985,7 +19974,6 @@ packages: object-assign: 4.1.1 react: 17.0.2 scheduler: 0.20.2 - dev: false /react-dom/18.2.0_react@18.2.0: resolution: {integrity: sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==} @@ -19996,14 +19984,14 @@ packages: react: 18.2.0 scheduler: 0.23.0 - /react-dom/18.3.0-canary-dd480ef92-20230822_hhgf3bgmselb7o32scmuz3hjam: + /react-dom/18.3.0-canary-dd480ef92-20230822: resolution: {integrity: sha512-xAUst7w1A+Cupsv8x9pT/hZ8VmkA4UwZixUVMiay2keN9oRY8f0xvQTcwXgFgOH6wqgsoT2KPpmm6Yf8QMik5g==} peerDependencies: react: 18.3.0-canary-dd480ef92-20230822 dependencies: loose-envify: 1.4.0 - react: 18.3.0-canary-dd480ef92-20230822 scheduler: 0.24.0-canary-dd480ef92-20230822 + dev: true /react-error-overlay/6.0.11: resolution: {integrity: sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg==} @@ -20155,7 +20143,7 @@ packages: tiny-invariant: 1.3.1 tiny-warning: 1.0.3 - /react-router-dom/6.14.2_i5uyhljmd6xc2xkotszrmzynhy: + /react-router-dom/6.14.2_biqbaboplfbrettd7655fr4n2y: resolution: {integrity: sha512-5pWX0jdKR48XFZBuJqHosX3AAHjRAzygouMTyimnBPOLdY3WjzUSKhus2FVMihUFWzeLebDgr4r8UeQFAct7Bg==} engines: {node: '>=14'} peerDependencies: @@ -20163,9 +20151,9 @@ packages: react-dom: '>=16.8' dependencies: '@remix-run/router': 1.7.2 - react: 18.3.0-canary-dd480ef92-20230822 - react-dom: 18.3.0-canary-dd480ef92-20230822_hhgf3bgmselb7o32scmuz3hjam - react-router: 6.14.2_hhgf3bgmselb7o32scmuz3hjam + react: 18.2.0 + react-dom: 18.2.0_react@18.2.0 + react-router: 6.14.2_react@18.2.0 dev: false /react-router/5.3.4_react@17.0.2: @@ -20184,42 +20172,31 @@ packages: tiny-invariant: 1.3.1 tiny-warning: 1.0.3 - /react-router/6.14.2_hhgf3bgmselb7o32scmuz3hjam: - resolution: {integrity: sha512-09Zss2dE2z+T1D03IheqAFtK4UzQyX8nFPWx6jkwdYzGLXd5ie06A6ezS2fO6zJfEb/SpG6UocN2O1hfD+2urQ==} - engines: {node: '>=14'} - peerDependencies: - react: '>=16.8' - dependencies: - '@remix-run/router': 1.7.2 - react: 18.3.0-canary-dd480ef92-20230822 - dev: false - - /react-router/6.14.2_osgg5tsgainv67oqv2d3ptcxsm: + /react-router/6.14.2_react@18.2.0: resolution: {integrity: sha512-09Zss2dE2z+T1D03IheqAFtK4UzQyX8nFPWx6jkwdYzGLXd5ie06A6ezS2fO6zJfEb/SpG6UocN2O1hfD+2urQ==} engines: {node: '>=14'} peerDependencies: react: '>=16.8' dependencies: '@remix-run/router': 1.7.2 - react: 18.3.0-next-3ba7add60-20221201 - dev: true + react: 18.2.0 - /react-server-dom-webpack/18.3.0-canary-dd480ef92-20230822_eaktsl3pcltpekt37vdcusnisq: - resolution: {integrity: sha512-vBIBAkrOMrqZZGKgjSY9ly82YgZrmQgK4OOMBfMD5ZpAl58eifQFF18ZtVYNX9sLdPPi4MrizYfGjMaS9fP2VQ==} + /react-server-dom-webpack/18.3.0-canary-9b4f847d9-20230901_biqbaboplfbrettd7655fr4n2y: + resolution: {integrity: sha512-eTcOkbT+ZiZK7TDfQADQZoX3cv5JZFMKUaHJLkdQYXGyE3BHcn8tuZ3IK9CGX61SQ82J+X1+fZ1RyZDSvutaCA==} engines: {node: '>=0.10.0'} peerDependencies: - react: 18.3.0-canary-dd480ef92-20230822 - react-dom: 18.3.0-canary-dd480ef92-20230822 + react: 18.3.0-canary-9b4f847d9-20230901 + react-dom: 18.3.0-canary-9b4f847d9-20230901 webpack: ^5.59.0 dependencies: acorn-loose: 8.3.0 loose-envify: 1.4.0 neo-async: 2.6.2 - react: 18.3.0-next-3ba7add60-20221201 - webpack: 5.88.2_esbuild@0.17.16 + react: 18.2.0 + react-dom: 18.2.0_react@18.2.0 dev: true - /react-server-dom-webpack/18.3.0-canary-dd480ef92-20230822_i5uyhljmd6xc2xkotszrmzynhy: + /react-server-dom-webpack/18.3.0-canary-dd480ef92-20230822_webpack@5.88.2: resolution: {integrity: sha512-vBIBAkrOMrqZZGKgjSY9ly82YgZrmQgK4OOMBfMD5ZpAl58eifQFF18ZtVYNX9sLdPPi4MrizYfGjMaS9fP2VQ==} engines: {node: '>=0.10.0'} peerDependencies: @@ -20230,8 +20207,8 @@ packages: acorn-loose: 8.3.0 loose-envify: 1.4.0 neo-async: 2.6.2 - react: 18.3.0-canary-dd480ef92-20230822 - react-dom: 18.3.0-canary-dd480ef92-20230822_hhgf3bgmselb7o32scmuz3hjam + webpack: 5.88.2_yt3h3qjhcnsf3663codtuni62a + dev: true /react-textarea-autosize/8.4.0_h7fc2el62uaa77gho3xhys6ola: resolution: {integrity: sha512-YrTFaEHLgJsi8sJVYHBzYn+mkP3prGkmP2DKb/tm0t7CLJY5t1Rxix8070LAKb0wby7bl/lf2EeHkuMihMZMwQ==} @@ -20267,7 +20244,6 @@ packages: dependencies: loose-envify: 1.4.0 object-assign: 4.1.1 - dev: false /react/18.2.0: resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==} @@ -20280,12 +20256,6 @@ packages: engines: {node: '>=0.10.0'} dependencies: loose-envify: 1.4.0 - - /react/18.3.0-next-3ba7add60-20221201: - resolution: {integrity: sha512-/hwADSpnz/GeDEljbg7Z2mF2MaYw7V1CsdbGvvhCUse4RvaRueHjcH7B/jbik8wRll3rxBPlomt15rSjIMjEJQ==} - engines: {node: '>=0.10.0'} - dependencies: - loose-envify: 1.4.0 dev: true /read-cache/1.0.0: @@ -20905,7 +20875,6 @@ packages: dependencies: loose-envify: 1.4.0 object-assign: 4.1.1 - dev: false /scheduler/0.21.0: resolution: {integrity: sha512-1r87x5fz9MXqswA2ERLo0EbOAU74DpIUO090gIasYTqlVoJeMcl+Z1Rg7WHz+qtPujhS/hGIt9kxZOYBV3faRQ==} @@ -20922,6 +20891,7 @@ packages: resolution: {integrity: sha512-6hp1jChwe5RNdfVyA8rXw28CdPh7/hVGALqjwNwpaVrTM0SdPHy0Hes6Rqon1c9qKfUrQFhds+C+0fNMgy9hRw==} dependencies: loose-envify: 1.4.0 + dev: true /schema-utils/2.7.0: resolution: {integrity: sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A==} @@ -21985,7 +21955,6 @@ packages: serialize-javascript: 6.0.1 terser: 5.14.2 webpack: 5.76.0_yt3h3qjhcnsf3663codtuni62a - dev: false /terser-webpack-plugin/5.3.5_muqrkd6dqvsxxmw22vfpzybwpe: resolution: {integrity: sha512-AOEDLDxD2zylUGf/wxHxklEkOe2/r+seuyOWujejFrIxHf11brA1/dWQNIgXa1c6/Wkxgu7zvv0JhOWfc2ELEA==} @@ -22135,7 +22104,6 @@ packages: serialize-javascript: 6.0.1 terser: 5.16.5 webpack: 5.88.2_yt3h3qjhcnsf3663codtuni62a - dev: true /terser-webpack-plugin/5.3.7_webpack@5.88.2: resolution: {integrity: sha512-AfKwIktyP7Cu50xNjXF/6Qb5lBNzYaWpU6YfoX3uZicTx0zTy0stDDCsvjDapKsSDvOeWo5MEq4TmdBy2cNoHw==} @@ -23786,7 +23754,6 @@ packages: - '@swc/core' - esbuild - uglify-js - dev: false /webpack/5.86.0_esbuild@0.17.16: resolution: {integrity: sha512-3BOvworZ8SO/D4GVP+GoRC3fVeg5MO4vzmq8TJJEkdmopxyazGDxN8ClqN12uzrZW9Tv8EED8v5VSb6Sqyi0pg==} @@ -23945,7 +23912,6 @@ packages: - '@swc/core' - esbuild - uglify-js - dev: true /webpackbar/5.0.2_webpack@5.88.2: resolution: {integrity: sha512-BmFJo7veBDgQzfWXl/wwYXr/VFus0614qZ8i9znqcl9fnEdiVkdbi0TedLQ6xAK92HZHDJ0QmyQ0fmuZPAgCYQ==} From cfe85e476bf326fcbe62f33c73ee5a614ad33ad0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B0=B4=E6=BE=9C?= <shuilan.cj@taobao.com> Date: Wed, 13 Sep 2023 14:22:07 +0800 Subject: [PATCH 05/17] feat: rsc server route (#6528) * feat: rsc router * feat: use server context * fix: lint * feat: pass children to router * fix: lint * feat: server route * refactor: rsc entry * chore: remove dead code --- .../src/components/Counter.client.tsx | 4 + examples/with-rsc/src/pages/index.tsx | 9 +- examples/with-rsc/src/pages/layout.tsx | 6 +- packages/ice/src/plugins/web/task.ts | 2 +- packages/ice/src/routes.ts | 11 +- .../ice/templates/core/clientEntry.tsx.ejs | 19 --- .../ice/templates/core/entry.server.ts.ejs | 5 + .../ice/templates/core/rsc.client.tsx.ejs | 8 ++ packages/runtime/src/AppContext.tsx | 9 +- packages/runtime/src/index.server.ts | 2 + packages/runtime/src/index.ts | 5 +- packages/runtime/src/routes.tsx | 7 +- .../{runRSCApp.tsx => runRSCClientApp.tsx} | 17 ++- packages/runtime/src/runRSCServerApp.tsx | 108 ++++++++++++++++ packages/runtime/src/runServerApp.tsx | 119 ++++-------------- packages/runtime/src/types.ts | 28 +++++ packages/runtime/src/utils/getLocation.ts | 22 ++++ pnpm-lock.yaml | 50 ++++++-- 18 files changed, 275 insertions(+), 156 deletions(-) delete mode 100644 packages/ice/templates/core/clientEntry.tsx.ejs create mode 100644 packages/ice/templates/core/rsc.client.tsx.ejs rename packages/runtime/src/{runRSCApp.tsx => runRSCClientApp.tsx} (71%) create mode 100644 packages/runtime/src/runRSCServerApp.tsx create mode 100644 packages/runtime/src/utils/getLocation.ts diff --git a/examples/with-rsc/src/components/Counter.client.tsx b/examples/with-rsc/src/components/Counter.client.tsx index d4c233afdd..c61fbaa994 100644 --- a/examples/with-rsc/src/components/Counter.client.tsx +++ b/examples/with-rsc/src/components/Counter.client.tsx @@ -1,5 +1,6 @@ 'use client'; import { useState } from 'react'; +import { useAppContext } from 'ice'; import styles from './index.module.css'; export default function Counter() { @@ -9,6 +10,9 @@ export default function Counter() { setCount(count + 1); } + const appContext = useAppContext(); + console.log(appContext); + return ( <button className={styles.button} type="button" onClick={updateCount}> 👍🏻 {count} diff --git a/examples/with-rsc/src/pages/index.tsx b/examples/with-rsc/src/pages/index.tsx index 40144ed28b..0305d82e97 100644 --- a/examples/with-rsc/src/pages/index.tsx +++ b/examples/with-rsc/src/pages/index.tsx @@ -1,15 +1,16 @@ -import { useState } from 'react'; +import { useAppContext } from 'ice'; import styles from './index.module.css'; -// import Comments from '@/components/Comments'; -// import Footer from '@/components/Footer'; import EditButton from '@/components/EditButton.client'; import Counter from '@/components/Counter.client'; export default function Home() { console.log('Render: Index'); + const appContext = useAppContext(); + console.log(appContext); + return ( - <div> + <div className={styles.app}> <h2>Home Page</h2> <Counter /> <EditButton noteId="editButton"> diff --git a/examples/with-rsc/src/pages/layout.tsx b/examples/with-rsc/src/pages/layout.tsx index 6456f4b6e3..71a8cec4e2 100644 --- a/examples/with-rsc/src/pages/layout.tsx +++ b/examples/with-rsc/src/pages/layout.tsx @@ -1,12 +1,10 @@ -import { Outlet } from 'ice'; - -export default function Layout() { +export default function Layout(props) { console.log('Render: Layout'); return ( <div> <h1>Suspense App</h1> - <Outlet /> + {props.children} </div> ); } \ No newline at end of file diff --git a/packages/ice/src/plugins/web/task.ts b/packages/ice/src/plugins/web/task.ts index f52a09c00f..74c9bba8c0 100644 --- a/packages/ice/src/plugins/web/task.ts +++ b/packages/ice/src/plugins/web/task.ts @@ -46,7 +46,7 @@ const getWebTask = ({ rootDir, command, userConfig }): Config => { target: WEB, ...(userConfig.rsc ? { // TODO: temporary solution for rsc. - entry: { main: [path.join(rootDir, RUNTIME_TMP_DIR, 'clientEntry.tsx')] }, + entry: { main: [path.join(rootDir, RUNTIME_TMP_DIR, 'rsc.client.tsx')] }, } : {}), }; }; diff --git a/packages/ice/src/routes.ts b/packages/ice/src/routes.ts index e7f26469f5..930d8dfe6c 100644 --- a/packages/ice/src/routes.ts +++ b/packages/ice/src/routes.ts @@ -73,11 +73,12 @@ export function getRoutesDefinition(nestRouteManifest: NestedRouteManifest[], la routeImports.push(`import * as ${routeSpecifier} from '${formatPath(componentPath)}';`); loadStatement = routeSpecifier; } - const component = `Component: () => WrapRouteComponent({ - routeId: '${id}', - isLayout: ${layout}, - routeExports: ${lazy ? 'componentModule' : loadStatement}, - })`; + const component = `Component: (props) => WrapRouteComponent({ + routeId: '${id}', + isLayout: ${layout}, + routeExports: ${lazy ? 'componentModule' : loadStatement}, + children: props?.children + })`; const loader = `loader: createRouteLoader({ routeId: '${id}', requestContext, diff --git a/packages/ice/templates/core/clientEntry.tsx.ejs b/packages/ice/templates/core/clientEntry.tsx.ejs deleted file mode 100644 index ea55d772ed..0000000000 --- a/packages/ice/templates/core/clientEntry.tsx.ejs +++ /dev/null @@ -1,19 +0,0 @@ -<% if (importCoreJs) { -%>import 'core-js';<% } %> -import { createElement, Fragment } from 'react'; -import { runRSCApp, getAppConfig } from '<%- iceRuntimePath %>'; -import { commons, statics } from './runtimeModules'; -import * as app from '@/app'; -<%- runtimeOptions.imports %> -<% if(dataLoaderImport.imports) {-%><%-dataLoaderImport.imports%><% } -%> -const getRouterBasename = () => { - const appConfig = getAppConfig(app); - return appConfig?.router?.basename ?? <%- basename %> ?? ''; -} -// Add react fragment for split chunks of app. -// Otherwise chunk of route component will pack @ice/jsx-runtime and depend on framework bundle. - -const render = (customOptions = {}) => { - return runRSCApp(); -}; - -<%- entryCode %> diff --git a/packages/ice/templates/core/entry.server.ts.ejs b/packages/ice/templates/core/entry.server.ts.ejs index 6383067a33..eee1534dbc 100644 --- a/packages/ice/templates/core/entry.server.ts.ejs +++ b/packages/ice/templates/core/entry.server.ts.ejs @@ -62,6 +62,11 @@ export async function renderToResponse(requestContext, options: RenderOptions = setRuntimeEnv(renderMode); const mergedOptions = mergeOptions(options); + + <% if(rsc) {-%> + return runtime.runRSCServerApp(requestContext, mergedOptions); + <% }-%> + return runtime.renderToResponse(requestContext, mergedOptions); } diff --git a/packages/ice/templates/core/rsc.client.tsx.ejs b/packages/ice/templates/core/rsc.client.tsx.ejs new file mode 100644 index 0000000000..812d527509 --- /dev/null +++ b/packages/ice/templates/core/rsc.client.tsx.ejs @@ -0,0 +1,8 @@ +<% if (importCoreJs) { -%>import 'core-js';<% } %> +import { runRSCClientApp } from '<%- iceRuntimePath %>'; + +const render = (customOptions = {}) => { + return runRSCClientApp(); +}; + +<%- entryCode %> diff --git a/packages/runtime/src/AppContext.tsx b/packages/runtime/src/AppContext.tsx index ff05e7fdbf..5998beb8af 100644 --- a/packages/runtime/src/AppContext.tsx +++ b/packages/runtime/src/AppContext.tsx @@ -1,17 +1,22 @@ import * as React from 'react'; import type { AppContext } from './types.js'; -const Context = React.createContext<AppContext | undefined>(undefined); +// @ts-ignore +const Context = React.createServerContext + // @ts-ignore + ? React.createServerContext<AppContext | undefined>(undefined) + : React.createContext<AppContext | undefined>(undefined); Context.displayName = 'AppContext'; function useAppContext() { - const value = React.useContext(Context); + const value: AppContext = React.useContext(Context); return value; } function useAppData() { const value = React.useContext(Context); + // @ts-ignore return value.appData; } diff --git a/packages/runtime/src/index.server.ts b/packages/runtime/src/index.server.ts index e1390daf38..83dd937a2a 100644 --- a/packages/runtime/src/index.server.ts +++ b/packages/runtime/src/index.server.ts @@ -1,2 +1,4 @@ export { renderToResponse, renderToHTML, renderToEntry } from './runServerApp.js'; +export { runRSCServerApp } from './runRSCServerApp.js'; + export * from './index.js'; diff --git a/packages/runtime/src/index.ts b/packages/runtime/src/index.ts index 7b805f5a82..2a618bfa4f 100644 --- a/packages/runtime/src/index.ts +++ b/packages/runtime/src/index.ts @@ -26,7 +26,8 @@ import type { RunClientAppOptions, CreateRoutes } from './runClientApp.js'; import { useAppContext as useInternalAppContext, useAppData, AppContextProvider } from './AppContext.js'; import { getAppData } from './appData.js'; import { useData, useConfig } from './RouteContext.js'; -import runRSCApp from './runRSCApp.js'; +import { runRSCClientApp } from './runRSCClientApp.js'; + import { Meta, Title, @@ -144,7 +145,7 @@ export { WrapRouteComponent, RouteErrorComponent, - runRSCApp, + runRSCClientApp, }; export type { diff --git a/packages/runtime/src/routes.tsx b/packages/runtime/src/routes.tsx index 6c2fde77bc..2751a88027 100644 --- a/packages/runtime/src/routes.tsx +++ b/packages/runtime/src/routes.tsx @@ -57,13 +57,16 @@ export function WrapRouteComponent(options: { routeId: string; isLayout?: boolean; routeExports: ComponentModule; + children?: Array<ComponentModule>; }) { - const { routeId, isLayout, routeExports } = options; + const { routeId, isLayout, routeExports, children } = options; const { RouteWrappers } = useAppContext() || {}; return ( <RouteWrapper routeExports={routeExports} id={routeId} isLayout={isLayout} wrappers={RouteWrappers}> - <routeExports.default /> + <routeExports.default> + { children } + </routeExports.default> </RouteWrapper> ); } diff --git a/packages/runtime/src/runRSCApp.tsx b/packages/runtime/src/runRSCClientApp.tsx similarity index 71% rename from packages/runtime/src/runRSCApp.tsx rename to packages/runtime/src/runRSCClientApp.tsx index 8f47500949..14b0ece3a7 100644 --- a/packages/runtime/src/runRSCApp.tsx +++ b/packages/runtime/src/runRSCClientApp.tsx @@ -1,29 +1,26 @@ import * as React from 'react'; import * as ReactDOM from 'react-dom/client'; import pkg from 'react-server-dom-webpack/client'; -const { createFromFetch } = pkg; + // @ts-ignore const { Suspense, use } = React; +const { createFromFetch } = pkg; -export default async function runRSCApp() { - function Message({ response }) { - const body = use(response); - return <div>{body}</div>; - } - +export async function runRSCClientApp() { function App({ response }) { return ( <Suspense fallback={<h1>Loading...</h1>}> - <Message response={response} /> + {use(response)} </Suspense> ); } + const rscPath = location.href + (location.href.indexOf('?') ? '?rsc' : '&rsc'); const response = createFromFetch( - fetch('/?body'), + fetch(rscPath), ); const container = document.getElementById('app'); const root = ReactDOM.createRoot(container); root.render(<App response={response} />); -} +} \ No newline at end of file diff --git a/packages/runtime/src/runRSCServerApp.tsx b/packages/runtime/src/runRSCServerApp.tsx new file mode 100644 index 0000000000..11f3c0e4d8 --- /dev/null +++ b/packages/runtime/src/runRSCServerApp.tsx @@ -0,0 +1,108 @@ +import * as React from 'react'; +import * as ReactDOMServer from 'react-dom/server'; +import { renderToPipeableStream } from 'react-server-dom-webpack/server.node'; +import { AppContextProvider } from './AppContext.js'; +import { DocumentContextProvider } from './Document.js'; +import { loadRouteModules } from './routes.js'; +import getAppConfig from './appConfig.js'; +import getRequestContext from './requestContext.js'; +import getLocation from './utils/getLocation.js'; +import addLeadingSlash from './utils/addLeadingSlash.js'; +import matchRoutes from './matchRoutes.js'; +import type { + AppContext, + ServerContext, + RouteMatch, + RouteModules, + ServerRenderOptions as RenderOptions, +} from './types.js'; + +export async function runRSCServerApp(serverContext: ServerContext, renderOptions: RenderOptions) { + const { req, res } = serverContext; + + const { + app, + createRoutes, + renderMode, + basename, + serverOnlyBasename, + clientManifest, + assetsManifest, + } = renderOptions; + + const location = getLocation(req.url); + const requestContext = getRequestContext(location, serverContext); + const routes = createRoutes({ + requestContext, + renderMode, + }); + const finalBasename = addLeadingSlash(serverOnlyBasename || basename); + const matches = matchRoutes(routes, location, finalBasename); + + const appConfig = getAppConfig(app); + const appContext: AppContext = { + appConfig, + appData: null, + renderMode, + assetsManifest, + basename: finalBasename, + matches: [], + }; + + if (req.url?.indexOf('rsc') === -1) { + return renderDocument(serverContext, renderOptions, appContext); + } + + const routeModules = await loadRouteModules(matches.map(({ route: { id, lazy } }) => ({ id, lazy }))); + + const element = ( + <AppContextProvider value={appContext}> + {renderMatches(matches, routeModules)} + </AppContextProvider> + ); + + const { pipe } = renderToPipeableStream( + element, + clientManifest, + ); + + pipe(res); +} + +function renderMatches(matches: RouteMatch[], routeModules: RouteModules) { + return matches.reduceRight((children, match) => { + if (match.route) { + const Component = routeModules[match.route.id].default; + + return React.createElement(Component, { + children, + }); + } + + return children; + }, React.createElement(null)); +} + +function renderDocument(requestContext, renderOptions, appContext) { + const { res } = requestContext; + + const { + Document, + } = renderOptions; + + const documentContext = { + main: null, + }; + + const htmlStr = ReactDOMServer.renderToString( + <AppContextProvider value={appContext}> + <DocumentContextProvider value={documentContext}> + <Document /> + </DocumentContextProvider> + </AppContextProvider>, + ); + + res.setHeader('Content-Type', 'text/html; charset=utf-8'); + res.send(`<!DOCTYPE html>${htmlStr}`); +} + diff --git a/packages/runtime/src/runServerApp.tsx b/packages/runtime/src/runServerApp.tsx index c0c6ee6bf0..3c028809d1 100644 --- a/packages/runtime/src/runServerApp.tsx +++ b/packages/runtime/src/runServerApp.tsx @@ -1,21 +1,14 @@ import type { ServerResponse, IncomingMessage } from 'http'; import * as React from 'react'; -import type { RenderToPipeableStreamOptions } from 'react-dom/server'; import * as ReactDOMServer from 'react-dom/server'; import type { Location } from 'history'; -import { renderToPipeableStream } from 'react-server-dom-webpack/server.node'; -import { parsePath } from 'history'; import { isFunction } from '@ice/shared'; import type { AppContext, RouteItem, ServerContext, - AppExport, AssetsManifest, RouteMatch, - PageConfig, - RenderMode, - DocumentComponent, - RuntimeModules, AppData, - ServerAppRouterProps, DataLoaderConfig, + ServerAppRouterProps, + ServerRenderOptions as RenderOptions, } from './types.js'; import Runtime from './runtime.js'; import { AppContextProvider } from './AppContext.js'; @@ -23,7 +16,6 @@ import { getAppData } from './appData.js'; import getAppConfig from './appConfig.js'; import { DocumentContextProvider } from './Document.js'; import { loadRouteModules } from './routes.js'; -import type { RouteLoaderOptions } from './routes.js'; import { pipeToString, renderToNodeStream } from './server/streamRender.js'; import type { NodeWritablePiper } from './server/streamRender.js'; import getRequestContext from './requestContext.js'; @@ -32,38 +24,13 @@ import getCurrentRoutePath from './utils/getCurrentRoutePath.js'; import ServerRouter from './ServerRouter.js'; import { renderHTMLToJS } from './renderHTMLToJS.js'; import addLeadingSlash from './utils/addLeadingSlash.js'; - - -interface RenderOptions { - app: AppExport; - assetsManifest: AssetsManifest; - createRoutes: (options: Pick<RouteLoaderOptions, 'requestContext' | 'renderMode'>) => RouteItem[]; - runtimeModules: RuntimeModules; - documentDataLoader?: DataLoaderConfig; - Document: DocumentComponent; - documentOnly?: boolean; - renderMode?: RenderMode; - // basename is used both for server and client, once set, it will be sync to client. - basename?: string; - // serverOnlyBasename is used when just want to change basename for server. - serverOnlyBasename?: string; - routePath?: string; - disableFallback?: boolean; - routesConfig: { - [key: string]: PageConfig; - }; - runtimeOptions?: Record<string, any>; - distType?: Array<'html' | 'javascript'>; - prependCode?: string; - serverData?: any; - streamOptions?: RenderToPipeableStreamOptions; - clientManifest: any; -} +import getLocation from './utils/getLocation.js'; interface Piper { pipe: NodeWritablePiper; - fallback: Function; + fallback?: Function; } + interface Response { statusCode?: number; statusText?: string; @@ -381,16 +348,16 @@ interface RenderServerEntry { async function renderServerEntry( { runtime, - matches, location, renderOptions, }: RenderServerEntry, ): Promise<Response> { const { Document } = renderOptions; const appContext = runtime.getAppContext(); - const { routes, routePath, loaderData, basename } = appContext; + const { routes, matches, routePath, loaderData, basename } = appContext; const AppRuntimeProvider = runtime.composeAppProvider() || React.Fragment; const AppRouter = runtime.getAppRouter<ServerAppRouterProps>(); + const routerContext: ServerAppRouterProps['routerContext'] = { // @ts-expect-error matches type should be use `AgnosticDataRouteMatch[]` matches, @@ -399,35 +366,21 @@ async function renderServerEntry( location, }; - let element: JSX.Element; - - if (renderOptions.clientManifest) { - const Page = await matches[1].route.lazy(); - // @ts-expect-error - const PageComponent = Page.Component; - - element = ( - <div> - <PageComponent /> - </div> - ); - } else { - const documentContext = { - main: ( - <AppRouter routes={routes} routerContext={routerContext} /> - ), - }; + const documentContext = { + main: ( + <AppRouter routes={routes} routerContext={routerContext} /> + ), + }; - element = ( - <AppContextProvider value={appContext}> - <AppRuntimeProvider> - <DocumentContextProvider value={documentContext}> - <Document pagePath={routePath} /> - </DocumentContextProvider> - </AppRuntimeProvider> - </AppContextProvider> - ); - } + const element: JSX.Element = ( + <AppContextProvider value={appContext}> + <AppRuntimeProvider> + <DocumentContextProvider value={documentContext}> + <Document pagePath={routePath} /> + </DocumentContextProvider> + </AppRuntimeProvider> + </AppContextProvider> + ); const fallback = () => { return renderDocument({ @@ -439,15 +392,9 @@ async function renderServerEntry( documentData: appContext.documentData, }); }; - let pipe: NodeWritablePiper; - if (renderOptions.clientManifest) { - pipe = renderToPipeableStream( - element, - renderOptions.clientManifest, - ).pipe; - } else { - pipe = renderToNodeStream(element); - } + + const pipe: NodeWritablePiper = renderToNodeStream(element); + return { value: { pipe, @@ -537,21 +484,3 @@ function renderDocument(options: RenderDocumentOptions): Response { }; } -/** - * ref: https://github.com/remix-run/react-router/blob/main/packages/react-router-dom/server.tsx - */ -const REGEXP_WITH_HOSTNAME = /^https?:\/\/[^/]+/i; -function getLocation(url: string) { - // In case of invalid URL, provide a default base url. - const locationPath = url.replace(REGEXP_WITH_HOSTNAME, '') || '/'; - const locationProps = parsePath(locationPath); - const location: Location = { - pathname: locationProps.pathname || '/', - search: locationProps.search || '', - hash: locationProps.hash || '', - state: null, - key: 'default', - }; - - return location; -} diff --git a/packages/runtime/src/types.ts b/packages/runtime/src/types.ts index 6ac6110b2e..bf8d542fa6 100644 --- a/packages/runtime/src/types.ts +++ b/packages/runtime/src/types.ts @@ -3,6 +3,8 @@ import type { InitialEntry, AgnosticRouteObject, Location, History, RouterInit, import type { ComponentType, PropsWithChildren } from 'react'; import type { HydrationOptions, Root } from 'react-dom/client'; import type { Params, RouteObject } from 'react-router-dom'; +import type { RenderToPipeableStreamOptions } from 'react-dom/server'; +import type { RouteLoaderOptions } from './routes.js'; type UseConfig = () => RouteConfig<Record<string, any>>; type UseData = () => RouteData; @@ -304,3 +306,29 @@ declare global { env: Record<string, string>; } } + +export interface ServerRenderOptions { + app: AppExport; + assetsManifest: AssetsManifest; + createRoutes: (options: Pick<RouteLoaderOptions, 'requestContext' | 'renderMode'>) => RouteItem[]; + runtimeModules: RuntimeModules; + documentDataLoader?: DataLoaderConfig; + Document: DocumentComponent; + documentOnly?: boolean; + renderMode?: RenderMode; + // basename is used both for server and client, once set, it will be sync to client. + basename?: string; + // serverOnlyBasename is used when just want to change basename for server. + serverOnlyBasename?: string; + routePath?: string; + disableFallback?: boolean; + routesConfig: { + [key: string]: PageConfig; + }; + runtimeOptions?: Record<string, any>; + distType?: Array<'html' | 'javascript'>; + prependCode?: string; + serverData?: any; + streamOptions?: RenderToPipeableStreamOptions; + clientManifest?: any; +} diff --git a/packages/runtime/src/utils/getLocation.ts b/packages/runtime/src/utils/getLocation.ts new file mode 100644 index 0000000000..fc3d6c9e72 --- /dev/null +++ b/packages/runtime/src/utils/getLocation.ts @@ -0,0 +1,22 @@ +/** + * ref: https://github.com/remix-run/react-router/blob/main/packages/react-router-dom/server.tsx + */ +import { parsePath } from 'history'; +import type { Location } from 'history'; + +const REGEXP_WITH_HOSTNAME = /^https?:\/\/[^/]+/i; + +export default function getLocation(url: string) { + // In case of invalid URL, provide a default base url. + const locationPath = url.replace(REGEXP_WITH_HOSTNAME, '') || '/'; + const locationProps = parsePath(locationPath); + const location: Location = { + pathname: locationProps.pathname || '/', + search: locationProps.search || '', + hash: locationProps.hash || '', + state: null, + key: 'default', + }; + + return location; +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d8152e9135..587f72c2f4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1646,7 +1646,7 @@ importers: '@types/react-dom': 18.0.11 react: 18.2.0 react-dom: 18.2.0_react@18.2.0 - react-server-dom-webpack: 18.3.0-canary-9b4f847d9-20230901_biqbaboplfbrettd7655fr4n2y + react-server-dom-webpack: 18.3.0-canary-627b7abd6-20230911_biqbaboplfbrettd7655fr4n2y regenerator-runtime: 0.13.11 packages/shared: @@ -7488,6 +7488,7 @@ packages: cpu: [arm64] os: [darwin] requiresBuild: true + dev: false optional: true /@swc/core-darwin-x64/1.3.32: @@ -7505,6 +7506,7 @@ packages: cpu: [x64] os: [darwin] requiresBuild: true + dev: false optional: true /@swc/core-linux-arm-gnueabihf/1.3.32: @@ -7522,6 +7524,7 @@ packages: cpu: [arm] os: [linux] requiresBuild: true + dev: false optional: true /@swc/core-linux-arm64-gnu/1.3.32: @@ -7539,6 +7542,7 @@ packages: cpu: [arm64] os: [linux] requiresBuild: true + dev: false optional: true /@swc/core-linux-arm64-musl/1.3.32: @@ -7556,6 +7560,7 @@ packages: cpu: [arm64] os: [linux] requiresBuild: true + dev: false optional: true /@swc/core-linux-x64-gnu/1.3.32: @@ -7573,6 +7578,7 @@ packages: cpu: [x64] os: [linux] requiresBuild: true + dev: false optional: true /@swc/core-linux-x64-musl/1.3.32: @@ -7590,6 +7596,7 @@ packages: cpu: [x64] os: [linux] requiresBuild: true + dev: false optional: true /@swc/core-win32-arm64-msvc/1.3.32: @@ -7607,6 +7614,7 @@ packages: cpu: [arm64] os: [win32] requiresBuild: true + dev: false optional: true /@swc/core-win32-ia32-msvc/1.3.32: @@ -7624,6 +7632,7 @@ packages: cpu: [ia32] os: [win32] requiresBuild: true + dev: false optional: true /@swc/core-win32-x64-msvc/1.3.32: @@ -7641,6 +7650,7 @@ packages: cpu: [x64] os: [win32] requiresBuild: true + dev: false optional: true /@swc/core/1.3.32: @@ -7682,6 +7692,7 @@ packages: '@swc/core-win32-arm64-msvc': 1.3.80 '@swc/core-win32-ia32-msvc': 1.3.80 '@swc/core-win32-x64-msvc': 1.3.80 + dev: false /@swc/helpers/0.4.14: resolution: {integrity: sha512-4C7nX/dvpzB7za4Ql9K81xK3HPxCpHMgwTZVyf+9JQ6VUbn9jjZVN7/Nkdz/Ugzs2CSjqnL/UPXroiVBVHUWUw==} @@ -7696,6 +7707,7 @@ packages: /@swc/types/0.1.4: resolution: {integrity: sha512-z/G02d+59gyyUb7KYhKi9jOhicek6QD2oMaotUyG+lUkybpXoV49dY9bj7Ah5Q+y7knK2jU67UTX9FyfGzaxQg==} + dev: false /@szmarczak/http-timer/1.1.2: resolution: {integrity: sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==} @@ -8162,6 +8174,7 @@ packages: '@types/prop-types': 15.7.5 '@types/scheduler': 0.16.2 csstype: 3.1.1 + dev: true /@types/react/18.0.28: resolution: {integrity: sha512-RD0ivG1kEztNBdoAK7lekI9M+azSnitIn85h4iOiaLjaTrMjzslhaqCGaI4IyCJ1RljWiLCEu4jyrLLgqxBTew==} @@ -10436,8 +10449,8 @@ packages: engines: {node: '>=10'} hasBin: true dependencies: - JSONStream: 1.3.5 is-text-path: 1.0.1 + JSONStream: 1.3.5 lodash: 4.17.21 meow: 8.1.2 split2: 3.2.2 @@ -10467,6 +10480,7 @@ packages: resolution: {integrity: sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==} dependencies: is-what: 3.14.1 + dev: false /copy-text-to-clipboard/3.0.1: resolution: {integrity: sha512-rvVsHrpFcL4F2P8ihsoLdFHmd404+CMg71S756oRSeQgqk51U3kicGdnvfkrxva0xXH92SjGS62B0XIJsbh+9Q==} @@ -11672,6 +11686,7 @@ packages: requiresBuild: true dependencies: prr: 1.0.1 + dev: false optional: true /error-ex/1.3.2: @@ -14045,6 +14060,7 @@ packages: engines: {node: '>=0.10.0'} hasBin: true requiresBuild: true + dev: false optional: true /image-size/1.0.2: @@ -14558,6 +14574,7 @@ packages: /is-what/3.14.1: resolution: {integrity: sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==} + dev: false /is-whitespace-character/1.0.4: resolution: {integrity: sha512-SDweEzfIZM0SJV0EUga669UTKlmL0Pq8Lno0QDQsPnvECB3IM2aP0gdx5TrU0A01MAPfViaZiI2V1QMZLaKK5w==} @@ -15839,6 +15856,7 @@ packages: source-map: 0.6.1 transitivePeerDependencies: - supports-color + dev: false /leven/3.1.0: resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} @@ -16142,6 +16160,7 @@ packages: dependencies: pify: 4.0.1 semver: 5.7.1 + dev: false optional: true /make-dir/3.1.0: @@ -16537,6 +16556,7 @@ packages: sax: 1.2.4 transitivePeerDependencies: - supports-color + dev: false optional: true /negotiator/0.6.3: @@ -16989,6 +17009,7 @@ packages: /parse-node-version/1.0.1: resolution: {integrity: sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==} engines: {node: '>= 0.10'} + dev: false /parse-numeric-range/1.3.0: resolution: {integrity: sha512-twN+njEipszzlMJd4ONUYgSfZPDxgHhT9Ahed5uTigpQn90FggW4SA/AIPq/6a149fTbE9qBEcSwE3FAEp6wQQ==} @@ -18630,6 +18651,7 @@ packages: nanoid: 3.3.4 picocolors: 1.0.0 source-map-js: 1.0.2 + dev: false /postcss/8.4.21: resolution: {integrity: sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==} @@ -18787,6 +18809,7 @@ packages: /prr/1.0.1: resolution: {integrity: sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==} + dev: false optional: true /pseudomap/1.0.2: @@ -19927,12 +19950,6 @@ packages: /react-dev-utils/12.0.1_rggdtlzfqxxwxudp3onsqdyocm: resolution: {integrity: sha512-84Ivxmr17KjUupyqzFode6xKhjwuEJDROWKJy/BthkL7Wn6NJ8h4WE6k/exAv6ImS+0oZLRRW5j/aINMHyeGeQ==} engines: {node: '>=14'} - peerDependencies: - typescript: '>=2.7' - webpack: '>=4' - peerDependenciesMeta: - typescript: - optional: true dependencies: '@babel/code-frame': 7.18.6 address: 1.2.2 @@ -19963,7 +19980,9 @@ packages: transitivePeerDependencies: - eslint - supports-color + - typescript - vue-template-compiler + - webpack /react-dom/17.0.2_react@17.0.2: resolution: {integrity: sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==} @@ -19974,6 +19993,7 @@ packages: object-assign: 4.1.1 react: 17.0.2 scheduler: 0.20.2 + dev: false /react-dom/18.2.0_react@18.2.0: resolution: {integrity: sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==} @@ -20181,12 +20201,12 @@ packages: '@remix-run/router': 1.7.2 react: 18.2.0 - /react-server-dom-webpack/18.3.0-canary-9b4f847d9-20230901_biqbaboplfbrettd7655fr4n2y: - resolution: {integrity: sha512-eTcOkbT+ZiZK7TDfQADQZoX3cv5JZFMKUaHJLkdQYXGyE3BHcn8tuZ3IK9CGX61SQ82J+X1+fZ1RyZDSvutaCA==} + /react-server-dom-webpack/18.3.0-canary-627b7abd6-20230911_biqbaboplfbrettd7655fr4n2y: + resolution: {integrity: sha512-Nv2QERdglsfbW9cUBhzMsWmCvF58B7fc4xKy++l4UEwLxqgWLkuF8y3Cqc4xyt1A6hoalz3qV8c5HUMf1XgLXw==} engines: {node: '>=0.10.0'} peerDependencies: - react: 18.3.0-canary-9b4f847d9-20230901 - react-dom: 18.3.0-canary-9b4f847d9-20230901 + react: 18.3.0-canary-627b7abd6-20230911 + react-dom: 18.3.0-canary-627b7abd6-20230911 webpack: ^5.59.0 dependencies: acorn-loose: 8.3.0 @@ -20244,6 +20264,7 @@ packages: dependencies: loose-envify: 1.4.0 object-assign: 4.1.1 + dev: false /react/18.2.0: resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==} @@ -20875,6 +20896,7 @@ packages: dependencies: loose-envify: 1.4.0 object-assign: 4.1.1 + dev: false /scheduler/0.21.0: resolution: {integrity: sha512-1r87x5fz9MXqswA2ERLo0EbOAU74DpIUO090gIasYTqlVoJeMcl+Z1Rg7WHz+qtPujhS/hGIt9kxZOYBV3faRQ==} @@ -21955,6 +21977,7 @@ packages: serialize-javascript: 6.0.1 terser: 5.14.2 webpack: 5.76.0_yt3h3qjhcnsf3663codtuni62a + dev: false /terser-webpack-plugin/5.3.5_muqrkd6dqvsxxmw22vfpzybwpe: resolution: {integrity: sha512-AOEDLDxD2zylUGf/wxHxklEkOe2/r+seuyOWujejFrIxHf11brA1/dWQNIgXa1c6/Wkxgu7zvv0JhOWfc2ELEA==} @@ -22104,6 +22127,7 @@ packages: serialize-javascript: 6.0.1 terser: 5.16.5 webpack: 5.88.2_yt3h3qjhcnsf3663codtuni62a + dev: true /terser-webpack-plugin/5.3.7_webpack@5.88.2: resolution: {integrity: sha512-AfKwIktyP7Cu50xNjXF/6Qb5lBNzYaWpU6YfoX3uZicTx0zTy0stDDCsvjDapKsSDvOeWo5MEq4TmdBy2cNoHw==} @@ -23754,6 +23778,7 @@ packages: - '@swc/core' - esbuild - uglify-js + dev: false /webpack/5.86.0_esbuild@0.17.16: resolution: {integrity: sha512-3BOvworZ8SO/D4GVP+GoRC3fVeg5MO4vzmq8TJJEkdmopxyazGDxN8ClqN12uzrZW9Tv8EED8v5VSb6Sqyi0pg==} @@ -23912,6 +23937,7 @@ packages: - '@swc/core' - esbuild - uglify-js + dev: true /webpackbar/5.0.2_webpack@5.88.2: resolution: {integrity: sha512-BmFJo7veBDgQzfWXl/wwYXr/VFus0614qZ8i9znqcl9fnEdiVkdbi0TedLQ6xAK92HZHDJ0QmyQ0fmuZPAgCYQ==} From a8a18ebc8c730a537253c9005581443fa3c1ef0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B0=B4=E6=BE=9C?= <shuilan.cj@taobao.com> Date: Mon, 18 Sep 2023 17:37:56 +0800 Subject: [PATCH 06/17] feat: rsc refresh (#6532) * feat: refresh * refactor: refresh api --- .../src/components/RefreshButton.client.tsx | 19 ++++++ examples/with-rsc/src/pages/about.tsx | 26 ++++++++ packages/runtime/src/index.ts | 4 +- packages/runtime/src/runRSCClientApp.tsx | 61 +++++++++++++++---- 4 files changed, 96 insertions(+), 14 deletions(-) create mode 100644 examples/with-rsc/src/components/RefreshButton.client.tsx create mode 100644 examples/with-rsc/src/pages/about.tsx diff --git a/examples/with-rsc/src/components/RefreshButton.client.tsx b/examples/with-rsc/src/components/RefreshButton.client.tsx new file mode 100644 index 0000000000..643ec10bbf --- /dev/null +++ b/examples/with-rsc/src/components/RefreshButton.client.tsx @@ -0,0 +1,19 @@ +'use client'; +import { useRefresh } from '@ice/runtime'; + +export default function Button({ children }) { + const refresh = useRefresh(); + + return ( + <button + className={[ + 'edit-button', + 'edit-button--solid', + ].join(' ')} + onClick={() => refresh()} + role="menuitem" + > + {children} + </button> + ); +} diff --git a/examples/with-rsc/src/pages/about.tsx b/examples/with-rsc/src/pages/about.tsx new file mode 100644 index 0000000000..b9a1859c37 --- /dev/null +++ b/examples/with-rsc/src/pages/about.tsx @@ -0,0 +1,26 @@ +import { useAppContext } from 'ice'; +import styles from './index.module.css'; +import RefreshButton from '@/components/RefreshButton.client'; +import Counter from '@/components/Counter.client'; + +if (!global.requestCount) { + global.requestCount = 0; +} + +export default function Home() { + console.log('Render: Index'); + + const appContext = useAppContext(); + console.log(appContext); + + return ( + <div className={styles.app}> + <h2>About Page</h2> + <div>server request count: { global.requestCount++ }</div> + <Counter /> + <RefreshButton> + Refresh Button + </RefreshButton> + </div> + ); +} diff --git a/packages/runtime/src/index.ts b/packages/runtime/src/index.ts index 2a618bfa4f..9b09642ac8 100644 --- a/packages/runtime/src/index.ts +++ b/packages/runtime/src/index.ts @@ -26,8 +26,7 @@ import type { RunClientAppOptions, CreateRoutes } from './runClientApp.js'; import { useAppContext as useInternalAppContext, useAppData, AppContextProvider } from './AppContext.js'; import { getAppData } from './appData.js'; import { useData, useConfig } from './RouteContext.js'; -import { runRSCClientApp } from './runRSCClientApp.js'; - +import { runRSCClientApp, useRefresh } from './runRSCClientApp.js'; import { Meta, Title, @@ -146,6 +145,7 @@ export { RouteErrorComponent, runRSCClientApp, + useRefresh, }; export type { diff --git a/packages/runtime/src/runRSCClientApp.tsx b/packages/runtime/src/runRSCClientApp.tsx index 14b0ece3a7..b9fe82d8e5 100644 --- a/packages/runtime/src/runRSCClientApp.tsx +++ b/packages/runtime/src/runRSCClientApp.tsx @@ -3,24 +3,61 @@ import * as ReactDOM from 'react-dom/client'; import pkg from 'react-server-dom-webpack/client'; // @ts-ignore -const { Suspense, use } = React; +const { Suspense, use, useState, createContext, useContext, startTransition } = React; const { createFromFetch } = pkg; export async function runRSCClientApp() { - function App({ response }) { - return ( - <Suspense fallback={<h1>Loading...</h1>}> - {use(response)} - </Suspense> + const container = document.getElementById('app'); + const root = ReactDOM.createRoot(container); + root.render(<Root />); +} + +function Root() { + return ( + <Router /> + ); +} + +const RouterContext = createContext(null); +const initialCache = new Map(); + +function Router() { + const [cache, setCache] = useState(initialCache); + const [location, setLocation] = useState(window.location.href); + + let content = cache.get(location); + if (!content) { + content = createFromFetch( + getReactTree(location), ); + cache.set(location, content); + } + + function refresh() { + startTransition(() => { + const nextCache = new Map(); + const nextContent = createFromFetch( + getReactTree(location), + ); + nextCache.set(location, nextContent); + setCache(nextCache); + }); } - const rscPath = location.href + (location.href.indexOf('?') ? '?rsc' : '&rsc'); - const response = createFromFetch( - fetch(rscPath), + return ( + <RouterContext.Provider value={{ location, refresh }}> + <Suspense fallback={<h1>Loading...</h1>}> + {use(content)} + </Suspense> + </RouterContext.Provider> ); +} - const container = document.getElementById('app'); - const root = ReactDOM.createRoot(container); - root.render(<App response={response} />); +export function useRefresh() { + const router = useContext(RouterContext); + return router.refresh; +} + +function getReactTree(location) { + return fetch(location + location.indexOf('?') ? '?rsc' : '&rsc'); } \ No newline at end of file From 930d5b7ea75f2480a27eda01ba5229455a86549e Mon Sep 17 00:00:00 2001 From: ClarkXia <xiawenwu41@gmail.com> Date: Fri, 22 Sep 2023 13:33:56 +0800 Subject: [PATCH 07/17] feat: support rsc transform by swc plugin (#6538) * feat: support rsc transform by swc plugin * chore: add async component demo * fix: lint --- examples/with-rsc/src/components/Comments.tsx | 10 +- examples/with-rsc/src/pages/index.tsx | 6 + packages/bundles/package.json | 3 +- packages/bundles/src/index.ts | 6 + packages/bundles/webpack/bundle.js | 2 + .../webpack/packages/ModuleDependency.js | 1 + .../webpack/packages/NullDependency.js | 1 + .../src/bundler/webpack/getWebpackConfig.ts | 13 +- packages/ice/src/esbuild/rscServerRegister.ts | 27 -- packages/ice/src/plugins/web/index.ts | 1 + packages/ice/src/service/serverCompiler.ts | 2 - .../ice/src/webpack/FlightManifestPlugin.ts | 340 ++++++++++++++++++ .../shared-config/src/getCompilerPlugins.ts | 3 + packages/shared-config/src/types.ts | 2 + .../src/unPlugins/compilation.ts | 17 +- packages/webpack-config/src/index.ts | 3 + pnpm-lock.yaml | 204 +++++------ 17 files changed, 480 insertions(+), 161 deletions(-) create mode 100644 packages/bundles/webpack/packages/ModuleDependency.js create mode 100644 packages/bundles/webpack/packages/NullDependency.js delete mode 100644 packages/ice/src/esbuild/rscServerRegister.ts create mode 100644 packages/ice/src/webpack/FlightManifestPlugin.ts diff --git a/examples/with-rsc/src/components/Comments.tsx b/examples/with-rsc/src/components/Comments.tsx index 97f3cab4c5..616b32df3f 100644 --- a/examples/with-rsc/src/components/Comments.tsx +++ b/examples/with-rsc/src/components/Comments.tsx @@ -1,7 +1,5 @@ -import { useSuspenseData, withSuspense } from 'ice'; - -function Comments() { - const comments = useSuspenseData(getData); +async function Comments() { + const comments = await getData(); console.log('Render: Comments'); @@ -16,7 +14,7 @@ function Comments() { ); } -export default withSuspense(Comments); +export default Comments; const fakeData = [ "Wait, it doesn't wait for React to load?", @@ -32,4 +30,4 @@ async function getData() { }); return fakeData; -} \ No newline at end of file +} diff --git a/examples/with-rsc/src/pages/index.tsx b/examples/with-rsc/src/pages/index.tsx index 0305d82e97..2f951e4ba0 100644 --- a/examples/with-rsc/src/pages/index.tsx +++ b/examples/with-rsc/src/pages/index.tsx @@ -1,7 +1,9 @@ +import { Suspense } from 'react'; import { useAppContext } from 'ice'; import styles from './index.module.css'; import EditButton from '@/components/EditButton.client'; import Counter from '@/components/Counter.client'; +import Comments from '@/components/Comments'; export default function Home() { console.log('Render: Index'); @@ -13,6 +15,10 @@ export default function Home() { <div className={styles.app}> <h2>Home Page</h2> <Counter /> + <Suspense fallback={<>loading</>}> + {/* @ts-ignore */} + <Comments /> + </Suspense> <EditButton noteId="editButton"> hello world </EditButton> diff --git a/packages/bundles/package.json b/packages/bundles/package.json index 85536b0375..ee9a256ef0 100644 --- a/packages/bundles/package.json +++ b/packages/bundles/package.json @@ -15,10 +15,11 @@ "main": "./esm/index.js", "type": "module", "dependencies": { - "@swc/core": "1.3.80", + "@swc/core": "1.3.85", "@ice/swc-plugin-remove-export": "0.2.0", "@ice/swc-plugin-keep-export": "0.2.0", "@ice/swc-plugin-node-transform": "0.2.0", + "@ice/swc-plugin-react-server-component": "0.1.1", "ansi-html-community": "^0.0.8", "html-entities": "^2.3.2", "core-js": "3.32.0", diff --git a/packages/bundles/src/index.ts b/packages/bundles/src/index.ts index 4cc767dd61..d6ac73e769 100644 --- a/packages/bundles/src/index.ts +++ b/packages/bundles/src/index.ts @@ -7,11 +7,14 @@ import swc from '@swc/core'; import esbuild from 'esbuild'; import * as caniuseLite from 'caniuse-lite'; import { getCssModulesLocalIdent } from '@ice/css-modules-hash'; +import asyncLib from 'neo-async'; +import * as acorn from 'acorn-loose'; const require = createRequire(import.meta.url); const swcPluginRemoveExport = require.resolve('@ice/swc-plugin-remove-export'); const swcPluginKeepExport = require.resolve('@ice/swc-plugin-keep-export'); const swcPluginNodeTransform = require.resolve('@ice/swc-plugin-node-transform'); +const swcPluginReactServerComponent = require.resolve('@ice/swc-plugin-react-server-component'); const coreJsPath = dirname(require.resolve('core-js/package.json')); export { postcss, @@ -22,12 +25,15 @@ export { swcPluginRemoveExport, swcPluginKeepExport, swcPluginNodeTransform, + swcPluginReactServerComponent, coreJsPath, esbuild, caniuseLite, getCssModulesLocalIdent, + asyncLib, + acorn, }; export type { ProcessOptions } from 'postcss'; diff --git a/packages/bundles/webpack/bundle.js b/packages/bundles/webpack/bundle.js index 4b9bfbb841..b65e9f5542 100644 --- a/packages/bundles/webpack/bundle.js +++ b/packages/bundles/webpack/bundle.js @@ -13,6 +13,8 @@ module.exports = { StringXor: require('webpack/lib/util/StringXor'), NormalModule: require('webpack/lib/NormalModule'), EntryDependency: require('webpack/lib/dependencies/EntryDependency'), + ModuleDependency: require('webpack/lib/dependencies/ModuleDependency'), + NullDependency: require('webpack/lib/dependencies/NullDependency'), sources: require('webpack').sources, webpack: require('webpack'), package: { diff --git a/packages/bundles/webpack/packages/ModuleDependency.js b/packages/bundles/webpack/packages/ModuleDependency.js new file mode 100644 index 0000000000..8b970cbad1 --- /dev/null +++ b/packages/bundles/webpack/packages/ModuleDependency.js @@ -0,0 +1 @@ +module.exports = require('./bundle').ModuleDependency; diff --git a/packages/bundles/webpack/packages/NullDependency.js b/packages/bundles/webpack/packages/NullDependency.js new file mode 100644 index 0000000000..910cb4ea23 --- /dev/null +++ b/packages/bundles/webpack/packages/NullDependency.js @@ -0,0 +1 @@ +module.exports = require('./bundle').NullDependency; diff --git a/packages/ice/src/bundler/webpack/getWebpackConfig.ts b/packages/ice/src/bundler/webpack/getWebpackConfig.ts index 03e5d9116b..c0e7843198 100644 --- a/packages/ice/src/bundler/webpack/getWebpackConfig.ts +++ b/packages/ice/src/bundler/webpack/getWebpackConfig.ts @@ -1,9 +1,8 @@ -import path from 'path'; import webpack from '@ice/bundles/compiled/webpack/index.js'; import lodash from '@ice/bundles/compiled/lodash/index.js'; import { getWebpackConfig as getDefaultWebpackConfig } from '@ice/webpack-config'; import type { Configuration } from 'webpack'; -import ReactServerWebpackPlugin from '@ice/bundles/compiled/react-server-dom-webpack/plugin.js'; +import { FlightManifestPlugin } from '../../webpack/FlightManifestPlugin.js'; import { getExpandedEnvs } from '../../utils/runtimeEnv.js'; import { getRouteExportConfig } from '../../service/config.js'; import { getFileHash } from '../../utils/hash.js'; @@ -119,15 +118,7 @@ const getWebpackConfig: GetWebpackConfig = async (context, options) => { // Add spinner for webpack task. webpackConfig.plugins.push(getSpinnerPlugin(spinner)); if (userConfig.rsc) { - webpackConfig.plugins.push(new ReactServerWebpackPlugin({ - isServer: false, - clientReferences: [{ - directory: path.join(rootDir, 'src'), - recursive: true, - include: /\.(js|ts|jsx|tsx)$/, - exclude: /types.ts|.d.ts/, - }], - })); + webpackConfig.plugins.push(new FlightManifestPlugin()); } return webpackConfig; diff --git a/packages/ice/src/esbuild/rscServerRegister.ts b/packages/ice/src/esbuild/rscServerRegister.ts deleted file mode 100644 index ff90045b6d..0000000000 --- a/packages/ice/src/esbuild/rscServerRegister.ts +++ /dev/null @@ -1,27 +0,0 @@ -import url from 'url'; -import type { Plugin, PluginBuild } from 'esbuild'; - -const rscServerRegister = (): Plugin => { - return { - name: 'rsc-server-register', - setup: async (build: PluginBuild) => { - build.onLoad({ filter: /\/src\/.*\.client\.(js|ts|jsx|tsx)$/ }, async (args) => { // /src\/.*\ - const { path } = args; - const loader = path.endsWith('.tsx') || path.endsWith('.ts') ? 'tsx' : 'jsx'; - const moduleId: string = url.pathToFileURL(path).href; - let source = 'const Server: any = require(\'react-server-dom-webpack/server.node\');const createClientModuleProxy = Server.createClientModuleProxy;'; - source += transformContent(moduleId); - return { contents: source, loader }; - }); - }, - }; -}; - -function transformContent(moduleId: string) { - const content = `\ - const comp = createClientModuleProxy('${moduleId}'); - module.exports = comp`; - return content; -} - -export default rscServerRegister; \ No newline at end of file diff --git a/packages/ice/src/plugins/web/index.ts b/packages/ice/src/plugins/web/index.ts index 805f7cf3c5..e8256fdf8d 100644 --- a/packages/ice/src/plugins/web/index.ts +++ b/packages/ice/src/plugins/web/index.ts @@ -45,6 +45,7 @@ const plugin: Plugin = () => ({ swcOptions: { removeExportExprs, }, + serverComponent: userConfig.rsc, ...(userConfig.rsc ? { alias: createRSCAliases(), // TODO: temporary solution for rsc. diff --git a/packages/ice/src/service/serverCompiler.ts b/packages/ice/src/service/serverCompiler.ts index f20160b4ca..ba8af7fc46 100644 --- a/packages/ice/src/service/serverCompiler.ts +++ b/packages/ice/src/service/serverCompiler.ts @@ -23,7 +23,6 @@ import formatPath from '../utils/formatPath.js'; import { createLogger } from '../utils/logger.js'; import { getExpandedEnvs } from '../utils/runtimeEnv.js'; import getCSSModuleIdent from '../utils/getCSSModuleIdent.js'; -import rscServerRegister from '../esbuild/rscServerRegister.js'; import { scanImports } from './analyze.js'; import type { PreBundleDepsMetaData } from './preBundleDeps.js'; import preBundleDeps from './preBundleDeps.js'; @@ -215,7 +214,6 @@ export function createServerCompiler(options: Options) { externals: server.externals, }), server?.ignores && ignorePlugin(server.ignores), - rscServerRegister(), cssModulesPlugin({ extract: false, generateLocalIdentName: function (name: string, fileName: string) { diff --git a/packages/ice/src/webpack/FlightManifestPlugin.ts b/packages/ice/src/webpack/FlightManifestPlugin.ts new file mode 100644 index 0000000000..49cab9afea --- /dev/null +++ b/packages/ice/src/webpack/FlightManifestPlugin.ts @@ -0,0 +1,340 @@ +// Fork form https://github.com/facebook/react/blob/main/packages/react-server-dom-webpack/src/ReactFlightWebpackPlugin.js +// Add special handling for ice.js when enable RSC. +import * as path from 'path'; +import { asyncLib, acorn } from '@ice/bundles'; +import ModuleDependency from '@ice/bundles/compiled/webpack/ModuleDependency.js'; +import NullDependency from '@ice/bundles/compiled/webpack/NullDependency.js'; +import webpack from '@ice/bundles/compiled/webpack/index.js'; +import type { Compiler, Compilation } from 'webpack'; + +const PLUGIN_NAME = 'FlightManifestPlugin'; + +interface ClientReferenceSearchPath { + directory: string; + recursive?: boolean; + include: RegExp; + exclude?: RegExp; +} + +interface Options { + clientReferences?: ClientReferenceSearchPath[]; + chunkName?: string; + clientManifestFilename?: string; + ssrManifestFilename?: string; +} + +interface SSRExports { + [chunkName: string]: { specifier: string; name: string }; +} + +class ClientReferenceDependency extends ModuleDependency { + userRequest: string; + request: string; + + constructor(request: string) { + super(request); + this.request = request; + } + get type(): string { + return 'client-reference'; + } +} +// Webpack template utils of toPath. +const PATH_NAME_NORMALIZE_REPLACE_REGEX = /[^a-zA-Z0-9_!§$()=\-^°]+/g; +const MATCH_PADDED_HYPHENS_REPLACE_REGEX = /^-|-$/g; +const toPath = (str: any) => { + if (typeof str !== 'string') return ''; + return str + .replace(PATH_NAME_NORMALIZE_REPLACE_REGEX, '-') + .replace(MATCH_PADDED_HYPHENS_REPLACE_REGEX, ''); +}; + +export class FlightManifestPlugin { + clientReferences: ClientReferenceSearchPath[]; + chunkName?: string; + clientManifestFilename?: string; + ssrManifestFilename?: string; + + constructor(options: Options = {}) { + if (options.clientReferences) { + this.clientReferences = options.clientReferences; + } else { + this.clientReferences = [ + { + directory: '.', + recursive: true, + include: /\.(js|ts|jsx|tsx)$/, + exclude: /types.ts|.d.ts|node_modules/, + }, + ]; + } + if (typeof options.chunkName === 'string') { + this.chunkName = options.chunkName; + if (!/\[(index|request)\]/.test(this.chunkName)) { + this.chunkName += '[index]'; + } + } else { + this.chunkName = 'client[index]'; + } + this.clientManifestFilename = + options.clientManifestFilename || 'react-client-manifest.json'; + this.ssrManifestFilename = + options.ssrManifestFilename || 'react-ssr-manifest.json'; + } + + apply(compiler: Compiler) { + const _this = this; + let resolvedClientReferences: ClientReferenceDependency[]; + let clientFileNameFound = false; + + compiler.hooks.beforeCompile.tapAsync(PLUGIN_NAME, ({ contextModuleFactory }, callback) => { + const contextResolver = compiler.resolverFactory.get('context', {}); + const normalResolver = compiler.resolverFactory.get('normal'); + + _this.resolveClientFiles( + compiler.context, + contextResolver, + normalResolver, + compiler.inputFileSystem, + contextModuleFactory, + (err, resolvedClientRefs) => { + if (err) { + callback(err); + return; + } + resolvedClientReferences = resolvedClientRefs; + callback(); + }, + ); + }); + + compiler.hooks.thisCompilation.tap(PLUGIN_NAME, (compilation, { normalModuleFactory }) => { + // @ts-expect-error TODO: add types for ModuleDependency. + compilation.dependencyFactories.set(ClientReferenceDependency, normalModuleFactory); + // @ts-expect-error TODO: add types for ModuleDependency. + compilation.dependencyTemplates.set(ClientReferenceDependency, new NullDependency.Template()); + + const handler = (parser) => { + parser.hooks.program.tap(PLUGIN_NAME, () => { + const { module } = parser.state; + if (!module.resource.includes('react-server-dom-webpack/client.browser')) { + return; + } + clientFileNameFound = true; + if (resolvedClientReferences) { + if (resolvedClientReferences) { + for (let i = 0; i < resolvedClientReferences.length; i++) { + const dep = resolvedClientReferences[i]; + + const chunkName = _this.chunkName + .replace(/\[index\]/g, `${i}`) + .replace(/\[request\]/g, toPath(dep.userRequest)); + + const block = new webpack.AsyncDependenciesBlock( + { + name: chunkName, + }, + null, + dep.request, + ); + // @ts-expect-error TODO: add types for ModuleDependency. + block.addDependency(dep); + module.addBlock(block); + } + } + } + }); + }; + + normalModuleFactory.hooks.parser.for('javascript/auto').tap('HarmonyModulesPlugin', handler); + normalModuleFactory.hooks.parser.for('javascript/esm').tap('HarmonyModulesPlugin', handler); + normalModuleFactory.hooks.parser.for('javascript/dynamic').tap('HarmonyModulesPlugin', handler); + }); + + compiler.hooks.make.tap(PLUGIN_NAME, (compilation) => { + compilation.hooks.processAssets.tap({ + name: PLUGIN_NAME, + stage: webpack.Compilation.PROCESS_ASSETS_STAGE_REPORT, + }, () => { + if (clientFileNameFound === false) { + compilation.warnings.push( + // @ts-expect-error mismatch import path of webpack. + new webpack.WebpackError( + `Client runtime at 'react-server-dom-webpack/client' was not found. React Server Components module map file ${_this.clientManifestFilename} was not created.`, + ), + ); + return; + } + + const resolveClientFiles = new Set((resolvedClientReferences || []).map((dep) => dep.request)); + const clientManifest: { [key: string]: { + chunks: (string | number)[]; + id: string | number; + name: string; + };} = {}; + const ssrManifest: { + [key: string]: SSRExports; + } = {}; + + compilation.chunkGroups.forEach((chunkGroup) => { + const chunkIds = chunkGroup.chunks.map((chunk) => chunk.id); + const recordModule = (id: string | number, module: any) => { + if (!resolveClientFiles.has(module.resource)) { + return; + } + // const modId = path.relative(compiler.context, module.resource); + const modId = module.resource; + if (modId !== undefined) { + clientManifest[modId] = { + id, + chunks: chunkIds, + name: '*', + }; + // TODO: If this module ends up split into multiple modules, then + // we should encode each the chunks needed for the specific export. + // When the module isn't split, it doesn't matter and we can just + // encode the id of the whole module. This code doesn't currently + // deal with module splitting so is likely broken from ESM anyway. + ssrManifest[id] = { + '*': { + specifier: modId, + name: '*', + }, + }; + } + }; + + chunkGroup.chunks.forEach((chunk) => { + const chunkModules = compilation.chunkGraph.getChunkModulesIterable(chunk); + [...chunkModules].forEach((module) => { + const moduleId = compilation.chunkGraph.getModuleId(module); + recordModule(moduleId, module); + // If this is a concatenation, register each child to the parent ID. + // @ts-expect-error + if (module.modules) { + // @ts-expect-error + module.modules.forEach(concatenatedMod => { + recordModule(moduleId, concatenatedMod); + }); + } + }); + }); + }); + const clientOutput = JSON.stringify(clientManifest, null, 2); + compilation.emitAsset( + _this.clientManifestFilename, + new webpack.sources.RawSource(clientOutput, false), + ); + const ssrOutput = JSON.stringify(ssrManifest, null, 2); + compilation.emitAsset( + _this.ssrManifestFilename, + new webpack.sources.RawSource(ssrOutput, false), + ); + }); + }); + } + + resolveClientFiles( + context: string, + contenxtResolver: ReturnType<Compiler['resolverFactory']['get']>, + normalResolver: ReturnType<Compiler['resolverFactory']['get']>, + fs: Compilation['inputFileSystem'], + contextModuleFactory: Compilation['params']['contextModuleFactory'], + callback: (err: Error | null, files?: ClientReferenceDependency[]) => void, + ) { + function hasUseClientDirective(source: string): boolean { + if (source.indexOf('use client') === -1) { + return false; + } + let body; + try { + // TODO: check client directive by comment injected by swc plugin. + body = acorn.parse(source, { + ecmaVersion: '2024', + sourceType: 'module', + }).body; + } catch (x) { + return false; + } + for (let i = 0; i < body.length; i++) { + const node = body[i]; + if (node.type !== 'ExpressionStatement' || !node.directive) { + break; + } + if (node.directive === 'use client') { + return true; + } + } + return false; + } + asyncLib.map(this.clientReferences, ( + clientReference: ClientReferenceSearchPath, + cb: (err: null | Error, result?: ClientReferenceDependency[]) => void, + ) => { + contenxtResolver.resolve({}, context, clientReference.directory, {}, (err, resolvedDirectory) => { + if (err) return cb(err); + const options = { + resource: resolvedDirectory, + resourceQuery: '', + recursive: + clientReference.recursive === undefined + ? true + : clientReference.recursive, + regExp: clientReference.include, + include: undefined, + exclude: clientReference.exclude, + }; + // @ts-expect-error TODO: add types for resolveDependencies options. + contextModuleFactory.resolveDependencies(fs, options, (err, dependencies) => { + if (err) return cb(err); + const clientRefDeps = dependencies.map(dep => { + // Use userRequest instead of request. request always end with undefined which is wrong. + const request = path.join(resolvedDirectory as string, dep.userRequest); + const clientRefDep = new ClientReferenceDependency(request); + clientRefDep.userRequest = dep.userRequest; + return clientRefDep; + }); + asyncLib.filter( + clientRefDeps, + (dep: ClientReferenceDependency, filterCb: (err: null | Error, truthValue: boolean) => void, + ) => { + normalResolver.resolve( + {}, + context, + dep.request, + {}, + (err: null | Error, resolvedPath: any) => { + if (err || typeof resolvedPath !== 'string') { + return filterCb(null, false); + } + + fs.readFile( + resolvedPath, + 'utf-8', + // @ts-expect-error + (err: null | Error, content: string) => { + if (err || typeof content !== 'string') { + return filterCb(null, false); + } + const useClient = hasUseClientDirective(content); + filterCb(null, useClient); + }, + ); + }, + ); + }, cb); + }); + }); + }, ( + err: null | Error, + result: ClientReferenceDependency[], + ) => { + if (err) return callback(err); + const flat: ClientReferenceDependency[] = []; + for (let i = 0; i < result.length; i++) { + flat.push.apply(flat, result[i]); + } + callback(null, flat); + }); + } +} diff --git a/packages/shared-config/src/getCompilerPlugins.ts b/packages/shared-config/src/getCompilerPlugins.ts index 0c4a4ac3b9..df00166c8d 100644 --- a/packages/shared-config/src/getCompilerPlugins.ts +++ b/packages/shared-config/src/getCompilerPlugins.ts @@ -47,6 +47,7 @@ function getCompilerPlugins(rootDir: string, config: Config, compiler: Compiler, polyfill, enableEnv, getRoutesFile, + serverComponent, } = config; const compilerPlugins = []; @@ -71,6 +72,8 @@ function getCompilerPlugins(rootDir: string, config: Config, compiler: Compiler, polyfill, enableEnv, getRoutesFile, + serverComponent, + isServer: true, })); } diff --git a/packages/shared-config/src/types.ts b/packages/shared-config/src/types.ts index d5fa8e3942..e786cfa5ab 100644 --- a/packages/shared-config/src/types.ts +++ b/packages/shared-config/src/types.ts @@ -193,4 +193,6 @@ export interface Config { useDevServer?: boolean; useDataLoader?: boolean; + + serverComponent?: boolean; } diff --git a/packages/shared-config/src/unPlugins/compilation.ts b/packages/shared-config/src/unPlugins/compilation.ts index 43b9729705..0e3c142377 100644 --- a/packages/shared-config/src/unPlugins/compilation.ts +++ b/packages/shared-config/src/unPlugins/compilation.ts @@ -1,5 +1,5 @@ import path from 'path'; -import { swc, swcPluginRemoveExport, swcPluginKeepExport, swcPluginNodeTransform, coreJsPath, caniuseLite } from '@ice/bundles'; +import { swc, swcPluginRemoveExport, swcPluginKeepExport, swcPluginNodeTransform, swcPluginReactServerComponent, coreJsPath, caniuseLite } from '@ice/bundles'; import browserslist from 'browserslist'; import consola from 'consola'; import type { SwcConfig, ReactConfig } from '@ice/bundles'; @@ -24,6 +24,8 @@ interface Options { polyfill?: Config['polyfill']; enableEnv?: boolean; getRoutesFile?: () => string[]; + serverComponent?: boolean; + isServer?: boolean; } const formatId = (id: string) => id.split(path.sep).join('/'); @@ -44,6 +46,8 @@ const compilationPlugin = (options: Options): UnpluginOptions => { polyfill, enableEnv, getRoutesFile, + serverComponent, + isServer, } = options; const { removeExportExprs, compilationConfig, keepExports, nodeTransform } = swcOptions; @@ -107,6 +111,16 @@ const compilationPlugin = (options: Options): UnpluginOptions => { const swcPlugins = []; + if (serverComponent) { + swcPlugins.push([ + swcPluginReactServerComponent, + { + isServer, + assertImports: false, + }, + ]); + } + // handle app.tsx and page entries only if (removeExportExprs) { if (isRouteEntry(id) || isAppEntry(id)) { @@ -218,7 +232,6 @@ function getJsxTransformOptions({ }, module: { type: 'es6', - noInterop: false, }, }; if (enableEnv) { diff --git a/packages/webpack-config/src/index.ts b/packages/webpack-config/src/index.ts index fe9b9d2081..6a34f857cd 100644 --- a/packages/webpack-config/src/index.ts +++ b/packages/webpack-config/src/index.ts @@ -118,6 +118,7 @@ export function getWebpackConfig(options: GetWebpackConfigOptions): Configuratio enableCopyPlugin, polyfill, enableRpx2Vw = true, + serverComponent, } = config; const absoluteOutputDir = path.isAbsolute(outputDir) ? outputDir : path.join(rootDir, outputDir); const dev = mode !== 'production'; @@ -173,6 +174,8 @@ export function getWebpackConfig(options: GetWebpackConfigOptions): Configuratio polyfill, enableEnv: true, getRoutesFile, + serverComponent, + isServer: false, }); const webpackConfig = { mode, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 81adc393b3..0e466e300c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -918,11 +918,12 @@ importers: '@ice/css-modules-hash': 0.0.6 '@ice/swc-plugin-keep-export': 0.2.0 '@ice/swc-plugin-node-transform': 0.2.0 + '@ice/swc-plugin-react-server-component': 0.1.1 '@ice/swc-plugin-remove-export': 0.2.0 '@pmmmwh/react-refresh-webpack-plugin': 0.5.10 '@rspack/core': 0.3.0 '@rspack/dev-server': 0.3.0 - '@swc/core': 1.3.80 + '@swc/core': 1.3.85 '@types/less': ^3.0.3 '@types/lodash': ^4.14.181 '@types/webpack-bundle-analyzer': ^4.4.1 @@ -1006,10 +1007,11 @@ importers: '@ice/css-modules-hash': 0.0.6 '@ice/swc-plugin-keep-export': 0.2.0 '@ice/swc-plugin-node-transform': 0.2.0 + '@ice/swc-plugin-react-server-component': 0.1.1 '@ice/swc-plugin-remove-export': 0.2.0 '@rspack/core': 0.3.0_zur76qpjdwubwowmoyfe2ntqhe - '@rspack/dev-server': 0.3.0_bioma5hrmjqlc63rjodddzwoma - '@swc/core': 1.3.80 + '@rspack/dev-server': 0.3.0_j26wtsbar5zhggjrhbiiftx5au + '@swc/core': 1.3.85 acorn-loose: 8.3.0 ansi-html-community: 0.0.8 caniuse-lite: 1.0.30001462 @@ -1030,7 +1032,7 @@ importers: '@pmmmwh/react-refresh-webpack-plugin': 0.5.10_ynqbgb5bmgbvx2am6mt2h3lxsq '@types/less': 3.0.3 '@types/lodash': 4.14.191 - '@types/webpack-bundle-analyzer': 4.6.0_yt3h3qjhcnsf3663codtuni62a + '@types/webpack-bundle-analyzer': 4.6.0_pur5qe7dhbhqwjtj2daaog4n7u bonjour-service: 1.1.0 cacache: 17.0.4 colorette: 2.0.19 @@ -1082,11 +1084,11 @@ importers: spdy: 4.0.2 tapable: 2.2.1 terser: 5.14.2 - terser-webpack-plugin: 5.3.5_muqrkd6dqvsxxmw22vfpzybwpe + terser-webpack-plugin: 5.3.5_ghmre4bibzh3hfhoafsn4shpjy trusted-cert: 1.1.3 typescript: 4.9.5 unplugin: 0.9.5_4yjf5voakpkrj4qbnm3gtqjbli - webpack: 5.88.2_yt3h3qjhcnsf3663codtuni62a + webpack: 5.88.2_pur5qe7dhbhqwjtj2daaog4n7u webpack-bundle-analyzer: 4.5.0 webpack-dev-middleware: 5.3.3_webpack@5.88.2 webpack-dev-server: 4.15.0_webpack@5.88.2 @@ -1652,7 +1654,7 @@ importers: '@types/react-dom': 18.0.11 react: 18.2.0 react-dom: 18.2.0_react@18.2.0 - react-server-dom-webpack: 18.3.0-canary-627b7abd6-20230911_biqbaboplfbrettd7655fr4n2y + react-server-dom-webpack: 18.3.0-canary-2807d781a-20230918_biqbaboplfbrettd7655fr4n2y regenerator-runtime: 0.13.11 packages/shared: @@ -5640,6 +5642,10 @@ packages: resolution: {integrity: sha512-06NtOUGVAUKP1eQXGMkaIZpNl9d5RK6SB6xQJsMY/DIso8WnwymyN7hmoFXPzX0eFkhmQEc7jzJ7NDBXaXRqWQ==} dev: false + /@ice/swc-plugin-react-server-component/0.1.1: + resolution: {integrity: sha512-3FdXOZ7HTBHY+DKQXDpzqV10ngfl0ifffc7HFV0P4YPLfvEJjT0RxIZJW1QwRZ3QeB2ph4zvXfdBG1lYTzT58Q==} + dev: false + /@ice/swc-plugin-remove-export/0.2.0: resolution: {integrity: sha512-kmyrCMtuEsS7J3rpENT5qUhhbuu3eldsN1WpJjtXX4rgogJ1+QmnAPjnhB0SWzr0/b5ArGfz83O6M+5NNGRd+A==} dev: false @@ -6407,7 +6413,7 @@ packages: react-refresh: 0.14.0 schema-utils: 3.1.1 source-map: 0.7.4 - webpack: 5.76.0_yt3h3qjhcnsf3663codtuni62a + webpack: 5.76.0_pur5qe7dhbhqwjtj2daaog4n7u webpack-dev-server: 4.13.1_webpack@5.76.0 dev: false @@ -6564,7 +6570,7 @@ packages: react-refresh: 0.14.0 schema-utils: 3.1.1 source-map: 0.7.4 - webpack: 5.88.2_yt3h3qjhcnsf3663codtuni62a + webpack: 5.88.2_pur5qe7dhbhqwjtj2daaog4n7u webpack-dev-server: 4.15.0_webpack@5.88.2 /@polka/url/1.0.0-next.21: @@ -7109,7 +7115,7 @@ packages: - webpack-plugin-serve dev: false - /@rspack/dev-server/0.3.0_bioma5hrmjqlc63rjodddzwoma: + /@rspack/dev-server/0.3.0_j26wtsbar5zhggjrhbiiftx5au: resolution: {integrity: sha512-aKY1mUP1PdOWXDvxpUA14mEE7p+IFYnU67i7cAUh361z2/v5KbCTngt521ly8H1LqJv3SJIoEXqSqNc8c62Dsg==} peerDependencies: '@rspack/core': '*' @@ -7121,7 +7127,7 @@ packages: express: 4.18.1 http-proxy-middleware: 2.0.6 mime-types: 2.1.35 - webpack: 5.76.0_yt3h3qjhcnsf3663codtuni62a + webpack: 5.76.0_pur5qe7dhbhqwjtj2daaog4n7u webpack-dev-middleware: 6.0.2_webpack@5.76.0 webpack-dev-server: 4.13.1_webpack@5.76.0 ws: 8.8.1 @@ -7488,13 +7494,12 @@ packages: dev: true optional: true - /@swc/core-darwin-arm64/1.3.80: - resolution: {integrity: sha512-rhoFTcQMUGfO7IkfOnopPSF6O0/aVJ58B7KueIKbvrMe6YvSfFj9QfObELFjYCcrJZTvUWBhig0QrsfPIiUphA==} + /@swc/core-darwin-arm64/1.3.85: + resolution: {integrity: sha512-jTikp+i4nO4Ofe6qGm4I3sFeebD1OvueBCHITux5tQKD6umN1c2z4CRGv6K49NIz/qEpUcdr6Qny6K+3yibVFQ==} engines: {node: '>=10'} cpu: [arm64] os: [darwin] requiresBuild: true - dev: false optional: true /@swc/core-darwin-x64/1.3.32: @@ -7506,13 +7511,12 @@ packages: dev: true optional: true - /@swc/core-darwin-x64/1.3.80: - resolution: {integrity: sha512-0dOLedFpVXe+ugkKHXsqSxMKqvQYfFtibWbrZ7j8wOaErzSGPr0VpyWvepNVb9s046725kPXSw+fsGhqZR8wrw==} + /@swc/core-darwin-x64/1.3.85: + resolution: {integrity: sha512-3uHYkjVU+2F+YbVYtq5rH0uCJIztFTALaS3mQEfQUZKXZ5/8jD5titTCRqFKtSlQg0CzaFZgsYsuqwYBmgN0mA==} engines: {node: '>=10'} cpu: [x64] os: [darwin] requiresBuild: true - dev: false optional: true /@swc/core-linux-arm-gnueabihf/1.3.32: @@ -7524,13 +7528,12 @@ packages: dev: true optional: true - /@swc/core-linux-arm-gnueabihf/1.3.80: - resolution: {integrity: sha512-QIjwP3PtDeHBDkwF6+ZZqdUsqAhORbMpxrw2jq3mHe4lQrxBttSFTq018vlMRo2mFEorOvXdadzaD9m+NymPrw==} + /@swc/core-linux-arm-gnueabihf/1.3.85: + resolution: {integrity: sha512-ouHzAHsFaEOkRuoTAOI/8n2m8BQAAnb4vr/xbMhhDOmix0lp5eNsW5Iac/EcJ2uG6B3n7P2K8oycj9SWkj+pfw==} engines: {node: '>=10'} cpu: [arm] os: [linux] requiresBuild: true - dev: false optional: true /@swc/core-linux-arm64-gnu/1.3.32: @@ -7542,13 +7545,12 @@ packages: dev: true optional: true - /@swc/core-linux-arm64-gnu/1.3.80: - resolution: {integrity: sha512-cg8WriIueab58ZwkzXmIACnjSzFLzOBwxlC9k65gPXMNgCjab2YbqEYvAbjBqneuqaao02gW6tad2uhjgYaExw==} + /@swc/core-linux-arm64-gnu/1.3.85: + resolution: {integrity: sha512-/Z1CZOWiO+NqJEh1J20PIxQFHMH43upQJ1l7FJ5Z7+MyuYF8WkeJ7OSovau729pBR+38vvvccEJrMZIztfv7hQ==} engines: {node: '>=10'} cpu: [arm64] os: [linux] requiresBuild: true - dev: false optional: true /@swc/core-linux-arm64-musl/1.3.32: @@ -7560,13 +7562,12 @@ packages: dev: true optional: true - /@swc/core-linux-arm64-musl/1.3.80: - resolution: {integrity: sha512-AhdCQ7QKx5mWrtpaOA1mFRiWWvuiiUtspvo0QSpspDetRKTND1rlf/3UB5+gp0kCeCNUTsVmJWU7fIA9ICZtXA==} + /@swc/core-linux-arm64-musl/1.3.85: + resolution: {integrity: sha512-gfh7CfKavi076dbMBTzfdawSGcYfZ4+1Q+8aRkSesqepKHcIWIJti8Cf3zB4a6CHNhJe+VN0Gb7DEfumydAm1w==} engines: {node: '>=10'} cpu: [arm64] os: [linux] requiresBuild: true - dev: false optional: true /@swc/core-linux-x64-gnu/1.3.32: @@ -7578,13 +7579,12 @@ packages: dev: true optional: true - /@swc/core-linux-x64-gnu/1.3.80: - resolution: {integrity: sha512-+2e5oni1vOrLIjM5Q2/GIzK/uS2YEtuJqnjPvCK8SciRJsSl8OgVsRvyCDbmKeZNtJ2Q+o/O2AQ2w1qpAJG6jg==} + /@swc/core-linux-x64-gnu/1.3.85: + resolution: {integrity: sha512-lWVqjHKzofb9q1qrBM4dLqO7CIisp08/xMS5Hz9DWex1gTc5F2b6yJO6Ceqwa256GMweJcdP6A5EvEFQAiZ5dg==} engines: {node: '>=10'} cpu: [x64] os: [linux] requiresBuild: true - dev: false optional: true /@swc/core-linux-x64-musl/1.3.32: @@ -7596,13 +7596,12 @@ packages: dev: true optional: true - /@swc/core-linux-x64-musl/1.3.80: - resolution: {integrity: sha512-8OK9IlI1zpWOm7vIp1iXmZSEzLAwFpqhsGSEhxPavpOx2m54kLFdPcw/Uv3n461f6TCtszIxkGq1kSqBUdfUBA==} + /@swc/core-linux-x64-musl/1.3.85: + resolution: {integrity: sha512-EPJmlfqC05TUetnlErxNRyIp7Nc3B2w9abET6oQ/EgldeAeQnZ3M6svMViET/c2QSomgrU3rdP+Qcozkt62/4A==} engines: {node: '>=10'} cpu: [x64] os: [linux] requiresBuild: true - dev: false optional: true /@swc/core-win32-arm64-msvc/1.3.32: @@ -7614,13 +7613,12 @@ packages: dev: true optional: true - /@swc/core-win32-arm64-msvc/1.3.80: - resolution: {integrity: sha512-RKhatwiAGlffnF6z2Mm3Ddid0v3KB+uf5m/Gc7N9zO/EUAV0PnHRuYuZSGyqodHmGFC+mK8YrCooFCEmHL9n+w==} + /@swc/core-win32-arm64-msvc/1.3.85: + resolution: {integrity: sha512-ibckJDZw8kNosciMexwk0z75ZyUhwtiFMV9rSBpup0opa7NNCUCoERCJ1e9LRyMdhsVUoLpZg/KZiHCdTw96hQ==} engines: {node: '>=10'} cpu: [arm64] os: [win32] requiresBuild: true - dev: false optional: true /@swc/core-win32-ia32-msvc/1.3.32: @@ -7632,13 +7630,12 @@ packages: dev: true optional: true - /@swc/core-win32-ia32-msvc/1.3.80: - resolution: {integrity: sha512-3jiiZzU/kaw7k4zUp1yMq1QiUe4wJVtCEXIhf+fKuBsIwm7rdvyK/+PIx5KHnZy4TGQnYczKBRhJA5nuBcrUCQ==} + /@swc/core-win32-ia32-msvc/1.3.85: + resolution: {integrity: sha512-hY4MpHGUVQHL1T2kgRXOigDho4DTIpVPYzJ4uyy8VQRbS7GzN5XtvdGP/fA4zp8+2BQjcig+6J7Y92SY15ouNQ==} engines: {node: '>=10'} cpu: [ia32] os: [win32] requiresBuild: true - dev: false optional: true /@swc/core-win32-x64-msvc/1.3.32: @@ -7650,13 +7647,12 @@ packages: dev: true optional: true - /@swc/core-win32-x64-msvc/1.3.80: - resolution: {integrity: sha512-2eZtIoIWQBWqykfms92Zd37lveYOBWQTZjdooBGlsLHtcoQLkNpf1NXmR6TKY0yy8q6Yl3OhPvY+izjmO08MSg==} + /@swc/core-win32-x64-msvc/1.3.85: + resolution: {integrity: sha512-ktxWOMFJ0iqKn6WUHtXqi4CS7xkyHmrRtjllGRuGqxmLmDX/HSOfuQ55Tm1KXKk5oHLacJkUbOSF2kBrpZ8dpg==} engines: {node: '>=10'} cpu: [x64] os: [win32] requiresBuild: true - dev: false optional: true /@swc/core/1.3.32: @@ -7676,8 +7672,8 @@ packages: '@swc/core-win32-x64-msvc': 1.3.32 dev: true - /@swc/core/1.3.80: - resolution: {integrity: sha512-yX2xV5I/lYswHHR+44TPvzBgq3/Y8N1YWpTQADYuvSiX3Jxyvemk5Jpx3rRtigYb8WBkWAAf2i5d5ZJ2M7hhgw==} + /@swc/core/1.3.85: + resolution: {integrity: sha512-qnoxp+2O0GtvRdYnXgR1v8J7iymGGYpx6f6yCK9KxipOZOjrlKILFANYlghQxZyPUfXwK++TFxfSlX4r9wK+kg==} engines: {node: '>=10'} requiresBuild: true peerDependencies: @@ -7688,17 +7684,16 @@ packages: dependencies: '@swc/types': 0.1.4 optionalDependencies: - '@swc/core-darwin-arm64': 1.3.80 - '@swc/core-darwin-x64': 1.3.80 - '@swc/core-linux-arm-gnueabihf': 1.3.80 - '@swc/core-linux-arm64-gnu': 1.3.80 - '@swc/core-linux-arm64-musl': 1.3.80 - '@swc/core-linux-x64-gnu': 1.3.80 - '@swc/core-linux-x64-musl': 1.3.80 - '@swc/core-win32-arm64-msvc': 1.3.80 - '@swc/core-win32-ia32-msvc': 1.3.80 - '@swc/core-win32-x64-msvc': 1.3.80 - dev: false + '@swc/core-darwin-arm64': 1.3.85 + '@swc/core-darwin-x64': 1.3.85 + '@swc/core-linux-arm-gnueabihf': 1.3.85 + '@swc/core-linux-arm64-gnu': 1.3.85 + '@swc/core-linux-arm64-musl': 1.3.85 + '@swc/core-linux-x64-gnu': 1.3.85 + '@swc/core-linux-x64-musl': 1.3.85 + '@swc/core-win32-arm64-msvc': 1.3.85 + '@swc/core-win32-ia32-msvc': 1.3.85 + '@swc/core-win32-x64-msvc': 1.3.85 /@swc/helpers/0.5.1: resolution: {integrity: sha512-sJ902EfIzn1Fa+qYmjdQqh8tPsoxyBz+8yBKC2HKUxyezKJFwPGOn7pv4WY6QuQW//ySQi5lJjA/ZT9sNWWNTg==} @@ -7707,7 +7702,6 @@ packages: /@swc/types/0.1.4: resolution: {integrity: sha512-z/G02d+59gyyUb7KYhKi9jOhicek6QD2oMaotUyG+lUkybpXoV49dY9bj7Ah5Q+y7knK2jU67UTX9FyfGzaxQg==} - dev: false /@szmarczak/http-timer/1.1.2: resolution: {integrity: sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==} @@ -8174,7 +8168,6 @@ packages: '@types/prop-types': 15.7.5 '@types/scheduler': 0.16.2 csstype: 3.1.1 - dev: true /@types/react/18.0.28: resolution: {integrity: sha512-RD0ivG1kEztNBdoAK7lekI9M+azSnitIn85h4iOiaLjaTrMjzslhaqCGaI4IyCJ1RljWiLCEu4jyrLLgqxBTew==} @@ -8267,12 +8260,12 @@ packages: /@types/unist/2.0.6: resolution: {integrity: sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ==} - /@types/webpack-bundle-analyzer/4.6.0_yt3h3qjhcnsf3663codtuni62a: + /@types/webpack-bundle-analyzer/4.6.0_pur5qe7dhbhqwjtj2daaog4n7u: resolution: {integrity: sha512-XeQmQCCXdZdap+A/60UKmxW5Mz31Vp9uieGlHB3T4z/o2OLVLtTI3bvTuS6A2OWd/rbAAQiGGWIEFQACu16szA==} dependencies: '@types/node': 18.14.6 tapable: 2.2.1 - webpack: 5.88.2_yt3h3qjhcnsf3663codtuni62a + webpack: 5.88.2_pur5qe7dhbhqwjtj2daaog4n7u transitivePeerDependencies: - '@swc/core' - esbuild @@ -10449,8 +10442,8 @@ packages: engines: {node: '>=10'} hasBin: true dependencies: - is-text-path: 1.0.1 JSONStream: 1.3.5 + is-text-path: 1.0.1 lodash: 4.17.21 meow: 8.1.2 split2: 3.2.2 @@ -10480,7 +10473,6 @@ packages: resolution: {integrity: sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==} dependencies: is-what: 3.14.1 - dev: false /copy-text-to-clipboard/3.0.1: resolution: {integrity: sha512-rvVsHrpFcL4F2P8ihsoLdFHmd404+CMg71S756oRSeQgqk51U3kicGdnvfkrxva0xXH92SjGS62B0XIJsbh+9Q==} @@ -10505,7 +10497,7 @@ packages: normalize-path: 3.0.0 schema-utils: 4.0.0 serialize-javascript: 6.0.1 - webpack: 5.88.2_yt3h3qjhcnsf3663codtuni62a + webpack: 5.88.2_pur5qe7dhbhqwjtj2daaog4n7u dev: true /copy-webpack-plugin/11.0.0_webpack@5.88.2: @@ -10710,7 +10702,7 @@ packages: postcss-modules-values: 4.0.0_postcss@8.4.21 postcss-value-parser: 4.2.0 semver: 7.3.8 - webpack: 5.88.2_yt3h3qjhcnsf3663codtuni62a + webpack: 5.88.2_pur5qe7dhbhqwjtj2daaog4n7u dev: true /css-loader/6.7.3_webpack@5.88.2: @@ -10755,7 +10747,7 @@ packages: schema-utils: 4.0.0 serialize-javascript: 6.0.1 source-map: 0.6.1 - webpack: 5.88.2_yt3h3qjhcnsf3663codtuni62a + webpack: 5.88.2_pur5qe7dhbhqwjtj2daaog4n7u dev: true /css-minimizer-webpack-plugin/4.2.2_ltzhhs6ml74uoexipkdt2pgtmi: @@ -11687,7 +11679,6 @@ packages: requiresBuild: true dependencies: prr: 1.0.1 - dev: false optional: true /error-ex/1.3.2: @@ -12540,7 +12531,7 @@ packages: micromatch: 4.0.5 normalize-path: 3.0.0 schema-utils: 3.1.1 - webpack: 5.88.2_yt3h3qjhcnsf3663codtuni62a + webpack: 5.88.2_pur5qe7dhbhqwjtj2daaog4n7u dev: true /eslint/8.35.0: @@ -13165,7 +13156,7 @@ packages: semver: 7.3.8 tapable: 2.2.1 typescript: 4.9.5 - webpack: 5.88.2_yt3h3qjhcnsf3663codtuni62a + webpack: 5.88.2_pur5qe7dhbhqwjtj2daaog4n7u dev: true /form-data/2.3.3: @@ -14061,7 +14052,6 @@ packages: engines: {node: '>=0.10.0'} hasBin: true requiresBuild: true - dev: false optional: true /image-size/1.0.2: @@ -14575,7 +14565,6 @@ packages: /is-what/3.14.1: resolution: {integrity: sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==} - dev: false /is-whitespace-character/1.0.4: resolution: {integrity: sha512-SDweEzfIZM0SJV0EUga669UTKlmL0Pq8Lno0QDQsPnvECB3IM2aP0gdx5TrU0A01MAPfViaZiI2V1QMZLaKK5w==} @@ -15836,7 +15825,7 @@ packages: dependencies: klona: 2.0.6 less: 4.1.2 - webpack: 5.88.2_yt3h3qjhcnsf3663codtuni62a + webpack: 5.88.2_pur5qe7dhbhqwjtj2daaog4n7u dev: true /less/4.1.2: @@ -15857,7 +15846,6 @@ packages: source-map: 0.6.1 transitivePeerDependencies: - supports-color - dev: false /leven/3.1.0: resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} @@ -16161,7 +16149,6 @@ packages: dependencies: pify: 4.0.1 semver: 5.7.1 - dev: false optional: true /make-dir/3.1.0: @@ -16373,7 +16360,7 @@ packages: webpack: ^5.0.0 dependencies: schema-utils: 4.0.0 - webpack: 5.88.2_yt3h3qjhcnsf3663codtuni62a + webpack: 5.88.2_pur5qe7dhbhqwjtj2daaog4n7u dev: true /mini-css-extract-plugin/2.7.2_webpack@5.88.2: @@ -16557,7 +16544,6 @@ packages: sax: 1.2.4 transitivePeerDependencies: - supports-color - dev: false optional: true /negotiator/0.6.3: @@ -17010,7 +16996,6 @@ packages: /parse-node-version/1.0.1: resolution: {integrity: sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==} engines: {node: '>= 0.10'} - dev: false /parse-numeric-range/1.3.0: resolution: {integrity: sha512-twN+njEipszzlMJd4ONUYgSfZPDxgHhT9Ahed5uTigpQn90FggW4SA/AIPq/6a149fTbE9qBEcSwE3FAEp6wQQ==} @@ -17617,7 +17602,7 @@ packages: klona: 2.0.6 postcss: 8.4.12 semver: 7.3.8 - webpack: 5.88.2_yt3h3qjhcnsf3663codtuni62a + webpack: 5.88.2_pur5qe7dhbhqwjtj2daaog4n7u dev: true /postcss-loader/7.0.2_pu275c3rt57tiockloa6nvewbm: @@ -18652,7 +18637,6 @@ packages: nanoid: 3.3.4 picocolors: 1.0.0 source-map-js: 1.0.2 - dev: false /postcss/8.4.21: resolution: {integrity: sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==} @@ -18810,7 +18794,6 @@ packages: /prr/1.0.1: resolution: {integrity: sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==} - dev: false optional: true /pseudomap/1.0.2: @@ -19951,6 +19934,12 @@ packages: /react-dev-utils/12.0.1_rggdtlzfqxxwxudp3onsqdyocm: resolution: {integrity: sha512-84Ivxmr17KjUupyqzFode6xKhjwuEJDROWKJy/BthkL7Wn6NJ8h4WE6k/exAv6ImS+0oZLRRW5j/aINMHyeGeQ==} engines: {node: '>=14'} + peerDependencies: + typescript: '>=2.7' + webpack: '>=4' + peerDependenciesMeta: + typescript: + optional: true dependencies: '@babel/code-frame': 7.18.6 address: 1.2.2 @@ -19981,9 +19970,7 @@ packages: transitivePeerDependencies: - eslint - supports-color - - typescript - vue-template-compiler - - webpack /react-dom/17.0.2_react@17.0.2: resolution: {integrity: sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==} @@ -19994,7 +19981,6 @@ packages: object-assign: 4.1.1 react: 17.0.2 scheduler: 0.20.2 - dev: false /react-dom/18.2.0_react@18.2.0: resolution: {integrity: sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==} @@ -20202,12 +20188,12 @@ packages: '@remix-run/router': 1.7.2 react: 18.2.0 - /react-server-dom-webpack/18.3.0-canary-627b7abd6-20230911_biqbaboplfbrettd7655fr4n2y: - resolution: {integrity: sha512-Nv2QERdglsfbW9cUBhzMsWmCvF58B7fc4xKy++l4UEwLxqgWLkuF8y3Cqc4xyt1A6hoalz3qV8c5HUMf1XgLXw==} + /react-server-dom-webpack/18.3.0-canary-2807d781a-20230918_biqbaboplfbrettd7655fr4n2y: + resolution: {integrity: sha512-xyamMF0z/mYSc/AAUSvzQviE2a5dCubrH47O+F74grcOePONmaEgWZROwVpNOpK3cvmTJZ/SPzZkeM8uoZmXeQ==} engines: {node: '>=0.10.0'} peerDependencies: - react: 18.3.0-canary-627b7abd6-20230911 - react-dom: 18.3.0-canary-627b7abd6-20230911 + react: 18.3.0-canary-2807d781a-20230918 + react-dom: 18.3.0-canary-2807d781a-20230918 webpack: ^5.59.0 dependencies: acorn-loose: 8.3.0 @@ -20228,7 +20214,7 @@ packages: acorn-loose: 8.3.0 loose-envify: 1.4.0 neo-async: 2.6.2 - webpack: 5.88.2_yt3h3qjhcnsf3663codtuni62a + webpack: 5.88.2_pur5qe7dhbhqwjtj2daaog4n7u dev: true /react-textarea-autosize/8.4.0_h7fc2el62uaa77gho3xhys6ola: @@ -20265,7 +20251,6 @@ packages: dependencies: loose-envify: 1.4.0 object-assign: 4.1.1 - dev: false /react/18.2.0: resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==} @@ -20870,7 +20855,7 @@ packages: klona: 2.0.6 neo-async: 2.6.2 sass: 1.50.0 - webpack: 5.88.2_yt3h3qjhcnsf3663codtuni62a + webpack: 5.88.2_pur5qe7dhbhqwjtj2daaog4n7u dev: true /sass/1.50.0: @@ -20897,7 +20882,6 @@ packages: dependencies: loose-envify: 1.4.0 object-assign: 4.1.1 - dev: false /scheduler/0.21.0: resolution: {integrity: sha512-1r87x5fz9MXqswA2ERLo0EbOAU74DpIUO090gIasYTqlVoJeMcl+Z1Rg7WHz+qtPujhS/hGIt9kxZOYBV3faRQ==} @@ -21954,7 +21938,7 @@ packages: supports-hyperlinks: 2.3.0 dev: true - /terser-webpack-plugin/5.3.5_c2jhsnh755mj2bl6newvfwu7wy: + /terser-webpack-plugin/5.3.5_ghmre4bibzh3hfhoafsn4shpjy: resolution: {integrity: sha512-AOEDLDxD2zylUGf/wxHxklEkOe2/r+seuyOWujejFrIxHf11brA1/dWQNIgXa1c6/Wkxgu7zvv0JhOWfc2ELEA==} engines: {node: '>= 10.13.0'} peerDependencies: @@ -21971,16 +21955,16 @@ packages: optional: true dependencies: '@jridgewell/trace-mapping': 0.3.17 - '@swc/core': 1.3.80 + '@swc/core': 1.3.85 esbuild: 0.17.16 jest-worker: 27.5.1 schema-utils: 3.1.1 serialize-javascript: 6.0.1 terser: 5.14.2 - webpack: 5.76.0_yt3h3qjhcnsf3663codtuni62a - dev: false + webpack: 5.88.2_pur5qe7dhbhqwjtj2daaog4n7u + dev: true - /terser-webpack-plugin/5.3.5_muqrkd6dqvsxxmw22vfpzybwpe: + /terser-webpack-plugin/5.3.5_o2c6qj4wewpo6lqphnxqo7wwae: resolution: {integrity: sha512-AOEDLDxD2zylUGf/wxHxklEkOe2/r+seuyOWujejFrIxHf11brA1/dWQNIgXa1c6/Wkxgu7zvv0JhOWfc2ELEA==} engines: {node: '>= 10.13.0'} peerDependencies: @@ -21997,14 +21981,13 @@ packages: optional: true dependencies: '@jridgewell/trace-mapping': 0.3.17 - '@swc/core': 1.3.80 + '@swc/core': 1.3.85 esbuild: 0.17.16 jest-worker: 27.5.1 schema-utils: 3.1.1 serialize-javascript: 6.0.1 terser: 5.14.2 - webpack: 5.88.2_yt3h3qjhcnsf3663codtuni62a - dev: true + webpack: 5.76.0_pur5qe7dhbhqwjtj2daaog4n7u /terser-webpack-plugin/5.3.5_sozpi7ywd3sv63uu2kzspstlze: resolution: {integrity: sha512-AOEDLDxD2zylUGf/wxHxklEkOe2/r+seuyOWujejFrIxHf11brA1/dWQNIgXa1c6/Wkxgu7zvv0JhOWfc2ELEA==} @@ -22104,7 +22087,7 @@ packages: webpack: 5.88.2_esbuild@0.17.16 dev: true - /terser-webpack-plugin/5.3.7_muqrkd6dqvsxxmw22vfpzybwpe: + /terser-webpack-plugin/5.3.7_ghmre4bibzh3hfhoafsn4shpjy: resolution: {integrity: sha512-AfKwIktyP7Cu50xNjXF/6Qb5lBNzYaWpU6YfoX3uZicTx0zTy0stDDCsvjDapKsSDvOeWo5MEq4TmdBy2cNoHw==} engines: {node: '>= 10.13.0'} peerDependencies: @@ -22121,14 +22104,13 @@ packages: optional: true dependencies: '@jridgewell/trace-mapping': 0.3.17 - '@swc/core': 1.3.80 + '@swc/core': 1.3.85 esbuild: 0.17.16 jest-worker: 27.5.1 schema-utils: 3.3.0 serialize-javascript: 6.0.1 terser: 5.16.5 - webpack: 5.88.2_yt3h3qjhcnsf3663codtuni62a - dev: true + webpack: 5.88.2_pur5qe7dhbhqwjtj2daaog4n7u /terser-webpack-plugin/5.3.7_webpack@5.88.2: resolution: {integrity: sha512-AfKwIktyP7Cu50xNjXF/6Qb5lBNzYaWpU6YfoX3uZicTx0zTy0stDDCsvjDapKsSDvOeWo5MEq4TmdBy2cNoHw==} @@ -22761,7 +22743,7 @@ packages: acorn: 8.8.2 chokidar: 3.5.3 esbuild: 0.17.16 - webpack: 5.88.2_yt3h3qjhcnsf3663codtuni62a + webpack: 5.88.2_pur5qe7dhbhqwjtj2daaog4n7u webpack-sources: 3.2.3 webpack-virtual-modules: 0.4.6 dev: true @@ -23333,7 +23315,7 @@ packages: mime-types: 2.1.35 range-parser: 1.2.1 schema-utils: 4.0.0 - webpack: 5.76.0_yt3h3qjhcnsf3663codtuni62a + webpack: 5.76.0_pur5qe7dhbhqwjtj2daaog4n7u /webpack-dev-middleware/5.3.3_webpack@5.86.0: resolution: {integrity: sha512-hj5CYrY0bZLB+eTO+x/j67Pkrquiy7kWepMHmUMoPsmcUaeEnQJqFzHJOyxgWlq746/wUuA64p9ta34Kyb01pA==} @@ -23360,7 +23342,7 @@ packages: mime-types: 2.1.35 range-parser: 1.2.1 schema-utils: 4.0.0 - webpack: 5.88.2_yt3h3qjhcnsf3663codtuni62a + webpack: 5.88.2_pur5qe7dhbhqwjtj2daaog4n7u /webpack-dev-middleware/6.0.2_webpack@5.76.0: resolution: {integrity: sha512-iOddiJzPcQC6lwOIu60vscbGWth8PCRcWRCwoQcTQf9RMoOWBHg5EyzpGdtSmGMrSPd5vHEfFXmVErQEmkRngQ==} @@ -23376,7 +23358,7 @@ packages: mime-types: 2.1.35 range-parser: 1.2.1 schema-utils: 4.0.0 - webpack: 5.76.0_yt3h3qjhcnsf3663codtuni62a + webpack: 5.76.0_pur5qe7dhbhqwjtj2daaog4n7u /webpack-dev-server/4.11.1_webpack@5.88.2: resolution: {integrity: sha512-lILVz9tAUy1zGFwieuaQtYiadImb5M3d+H+L1zDYalYoDl0cksAB1UNyuE5MMWJrG6zR1tXkCP2fitl7yoUJiw==} @@ -23467,7 +23449,7 @@ packages: serve-index: 1.9.1 sockjs: 0.3.24 spdy: 4.0.2 - webpack: 5.76.0_yt3h3qjhcnsf3663codtuni62a + webpack: 5.76.0_pur5qe7dhbhqwjtj2daaog4n7u webpack-dev-middleware: 5.3.3_webpack@5.76.0 ws: 8.13.0 transitivePeerDependencies: @@ -23669,7 +23651,7 @@ packages: serve-index: 1.9.1 sockjs: 0.3.24 spdy: 4.0.2 - webpack: 5.88.2_yt3h3qjhcnsf3663codtuni62a + webpack: 5.88.2_pur5qe7dhbhqwjtj2daaog4n7u webpack-dev-middleware: 5.3.3_webpack@5.88.2 ws: 8.13.0 transitivePeerDependencies: @@ -23741,7 +23723,7 @@ packages: - uglify-js dev: true - /webpack/5.76.0_yt3h3qjhcnsf3663codtuni62a: + /webpack/5.76.0_pur5qe7dhbhqwjtj2daaog4n7u: resolution: {integrity: sha512-l5sOdYBDunyf72HW8dF23rFtWq/7Zgvt/9ftMof71E/yUb1YLOBmTgA2K4vQthB3kotMrSj609txVE0dnr2fjA==} engines: {node: '>=10.13.0'} hasBin: true @@ -23772,14 +23754,13 @@ packages: neo-async: 2.6.2 schema-utils: 3.3.0 tapable: 2.2.1 - terser-webpack-plugin: 5.3.5_c2jhsnh755mj2bl6newvfwu7wy + terser-webpack-plugin: 5.3.5_o2c6qj4wewpo6lqphnxqo7wwae watchpack: 2.4.0 webpack-sources: 3.2.3 transitivePeerDependencies: - '@swc/core' - esbuild - uglify-js - dev: false /webpack/5.86.0_esbuild@0.17.16: resolution: {integrity: sha512-3BOvworZ8SO/D4GVP+GoRC3fVeg5MO4vzmq8TJJEkdmopxyazGDxN8ClqN12uzrZW9Tv8EED8v5VSb6Sqyi0pg==} @@ -23900,7 +23881,7 @@ packages: - uglify-js dev: true - /webpack/5.88.2_yt3h3qjhcnsf3663codtuni62a: + /webpack/5.88.2_pur5qe7dhbhqwjtj2daaog4n7u: resolution: {integrity: sha512-JmcgNZ1iKj+aiR0OvTYtWQqJwq37Pf683dY9bVORwVbUrDhLhdn/PlO2sHsFHPkj7sHNQF3JwaAkp49V+Sq1tQ==} engines: {node: '>=10.13.0'} hasBin: true @@ -23931,14 +23912,13 @@ packages: neo-async: 2.6.2 schema-utils: 3.3.0 tapable: 2.2.1 - terser-webpack-plugin: 5.3.7_muqrkd6dqvsxxmw22vfpzybwpe + terser-webpack-plugin: 5.3.7_ghmre4bibzh3hfhoafsn4shpjy watchpack: 2.4.0 webpack-sources: 3.2.3 transitivePeerDependencies: - '@swc/core' - esbuild - uglify-js - dev: true /webpackbar/5.0.2_webpack@5.88.2: resolution: {integrity: sha512-BmFJo7veBDgQzfWXl/wwYXr/VFus0614qZ8i9znqcl9fnEdiVkdbi0TedLQ6xAK92HZHDJ0QmyQ0fmuZPAgCYQ==} From 823af35b99c87b4d47f4afd005d32083c93b81df Mon Sep 17 00:00:00 2001 From: ClarkXia <xiawenwu41@gmail.com> Date: Tue, 26 Sep 2023 10:11:16 +0800 Subject: [PATCH 08/17] chore: changeset --- .changeset/chilled-jars-pump.md | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 .changeset/chilled-jars-pump.md diff --git a/.changeset/chilled-jars-pump.md b/.changeset/chilled-jars-pump.md new file mode 100644 index 0000000000..4d27994b22 --- /dev/null +++ b/.changeset/chilled-jars-pump.md @@ -0,0 +1,9 @@ +--- +'@ice/webpack-config': minor +'@ice/shared-config': minor +'@ice/runtime': minor +'@ice/app': minor +'@ice/bundles': patch +--- + +feat: support react server component From 9301d5d62251a1a0ec094258721467e2fd63ecf3 Mon Sep 17 00:00:00 2001 From: ClarkXia <xiawenwu41@gmail.com> Date: Tue, 26 Sep 2023 10:16:48 +0800 Subject: [PATCH 09/17] chore: package name --- examples/with-rsc/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/with-rsc/package.json b/examples/with-rsc/package.json index 76c4d522de..d8b3cd8f41 100644 --- a/examples/with-rsc/package.json +++ b/examples/with-rsc/package.json @@ -1,5 +1,5 @@ { - "name": "with-server-component", + "name": "@examples/with-server-component", "version": "1.0.0", "scripts": { "start": "ice start", From e5c9c4ef166e3b2c8c95955cc6d9786de2f762ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B0=B4=E6=BE=9C?= <shuilan.cj@taobao.com> Date: Wed, 27 Sep 2023 16:52:23 +0800 Subject: [PATCH 10/17] fix: root id (#6556) * fix: root id * chore: remove debug code * chore: revert lock file * fix: lint --- packages/ice/templates/core/rsc.client.tsx.ejs | 6 ++++-- packages/runtime/src/runRSCClientApp.tsx | 8 +++++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/packages/ice/templates/core/rsc.client.tsx.ejs b/packages/ice/templates/core/rsc.client.tsx.ejs index 812d527509..0ded0e7f79 100644 --- a/packages/ice/templates/core/rsc.client.tsx.ejs +++ b/packages/ice/templates/core/rsc.client.tsx.ejs @@ -1,8 +1,10 @@ <% if (importCoreJs) { -%>import 'core-js';<% } %> -import { runRSCClientApp } from '<%- iceRuntimePath %>'; +import { runRSCClientApp, getAppConfig } from '<%- iceRuntimePath %>'; +import * as app from '@/app'; const render = (customOptions = {}) => { - return runRSCClientApp(); + const appConfig = getAppConfig(app); + return runRSCClientApp(appConfig); }; <%- entryCode %> diff --git a/packages/runtime/src/runRSCClientApp.tsx b/packages/runtime/src/runRSCClientApp.tsx index b9fe82d8e5..c07392a5cb 100644 --- a/packages/runtime/src/runRSCClientApp.tsx +++ b/packages/runtime/src/runRSCClientApp.tsx @@ -1,13 +1,15 @@ import * as React from 'react'; import * as ReactDOM from 'react-dom/client'; import pkg from 'react-server-dom-webpack/client'; +import type { AppConfig } from './types.js'; // @ts-ignore const { Suspense, use, useState, createContext, useContext, startTransition } = React; const { createFromFetch } = pkg; -export async function runRSCClientApp() { - const container = document.getElementById('app'); +export async function runRSCClientApp(appConfig: AppConfig) { + const rootId = appConfig.app.rootId || 'app'; + const container = document.getElementById(rootId); const root = ReactDOM.createRoot(container); root.render(<Root />); } @@ -23,7 +25,7 @@ const initialCache = new Map(); function Router() { const [cache, setCache] = useState(initialCache); - const [location, setLocation] = useState(window.location.href); + const [location] = useState(window.location.href); let content = cache.get(location); if (!content) { From c136c385c43aa022d04794cee5061c65880d7bad Mon Sep 17 00:00:00 2001 From: ClarkXia <xiawenwu41@gmail.com> Date: Wed, 27 Sep 2023 16:59:45 +0800 Subject: [PATCH 11/17] chore: do not publish rsc example --- examples/with-rsc/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/with-rsc/package.json b/examples/with-rsc/package.json index d8b3cd8f41..1f1edeef31 100644 --- a/examples/with-rsc/package.json +++ b/examples/with-rsc/package.json @@ -1,5 +1,6 @@ { "name": "@examples/with-server-component", + "private": true, "version": "1.0.0", "scripts": { "start": "ice start", From b02f088e17e20793c3ebafb1acd2e49abadcce88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B0=B4=E6=BE=9C?= <shuilan.cj@taobao.com> Date: Fri, 13 Oct 2023 16:11:00 +0800 Subject: [PATCH 12/17] fix: decoupled from express (#6582) --- packages/runtime/src/runRSCServerApp.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/runtime/src/runRSCServerApp.tsx b/packages/runtime/src/runRSCServerApp.tsx index 11f3c0e4d8..87e3263881 100644 --- a/packages/runtime/src/runRSCServerApp.tsx +++ b/packages/runtime/src/runRSCServerApp.tsx @@ -103,6 +103,7 @@ function renderDocument(requestContext, renderOptions, appContext) { ); res.setHeader('Content-Type', 'text/html; charset=utf-8'); - res.send(`<!DOCTYPE html>${htmlStr}`); + res.write(`<!DOCTYPE html>${htmlStr}`); + res.end(); } From bcf6d4f8cc594998593f9be50b95a8f9a95ae0e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B0=B4=E6=BE=9C?= <shuilan.cj@taobao.com> Date: Thu, 26 Oct 2023 11:24:16 +0800 Subject: [PATCH 13/17] feat: bundle for client chunk (#6596) * chore: bundle client imports * chore: build as chunk * refactor: entry plugin * feat: generate client entry for rsc * fix: type * feat: remove temp route assets * feat: load assets by default * fix: avoid chunk information being overwritten * revert: example * fix: entry * fix: lint * fix: lint * fix: append manifest * chore: lock react plugin version * chore: update lock * refactor: use utils * chore: get routes file * fix: lint * fix: rsc url --- .../src/components/Counter.client.tsx | 2 +- .../src/components/counter.module.css | 14 + .../about.module.css} | 27 +- examples/with-rsc/src/pages/about.tsx | 4 +- examples/with-rsc/src/pages/index.module.css | 17 +- .../src/bundler/webpack/getWebpackConfig.ts | 15 + packages/ice/src/plugins/web/index.ts | 6 +- .../src/webpack/FlightClientEntryLoader.ts | 24 + .../src/webpack/FlightClientEntryPlugin.ts | 343 ++++ .../ice/src/webpack/FlightManifestPlugin.ts | 328 +--- packages/route-manifest/src/index.ts | 5 +- packages/runtime/package.json | 2 +- packages/runtime/src/routesConfig.ts | 2 +- packages/runtime/src/runRSCClientApp.tsx | 2 +- packages/runtime/src/runRSCServerApp.tsx | 21 +- .../webpackPlugins/AssetsManifestPlugin.ts | 38 +- pnpm-lock.yaml | 1382 ++++++++++++++--- 17 files changed, 1699 insertions(+), 533 deletions(-) create mode 100644 examples/with-rsc/src/components/counter.module.css rename examples/with-rsc/src/{components/index.module.css => pages/about.module.css} (52%) create mode 100644 packages/ice/src/webpack/FlightClientEntryLoader.ts create mode 100644 packages/ice/src/webpack/FlightClientEntryPlugin.ts diff --git a/examples/with-rsc/src/components/Counter.client.tsx b/examples/with-rsc/src/components/Counter.client.tsx index c61fbaa994..a9ed6568d3 100644 --- a/examples/with-rsc/src/components/Counter.client.tsx +++ b/examples/with-rsc/src/components/Counter.client.tsx @@ -1,7 +1,7 @@ 'use client'; import { useState } from 'react'; import { useAppContext } from 'ice'; -import styles from './index.module.css'; +import styles from './counter.module.css'; export default function Counter() { const [count, setCount] = useState(0); diff --git a/examples/with-rsc/src/components/counter.module.css b/examples/with-rsc/src/components/counter.module.css new file mode 100644 index 0000000000..75eea836a4 --- /dev/null +++ b/examples/with-rsc/src/components/counter.module.css @@ -0,0 +1,14 @@ +.link { + font-size: 1.2rem; + color: var(--primary); +} + +.button { + outline: none; + border: none; + border-radius: 8px; + padding: 10px 35px; + background: var(--primary); + box-shadow: 0 5px 10px 0 #ddd; + font-size: calc(10px + 2vmin); +} diff --git a/examples/with-rsc/src/components/index.module.css b/examples/with-rsc/src/pages/about.module.css similarity index 52% rename from examples/with-rsc/src/components/index.module.css rename to examples/with-rsc/src/pages/about.module.css index d11aa6a0b6..18968098e0 100644 --- a/examples/with-rsc/src/components/index.module.css +++ b/examples/with-rsc/src/pages/about.module.css @@ -1,4 +1,4 @@ -.app { +.about { display: flex; flex-direction: column; align-items: center; @@ -6,40 +6,25 @@ height: 100vh; } -.app > header { +.about > header { display: flex; flex-direction: column; align-items: center; } -.app > header > img { +.about > header > img { width: 120px; } -.app > header > p { +.about > header > p { margin: 20px 0; text-align: center; font-size: 2.6rem; } -.app > main { +.about > main { display: flex; flex-direction: column; margin: 20px 0 10px; font-size: 0.9rem; -} - -.link { - font-size: 1.2rem; - color: var(--primary); -} - -.button { - outline: none; - border: none; - border-radius: 8px; - padding: 10px 35px; - background: var(--primary); - box-shadow: 0 5px 10px 0 #ddd; - font-size: calc(10px + 2vmin); -} +} \ No newline at end of file diff --git a/examples/with-rsc/src/pages/about.tsx b/examples/with-rsc/src/pages/about.tsx index b9a1859c37..916a34a9ed 100644 --- a/examples/with-rsc/src/pages/about.tsx +++ b/examples/with-rsc/src/pages/about.tsx @@ -1,5 +1,5 @@ import { useAppContext } from 'ice'; -import styles from './index.module.css'; +import styles from './about.module.css'; import RefreshButton from '@/components/RefreshButton.client'; import Counter from '@/components/Counter.client'; @@ -14,7 +14,7 @@ export default function Home() { console.log(appContext); return ( - <div className={styles.app}> + <div className={styles.about}> <h2>About Page</h2> <div>server request count: { global.requestCount++ }</div> <Counter /> diff --git a/examples/with-rsc/src/pages/index.module.css b/examples/with-rsc/src/pages/index.module.css index d11aa6a0b6..67e8c355ea 100644 --- a/examples/with-rsc/src/pages/index.module.css +++ b/examples/with-rsc/src/pages/index.module.css @@ -27,19 +27,4 @@ flex-direction: column; margin: 20px 0 10px; font-size: 0.9rem; -} - -.link { - font-size: 1.2rem; - color: var(--primary); -} - -.button { - outline: none; - border: none; - border-radius: 8px; - padding: 10px 35px; - background: var(--primary); - box-shadow: 0 5px 10px 0 #ddd; - font-size: calc(10px + 2vmin); -} +} \ No newline at end of file diff --git a/packages/ice/src/bundler/webpack/getWebpackConfig.ts b/packages/ice/src/bundler/webpack/getWebpackConfig.ts index c0e7843198..b256536fe4 100644 --- a/packages/ice/src/bundler/webpack/getWebpackConfig.ts +++ b/packages/ice/src/bundler/webpack/getWebpackConfig.ts @@ -1,8 +1,11 @@ +import * as path from 'path'; +import { fileURLToPath } from 'url'; import webpack from '@ice/bundles/compiled/webpack/index.js'; import lodash from '@ice/bundles/compiled/lodash/index.js'; import { getWebpackConfig as getDefaultWebpackConfig } from '@ice/webpack-config'; import type { Configuration } from 'webpack'; import { FlightManifestPlugin } from '../../webpack/FlightManifestPlugin.js'; +import { FlightClientEntryPlugin } from '../../webpack/FlightClientEntryPlugin.js'; import { getExpandedEnvs } from '../../utils/runtimeEnv.js'; import { getRouteExportConfig } from '../../service/config.js'; import { getFileHash } from '../../utils/hash.js'; @@ -14,6 +17,8 @@ import type ServerRunnerPlugin from '../../webpack/ServerRunnerPlugin.js'; import type ServerCompilerPlugin from '../../webpack/ServerCompilerPlugin.js'; import type { BundlerOptions, Context } from '../types.js'; +const __dirname = path.dirname(fileURLToPath(import.meta.url)); + const { debounce } = lodash; type GetWebpackConfig = ( @@ -118,6 +123,16 @@ const getWebpackConfig: GetWebpackConfig = async (context, options) => { // Add spinner for webpack task. webpackConfig.plugins.push(getSpinnerPlugin(spinner)); if (userConfig.rsc) { + webpackConfig.resolveLoader = { + alias: { + 'flight-client-entry-loader': path.join(__dirname, '../../webpack/FlightClientEntryLoader.js'), + }, + }; + + webpackConfig.plugins.push(new FlightClientEntryPlugin({ + rootDir, + getRoutesFile, + })); webpackConfig.plugins.push(new FlightManifestPlugin()); } diff --git a/packages/ice/src/plugins/web/index.ts b/packages/ice/src/plugins/web/index.ts index e8256fdf8d..7cd7eff5ec 100644 --- a/packages/ice/src/plugins/web/index.ts +++ b/packages/ice/src/plugins/web/index.ts @@ -49,8 +49,10 @@ const plugin: Plugin = () => ({ ...(userConfig.rsc ? { alias: createRSCAliases(), // TODO: temporary solution for rsc. - entry: { main: [path.join(rootDir, RUNTIME_TMP_DIR, 'rsc.client.tsx')] }, - } : {}), + entry: { + main: [path.join(rootDir, RUNTIME_TMP_DIR, 'rsc.client.tsx')], + route: [path.join(rootDir, RUNTIME_TMP_DIR, 'routes.tsx')], + } } : {}), }); onHook('after.start.compile', async ({ isSuccessful, isFirstCompile, urls, devUrlInfo }) => { diff --git a/packages/ice/src/webpack/FlightClientEntryLoader.ts b/packages/ice/src/webpack/FlightClientEntryLoader.ts new file mode 100644 index 0000000000..748c947526 --- /dev/null +++ b/packages/ice/src/webpack/FlightClientEntryLoader.ts @@ -0,0 +1,24 @@ +export type ClientComponentImports = string[]; +export type CssImports = Record<string, string[]>; + +export type FlightClientEntryLoaderOptions = { + modules: ClientComponentImports; +}; + +export default function transformSource() { + let { modules }: FlightClientEntryLoaderOptions = this.getOptions(); + + if (!Array.isArray(modules)) { + modules = modules ? [modules] : []; + } + + const requests = modules as string[]; + const code = requests + .map( + (request) => + `import(/* webpackMode: "eager" */ ${JSON.stringify(request)})`, + ) + .join(';\n'); + + return code; +} diff --git a/packages/ice/src/webpack/FlightClientEntryPlugin.ts b/packages/ice/src/webpack/FlightClientEntryPlugin.ts new file mode 100644 index 0000000000..32900200e3 --- /dev/null +++ b/packages/ice/src/webpack/FlightClientEntryPlugin.ts @@ -0,0 +1,343 @@ +import { join, relative } from 'path'; +import { stringify } from 'querystring'; +import { asyncLib, acorn } from '@ice/bundles'; +import webpack from '@ice/bundles/compiled/webpack/index.js'; +import NullDependency from '@ice/bundles/compiled/webpack/NullDependency.js'; +import ModuleDependency from '@ice/bundles/compiled/webpack/ModuleDependency.js'; +import type { Compiler, Compilation } from 'webpack'; +import { createComponentName } from '@ice/route-manifest'; +import formatPath from '../utils/formatPath.js'; + +const PLUGIN_NAME = 'FlightClientEntryPlugin'; + +interface ClientReferenceSearchPath { + directory: string; + recursive?: boolean; + include: RegExp; + exclude?: RegExp; +} + +interface Options { + rootDir: string; + clientReferences?: ClientReferenceSearchPath[]; + getRoutesFile: () => string[]; +} + +class ClientReferenceDependency extends ModuleDependency { + userRequest: string; + request: string; + + constructor(request: string) { + super(request); + this.request = request; + } + get type(): string { + return 'client-reference'; + } +} + +export class FlightClientEntryPlugin { + clientReferences: ClientReferenceSearchPath[]; + clientFiles = new Set(); + pageDir: string; + rootDir: string; + getRoutesFile: () => string[]; + + constructor(options: Options) { + this.rootDir = options.rootDir; + this.pageDir = join(options.rootDir, 'src', 'pages'); + + this.getRoutesFile = options.getRoutesFile; + + if (options.clientReferences) { + this.clientReferences = options.clientReferences; + } else { + this.clientReferences = [ + { + directory: '.', + recursive: true, + include: /\.(js|ts|jsx|tsx)$/, + exclude: /types.ts|.d.ts|node_modules/, + }, + ]; + } + } + + apply(compiler: Compiler) { + const _this = this; + + compiler.hooks.thisCompilation.tap(PLUGIN_NAME, (compilation, { normalModuleFactory }) => { + // @ts-expect-error TODO: add types for ModuleDependency. + compilation.dependencyFactories.set(ClientReferenceDependency, normalModuleFactory); + // @ts-expect-error TODO: add types for ModuleDependency. + compilation.dependencyTemplates.set(ClientReferenceDependency, new NullDependency.Template()); + }); + + compiler.hooks.beforeCompile.tapAsync(PLUGIN_NAME, ({ contextModuleFactory }, callback) => { + const contextResolver = compiler.resolverFactory.get('context', {}); + const normalResolver = compiler.resolverFactory.get('normal'); + + _this.resolveClientFiles( + compiler.context, + contextResolver, + normalResolver, + compiler.inputFileSystem, + contextModuleFactory, + (err, resolvedClientRefs) => { + if (err) { + callback(err); + return; + } + resolvedClientRefs.forEach(dep => { + _this.clientFiles.add(dep.request); + }); + + callback(); + }, + ); + }); + + compiler.hooks.finishMake.tapPromise(PLUGIN_NAME, (compilation) => + _this.createClientEntries(compiler, compilation), + ); + + compiler.hooks.make.tap(PLUGIN_NAME, (compilation) => { + compilation.hooks.processAssets.tap({ + name: PLUGIN_NAME, + stage: webpack.Compilation.PROCESS_ASSETS_STAGE_PRE_PROCESS, + }, () => { + compilation.chunks.forEach((chunk) => { + if (chunk.name === 'route' || chunk.runtime === 'route') { + chunk.files.forEach((file) => { + delete compilation.assets[file]; + }); + } + }); + }); + }); + } + + async createClientEntries(compiler: Compiler, compilation: Compilation) { + const routes = this.getRoutesFile().map(file => join(this.rootDir, file)); + const addClientEntryList = []; + + for (const [name, entry] of compilation.entries.entries()) { + if (name === 'main') { + continue; + } + + const entryDependency = entry.dependencies?.[0]; + if (!entryDependency) { + continue; + } + + const entryModule = compilation.moduleGraph.getResolvedModule(entryDependency); + for (const connection of compilation.moduleGraph.getOutgoingConnections(entryModule)) { + // @ts-ignore + const entryRequest = connection.resolvedModule?.resource; + + if (routes.indexOf(entryRequest) === -1) continue; + + const { clientComponentImports, CSSImports } = this.collectComponentInfoFromDependency({ + compilation, + resolvedModule: connection.resolvedModule, + }); + + if (clientComponentImports.length || CSSImports.length) { + const injected = this.injectClientEntry({ + compiler, + compilation, + bundlePath: entryRequest, + clientImports: [ + ...clientComponentImports, + ...CSSImports, + ], + }); + + addClientEntryList.push(injected); + } + } + } + + await Promise.all(addClientEntryList); + } + + injectClientEntry({ compiler, compilation, bundlePath, clientImports }) { + const clientLoader = `flight-client-entry-loader?${stringify({ + modules: clientImports, + })}!`; + + const componentName = createComponentName(formatPath(relative(this.pageDir, bundlePath))); + const name = `rsc_${componentName}`; + const clientComponentEntryDep = webpack.EntryPlugin.createDependency(clientLoader, { + name, + }); + + return new Promise<void>((resolve, reject) => { + compilation.addEntry(compiler.context, clientComponentEntryDep, { name, dependOn: ['main'] }, (err) => { + if (err) { + reject(err); + } + + resolve(); + }); + }); + } + + collectComponentInfoFromDependency({ compilation, resolvedModule }) { + // Keep track of checked modules to avoid infinite loops with recursive imports. + const visited = new Set(); + // Info to collect. + const clientComponentImports = []; + const CSSImports = []; + + const filterClientComponents = (mod) => { + if (!mod) return; + + const modRequest: string | undefined = mod.resourceResolveData?.path + mod.resourceResolveData?.query; + + if (!modRequest || visited.has(modRequest)) return; + visited.add(modRequest); + + const isCSS = isCSSMod(mod); + + if (isCSS) { + CSSImports.push(modRequest); + } + + if (this.isClientComponentEntryModule(mod)) { + clientComponentImports.push(modRequest); + return; + } + + compilation.moduleGraph.getOutgoingConnections(mod).forEach((connection) => { + filterClientComponents(connection.resolvedModule); + }); + }; + + // Traverse the module graph to find all client components. + filterClientComponents(resolvedModule); + + return { + clientComponentImports, + CSSImports, + }; + } + + isClientComponentEntryModule(mod) { + if (this.clientFiles.has(mod.resource)) { + return true; + } + + return false; + } + + resolveClientFiles( + context: string, + contenxtResolver: ReturnType<Compiler['resolverFactory']['get']>, + normalResolver: ReturnType<Compiler['resolverFactory']['get']>, + fs: Compilation['inputFileSystem'], + contextModuleFactory: Compilation['params']['contextModuleFactory'], + callback: (err: Error | null, files?: ClientReferenceDependency[]) => void, + ) { + function hasUseClientDirective(source: string): boolean { + if (source.indexOf('use client') === -1) { + return false; + } + let body; + try { + // TODO: check client directive by comment injected by swc plugin. + body = acorn.parse(source, { + ecmaVersion: '2024', + sourceType: 'module', + }).body; + } catch (x) { + return false; + } + for (let i = 0; i < body.length; i++) { + const node = body[i]; + if (node.type !== 'ExpressionStatement' || !node.directive) { + break; + } + if (node.directive === 'use client') { + return true; + } + } + return false; + } + asyncLib.map(this.clientReferences, ( + clientReference: ClientReferenceSearchPath, + cb: (err: null | Error, result?: ClientReferenceDependency[]) => void, + ) => { + contenxtResolver.resolve({}, context, clientReference.directory, {}, (err, resolvedDirectory) => { + if (err) return cb(err); + const options = { + resource: resolvedDirectory, + resourceQuery: '', + recursive: + clientReference.recursive === undefined + ? true + : clientReference.recursive, + regExp: clientReference.include, + include: undefined, + exclude: clientReference.exclude, + }; + // @ts-expect-error TODO: add types for resolveDependencies options. + contextModuleFactory.resolveDependencies(fs, options, (err, dependencies) => { + if (err) return cb(err); + const clientRefDeps = dependencies.map(dep => { + // Use userRequest instead of request. request always end with undefined which is wrong. + const request = join(resolvedDirectory as string, dep.userRequest); + const clientRefDep = new ClientReferenceDependency(request); + clientRefDep.userRequest = dep.userRequest; + return clientRefDep; + }); + asyncLib.filter( + clientRefDeps, + (dep: ClientReferenceDependency, filterCb: (err: null | Error, truthValue: boolean) => void, + ) => { + normalResolver.resolve( + {}, + context, + dep.request, + {}, + (err: null | Error, resolvedPath: any) => { + if (err || typeof resolvedPath !== 'string') { + return filterCb(null, false); + } + + fs.readFile( + resolvedPath, + 'utf-8', + // @ts-expect-error + (err: null | Error, content: string) => { + if (err || typeof content !== 'string') { + return filterCb(null, false); + } + const useClient = hasUseClientDirective(content); + filterCb(null, useClient); + }, + ); + }, + ); + }, cb); + }); + }); + }, ( + err: null | Error, + result: ClientReferenceDependency[], + ) => { + if (err) return callback(err); + const flat: ClientReferenceDependency[] = []; + for (let i = 0; i < result.length; i++) { + flat.push.apply(flat, result[i]); + } + callback(null, flat); + }); + } +} + +const regexCSS = /\.(css|scss|sass)(\?.*)?$/; +function isCSSMod(mod) { + return mod.resource && regexCSS.test(mod.resource); +} \ No newline at end of file diff --git a/packages/ice/src/webpack/FlightManifestPlugin.ts b/packages/ice/src/webpack/FlightManifestPlugin.ts index 49cab9afea..f8bda22836 100644 --- a/packages/ice/src/webpack/FlightManifestPlugin.ts +++ b/packages/ice/src/webpack/FlightManifestPlugin.ts @@ -1,24 +1,11 @@ // Fork form https://github.com/facebook/react/blob/main/packages/react-server-dom-webpack/src/ReactFlightWebpackPlugin.js // Add special handling for ice.js when enable RSC. -import * as path from 'path'; -import { asyncLib, acorn } from '@ice/bundles'; -import ModuleDependency from '@ice/bundles/compiled/webpack/ModuleDependency.js'; -import NullDependency from '@ice/bundles/compiled/webpack/NullDependency.js'; import webpack from '@ice/bundles/compiled/webpack/index.js'; -import type { Compiler, Compilation } from 'webpack'; +import type { Compiler } from 'webpack'; const PLUGIN_NAME = 'FlightManifestPlugin'; -interface ClientReferenceSearchPath { - directory: string; - recursive?: boolean; - include: RegExp; - exclude?: RegExp; -} - interface Options { - clientReferences?: ClientReferenceSearchPath[]; - chunkName?: string; clientManifestFilename?: string; ssrManifestFilename?: string; } @@ -27,55 +14,23 @@ interface SSRExports { [chunkName: string]: { specifier: string; name: string }; } -class ClientReferenceDependency extends ModuleDependency { - userRequest: string; - request: string; +interface ClientManifest { + [key: string]: { + chunks: (string | number)[]; + id: string | number; + name: string; +}; +} - constructor(request: string) { - super(request); - this.request = request; - } - get type(): string { - return 'client-reference'; - } +interface SsrManifest { + [key: string]: SSRExports; } -// Webpack template utils of toPath. -const PATH_NAME_NORMALIZE_REPLACE_REGEX = /[^a-zA-Z0-9_!§$()=\-^°]+/g; -const MATCH_PADDED_HYPHENS_REPLACE_REGEX = /^-|-$/g; -const toPath = (str: any) => { - if (typeof str !== 'string') return ''; - return str - .replace(PATH_NAME_NORMALIZE_REPLACE_REGEX, '-') - .replace(MATCH_PADDED_HYPHENS_REPLACE_REGEX, ''); -}; export class FlightManifestPlugin { - clientReferences: ClientReferenceSearchPath[]; - chunkName?: string; clientManifestFilename?: string; ssrManifestFilename?: string; constructor(options: Options = {}) { - if (options.clientReferences) { - this.clientReferences = options.clientReferences; - } else { - this.clientReferences = [ - { - directory: '.', - recursive: true, - include: /\.(js|ts|jsx|tsx)$/, - exclude: /types.ts|.d.ts|node_modules/, - }, - ]; - } - if (typeof options.chunkName === 'string') { - this.chunkName = options.chunkName; - if (!/\[(index|request)\]/.test(this.chunkName)) { - this.chunkName += '[index]'; - } - } else { - this.chunkName = 'client[index]'; - } this.clientManifestFilename = options.clientManifestFilename || 'react-client-manifest.json'; this.ssrManifestFilename = @@ -84,107 +39,34 @@ export class FlightManifestPlugin { apply(compiler: Compiler) { const _this = this; - let resolvedClientReferences: ClientReferenceDependency[]; - let clientFileNameFound = false; - - compiler.hooks.beforeCompile.tapAsync(PLUGIN_NAME, ({ contextModuleFactory }, callback) => { - const contextResolver = compiler.resolverFactory.get('context', {}); - const normalResolver = compiler.resolverFactory.get('normal'); - - _this.resolveClientFiles( - compiler.context, - contextResolver, - normalResolver, - compiler.inputFileSystem, - contextModuleFactory, - (err, resolvedClientRefs) => { - if (err) { - callback(err); - return; - } - resolvedClientReferences = resolvedClientRefs; - callback(); - }, - ); - }); - - compiler.hooks.thisCompilation.tap(PLUGIN_NAME, (compilation, { normalModuleFactory }) => { - // @ts-expect-error TODO: add types for ModuleDependency. - compilation.dependencyFactories.set(ClientReferenceDependency, normalModuleFactory); - // @ts-expect-error TODO: add types for ModuleDependency. - compilation.dependencyTemplates.set(ClientReferenceDependency, new NullDependency.Template()); - - const handler = (parser) => { - parser.hooks.program.tap(PLUGIN_NAME, () => { - const { module } = parser.state; - if (!module.resource.includes('react-server-dom-webpack/client.browser')) { - return; - } - clientFileNameFound = true; - if (resolvedClientReferences) { - if (resolvedClientReferences) { - for (let i = 0; i < resolvedClientReferences.length; i++) { - const dep = resolvedClientReferences[i]; - - const chunkName = _this.chunkName - .replace(/\[index\]/g, `${i}`) - .replace(/\[request\]/g, toPath(dep.userRequest)); - - const block = new webpack.AsyncDependenciesBlock( - { - name: chunkName, - }, - null, - dep.request, - ); - // @ts-expect-error TODO: add types for ModuleDependency. - block.addDependency(dep); - module.addBlock(block); - } - } - } - }); - }; - - normalModuleFactory.hooks.parser.for('javascript/auto').tap('HarmonyModulesPlugin', handler); - normalModuleFactory.hooks.parser.for('javascript/esm').tap('HarmonyModulesPlugin', handler); - normalModuleFactory.hooks.parser.for('javascript/dynamic').tap('HarmonyModulesPlugin', handler); - }); compiler.hooks.make.tap(PLUGIN_NAME, (compilation) => { compilation.hooks.processAssets.tap({ name: PLUGIN_NAME, stage: webpack.Compilation.PROCESS_ASSETS_STAGE_REPORT, }, () => { - if (clientFileNameFound === false) { - compilation.warnings.push( - // @ts-expect-error mismatch import path of webpack. - new webpack.WebpackError( - `Client runtime at 'react-server-dom-webpack/client' was not found. React Server Components module map file ${_this.clientManifestFilename} was not created.`, - ), - ); - return; - } - - const resolveClientFiles = new Set((resolvedClientReferences || []).map((dep) => dep.request)); - const clientManifest: { [key: string]: { - chunks: (string | number)[]; - id: string | number; - name: string; - };} = {}; - const ssrManifest: { - [key: string]: SSRExports; + const clientManifestMapping: { + [key: string]: ClientManifest; + } = {}; + const ssrManifestSetMapping: { + [key: string]: SsrManifest; } = {}; compilation.chunkGroups.forEach((chunkGroup) => { - const chunkIds = chunkGroup.chunks.map((chunk) => chunk.id); + const chunkGroupName = chunkGroup.name; + + const clientManifest: ClientManifest = {}; + + const ssrManifest: SsrManifest = {}; + + let hasRecord = false; + const recordModule = (id: string | number, module: any) => { - if (!resolveClientFiles.has(module.resource)) { - return; - } // const modId = path.relative(compiler.context, module.resource); const modId = module.resource; if (modId !== undefined) { + hasRecord = true; + clientManifest[modId] = { id, chunks: chunkIds, @@ -204,28 +86,62 @@ export class FlightManifestPlugin { } }; + const chunkIds = chunkGroup.chunks.map((chunk) => chunk.id); chunkGroup.chunks.forEach((chunk) => { const chunkModules = compilation.chunkGraph.getChunkModulesIterable(chunk); [...chunkModules].forEach((module) => { - const moduleId = compilation.chunkGraph.getModuleId(module); - recordModule(moduleId, module); - // If this is a concatenation, register each child to the parent ID. - // @ts-expect-error - if (module.modules) { - // @ts-expect-error - module.modules.forEach(concatenatedMod => { - recordModule(moduleId, concatenatedMod); - }); + const { request } = module as any; + + if ( + !request || + !request.includes('FlightClientEntryLoader.js') + ) { + return; + } + + const connections = compilation.moduleGraph.getOutgoingConnections(module); + + for (const connection of connections) { + const { dependency } = connection; + if (!dependency) continue; + + const clientEntryMod = compilation.moduleGraph.getResolvedModule( + dependency, + ) as any; + const modId = compilation.chunkGraph.getModuleId(clientEntryMod) as + | string + | number + | null; + + if (modId) { + recordModule(modId, clientEntryMod); + } else { + // If this is a concatenation, register each child to the parent ID. + if (connection.module?.constructor.name === 'ConcatenatedModule') { + const concatenatedMod = connection.module; + const concatenatedModId = + compilation.chunkGraph.getModuleId(concatenatedMod); + recordModule(concatenatedModId, clientEntryMod); + } + } } }); + + // One client component may bundle into serveral chunks, so we need to create manifest for each page. + if (hasRecord) { + clientManifestMapping[chunkGroupName] = clientManifest; + ssrManifestSetMapping[chunkGroupName] = ssrManifest; + } }); }); - const clientOutput = JSON.stringify(clientManifest, null, 2); + + const clientOutput = JSON.stringify(clientManifestMapping, null, 2); compilation.emitAsset( _this.clientManifestFilename, new webpack.sources.RawSource(clientOutput, false), ); - const ssrOutput = JSON.stringify(ssrManifest, null, 2); + + const ssrOutput = JSON.stringify(ssrManifestSetMapping, null, 2); compilation.emitAsset( _this.ssrManifestFilename, new webpack.sources.RawSource(ssrOutput, false), @@ -233,108 +149,4 @@ export class FlightManifestPlugin { }); }); } - - resolveClientFiles( - context: string, - contenxtResolver: ReturnType<Compiler['resolverFactory']['get']>, - normalResolver: ReturnType<Compiler['resolverFactory']['get']>, - fs: Compilation['inputFileSystem'], - contextModuleFactory: Compilation['params']['contextModuleFactory'], - callback: (err: Error | null, files?: ClientReferenceDependency[]) => void, - ) { - function hasUseClientDirective(source: string): boolean { - if (source.indexOf('use client') === -1) { - return false; - } - let body; - try { - // TODO: check client directive by comment injected by swc plugin. - body = acorn.parse(source, { - ecmaVersion: '2024', - sourceType: 'module', - }).body; - } catch (x) { - return false; - } - for (let i = 0; i < body.length; i++) { - const node = body[i]; - if (node.type !== 'ExpressionStatement' || !node.directive) { - break; - } - if (node.directive === 'use client') { - return true; - } - } - return false; - } - asyncLib.map(this.clientReferences, ( - clientReference: ClientReferenceSearchPath, - cb: (err: null | Error, result?: ClientReferenceDependency[]) => void, - ) => { - contenxtResolver.resolve({}, context, clientReference.directory, {}, (err, resolvedDirectory) => { - if (err) return cb(err); - const options = { - resource: resolvedDirectory, - resourceQuery: '', - recursive: - clientReference.recursive === undefined - ? true - : clientReference.recursive, - regExp: clientReference.include, - include: undefined, - exclude: clientReference.exclude, - }; - // @ts-expect-error TODO: add types for resolveDependencies options. - contextModuleFactory.resolveDependencies(fs, options, (err, dependencies) => { - if (err) return cb(err); - const clientRefDeps = dependencies.map(dep => { - // Use userRequest instead of request. request always end with undefined which is wrong. - const request = path.join(resolvedDirectory as string, dep.userRequest); - const clientRefDep = new ClientReferenceDependency(request); - clientRefDep.userRequest = dep.userRequest; - return clientRefDep; - }); - asyncLib.filter( - clientRefDeps, - (dep: ClientReferenceDependency, filterCb: (err: null | Error, truthValue: boolean) => void, - ) => { - normalResolver.resolve( - {}, - context, - dep.request, - {}, - (err: null | Error, resolvedPath: any) => { - if (err || typeof resolvedPath !== 'string') { - return filterCb(null, false); - } - - fs.readFile( - resolvedPath, - 'utf-8', - // @ts-expect-error - (err: null | Error, content: string) => { - if (err || typeof content !== 'string') { - return filterCb(null, false); - } - const useClient = hasUseClientDirective(content); - filterCb(null, useClient); - }, - ); - }, - ); - }, cb); - }); - }); - }, ( - err: null | Error, - result: ClientReferenceDependency[], - ) => { - if (err) return callback(err); - const flat: ClientReferenceDependency[] = []; - for (let i = 0; i < result.length; i++) { - flat.push.apply(flat, result[i]); - } - callback(null, flat); - }); - } } diff --git a/packages/route-manifest/src/index.ts b/packages/route-manifest/src/index.ts index af00031e2c..8175fbe6a1 100644 --- a/packages/route-manifest/src/index.ts +++ b/packages/route-manifest/src/index.ts @@ -46,11 +46,14 @@ const routeModuleExts = [ // '.mdx', ]; +export { + createComponentName, +}; + export function isRouteModuleFile(filename: string): boolean { return routeModuleExts.includes(path.extname(filename)); } - export function generateRouteManifest( rootDir: string, ignoreFiles: string[] = [], diff --git a/packages/runtime/package.json b/packages/runtime/package.json index 3385e8a4cf..37b9e6d683 100644 --- a/packages/runtime/package.json +++ b/packages/runtime/package.json @@ -44,7 +44,7 @@ "@types/react-dom": "^18.0.3", "react": "^18.2.0", "react-dom": "^18.2.0", - "react-server-dom-webpack": "canary", + "react-server-dom-webpack": "18.3.0-canary-dd480ef92-20230822", "regenerator-runtime": "^0.13.9", "@remix-run/web-fetch": "^4.3.3" }, diff --git a/packages/runtime/src/routesConfig.ts b/packages/runtime/src/routesConfig.ts index ceba4f3aba..ea3fce7cf3 100644 --- a/packages/runtime/src/routesConfig.ts +++ b/packages/runtime/src/routesConfig.ts @@ -32,7 +32,7 @@ function getMergedValue(key: string, matches: RouteMatch[], loadersData: Loaders let result; for (let match of matches) { const routeId = match.route.id; - const data = loadersData[routeId]?.pageConfig; + const data = loadersData?.[routeId]?.pageConfig; const value = data?.[key]; if (Array.isArray(value)) { diff --git a/packages/runtime/src/runRSCClientApp.tsx b/packages/runtime/src/runRSCClientApp.tsx index c07392a5cb..213b32eaee 100644 --- a/packages/runtime/src/runRSCClientApp.tsx +++ b/packages/runtime/src/runRSCClientApp.tsx @@ -61,5 +61,5 @@ export function useRefresh() { } function getReactTree(location) { - return fetch(location + location.indexOf('?') ? '?rsc' : '&rsc'); + return fetch(location + (location.indexOf('?') > -1 ? '&rsc' : '?rsc')); } \ No newline at end of file diff --git a/packages/runtime/src/runRSCServerApp.tsx b/packages/runtime/src/runRSCServerApp.tsx index 87e3263881..f39c8ae2ef 100644 --- a/packages/runtime/src/runRSCServerApp.tsx +++ b/packages/runtime/src/runRSCServerApp.tsx @@ -26,7 +26,7 @@ export async function runRSCServerApp(serverContext: ServerContext, renderOption renderMode, basename, serverOnlyBasename, - clientManifest, + clientManifest: clientManifestMapping, assetsManifest, } = renderOptions; @@ -50,7 +50,7 @@ export async function runRSCServerApp(serverContext: ServerContext, renderOption }; if (req.url?.indexOf('rsc') === -1) { - return renderDocument(serverContext, renderOptions, appContext); + return renderDocument(serverContext, renderOptions, appContext, matches); } const routeModules = await loadRouteModules(matches.map(({ route: { id, lazy } }) => ({ id, lazy }))); @@ -61,6 +61,16 @@ export async function runRSCServerApp(serverContext: ServerContext, renderOption </AppContextProvider> ); + // Merge client manifest for match route. + const clientManifest = {}; + matches.forEach(match => { + const { componentName } = match.route; + const manifest = clientManifestMapping[`rsc_${componentName}`]; + if (manifest) { + Object.assign(clientManifest, manifest); + } + }); + const { pipe } = renderToPipeableStream( element, clientManifest, @@ -83,11 +93,12 @@ function renderMatches(matches: RouteMatch[], routeModules: RouteModules) { }, React.createElement(null)); } -function renderDocument(requestContext, renderOptions, appContext) { +function renderDocument(requestContext, renderOptions, appContext, matches) { const { res } = requestContext; const { Document, + routePath, } = renderOptions; const documentContext = { @@ -95,9 +106,9 @@ function renderDocument(requestContext, renderOptions, appContext) { }; const htmlStr = ReactDOMServer.renderToString( - <AppContextProvider value={appContext}> + <AppContextProvider value={{ ...appContext, matches }}> <DocumentContextProvider value={documentContext}> - <Document /> + <Document pagePath={routePath} /> </DocumentContextProvider> </AppContextProvider>, ); diff --git a/packages/webpack-config/src/webpackPlugins/AssetsManifestPlugin.ts b/packages/webpack-config/src/webpackPlugins/AssetsManifestPlugin.ts index fe494cd1a9..e3e8ad98d2 100644 --- a/packages/webpack-config/src/webpackPlugins/AssetsManifestPlugin.ts +++ b/packages/webpack-config/src/webpackPlugins/AssetsManifestPlugin.ts @@ -9,13 +9,15 @@ interface Assets { getFiles: () => string[]; } -function filterAssets(assets: Assets): string[] { +function filterAssets(compilation: Compilation, assets: Assets): string[] { return ( assets ?.getFiles() .filter((file: string) => { + const exists = compilation.assets[file]; // We don't want to include `.hot-update.js` files into the initial page - return /(?<!\.hot-update)\.(js|css)($|\?)/.test(file); + const notHotUpdate = exists && /(?<!\.hot-update)\.(js|css)($|\?)/.test(file); + return exists && notHotUpdate; }) .map((file: string) => file.replace(/\\/g, '/')) ?? [] ); @@ -43,19 +45,38 @@ export default class AssetsManifestPlugin { assets[asset.sourceFilename] = asset.contenthash; } } + const entryFiles = []; for (const entrypoint of entrypoints) { const entryName = entrypoint.name; - const mainFiles = filterAssets(entrypoint); + + const entryChunk = entrypoint.getEntrypointChunk(); + + // Keep only main chunk as entry files. + if (entryChunk.runtime !== entryChunk.name) { + continue; + } + + const entryFile = [...entryChunk.files].filter((file) => file.endsWith('.js'))?.[0]; + // Temp files may have been deleted. + if (!compilation.assets[entryFile]) { + continue; + } + + const mainFiles = filterAssets(compilation, entrypoint); + if (!mainFiles.length) { + continue; + } + + entryFiles.push(entryFile); entries[entryName] = mainFiles; - const jsMainFiles = mainFiles.filter((file) => file.endsWith('.js')); - entryFiles.push(jsMainFiles[0]); - const chunks = entrypoint?.getChildren(); - chunks.forEach((chunk) => { + + const childChunks = entrypoint?.getChildren(); + childChunks.forEach((chunk) => { // Dynamic import missing chunk name, but not output solid assets. const chunkName = chunk.name; if (chunkName) { - pages[chunkName.replace(/^p_/, '')] = filterAssets(chunk); + pages[chunkName.replace(/^p_/, '').replace(/^rsc_/, '')] = filterAssets(compilation, chunk); } }); } @@ -76,6 +97,7 @@ export default class AssetsManifestPlugin { const output = JSON.stringify(manifest, null, 2); // Emit asset manifest for server compile. compilation.emitAsset(this.fileName, new webpack.sources.RawSource(output)); + // Inject assets manifest to entry file. entryFiles.forEach((entryFile) => { compilation.assets[entryFile] = new webpack.sources.ConcatSource( diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 778890e619..d8f172ace7 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1181,7 +1181,7 @@ importers: '@ice/bundles': link:../bundles '@ice/route-manifest': link:../route-manifest '@ice/rspack-config': link:../rspack-config - '@ice/runtime': link:../runtime + '@ice/runtime': 1.3.1_react@18.2.0 '@ice/shared-config': link:../shared-config '@ice/webpack-config': link:../webpack-config '@swc/helpers': 0.5.1 @@ -1287,7 +1287,7 @@ importers: react: ^18.1.0 react-dom: ^18.1.0 dependencies: - '@ice/runtime': link:../runtime + '@ice/runtime': 1.3.1_biqbaboplfbrettd7655fr4n2y '@ice/shared': link:../shared miniapp-history: 0.1.7 devDependencies: @@ -1303,7 +1303,7 @@ importers: dependencies: '@ice/style-import': link:../style-import devDependencies: - '@ice/app': link:../ice + '@ice/app': 3.3.5 packages/plugin-auth: specifiers: @@ -1313,8 +1313,8 @@ importers: '@types/react-dom': ^18.0.0 regenerator-runtime: ^0.13.9 devDependencies: - '@ice/app': link:../ice - '@ice/runtime': link:../runtime + '@ice/app': 3.3.5 + '@ice/runtime': 1.3.1 '@types/react': 18.0.28 '@types/react-dom': 18.0.11 regenerator-runtime: 0.13.11 @@ -1328,8 +1328,8 @@ importers: dependencies: '@ice/cache-canvas': link:../cache-canvas devDependencies: - '@ice/app': link:../ice - '@ice/runtime': link:../runtime + '@ice/app': 3.3.5_webpack@5.88.2 + '@ice/runtime': 1.3.1 webpack: 5.88.2 packages/plugin-css-assets-local: @@ -1341,7 +1341,7 @@ importers: consola: 2.15.3 extract-css-assets-webpack-plugin: 0.2.10 devDependencies: - '@ice/app': link:../ice + '@ice/app': 3.3.5 packages/plugin-fusion: specifiers: @@ -1350,7 +1350,7 @@ importers: dependencies: '@ice/style-import': link:../style-import devDependencies: - '@ice/app': link:../ice + '@ice/app': 3.3.5 packages/plugin-i18n: specifiers: @@ -1395,8 +1395,8 @@ importers: '@ice/stark': 2.7.5 '@ice/stark-app': 1.5.0 devDependencies: - '@ice/app': link:../ice - '@ice/runtime': link:../runtime + '@ice/app': 3.3.5 + '@ice/runtime': 1.3.1 '@types/react': 18.0.28 '@types/react-dom': 18.0.11 @@ -1423,7 +1423,7 @@ importers: babel-plugin-transform-jsx-slot: 0.1.2 babel-runtime-jsx-plus: 0.1.5 devDependencies: - '@ice/app': link:../ice + '@ice/app': 3.3.5 '@types/react': 18.0.28 '@types/react-dom': 18.0.11 @@ -1458,15 +1458,15 @@ importers: regenerator-runtime: 0.11.1 sax: 1.2.4 devDependencies: - '@ice/app': link:../ice - '@ice/runtime': link:../runtime + '@ice/app': 3.3.5_webpack@5.88.2 + '@ice/runtime': 1.3.1 webpack: 5.88.2 packages/plugin-moment-locales: specifiers: '@ice/app': ^3.3.2 devDependencies: - '@ice/app': link:../ice + '@ice/app': 3.3.5 packages/plugin-pha: specifiers: @@ -1489,7 +1489,7 @@ importers: humps: 2.0.1 lodash.clonedeep: 4.5.0 devDependencies: - '@ice/app': link:../ice + '@ice/app': 3.3.5_ls5vlc7kphql6b6gtepk5p7cmu build-scripts: 2.1.2-0 esbuild: 0.17.16 webpack: 5.88.2_esbuild@0.17.16 @@ -1522,7 +1522,7 @@ importers: style-unit: 3.0.5 stylesheet-loader: 0.9.1 devDependencies: - '@ice/app': link:../ice + '@ice/app': 3.3.5_webpack@5.88.2 '@types/lodash-es': 4.17.7 webpack: 5.88.2 @@ -1539,8 +1539,8 @@ importers: ahooks: 3.7.5 axios: 0.27.2 devDependencies: - '@ice/app': link:../ice - '@ice/runtime': link:../runtime + '@ice/app': 3.3.5 + '@ice/runtime': 1.3.1 '@types/react': 18.0.28 '@types/react-dom': 18.0.11 regenerator-runtime: 0.13.11 @@ -1638,7 +1638,7 @@ importers: react: ^18.2.0 react-dom: ^18.2.0 react-router-dom: 6.14.2 - react-server-dom-webpack: canary + react-server-dom-webpack: 18.3.0-canary-dd480ef92-20230822 regenerator-runtime: ^0.13.9 semver: ^7.4.0 source-map: ^0.7.4 @@ -1660,7 +1660,7 @@ importers: '@types/react-dom': 18.0.11 react: 18.2.0 react-dom: 18.2.0_react@18.2.0 - react-server-dom-webpack: 18.3.0-canary-e61a60fac-20231011_biqbaboplfbrettd7655fr4n2y + react-server-dom-webpack: 18.3.0-canary-dd480ef92-20230822_biqbaboplfbrettd7655fr4n2y regenerator-runtime: 0.13.11 packages/shared: @@ -5487,174 +5487,774 @@ packages: resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==} dev: true - /@ice/css-modules-hash-darwin-arm64/0.0.6: - resolution: {integrity: sha512-5QWZl3+biY5U/kRhymH+6X/kAk3Imvkqu9QpV+LTDxhoXEkdhzZd2sCO5ZNfrsODFuHy78iKzh6gEweADPwYkQ==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [darwin] - requiresBuild: true - dev: false - optional: true - - /@ice/css-modules-hash-darwin-universal/0.0.6: - resolution: {integrity: sha512-PLmDCFZHvpNysvMhUa363QWvgCMIwr6vYwEkHkC/AF9NZvl25r2R9mfdExHw8sZHu9fMHVINwWEBcMiYbZd/cg==} - engines: {node: '>= 10'} - os: [darwin] - requiresBuild: true - dev: false - optional: true - - /@ice/css-modules-hash-darwin-x64/0.0.6: - resolution: {integrity: sha512-HOmh+Yiw6rH9VJD2XBN7sZmigo+jwi7qAD/J12pbxVrMJ//aIsv3BwpgFhfGO8eqKeyVqNXac3S/vC2hq8t8jw==} - engines: {node: '>= 10'} - cpu: [x64] - os: [darwin] - requiresBuild: true - dev: false - optional: true - - /@ice/css-modules-hash-linux-x64-gnu/0.0.6: - resolution: {integrity: sha512-PS7lTINETFqzbU0nbgLgxXJOp+BU51VvNeNEF1h6Xz6soR23yqFht6d8xuNC1auBnPHZM+RDiQYzwi9MCBTvgA==} - engines: {node: '>= 10'} - cpu: [x64] - os: [linux] - requiresBuild: true - dev: false - optional: true - - /@ice/css-modules-hash-linux-x64-musl/0.0.6: - resolution: {integrity: sha512-UiDg8KpoDGmQrBt9z5lqjr+OAG2S2xQi00Unt2yali1dvhS1tpcN16isiBA2yO3JOy2b0Y0VtlmpJKxpMDsFcg==} - engines: {node: '>= 10'} - cpu: [x64] - os: [linux] - requiresBuild: true - dev: false - optional: true - - /@ice/css-modules-hash-win32-arm64-msvc/0.0.6: - resolution: {integrity: sha512-7rF1gX9QyhhGUo4JKZUQ6DSJs/xJiJlrKC9D91dkTHs81e0G6IQLv9EnIaX2OPF3/SPnqp7CAGxr7TOtDYsyAw==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [win32] - requiresBuild: true - dev: false - optional: true - - /@ice/css-modules-hash-win32-x64-msvc/0.0.6: - resolution: {integrity: sha512-on3tYfhvBW6XQ6tkE0KKZvFK0JB/iwBrvUiRo/Di3ceJPPwD619PJNNQnn78kqcrZIVdQZ41HMdyuEnz8UHVpQ==} - engines: {node: '>= 10'} - cpu: [x64] - os: [win32] - requiresBuild: true - dev: false - optional: true - - /@ice/css-modules-hash/0.0.6: - resolution: {integrity: sha512-UbYq2Ldw+hamc9HoIfKTZORmmYCaGnP6f361XdB/7PQZHZ5hAak6TePdcVQekLHGEg/+zIccN33mflJqucC1Aw==} - engines: {node: '>= 10'} - optionalDependencies: - '@ice/css-modules-hash-darwin-arm64': 0.0.6 - '@ice/css-modules-hash-darwin-universal': 0.0.6 - '@ice/css-modules-hash-darwin-x64': 0.0.6 - '@ice/css-modules-hash-linux-x64-gnu': 0.0.6 - '@ice/css-modules-hash-linux-x64-musl': 0.0.6 - '@ice/css-modules-hash-win32-arm64-msvc': 0.0.6 - '@ice/css-modules-hash-win32-x64-msvc': 0.0.6 - dev: false - - /@ice/pkg/1.5.5: - resolution: {integrity: sha512-0BIfv6Uzs2wpHv7RmFwz+kWfoJLfx0yJrQyh3yqy+F6TZWxTwrqQmX+5yRmgqK5f7lGGhYfMMVNWjRSCw5MHPQ==} - engines: {node: '>=16.14.0'} + /@ice/app/3.3.5: + resolution: {integrity: sha512-loVbr/CqH5suvWchw/mvbLS/yfO/qsxOx/KvcmdQYA8Unr0J1fYHrBFlYbKmpJe0aEDnSfSzDKebJsbyDTKGJQ==} + engines: {node: '>=14.19.0', npm: '>=3.0.0'} hasBin: true + requiresBuild: true + peerDependencies: + react: '>=18.0.0' + react-dom: '>=18.0.0' dependencies: - '@ampproject/remapping': 2.2.0 - '@babel/core': 7.21.0 - '@babel/parser': 7.21.2 - '@babel/preset-react': 7.18.6_@babel+core@7.21.0 - '@babel/preset-typescript': 7.21.0_@babel+core@7.21.0 - '@rollup/plugin-commonjs': 21.1.0_rollup@2.79.1 - '@rollup/plugin-image': 3.0.2_rollup@2.79.1 - '@rollup/plugin-json': 4.1.0_rollup@2.79.1 - '@rollup/plugin-node-resolve': 13.3.0_rollup@2.79.1 - '@rollup/plugin-replace': 5.0.2_rollup@2.79.1 - '@rollup/pluginutils': 4.2.1 - '@swc/core': 1.3.32 - acorn: 8.8.2 - autoprefixer: 10.4.13_postcss@8.4.31 - build-scripts: 2.1.0 - cac: 6.7.14 - chokidar: 3.5.3 + '@ice/bundles': 0.1.16_oikrtulvecolg3hvcan4tch6ku + '@ice/route-manifest': 1.2.2 + '@ice/rspack-config': 1.0.5_oikrtulvecolg3hvcan4tch6ku + '@ice/runtime': 1.3.1 + '@ice/shared-config': 1.1.0_oikrtulvecolg3hvcan4tch6ku + '@ice/webpack-config': 1.1.4_oikrtulvecolg3hvcan4tch6ku + '@swc/helpers': 0.5.1 + '@types/express': 4.17.17 + address: 1.2.2 + build-scripts: 2.1.2-0 + chalk: 4.1.2 + commander: 9.5.0 consola: 2.15.3 - debug: 4.3.4 - deepmerge: 4.3.0 - escape-string-regexp: 5.0.0 + cross-spawn: 7.0.3 + detect-port: 1.5.1 + dotenv: 16.0.3 + dotenv-expand: 8.0.3 + ejs: 3.1.8 + fast-glob: 3.3.0 + find-up: 5.0.0 fs-extra: 10.1.0 - globby: 11.1.0 - gzip-size: 7.0.0 - lodash.merge: 4.6.2 - magic-string: 0.25.9 - picocolors: 1.0.0 - postcss: 8.4.31 - rollup: 2.79.1 - rollup-plugin-styles: 4.0.0_rollup@2.79.1 - rollup-plugin-visualizer: 5.9.0_rollup@2.79.1 - tsc-alias: 1.8.5 - typescript: 4.9.5 + micromatch: 4.0.5 + mlly: 1.1.1 + mrmime: 1.0.1 + open: 8.4.2 + path-to-regexp: 6.2.1 + regenerator-runtime: 0.13.11 + resolve.exports: 1.1.1 + semver: 7.4.0 + source-map-support: 0.5.21 + temp: 0.9.4 + yargs-parser: 21.1.1 transitivePeerDependencies: + - '@types/webpack' + - bufferutil + - debug + - sockjs-client - supports-color + - type-fest + - uglify-js + - utf-8-validate + - webpack + - webpack-cli + - webpack-dev-server + - webpack-hot-middleware + - webpack-plugin-serve dev: true - /@ice/sandbox/1.1.4: - resolution: {integrity: sha512-MEVF0Ze3McKDutnFiUAhUoc+WwOFxITVBgSSHmbGpKtWbXJX9kUVlx3VsEVJvdqU3O1kiBNx6zE1sFMjKPRTIQ==} - dev: false - - /@ice/stark-app/1.5.0: - resolution: {integrity: sha512-9fuCri48eZj6TnfPkCju4vVLhGurz+mt6lFx4JQFHhnRBQ5MuiBqRZg5F/3vdnJ7dAYQJlCXmHlQtBHok82z+g==} - dev: false - - /@ice/stark/2.7.5: - resolution: {integrity: sha512-HyV3/6PtTfNiKBkncztunpjsWMBw/SyQ24TvrYLnpkuSmrlZ9t0/jkJWuaM6nGpAufyZ62YfQ2Tn032So9OeIg==} + /@ice/app/3.3.5_ls5vlc7kphql6b6gtepk5p7cmu: + resolution: {integrity: sha512-loVbr/CqH5suvWchw/mvbLS/yfO/qsxOx/KvcmdQYA8Unr0J1fYHrBFlYbKmpJe0aEDnSfSzDKebJsbyDTKGJQ==} + engines: {node: '>=14.19.0', npm: '>=3.0.0'} + hasBin: true + requiresBuild: true peerDependencies: - react: '>=15.0.0' + react: '>=18.0.0' + react-dom: '>=18.0.0' dependencies: - '@ice/sandbox': 1.1.4 - lodash.isempty: 4.4.0 - lodash.isequal: 4.5.0 - path-to-regexp: 1.8.0 - url-parse: 1.5.10 - dev: false + '@ice/bundles': 0.1.16_4mgkpocji6i4c7t543qhprlmp4 + '@ice/route-manifest': 1.2.2 + '@ice/rspack-config': 1.0.5_4mgkpocji6i4c7t543qhprlmp4 + '@ice/runtime': 1.3.1 + '@ice/shared-config': 1.1.0_4mgkpocji6i4c7t543qhprlmp4 + '@ice/webpack-config': 1.1.4_4mgkpocji6i4c7t543qhprlmp4 + '@swc/helpers': 0.5.1 + '@types/express': 4.17.17 + address: 1.2.2 + build-scripts: 2.1.2-0 + chalk: 4.1.2 + commander: 9.5.0 + consola: 2.15.3 + cross-spawn: 7.0.3 + detect-port: 1.5.1 + dotenv: 16.0.3 + dotenv-expand: 8.0.3 + ejs: 3.1.8 + fast-glob: 3.3.0 + find-up: 5.0.0 + fs-extra: 10.1.0 + micromatch: 4.0.5 + mlly: 1.1.1 + mrmime: 1.0.1 + open: 8.4.2 + path-to-regexp: 6.2.1 + regenerator-runtime: 0.13.11 + resolve.exports: 1.1.1 + semver: 7.4.0 + source-map-support: 0.5.21 + temp: 0.9.4 + yargs-parser: 21.1.1 + transitivePeerDependencies: + - '@types/webpack' + - bufferutil + - debug + - sockjs-client + - supports-color + - type-fest + - uglify-js + - utf-8-validate + - webpack + - webpack-cli + - webpack-dev-server + - webpack-hot-middleware + - webpack-plugin-serve + dev: true - /@ice/store/2.0.3_biqbaboplfbrettd7655fr4n2y: - resolution: {integrity: sha512-U1YcY380bejqc3+WtkEqIwE6HnjBjSKd4IWFyq8gakPeAvA6fEJ58Qx9hzscYxlogWbiCb0Wm9kqkcDU+njx7g==} + /@ice/app/3.3.5_webpack@5.88.2: + resolution: {integrity: sha512-loVbr/CqH5suvWchw/mvbLS/yfO/qsxOx/KvcmdQYA8Unr0J1fYHrBFlYbKmpJe0aEDnSfSzDKebJsbyDTKGJQ==} + engines: {node: '>=14.19.0', npm: '>=3.0.0'} + hasBin: true + requiresBuild: true peerDependencies: - react: ^16.8 || ^17 || ^18 + react: '>=18.0.0' + react-dom: '>=18.0.0' dependencies: - immer: 9.0.19 - lodash.isfunction: 3.0.9 - react: 18.2.0 - react-redux: 7.2.9_biqbaboplfbrettd7655fr4n2y - redux: 4.2.1 - redux-thunk: 2.4.2_redux@4.2.1 - transitivePeerDependencies: - - react-dom - - react-native - dev: false - - /@ice/swc-plugin-keep-export/0.2.0: - resolution: {integrity: sha512-N3tg4BOV78jZSR/9CypJf5YzHxrNi40dNlUAwFjf7nr9pzMvVlo9bZM0I/A9l6J9vMff/5mgtkW5+JiMYdyjig==} - dev: false - - /@ice/swc-plugin-node-transform/0.2.0: - resolution: {integrity: sha512-06NtOUGVAUKP1eQXGMkaIZpNl9d5RK6SB6xQJsMY/DIso8WnwymyN7hmoFXPzX0eFkhmQEc7jzJ7NDBXaXRqWQ==} - dev: false - - /@ice/swc-plugin-react-server-component/0.1.1: - resolution: {integrity: sha512-3FdXOZ7HTBHY+DKQXDpzqV10ngfl0ifffc7HFV0P4YPLfvEJjT0RxIZJW1QwRZ3QeB2ph4zvXfdBG1lYTzT58Q==} - dev: false + '@ice/bundles': 0.1.16_nybtr22olkopkms5hv7r5oud4i + '@ice/route-manifest': 1.2.2 + '@ice/rspack-config': 1.0.5_nybtr22olkopkms5hv7r5oud4i + '@ice/runtime': 1.3.1 + '@ice/shared-config': 1.1.0_nybtr22olkopkms5hv7r5oud4i + '@ice/webpack-config': 1.1.4_nybtr22olkopkms5hv7r5oud4i + '@swc/helpers': 0.5.1 + '@types/express': 4.17.17 + address: 1.2.2 + build-scripts: 2.1.2-0 + chalk: 4.1.2 + commander: 9.5.0 + consola: 2.15.3 + cross-spawn: 7.0.3 + detect-port: 1.5.1 + dotenv: 16.0.3 + dotenv-expand: 8.0.3 + ejs: 3.1.8 + fast-glob: 3.3.0 + find-up: 5.0.0 + fs-extra: 10.1.0 + micromatch: 4.0.5 + mlly: 1.1.1 + mrmime: 1.0.1 + open: 8.4.2 + path-to-regexp: 6.2.1 + regenerator-runtime: 0.13.11 + resolve.exports: 1.1.1 + semver: 7.4.0 + source-map-support: 0.5.21 + temp: 0.9.4 + yargs-parser: 21.1.1 + transitivePeerDependencies: + - '@types/webpack' + - bufferutil + - debug + - sockjs-client + - supports-color + - type-fest + - uglify-js + - utf-8-validate + - webpack + - webpack-cli + - webpack-dev-server + - webpack-hot-middleware + - webpack-plugin-serve + dev: true + + /@ice/bundles/0.1.16_4mgkpocji6i4c7t543qhprlmp4: + resolution: {integrity: sha512-1wpmStho4gUplggwERopzmIz2NkEaRwnzta7ZpoNBzCM/KaTI9FvbTGuty087kQq81uu4mFfozYS+Bw6kk6bVA==} + dependencies: + '@ice/css-modules-hash': 0.0.6 + '@ice/swc-plugin-keep-export': 0.2.0 + '@ice/swc-plugin-node-transform': 0.2.0 + '@ice/swc-plugin-remove-export': 0.2.0 + '@rspack/core': 0.3.0_ls5vlc7kphql6b6gtepk5p7cmu + '@rspack/dev-server': 0.3.0_xwlm2ukmbpiz7ykxwfclqtcmji + '@swc/core': 1.3.80_@swc+helpers@0.5.1 + ansi-html-community: 0.0.8 + caniuse-lite: 1.0.30001462 + chokidar: 3.5.3 + core-js: 3.32.0 + core-js-pure: 3.29.0 + error-stack-parser: 2.1.4 + esbuild: 0.17.16 + events: 3.3.0 + html-entities: 2.3.3 + jest-worker: 27.5.1 + less: 4.1.2 + postcss: 8.4.12 + react-refresh: 0.14.0 + sass: 1.50.0 + transitivePeerDependencies: + - '@swc/helpers' + - '@types/express' + - '@types/webpack' + - bufferutil + - debug + - sockjs-client + - supports-color + - type-fest + - uglify-js + - utf-8-validate + - webpack + - webpack-cli + - webpack-dev-server + - webpack-hot-middleware + - webpack-plugin-serve + dev: true + + /@ice/bundles/0.1.16_nybtr22olkopkms5hv7r5oud4i: + resolution: {integrity: sha512-1wpmStho4gUplggwERopzmIz2NkEaRwnzta7ZpoNBzCM/KaTI9FvbTGuty087kQq81uu4mFfozYS+Bw6kk6bVA==} + dependencies: + '@ice/css-modules-hash': 0.0.6 + '@ice/swc-plugin-keep-export': 0.2.0 + '@ice/swc-plugin-node-transform': 0.2.0 + '@ice/swc-plugin-remove-export': 0.2.0 + '@rspack/core': 0.3.0_webpack@5.88.2 + '@rspack/dev-server': 0.3.0_xwlm2ukmbpiz7ykxwfclqtcmji + '@swc/core': 1.3.80_@swc+helpers@0.5.1 + ansi-html-community: 0.0.8 + caniuse-lite: 1.0.30001462 + chokidar: 3.5.3 + core-js: 3.32.0 + core-js-pure: 3.29.0 + error-stack-parser: 2.1.4 + esbuild: 0.17.16 + events: 3.3.0 + html-entities: 2.3.3 + jest-worker: 27.5.1 + less: 4.1.2 + postcss: 8.4.12 + react-refresh: 0.14.0 + sass: 1.50.0 + transitivePeerDependencies: + - '@swc/helpers' + - '@types/express' + - '@types/webpack' + - bufferutil + - debug + - sockjs-client + - supports-color + - type-fest + - uglify-js + - utf-8-validate + - webpack + - webpack-cli + - webpack-dev-server + - webpack-hot-middleware + - webpack-plugin-serve + dev: true + + /@ice/bundles/0.1.16_oikrtulvecolg3hvcan4tch6ku: + resolution: {integrity: sha512-1wpmStho4gUplggwERopzmIz2NkEaRwnzta7ZpoNBzCM/KaTI9FvbTGuty087kQq81uu4mFfozYS+Bw6kk6bVA==} + dependencies: + '@ice/css-modules-hash': 0.0.6 + '@ice/swc-plugin-keep-export': 0.2.0 + '@ice/swc-plugin-node-transform': 0.2.0 + '@ice/swc-plugin-remove-export': 0.2.0 + '@rspack/core': 0.3.0 + '@rspack/dev-server': 0.3.0_xwlm2ukmbpiz7ykxwfclqtcmji + '@swc/core': 1.3.80_@swc+helpers@0.5.1 + ansi-html-community: 0.0.8 + caniuse-lite: 1.0.30001462 + chokidar: 3.5.3 + core-js: 3.32.0 + core-js-pure: 3.29.0 + error-stack-parser: 2.1.4 + esbuild: 0.17.16 + events: 3.3.0 + html-entities: 2.3.3 + jest-worker: 27.5.1 + less: 4.1.2 + postcss: 8.4.12 + react-refresh: 0.14.0 + sass: 1.50.0 + transitivePeerDependencies: + - '@swc/helpers' + - '@types/express' + - '@types/webpack' + - bufferutil + - debug + - sockjs-client + - supports-color + - type-fest + - uglify-js + - utf-8-validate + - webpack + - webpack-cli + - webpack-dev-server + - webpack-hot-middleware + - webpack-plugin-serve + dev: true + + /@ice/css-modules-hash-darwin-arm64/0.0.6: + resolution: {integrity: sha512-5QWZl3+biY5U/kRhymH+6X/kAk3Imvkqu9QpV+LTDxhoXEkdhzZd2sCO5ZNfrsODFuHy78iKzh6gEweADPwYkQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + optional: true + + /@ice/css-modules-hash-darwin-universal/0.0.6: + resolution: {integrity: sha512-PLmDCFZHvpNysvMhUa363QWvgCMIwr6vYwEkHkC/AF9NZvl25r2R9mfdExHw8sZHu9fMHVINwWEBcMiYbZd/cg==} + engines: {node: '>= 10'} + os: [darwin] + requiresBuild: true + optional: true + + /@ice/css-modules-hash-darwin-x64/0.0.6: + resolution: {integrity: sha512-HOmh+Yiw6rH9VJD2XBN7sZmigo+jwi7qAD/J12pbxVrMJ//aIsv3BwpgFhfGO8eqKeyVqNXac3S/vC2hq8t8jw==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + requiresBuild: true + optional: true + + /@ice/css-modules-hash-linux-x64-gnu/0.0.6: + resolution: {integrity: sha512-PS7lTINETFqzbU0nbgLgxXJOp+BU51VvNeNEF1h6Xz6soR23yqFht6d8xuNC1auBnPHZM+RDiQYzwi9MCBTvgA==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + requiresBuild: true + optional: true + + /@ice/css-modules-hash-linux-x64-musl/0.0.6: + resolution: {integrity: sha512-UiDg8KpoDGmQrBt9z5lqjr+OAG2S2xQi00Unt2yali1dvhS1tpcN16isiBA2yO3JOy2b0Y0VtlmpJKxpMDsFcg==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + requiresBuild: true + optional: true + + /@ice/css-modules-hash-win32-arm64-msvc/0.0.6: + resolution: {integrity: sha512-7rF1gX9QyhhGUo4JKZUQ6DSJs/xJiJlrKC9D91dkTHs81e0G6IQLv9EnIaX2OPF3/SPnqp7CAGxr7TOtDYsyAw==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + requiresBuild: true + optional: true + + /@ice/css-modules-hash-win32-x64-msvc/0.0.6: + resolution: {integrity: sha512-on3tYfhvBW6XQ6tkE0KKZvFK0JB/iwBrvUiRo/Di3ceJPPwD619PJNNQnn78kqcrZIVdQZ41HMdyuEnz8UHVpQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + requiresBuild: true + optional: true + + /@ice/css-modules-hash/0.0.6: + resolution: {integrity: sha512-UbYq2Ldw+hamc9HoIfKTZORmmYCaGnP6f361XdB/7PQZHZ5hAak6TePdcVQekLHGEg/+zIccN33mflJqucC1Aw==} + engines: {node: '>= 10'} + optionalDependencies: + '@ice/css-modules-hash-darwin-arm64': 0.0.6 + '@ice/css-modules-hash-darwin-universal': 0.0.6 + '@ice/css-modules-hash-darwin-x64': 0.0.6 + '@ice/css-modules-hash-linux-x64-gnu': 0.0.6 + '@ice/css-modules-hash-linux-x64-musl': 0.0.6 + '@ice/css-modules-hash-win32-arm64-msvc': 0.0.6 + '@ice/css-modules-hash-win32-x64-msvc': 0.0.6 + + /@ice/jsx-runtime/0.2.2: + resolution: {integrity: sha512-RKwn3QgqualrWz+HxGZh7gS5lmCHIwvF6oVRsZbUI6Ekll98RrgGGvUvkn1SdSF7fYqWOG4ZA4neplBCJqf4NA==} + peerDependencies: + react: ^16 || ^17 || ^18 + dependencies: + style-unit: 3.0.5 + dev: true + + /@ice/jsx-runtime/0.2.2_react@18.2.0: + resolution: {integrity: sha512-RKwn3QgqualrWz+HxGZh7gS5lmCHIwvF6oVRsZbUI6Ekll98RrgGGvUvkn1SdSF7fYqWOG4ZA4neplBCJqf4NA==} + peerDependencies: + react: ^16 || ^17 || ^18 + dependencies: + react: 18.2.0 + style-unit: 3.0.5 + dev: false + + /@ice/pkg/1.5.5: + resolution: {integrity: sha512-0BIfv6Uzs2wpHv7RmFwz+kWfoJLfx0yJrQyh3yqy+F6TZWxTwrqQmX+5yRmgqK5f7lGGhYfMMVNWjRSCw5MHPQ==} + engines: {node: '>=16.14.0'} + hasBin: true + dependencies: + '@ampproject/remapping': 2.2.0 + '@babel/core': 7.21.0 + '@babel/parser': 7.21.2 + '@babel/preset-react': 7.18.6_@babel+core@7.21.0 + '@babel/preset-typescript': 7.21.0_@babel+core@7.21.0 + '@rollup/plugin-commonjs': 21.1.0_rollup@2.79.1 + '@rollup/plugin-image': 3.0.2_rollup@2.79.1 + '@rollup/plugin-json': 4.1.0_rollup@2.79.1 + '@rollup/plugin-node-resolve': 13.3.0_rollup@2.79.1 + '@rollup/plugin-replace': 5.0.2_rollup@2.79.1 + '@rollup/pluginutils': 4.2.1 + '@swc/core': 1.3.32 + acorn: 8.8.2 + autoprefixer: 10.4.13_postcss@8.4.25 + build-scripts: 2.1.0 + cac: 6.7.14 + chokidar: 3.5.3 + consola: 2.15.3 + debug: 4.3.4 + deepmerge: 4.3.0 + escape-string-regexp: 5.0.0 + fs-extra: 10.1.0 + globby: 11.1.0 + gzip-size: 7.0.0 + lodash.merge: 4.6.2 + magic-string: 0.25.9 + picocolors: 1.0.0 + postcss: 8.4.25 + rollup: 2.79.1 + rollup-plugin-styles: 4.0.0_rollup@2.79.1 + rollup-plugin-visualizer: 5.9.0_rollup@2.79.1 + tsc-alias: 1.8.5 + typescript: 4.9.5 + transitivePeerDependencies: + - supports-color + dev: true + + /@ice/route-manifest/1.2.2: + resolution: {integrity: sha512-wu8qg/3MKnUkldOIq8fJYwnMoc2YmtQ/ry2OeQdnrHK8S+H4gbwR3uRseioKfoUhpMw0Ds7bjVDLX3ucGY078Q==} + dependencies: + minimatch: 5.1.6 + dev: true + + /@ice/rspack-config/1.0.5_4mgkpocji6i4c7t543qhprlmp4: + resolution: {integrity: sha512-dMvsK36Q3IzQGyT32b6fGpg7Rwla57jvo/gaQoQ8N5Zg+hnnTgSbfSj23/QaN82CxxnnSKCjsFlXeBA4tcDeBA==} + dependencies: + '@ice/bundles': 0.1.16_4mgkpocji6i4c7t543qhprlmp4 + '@ice/shared-config': 1.1.0_4mgkpocji6i4c7t543qhprlmp4 + transitivePeerDependencies: + - '@swc/helpers' + - '@types/express' + - '@types/webpack' + - bufferutil + - debug + - sockjs-client + - supports-color + - type-fest + - uglify-js + - utf-8-validate + - webpack + - webpack-cli + - webpack-dev-server + - webpack-hot-middleware + - webpack-plugin-serve + dev: true + + /@ice/rspack-config/1.0.5_nybtr22olkopkms5hv7r5oud4i: + resolution: {integrity: sha512-dMvsK36Q3IzQGyT32b6fGpg7Rwla57jvo/gaQoQ8N5Zg+hnnTgSbfSj23/QaN82CxxnnSKCjsFlXeBA4tcDeBA==} + dependencies: + '@ice/bundles': 0.1.16_nybtr22olkopkms5hv7r5oud4i + '@ice/shared-config': 1.1.0_nybtr22olkopkms5hv7r5oud4i + transitivePeerDependencies: + - '@swc/helpers' + - '@types/express' + - '@types/webpack' + - bufferutil + - debug + - sockjs-client + - supports-color + - type-fest + - uglify-js + - utf-8-validate + - webpack + - webpack-cli + - webpack-dev-server + - webpack-hot-middleware + - webpack-plugin-serve + dev: true + + /@ice/rspack-config/1.0.5_oikrtulvecolg3hvcan4tch6ku: + resolution: {integrity: sha512-dMvsK36Q3IzQGyT32b6fGpg7Rwla57jvo/gaQoQ8N5Zg+hnnTgSbfSj23/QaN82CxxnnSKCjsFlXeBA4tcDeBA==} + dependencies: + '@ice/bundles': 0.1.16_oikrtulvecolg3hvcan4tch6ku + '@ice/shared-config': 1.1.0_oikrtulvecolg3hvcan4tch6ku + transitivePeerDependencies: + - '@swc/helpers' + - '@types/express' + - '@types/webpack' + - bufferutil + - debug + - sockjs-client + - supports-color + - type-fest + - uglify-js + - utf-8-validate + - webpack + - webpack-cli + - webpack-dev-server + - webpack-hot-middleware + - webpack-plugin-serve + dev: true + + /@ice/runtime/1.3.1: + resolution: {integrity: sha512-Bil7i9KQF1Mu8BaT9eHvSEDk36/eYvhKQ16L6QEfiEu/rKB7AjcV38RK5q1RH8SYRQP6rdqH9z7OLsVxZjqOVA==} + requiresBuild: true + peerDependencies: + react: ^18.1.0 + react-dom: ^18.1.0 + dependencies: + '@ice/jsx-runtime': 0.2.2 + '@ice/shared': 1.0.2 + '@remix-run/router': 1.7.2 + abortcontroller-polyfill: 1.7.5 + ejs: 3.1.8 + fs-extra: 10.1.0 + history: 5.3.0 + htmlparser2: 8.0.1 + react-router-dom: 6.14.2 + semver: 7.4.0 + source-map: 0.7.4 + dev: true + + /@ice/runtime/1.3.1_biqbaboplfbrettd7655fr4n2y: + resolution: {integrity: sha512-Bil7i9KQF1Mu8BaT9eHvSEDk36/eYvhKQ16L6QEfiEu/rKB7AjcV38RK5q1RH8SYRQP6rdqH9z7OLsVxZjqOVA==} + requiresBuild: true + peerDependencies: + react: ^18.1.0 + react-dom: ^18.1.0 + dependencies: + '@ice/jsx-runtime': 0.2.2_react@18.2.0 + '@ice/shared': 1.0.2 + '@remix-run/router': 1.7.2 + abortcontroller-polyfill: 1.7.5 + ejs: 3.1.8 + fs-extra: 10.1.0 + history: 5.3.0 + htmlparser2: 8.0.1 + react: 18.2.0 + react-dom: 18.2.0_react@18.2.0 + react-router-dom: 6.14.2_biqbaboplfbrettd7655fr4n2y + semver: 7.4.0 + source-map: 0.7.4 + dev: false + + /@ice/runtime/1.3.1_react@18.2.0: + resolution: {integrity: sha512-Bil7i9KQF1Mu8BaT9eHvSEDk36/eYvhKQ16L6QEfiEu/rKB7AjcV38RK5q1RH8SYRQP6rdqH9z7OLsVxZjqOVA==} + requiresBuild: true + peerDependencies: + react: ^18.1.0 + react-dom: ^18.1.0 + dependencies: + '@ice/jsx-runtime': 0.2.2_react@18.2.0 + '@ice/shared': 1.0.2 + '@remix-run/router': 1.7.2 + abortcontroller-polyfill: 1.7.5 + ejs: 3.1.8 + fs-extra: 10.1.0 + history: 5.3.0 + htmlparser2: 8.0.1 + react: 18.2.0 + react-router-dom: 6.14.2_react@18.2.0 + semver: 7.4.0 + source-map: 0.7.4 + dev: false + + /@ice/sandbox/1.1.4: + resolution: {integrity: sha512-MEVF0Ze3McKDutnFiUAhUoc+WwOFxITVBgSSHmbGpKtWbXJX9kUVlx3VsEVJvdqU3O1kiBNx6zE1sFMjKPRTIQ==} + dev: false + + /@ice/shared-config/1.1.0_4mgkpocji6i4c7t543qhprlmp4: + resolution: {integrity: sha512-5llovTXzFFPyCZNVV+i1LcC6M8FLjNK3v8Y9DmeL2jtOyB+jBMlkCWRALPE6qsSoeJG1T41MfrDyaeIs8CY2kA==} + dependencies: + '@ice/bundles': 0.1.16_4mgkpocji6i4c7t543qhprlmp4 + '@rollup/pluginutils': 4.2.1 + browserslist: 4.21.5 + consola: 2.15.3 + fast-glob: 3.3.0 + process: 0.11.10 + transitivePeerDependencies: + - '@swc/helpers' + - '@types/express' + - '@types/webpack' + - bufferutil + - debug + - sockjs-client + - supports-color + - type-fest + - uglify-js + - utf-8-validate + - webpack + - webpack-cli + - webpack-dev-server + - webpack-hot-middleware + - webpack-plugin-serve + dev: true + + /@ice/shared-config/1.1.0_nybtr22olkopkms5hv7r5oud4i: + resolution: {integrity: sha512-5llovTXzFFPyCZNVV+i1LcC6M8FLjNK3v8Y9DmeL2jtOyB+jBMlkCWRALPE6qsSoeJG1T41MfrDyaeIs8CY2kA==} + dependencies: + '@ice/bundles': 0.1.16_nybtr22olkopkms5hv7r5oud4i + '@rollup/pluginutils': 4.2.1 + browserslist: 4.21.5 + consola: 2.15.3 + fast-glob: 3.3.0 + process: 0.11.10 + transitivePeerDependencies: + - '@swc/helpers' + - '@types/express' + - '@types/webpack' + - bufferutil + - debug + - sockjs-client + - supports-color + - type-fest + - uglify-js + - utf-8-validate + - webpack + - webpack-cli + - webpack-dev-server + - webpack-hot-middleware + - webpack-plugin-serve + dev: true + + /@ice/shared-config/1.1.0_oikrtulvecolg3hvcan4tch6ku: + resolution: {integrity: sha512-5llovTXzFFPyCZNVV+i1LcC6M8FLjNK3v8Y9DmeL2jtOyB+jBMlkCWRALPE6qsSoeJG1T41MfrDyaeIs8CY2kA==} + dependencies: + '@ice/bundles': 0.1.16_oikrtulvecolg3hvcan4tch6ku + '@rollup/pluginutils': 4.2.1 + browserslist: 4.21.5 + consola: 2.15.3 + fast-glob: 3.3.0 + process: 0.11.10 + transitivePeerDependencies: + - '@swc/helpers' + - '@types/express' + - '@types/webpack' + - bufferutil + - debug + - sockjs-client + - supports-color + - type-fest + - uglify-js + - utf-8-validate + - webpack + - webpack-cli + - webpack-dev-server + - webpack-hot-middleware + - webpack-plugin-serve + dev: true + + /@ice/shared/1.0.2: + resolution: {integrity: sha512-fSSTUzQEqodKsnvIFShJujp8qljCd88QjfEDJ9JIGgeHQfanMjZeL8s+jwI4o6L0oYl6Xg0hh/3UTIJ1Xar7KQ==} + + /@ice/stark-app/1.5.0: + resolution: {integrity: sha512-9fuCri48eZj6TnfPkCju4vVLhGurz+mt6lFx4JQFHhnRBQ5MuiBqRZg5F/3vdnJ7dAYQJlCXmHlQtBHok82z+g==} + dev: false + + /@ice/stark/2.7.5: + resolution: {integrity: sha512-HyV3/6PtTfNiKBkncztunpjsWMBw/SyQ24TvrYLnpkuSmrlZ9t0/jkJWuaM6nGpAufyZ62YfQ2Tn032So9OeIg==} + peerDependencies: + react: '>=15.0.0' + dependencies: + '@ice/sandbox': 1.1.4 + lodash.isempty: 4.4.0 + lodash.isequal: 4.5.0 + path-to-regexp: 1.8.0 + url-parse: 1.5.10 + dev: false + + /@ice/store/2.0.3_biqbaboplfbrettd7655fr4n2y: + resolution: {integrity: sha512-U1YcY380bejqc3+WtkEqIwE6HnjBjSKd4IWFyq8gakPeAvA6fEJ58Qx9hzscYxlogWbiCb0Wm9kqkcDU+njx7g==} + peerDependencies: + react: ^16.8 || ^17 || ^18 + dependencies: + immer: 9.0.19 + lodash.isfunction: 3.0.9 + react: 18.2.0 + react-redux: 7.2.9_biqbaboplfbrettd7655fr4n2y + redux: 4.2.1 + redux-thunk: 2.4.2_redux@4.2.1 + transitivePeerDependencies: + - react-dom + - react-native + dev: false + + /@ice/swc-plugin-keep-export/0.2.0: + resolution: {integrity: sha512-N3tg4BOV78jZSR/9CypJf5YzHxrNi40dNlUAwFjf7nr9pzMvVlo9bZM0I/A9l6J9vMff/5mgtkW5+JiMYdyjig==} + + /@ice/swc-plugin-node-transform/0.2.0: + resolution: {integrity: sha512-06NtOUGVAUKP1eQXGMkaIZpNl9d5RK6SB6xQJsMY/DIso8WnwymyN7hmoFXPzX0eFkhmQEc7jzJ7NDBXaXRqWQ==} + + /@ice/swc-plugin-react-server-component/0.1.1: + resolution: {integrity: sha512-3FdXOZ7HTBHY+DKQXDpzqV10ngfl0ifffc7HFV0P4YPLfvEJjT0RxIZJW1QwRZ3QeB2ph4zvXfdBG1lYTzT58Q==} + dev: false /@ice/swc-plugin-remove-export/0.2.0: resolution: {integrity: sha512-kmyrCMtuEsS7J3rpENT5qUhhbuu3eldsN1WpJjtXX4rgogJ1+QmnAPjnhB0SWzr0/b5ArGfz83O6M+5NNGRd+A==} - dev: false + + /@ice/webpack-config/1.1.4_4mgkpocji6i4c7t543qhprlmp4: + resolution: {integrity: sha512-h+ckjRPEPVydvFyca7Mkc6I+mexR+A+1p+QBYK3CfJ2MBEpbZx2t8E6XfaOBes8BZ3ag7yBQDeGrpu9J7Ad+oQ==} + dependencies: + '@ice/bundles': 0.1.16_4mgkpocji6i4c7t543qhprlmp4 + '@ice/shared-config': 1.1.0_4mgkpocji6i4c7t543qhprlmp4 + fast-glob: 3.3.0 + process: 0.11.10 + transitivePeerDependencies: + - '@swc/helpers' + - '@types/express' + - '@types/webpack' + - bufferutil + - debug + - sockjs-client + - supports-color + - type-fest + - uglify-js + - utf-8-validate + - webpack + - webpack-cli + - webpack-dev-server + - webpack-hot-middleware + - webpack-plugin-serve + dev: true + + /@ice/webpack-config/1.1.4_nybtr22olkopkms5hv7r5oud4i: + resolution: {integrity: sha512-h+ckjRPEPVydvFyca7Mkc6I+mexR+A+1p+QBYK3CfJ2MBEpbZx2t8E6XfaOBes8BZ3ag7yBQDeGrpu9J7Ad+oQ==} + dependencies: + '@ice/bundles': 0.1.16_nybtr22olkopkms5hv7r5oud4i + '@ice/shared-config': 1.1.0_nybtr22olkopkms5hv7r5oud4i + fast-glob: 3.3.0 + process: 0.11.10 + transitivePeerDependencies: + - '@swc/helpers' + - '@types/express' + - '@types/webpack' + - bufferutil + - debug + - sockjs-client + - supports-color + - type-fest + - uglify-js + - utf-8-validate + - webpack + - webpack-cli + - webpack-dev-server + - webpack-hot-middleware + - webpack-plugin-serve + dev: true + + /@ice/webpack-config/1.1.4_oikrtulvecolg3hvcan4tch6ku: + resolution: {integrity: sha512-h+ckjRPEPVydvFyca7Mkc6I+mexR+A+1p+QBYK3CfJ2MBEpbZx2t8E6XfaOBes8BZ3ag7yBQDeGrpu9J7Ad+oQ==} + dependencies: + '@ice/bundles': 0.1.16_oikrtulvecolg3hvcan4tch6ku + '@ice/shared-config': 1.1.0_oikrtulvecolg3hvcan4tch6ku + fast-glob: 3.3.0 + process: 0.11.10 + transitivePeerDependencies: + - '@swc/helpers' + - '@types/express' + - '@types/webpack' + - bufferutil + - debug + - sockjs-client + - supports-color + - type-fest + - uglify-js + - utf-8-validate + - webpack + - webpack-cli + - webpack-dev-server + - webpack-hot-middleware + - webpack-plugin-serve + dev: true /@iceworks/generate-project/2.0.2: resolution: {integrity: sha512-t7/uHl5kM71o+xyR+FnaPsgyFqhFQm89TdqPahM4Kv/ubdKDknFVUYLio1khMDGY8Ops0ahn/+KM+gFnHEKSQw==} @@ -6421,7 +7021,6 @@ packages: source-map: 0.7.4 webpack: 5.76.0_pur5qe7dhbhqwjtj2daaog4n7u webpack-dev-server: 4.13.1_webpack@5.76.0 - dev: false /@pmmmwh/react-refresh-webpack-plugin/0.5.10_p44l2xjftguod6ctnkuod3jp7e: resolution: {integrity: sha512-j0Ya0hCFZPd4x40qLzbhGsh9TMtdb+CJQiso+WxLOPNasohq9cc5SNUcwsZaRH6++Xh91Xkm/xHCkuIiIu0LUA==} @@ -6540,6 +7139,45 @@ packages: webpack-dev-server: 4.11.1_webpack@5.88.2 dev: true + /@pmmmwh/react-refresh-webpack-plugin/0.5.10_wrxi7ct7dz7g7lwv6srrq7wgqy: + resolution: {integrity: sha512-j0Ya0hCFZPd4x40qLzbhGsh9TMtdb+CJQiso+WxLOPNasohq9cc5SNUcwsZaRH6++Xh91Xkm/xHCkuIiIu0LUA==} + engines: {node: '>= 10.13'} + peerDependencies: + '@types/webpack': 4.x || 5.x + react-refresh: '>=0.10.0 <1.0.0' + sockjs-client: ^1.4.0 + type-fest: '>=0.17.0 <4.0.0' + webpack: '>=4.43.0 <6.0.0' + webpack-dev-server: 3.x || 4.x + webpack-hot-middleware: 2.x + webpack-plugin-serve: 0.x || 1.x + peerDependenciesMeta: + '@types/webpack': + optional: true + sockjs-client: + optional: true + type-fest: + optional: true + webpack-dev-server: + optional: true + webpack-hot-middleware: + optional: true + webpack-plugin-serve: + optional: true + dependencies: + ansi-html-community: 0.0.8 + common-path-prefix: 3.0.0 + core-js-pure: 3.29.0 + error-stack-parser: 2.1.4 + find-up: 5.0.0 + html-entities: 2.3.3 + loader-utils: 2.0.4 + react-refresh: 0.14.0 + schema-utils: 3.1.1 + source-map: 0.7.4 + webpack: 5.88.2 + dev: true + /@pmmmwh/react-refresh-webpack-plugin/0.5.10_ynqbgb5bmgbvx2am6mt2h3lxsq: resolution: {integrity: sha512-j0Ya0hCFZPd4x40qLzbhGsh9TMtdb+CJQiso+WxLOPNasohq9cc5SNUcwsZaRH6++Xh91Xkm/xHCkuIiIu0LUA==} engines: {node: '>= 10.13'} @@ -6993,6 +7631,35 @@ packages: - webpack-plugin-serve dev: true + /@rspack/core/0.3.0_webpack@5.88.2: + resolution: {integrity: sha512-YltE0AQimUMOSTIFuDP+BW2GoJsabrig/GmgCR1eDWlVeKlmGJ6wd2GdYjmW5TWdH6FBQPQ3YfU8GOB4XWsvgQ==} + dependencies: + '@rspack/binding': 0.3.0 + '@rspack/dev-client': 0.3.0_wrxi7ct7dz7g7lwv6srrq7wgqy + '@swc/helpers': 0.5.1 + browserslist: 4.21.5 + compare-versions: 6.0.0-rc.1 + enhanced-resolve: 5.12.0 + graceful-fs: 4.2.10 + neo-async: 2.6.2 + react-refresh: 0.14.0 + schema-utils: 4.0.0 + tapable: 2.2.1 + util: 0.12.5 + watchpack: 2.4.0 + webpack-sources: 3.2.3 + zod: 3.21.4 + zod-validation-error: 1.2.0_zod@3.21.4 + transitivePeerDependencies: + - '@types/webpack' + - sockjs-client + - type-fest + - webpack + - webpack-dev-server + - webpack-hot-middleware + - webpack-plugin-serve + dev: true + /@rspack/core/0.3.0_zur76qpjdwubwowmoyfe2ntqhe: resolution: {integrity: sha512-YltE0AQimUMOSTIFuDP+BW2GoJsabrig/GmgCR1eDWlVeKlmGJ6wd2GdYjmW5TWdH6FBQPQ3YfU8GOB4XWsvgQ==} dependencies: @@ -7040,7 +7707,6 @@ packages: - webpack-dev-server - webpack-hot-middleware - webpack-plugin-serve - dev: false /@rspack/dev-client/0.3.0_p44l2xjftguod6ctnkuod3jp7e: resolution: {integrity: sha512-nttTUBVctbh9auvPq91ThmjNDcBLj3kfLDjM/O1jBYA3xTz9MNsTN3rInLOb4S2fWEsSBLz7CVsNLP7LWtUecA==} @@ -7101,6 +7767,26 @@ packages: - webpack-plugin-serve dev: true + /@rspack/dev-client/0.3.0_wrxi7ct7dz7g7lwv6srrq7wgqy: + resolution: {integrity: sha512-nttTUBVctbh9auvPq91ThmjNDcBLj3kfLDjM/O1jBYA3xTz9MNsTN3rInLOb4S2fWEsSBLz7CVsNLP7LWtUecA==} + peerDependencies: + react-refresh: '>=0.10.0 <1.0.0' + peerDependenciesMeta: + react-refresh: + optional: true + dependencies: + '@pmmmwh/react-refresh-webpack-plugin': 0.5.10_wrxi7ct7dz7g7lwv6srrq7wgqy + react-refresh: 0.14.0 + transitivePeerDependencies: + - '@types/webpack' + - sockjs-client + - type-fest + - webpack + - webpack-dev-server + - webpack-hot-middleware + - webpack-plugin-serve + dev: true + /@rspack/dev-client/0.3.0_ynqbgb5bmgbvx2am6mt2h3lxsq: resolution: {integrity: sha512-nttTUBVctbh9auvPq91ThmjNDcBLj3kfLDjM/O1jBYA3xTz9MNsTN3rInLOb4S2fWEsSBLz7CVsNLP7LWtUecA==} peerDependencies: @@ -7153,21 +7839,55 @@ packages: - webpack-cli - webpack-hot-middleware - webpack-plugin-serve - dev: false + dev: false + + /@rspack/dev-server/0.3.0_saarlyqjwgcwik7cbeuxgtrvdm: + resolution: {integrity: sha512-aKY1mUP1PdOWXDvxpUA14mEE7p+IFYnU67i7cAUh361z2/v5KbCTngt521ly8H1LqJv3SJIoEXqSqNc8c62Dsg==} + peerDependencies: + '@rspack/core': '*' + dependencies: + '@rspack/core': 0.3.0_ls5vlc7kphql6b6gtepk5p7cmu + '@rspack/dev-client': 0.3.0_p44l2xjftguod6ctnkuod3jp7e + chokidar: 3.5.3 + connect-history-api-fallback: 2.0.0 + express: 4.18.1 + http-proxy-middleware: 2.0.6_@types+express@4.17.17 + mime-types: 2.1.35 + webpack: 5.76.0_esbuild@0.17.16 + webpack-dev-middleware: 6.0.2_webpack@5.76.0 + webpack-dev-server: 4.13.1_webpack@5.76.0 + ws: 8.8.1 + transitivePeerDependencies: + - '@swc/core' + - '@types/express' + - '@types/webpack' + - bufferutil + - debug + - esbuild + - react-refresh + - sockjs-client + - supports-color + - type-fest + - uglify-js + - utf-8-validate + - webpack-cli + - webpack-hot-middleware + - webpack-plugin-serve + dev: true - /@rspack/dev-server/0.3.0_saarlyqjwgcwik7cbeuxgtrvdm: + /@rspack/dev-server/0.3.0_xwlm2ukmbpiz7ykxwfclqtcmji: resolution: {integrity: sha512-aKY1mUP1PdOWXDvxpUA14mEE7p+IFYnU67i7cAUh361z2/v5KbCTngt521ly8H1LqJv3SJIoEXqSqNc8c62Dsg==} peerDependencies: '@rspack/core': '*' dependencies: - '@rspack/core': 0.3.0_ls5vlc7kphql6b6gtepk5p7cmu - '@rspack/dev-client': 0.3.0_p44l2xjftguod6ctnkuod3jp7e + '@rspack/core': 0.3.0 + '@rspack/dev-client': 0.3.0_4p7fys4vpjth4wnvvzaxfza3hm chokidar: 3.5.3 connect-history-api-fallback: 2.0.0 express: 4.18.1 http-proxy-middleware: 2.0.6_@types+express@4.17.17 mime-types: 2.1.35 - webpack: 5.76.0_esbuild@0.17.16 + webpack: 5.76.0_yt3h3qjhcnsf3663codtuni62a webpack-dev-middleware: 6.0.2_webpack@5.76.0 webpack-dev-server: 4.13.1_webpack@5.76.0 ws: 8.8.1 @@ -7500,6 +8220,15 @@ packages: dev: true optional: true + /@swc/core-darwin-arm64/1.3.80: + resolution: {integrity: sha512-rhoFTcQMUGfO7IkfOnopPSF6O0/aVJ58B7KueIKbvrMe6YvSfFj9QfObELFjYCcrJZTvUWBhig0QrsfPIiUphA==} + engines: {node: '>=10'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + /@swc/core-darwin-arm64/1.3.85: resolution: {integrity: sha512-jTikp+i4nO4Ofe6qGm4I3sFeebD1OvueBCHITux5tQKD6umN1c2z4CRGv6K49NIz/qEpUcdr6Qny6K+3yibVFQ==} engines: {node: '>=10'} @@ -7517,6 +8246,15 @@ packages: dev: true optional: true + /@swc/core-darwin-x64/1.3.80: + resolution: {integrity: sha512-0dOLedFpVXe+ugkKHXsqSxMKqvQYfFtibWbrZ7j8wOaErzSGPr0VpyWvepNVb9s046725kPXSw+fsGhqZR8wrw==} + engines: {node: '>=10'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + /@swc/core-darwin-x64/1.3.85: resolution: {integrity: sha512-3uHYkjVU+2F+YbVYtq5rH0uCJIztFTALaS3mQEfQUZKXZ5/8jD5titTCRqFKtSlQg0CzaFZgsYsuqwYBmgN0mA==} engines: {node: '>=10'} @@ -7534,6 +8272,15 @@ packages: dev: true optional: true + /@swc/core-linux-arm-gnueabihf/1.3.80: + resolution: {integrity: sha512-QIjwP3PtDeHBDkwF6+ZZqdUsqAhORbMpxrw2jq3mHe4lQrxBttSFTq018vlMRo2mFEorOvXdadzaD9m+NymPrw==} + engines: {node: '>=10'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@swc/core-linux-arm-gnueabihf/1.3.85: resolution: {integrity: sha512-ouHzAHsFaEOkRuoTAOI/8n2m8BQAAnb4vr/xbMhhDOmix0lp5eNsW5Iac/EcJ2uG6B3n7P2K8oycj9SWkj+pfw==} engines: {node: '>=10'} @@ -7551,6 +8298,15 @@ packages: dev: true optional: true + /@swc/core-linux-arm64-gnu/1.3.80: + resolution: {integrity: sha512-cg8WriIueab58ZwkzXmIACnjSzFLzOBwxlC9k65gPXMNgCjab2YbqEYvAbjBqneuqaao02gW6tad2uhjgYaExw==} + engines: {node: '>=10'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@swc/core-linux-arm64-gnu/1.3.85: resolution: {integrity: sha512-/Z1CZOWiO+NqJEh1J20PIxQFHMH43upQJ1l7FJ5Z7+MyuYF8WkeJ7OSovau729pBR+38vvvccEJrMZIztfv7hQ==} engines: {node: '>=10'} @@ -7568,6 +8324,15 @@ packages: dev: true optional: true + /@swc/core-linux-arm64-musl/1.3.80: + resolution: {integrity: sha512-AhdCQ7QKx5mWrtpaOA1mFRiWWvuiiUtspvo0QSpspDetRKTND1rlf/3UB5+gp0kCeCNUTsVmJWU7fIA9ICZtXA==} + engines: {node: '>=10'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@swc/core-linux-arm64-musl/1.3.85: resolution: {integrity: sha512-gfh7CfKavi076dbMBTzfdawSGcYfZ4+1Q+8aRkSesqepKHcIWIJti8Cf3zB4a6CHNhJe+VN0Gb7DEfumydAm1w==} engines: {node: '>=10'} @@ -7585,6 +8350,15 @@ packages: dev: true optional: true + /@swc/core-linux-x64-gnu/1.3.80: + resolution: {integrity: sha512-+2e5oni1vOrLIjM5Q2/GIzK/uS2YEtuJqnjPvCK8SciRJsSl8OgVsRvyCDbmKeZNtJ2Q+o/O2AQ2w1qpAJG6jg==} + engines: {node: '>=10'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@swc/core-linux-x64-gnu/1.3.85: resolution: {integrity: sha512-lWVqjHKzofb9q1qrBM4dLqO7CIisp08/xMS5Hz9DWex1gTc5F2b6yJO6Ceqwa256GMweJcdP6A5EvEFQAiZ5dg==} engines: {node: '>=10'} @@ -7602,6 +8376,15 @@ packages: dev: true optional: true + /@swc/core-linux-x64-musl/1.3.80: + resolution: {integrity: sha512-8OK9IlI1zpWOm7vIp1iXmZSEzLAwFpqhsGSEhxPavpOx2m54kLFdPcw/Uv3n461f6TCtszIxkGq1kSqBUdfUBA==} + engines: {node: '>=10'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@swc/core-linux-x64-musl/1.3.85: resolution: {integrity: sha512-EPJmlfqC05TUetnlErxNRyIp7Nc3B2w9abET6oQ/EgldeAeQnZ3M6svMViET/c2QSomgrU3rdP+Qcozkt62/4A==} engines: {node: '>=10'} @@ -7619,6 +8402,15 @@ packages: dev: true optional: true + /@swc/core-win32-arm64-msvc/1.3.80: + resolution: {integrity: sha512-RKhatwiAGlffnF6z2Mm3Ddid0v3KB+uf5m/Gc7N9zO/EUAV0PnHRuYuZSGyqodHmGFC+mK8YrCooFCEmHL9n+w==} + engines: {node: '>=10'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: true + optional: true + /@swc/core-win32-arm64-msvc/1.3.85: resolution: {integrity: sha512-ibckJDZw8kNosciMexwk0z75ZyUhwtiFMV9rSBpup0opa7NNCUCoERCJ1e9LRyMdhsVUoLpZg/KZiHCdTw96hQ==} engines: {node: '>=10'} @@ -7636,6 +8428,15 @@ packages: dev: true optional: true + /@swc/core-win32-ia32-msvc/1.3.80: + resolution: {integrity: sha512-3jiiZzU/kaw7k4zUp1yMq1QiUe4wJVtCEXIhf+fKuBsIwm7rdvyK/+PIx5KHnZy4TGQnYczKBRhJA5nuBcrUCQ==} + engines: {node: '>=10'} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: true + optional: true + /@swc/core-win32-ia32-msvc/1.3.85: resolution: {integrity: sha512-hY4MpHGUVQHL1T2kgRXOigDho4DTIpVPYzJ4uyy8VQRbS7GzN5XtvdGP/fA4zp8+2BQjcig+6J7Y92SY15ouNQ==} engines: {node: '>=10'} @@ -7653,6 +8454,15 @@ packages: dev: true optional: true + /@swc/core-win32-x64-msvc/1.3.80: + resolution: {integrity: sha512-2eZtIoIWQBWqykfms92Zd37lveYOBWQTZjdooBGlsLHtcoQLkNpf1NXmR6TKY0yy8q6Yl3OhPvY+izjmO08MSg==} + engines: {node: '>=10'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true + optional: true + /@swc/core-win32-x64-msvc/1.3.85: resolution: {integrity: sha512-ktxWOMFJ0iqKn6WUHtXqi4CS7xkyHmrRtjllGRuGqxmLmDX/HSOfuQ55Tm1KXKk5oHLacJkUbOSF2kBrpZ8dpg==} engines: {node: '>=10'} @@ -7678,6 +8488,31 @@ packages: '@swc/core-win32-x64-msvc': 1.3.32 dev: true + /@swc/core/1.3.80_@swc+helpers@0.5.1: + resolution: {integrity: sha512-yX2xV5I/lYswHHR+44TPvzBgq3/Y8N1YWpTQADYuvSiX3Jxyvemk5Jpx3rRtigYb8WBkWAAf2i5d5ZJ2M7hhgw==} + engines: {node: '>=10'} + requiresBuild: true + peerDependencies: + '@swc/helpers': ^0.5.0 + peerDependenciesMeta: + '@swc/helpers': + optional: true + dependencies: + '@swc/helpers': 0.5.1 + '@swc/types': 0.1.4 + optionalDependencies: + '@swc/core-darwin-arm64': 1.3.80 + '@swc/core-darwin-x64': 1.3.80 + '@swc/core-linux-arm-gnueabihf': 1.3.80 + '@swc/core-linux-arm64-gnu': 1.3.80 + '@swc/core-linux-arm64-musl': 1.3.80 + '@swc/core-linux-x64-gnu': 1.3.80 + '@swc/core-linux-x64-musl': 1.3.80 + '@swc/core-win32-arm64-msvc': 1.3.80 + '@swc/core-win32-ia32-msvc': 1.3.80 + '@swc/core-win32-x64-msvc': 1.3.80 + dev: true + /@swc/core/1.3.85: resolution: {integrity: sha512-qnoxp+2O0GtvRdYnXgR1v8J7iymGGYpx6f6yCK9KxipOZOjrlKILFANYlghQxZyPUfXwK++TFxfSlX4r9wK+kg==} engines: {node: '>=10'} @@ -8432,7 +9267,6 @@ packages: /@uni/env/1.1.0: resolution: {integrity: sha512-2GVgUzxIaO2vGElXEuc45+I7L6Jbw8inLDDFuC0K4htjKtPmYywKSE6oDhvmdAXb4GCOH8hmxECYtAh1rjsgoQ==} - dev: false /@use-gesture/core/10.2.20: resolution: {integrity: sha512-4lFhHc8so4yIHkBEs641DnEsBxPyhJ5GEjB4PURFDH4p/FcZriH6w99knZgI63zN/MBFfylMyb8+PDuj6RIXKQ==} @@ -8706,7 +9540,6 @@ packages: /abortcontroller-polyfill/1.7.5: resolution: {integrity: sha512-JMJ5soJWP18htbbxJjG7bG6yuI6pRhgJ0scHHTfkUjf6wjP912xZWvM+A4sJK3gqd9E8fcPbDnOefbA9Th/FIQ==} - dev: false /accept-language-parser/1.5.0: resolution: {integrity: sha512-QhyTbMLYo0BBGg1aWbeMG4ekWtds/31BrEU+DONOg/7ax23vxpL03Pb7/zBmha2v7vdD3AyzZVWBVGEZxKOXWw==} @@ -9275,7 +10108,6 @@ packages: /async/3.2.4: resolution: {integrity: sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==} - dev: false /asynckit/0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} @@ -9290,6 +10122,22 @@ packages: hasBin: true dev: false + /autoprefixer/10.4.13_postcss@8.4.25: + resolution: {integrity: sha512-49vKpMqcZYsJjwotvt4+h/BCjJVnhGwcLpDt5xkcaOG3eLrG/HUYLagrihYsQ+qrIBgIzX1Rw7a6L8I/ZA1Atg==} + engines: {node: ^10 || ^12 || >=14} + hasBin: true + peerDependencies: + postcss: ^8.1.0 + dependencies: + browserslist: 4.21.5 + caniuse-lite: 1.0.30001462 + fraction.js: 4.2.0 + normalize-range: 0.1.2 + picocolors: 1.0.0 + postcss: 8.4.25 + postcss-value-parser: 4.2.0 + dev: true + /autoprefixer/10.4.13_postcss@8.4.31: resolution: {integrity: sha512-49vKpMqcZYsJjwotvt4+h/BCjJVnhGwcLpDt5xkcaOG3eLrG/HUYLagrihYsQ+qrIBgIzX1Rw7a6L8I/ZA1Atg==} engines: {node: ^10 || ^12 || >=14} @@ -11407,12 +12255,10 @@ packages: /dotenv-expand/8.0.3: resolution: {integrity: sha512-SErOMvge0ZUyWd5B0NXMQlDkN+8r+HhVUsxgOO7IoPDOdDRD2JjExpN6y3KnFR66jsJMwSn1pqIivhU5rcJiNg==} engines: {node: '>=12'} - dev: false /dotenv/16.0.3: resolution: {integrity: sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==} engines: {node: '>=12'} - dev: false /dts-bundle/0.7.3: resolution: {integrity: sha512-EEAEuPRk8QyKhoN90NHTh+spSQujkkvOnKWUfuzpmC/fgryiWopL1SegSktx0UsoPfNidIGVDN7/AXpBDBv0WQ==} @@ -11454,7 +12300,6 @@ packages: hasBin: true dependencies: jake: 10.8.5 - dev: false /electron-to-chromium/1.4.322: resolution: {integrity: sha512-KovjizNC9XB7dno/2GjxX8VS0SlfPpCjtyoKft+bCO+UfD8bFy16hY4Sh9s0h9BDxbRH2U0zX5VBjpM1LTcNlg==} @@ -12829,7 +13674,6 @@ packages: resolution: {integrity: sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==} dependencies: minimatch: 5.1.6 - dev: false /filesize/8.0.7: resolution: {integrity: sha512-pjmC+bkIF8XI7fWaH8KxHcZL3DPybs1roSKP4rKDvy20tAWwIObE4+JIseG2byfGKhud5ZnM4YSGKBz7Sh0ndQ==} @@ -14498,7 +15342,6 @@ packages: chalk: 4.1.2 filelist: 1.0.4 minimatch: 3.1.2 - dev: false /jest-changed-files/28.1.3: resolution: {integrity: sha512-esaOfUWJXk2nfZt9SPyC8gA1kNfdKLkQWyzsMlqq8msYSlNKfmZxfRgZn4Cd4MGVUF+7v6dBs0d5TOAKa7iIiA==} @@ -15553,7 +16396,6 @@ packages: /jsonc-parser/3.2.0: resolution: {integrity: sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==} - dev: false /jsonfile/4.0.0: resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} @@ -16318,7 +17160,6 @@ packages: pathe: 1.1.0 pkg-types: 1.0.2 ufo: 1.1.1 - dev: false /moment/2.29.4: resolution: {integrity: sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==} @@ -16351,6 +17192,12 @@ packages: engines: {node: '>=12.0.0'} dev: true + /nanoid/3.3.4: + resolution: {integrity: sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + dev: true + /nanoid/3.3.6: resolution: {integrity: sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} @@ -16895,7 +17742,6 @@ packages: /path-to-regexp/6.2.1: resolution: {integrity: sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw==} - dev: false /path-type/4.0.0: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} @@ -16903,7 +17749,6 @@ packages: /pathe/1.1.0: resolution: {integrity: sha512-ODbEPR0KKHqECXW1GoxdDb+AZvULmXjVPy4rt+pGo2+TnjJTIPJQSVS6N63n8T2Ip+syHhbn52OewKicV0373w==} - dev: false /pathval/1.1.1: resolution: {integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==} @@ -16960,7 +17805,6 @@ packages: jsonc-parser: 3.2.0 mlly: 1.1.1 pathe: 1.1.0 - dev: false /pkg-up/3.1.0: resolution: {integrity: sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==} @@ -17815,9 +18659,27 @@ packages: source-map: 0.6.1 dev: false + /postcss/8.4.12: + resolution: {integrity: sha512-lg6eITwYe9v6Hr5CncVbK70SoioNQIq81nsaG86ev5hAidQvmOeETBqs7jm43K2F5/Ley3ytDtriImV6TpNiSg==} + engines: {node: ^10 || ^12 || >=14} + dependencies: + nanoid: 3.3.6 + picocolors: 1.0.0 + source-map-js: 1.0.2 + dev: true + /postcss/8.4.21: resolution: {integrity: sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==} engines: {node: ^10 || ^12 || >=14} + dependencies: + nanoid: 3.3.4 + picocolors: 1.0.0 + source-map-js: 1.0.2 + dev: true + + /postcss/8.4.25: + resolution: {integrity: sha512-7taJ/8t2av0Z+sQEvNzCkpDynl0tX3uJMCODi6nT3PfASC7dYCWV9aQ+uiCf+KBD4SEFcu+GvJdGdwzQ6OSjCw==} + engines: {node: ^10 || ^12 || >=14} dependencies: nanoid: 3.3.6 picocolors: 1.0.0 @@ -17917,7 +18779,6 @@ packages: /process/0.11.10: resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} engines: {node: '>= 0.6.0'} - dev: false /progress/2.0.3: resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==} @@ -19327,6 +20188,17 @@ packages: tiny-invariant: 1.3.1 tiny-warning: 1.0.3 + /react-router-dom/6.14.2: + resolution: {integrity: sha512-5pWX0jdKR48XFZBuJqHosX3AAHjRAzygouMTyimnBPOLdY3WjzUSKhus2FVMihUFWzeLebDgr4r8UeQFAct7Bg==} + engines: {node: '>=14'} + peerDependencies: + react: '>=16.8' + react-dom: '>=16.8' + dependencies: + '@remix-run/router': 1.7.2 + react-router: 6.14.2 + dev: true + /react-router-dom/6.14.2_biqbaboplfbrettd7655fr4n2y: resolution: {integrity: sha512-5pWX0jdKR48XFZBuJqHosX3AAHjRAzygouMTyimnBPOLdY3WjzUSKhus2FVMihUFWzeLebDgr4r8UeQFAct7Bg==} engines: {node: '>=14'} @@ -19340,6 +20212,18 @@ packages: react-router: 6.14.2_react@18.2.0 dev: false + /react-router-dom/6.14.2_react@18.2.0: + resolution: {integrity: sha512-5pWX0jdKR48XFZBuJqHosX3AAHjRAzygouMTyimnBPOLdY3WjzUSKhus2FVMihUFWzeLebDgr4r8UeQFAct7Bg==} + engines: {node: '>=14'} + peerDependencies: + react: '>=16.8' + react-dom: '>=16.8' + dependencies: + '@remix-run/router': 1.7.2 + react: 18.2.0 + react-router: 6.14.2_react@18.2.0 + dev: false + /react-router/5.3.4_react@17.0.2: resolution: {integrity: sha512-Ys9K+ppnJah3QuaRiLxk+jDWOR1MekYQrlytiXxC1RyfbdsZkS5pvKAzCCr031xHixZwpnsYNT5xysdFHQaYsA==} peerDependencies: @@ -19356,6 +20240,15 @@ packages: tiny-invariant: 1.3.1 tiny-warning: 1.0.3 + /react-router/6.14.2: + resolution: {integrity: sha512-09Zss2dE2z+T1D03IheqAFtK4UzQyX8nFPWx6jkwdYzGLXd5ie06A6ezS2fO6zJfEb/SpG6UocN2O1hfD+2urQ==} + engines: {node: '>=14'} + peerDependencies: + react: '>=16.8' + dependencies: + '@remix-run/router': 1.7.2 + dev: true + /react-router/6.14.2_react@18.2.0: resolution: {integrity: sha512-09Zss2dE2z+T1D03IheqAFtK4UzQyX8nFPWx6jkwdYzGLXd5ie06A6ezS2fO6zJfEb/SpG6UocN2O1hfD+2urQ==} engines: {node: '>=14'} @@ -19365,7 +20258,7 @@ packages: '@remix-run/router': 1.7.2 react: 18.2.0 - /react-server-dom-webpack/18.3.0-canary-dd480ef92-20230822_webpack@5.88.2: + /react-server-dom-webpack/18.3.0-canary-dd480ef92-20230822_biqbaboplfbrettd7655fr4n2y: resolution: {integrity: sha512-vBIBAkrOMrqZZGKgjSY9ly82YgZrmQgK4OOMBfMD5ZpAl58eifQFF18ZtVYNX9sLdPPi4MrizYfGjMaS9fP2VQ==} engines: {node: '>=0.10.0'} peerDependencies: @@ -19376,22 +20269,22 @@ packages: acorn-loose: 8.3.0 loose-envify: 1.4.0 neo-async: 2.6.2 - webpack: 5.88.2_pur5qe7dhbhqwjtj2daaog4n7u + react: 18.2.0 + react-dom: 18.2.0_react@18.2.0 dev: true - /react-server-dom-webpack/18.3.0-canary-e61a60fac-20231011_biqbaboplfbrettd7655fr4n2y: - resolution: {integrity: sha512-5QrTDm7L1wJulbQm05JcAw0TYM5zR2MHNEt/7jDRyL15S0/06G032QahaN1qcbUW29Shv0LTZq82jrA7aH+/dg==} + /react-server-dom-webpack/18.3.0-canary-dd480ef92-20230822_webpack@5.88.2: + resolution: {integrity: sha512-vBIBAkrOMrqZZGKgjSY9ly82YgZrmQgK4OOMBfMD5ZpAl58eifQFF18ZtVYNX9sLdPPi4MrizYfGjMaS9fP2VQ==} engines: {node: '>=0.10.0'} peerDependencies: - react: 18.3.0-canary-e61a60fac-20231011 - react-dom: 18.3.0-canary-e61a60fac-20231011 + react: 18.3.0-canary-dd480ef92-20230822 + react-dom: 18.3.0-canary-dd480ef92-20230822 webpack: ^5.59.0 dependencies: acorn-loose: 8.3.0 loose-envify: 1.4.0 neo-async: 2.6.2 - react: 18.2.0 - react-dom: 18.2.0_react@18.2.0 + webpack: 5.88.2_pur5qe7dhbhqwjtj2daaog4n7u dev: true /react-textarea-autosize/8.4.0_h7fc2el62uaa77gho3xhys6ola: @@ -19887,7 +20780,6 @@ packages: hasBin: true dependencies: glob: 7.2.3 - dev: false /rimraf/3.0.2: resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} @@ -20815,7 +21707,6 @@ packages: dependencies: '@babel/runtime': 7.21.0 universal-env: 3.3.3 - dev: false /stylehacks/5.1.1_postcss@8.4.31: resolution: {integrity: sha512-sBpcd5Hx7G6seo7b1LkpttvTz7ikD0LlH5RmdcBNb6fFR0Fl7LQwHDFr300q4cwUqi+IYrFGmsIHieMBfnN/Bw==} @@ -21078,7 +21969,6 @@ packages: dependencies: mkdirp: 0.5.6 rimraf: 2.6.3 - dev: false /term-size/2.2.1: resolution: {integrity: sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==} @@ -21093,6 +21983,32 @@ packages: supports-hyperlinks: 2.3.0 dev: true + /terser-webpack-plugin/5.3.5_c2jhsnh755mj2bl6newvfwu7wy: + resolution: {integrity: sha512-AOEDLDxD2zylUGf/wxHxklEkOe2/r+seuyOWujejFrIxHf11brA1/dWQNIgXa1c6/Wkxgu7zvv0JhOWfc2ELEA==} + engines: {node: '>= 10.13.0'} + peerDependencies: + '@swc/core': '*' + esbuild: '*' + uglify-js: '*' + webpack: ^5.1.0 + peerDependenciesMeta: + '@swc/core': + optional: true + esbuild: + optional: true + uglify-js: + optional: true + dependencies: + '@jridgewell/trace-mapping': 0.3.17 + '@swc/core': 1.3.80_@swc+helpers@0.5.1 + esbuild: 0.17.16 + jest-worker: 27.5.1 + schema-utils: 3.1.1 + serialize-javascript: 6.0.1 + terser: 5.14.2 + webpack: 5.76.0_yt3h3qjhcnsf3663codtuni62a + dev: true + /terser-webpack-plugin/5.3.5_ghmre4bibzh3hfhoafsn4shpjy: resolution: {integrity: sha512-AOEDLDxD2zylUGf/wxHxklEkOe2/r+seuyOWujejFrIxHf11brA1/dWQNIgXa1c6/Wkxgu7zvv0JhOWfc2ELEA==} engines: {node: '>= 10.13.0'} @@ -21167,7 +22083,6 @@ packages: serialize-javascript: 6.0.1 terser: 5.14.2 webpack: 5.76.0_esbuild@0.17.16 - dev: true /terser-webpack-plugin/5.3.6_webpack@5.88.2: resolution: {integrity: sha512-kfLFk+PoLUQIbLmB1+PZDMRSZS99Mp+/MHqDNmMA6tOItzRt+Npe3E+fsMs5mfcM0wCtrrdU387UnV+vnSffXQ==} @@ -21240,7 +22155,6 @@ packages: serialize-javascript: 6.0.1 terser: 5.16.5 webpack: 5.88.2_esbuild@0.17.16 - dev: true /terser-webpack-plugin/5.3.7_ghmre4bibzh3hfhoafsn4shpjy: resolution: {integrity: sha512-AfKwIktyP7Cu50xNjXF/6Qb5lBNzYaWpU6YfoX3uZicTx0zTy0stDDCsvjDapKsSDvOeWo5MEq4TmdBy2cNoHw==} @@ -21712,7 +22626,6 @@ packages: /ufo/1.1.1: resolution: {integrity: sha512-MvlCc4GHrmZdAllBc0iUDowff36Q9Ndw/UzqmEKyrfSzokTd9ZCy1i+IIk5hrYKkjoYVQyNbrw7/F8XJ2rEwTg==} - dev: false /uglify-js/3.17.4: resolution: {integrity: sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==} @@ -21859,7 +22772,6 @@ packages: engines: {npm: '>=3.0.0'} dependencies: '@uni/env': 1.1.0 - dev: false /universalify/0.1.2: resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} @@ -21898,7 +22810,7 @@ packages: acorn: 8.8.2 chokidar: 3.5.3 esbuild: 0.17.16 - webpack: 5.88.2_pur5qe7dhbhqwjtj2daaog4n7u + webpack: 5.88.2_esbuild@0.17.16 webpack-sources: 3.2.3 webpack-virtual-modules: 0.4.6 dev: true @@ -22470,7 +23382,7 @@ packages: mime-types: 2.1.35 range-parser: 1.2.1 schema-utils: 4.0.0 - webpack: 5.76.0_pur5qe7dhbhqwjtj2daaog4n7u + webpack: 5.76.0_esbuild@0.17.16 /webpack-dev-middleware/5.3.3_webpack@5.86.0: resolution: {integrity: sha512-hj5CYrY0bZLB+eTO+x/j67Pkrquiy7kWepMHmUMoPsmcUaeEnQJqFzHJOyxgWlq746/wUuA64p9ta34Kyb01pA==} @@ -22497,7 +23409,7 @@ packages: mime-types: 2.1.35 range-parser: 1.2.1 schema-utils: 4.0.0 - webpack: 5.88.2_pur5qe7dhbhqwjtj2daaog4n7u + webpack: 5.88.2_esbuild@0.17.16 /webpack-dev-middleware/6.0.2_webpack@5.76.0: resolution: {integrity: sha512-iOddiJzPcQC6lwOIu60vscbGWth8PCRcWRCwoQcTQf9RMoOWBHg5EyzpGdtSmGMrSPd5vHEfFXmVErQEmkRngQ==} @@ -22513,7 +23425,7 @@ packages: mime-types: 2.1.35 range-parser: 1.2.1 schema-utils: 4.0.0 - webpack: 5.76.0_pur5qe7dhbhqwjtj2daaog4n7u + webpack: 5.76.0_esbuild@0.17.16 /webpack-dev-server/4.11.1_webpack@5.88.2: resolution: {integrity: sha512-lILVz9tAUy1zGFwieuaQtYiadImb5M3d+H+L1zDYalYoDl0cksAB1UNyuE5MMWJrG6zR1tXkCP2fitl7yoUJiw==} @@ -22604,7 +23516,7 @@ packages: serve-index: 1.9.1 sockjs: 0.3.24 spdy: 4.0.2 - webpack: 5.76.0_pur5qe7dhbhqwjtj2daaog4n7u + webpack: 5.76.0_esbuild@0.17.16 webpack-dev-middleware: 5.3.3_webpack@5.76.0 ws: 8.13.0 transitivePeerDependencies: @@ -22876,7 +23788,6 @@ packages: - '@swc/core' - esbuild - uglify-js - dev: true /webpack/5.76.0_pur5qe7dhbhqwjtj2daaog4n7u: resolution: {integrity: sha512-l5sOdYBDunyf72HW8dF23rFtWq/7Zgvt/9ftMof71E/yUb1YLOBmTgA2K4vQthB3kotMrSj609txVE0dnr2fjA==} @@ -22917,6 +23828,46 @@ packages: - esbuild - uglify-js + /webpack/5.76.0_yt3h3qjhcnsf3663codtuni62a: + resolution: {integrity: sha512-l5sOdYBDunyf72HW8dF23rFtWq/7Zgvt/9ftMof71E/yUb1YLOBmTgA2K4vQthB3kotMrSj609txVE0dnr2fjA==} + engines: {node: '>=10.13.0'} + hasBin: true + peerDependencies: + webpack-cli: '*' + peerDependenciesMeta: + webpack-cli: + optional: true + dependencies: + '@types/eslint-scope': 3.7.4 + '@types/estree': 0.0.51 + '@webassemblyjs/ast': 1.11.1 + '@webassemblyjs/wasm-edit': 1.11.1 + '@webassemblyjs/wasm-parser': 1.11.1 + acorn: 8.8.2 + acorn-import-assertions: 1.9.0_acorn@8.8.2 + browserslist: 4.21.5 + chrome-trace-event: 1.0.3 + enhanced-resolve: 5.15.0 + es-module-lexer: 0.9.3 + eslint-scope: 5.1.1 + events: 3.3.0 + glob-to-regexp: 0.4.1 + graceful-fs: 4.2.10 + json-parse-even-better-errors: 2.3.1 + loader-runner: 4.3.0 + mime-types: 2.1.35 + neo-async: 2.6.2 + schema-utils: 3.3.0 + tapable: 2.2.1 + terser-webpack-plugin: 5.3.5_c2jhsnh755mj2bl6newvfwu7wy + watchpack: 2.4.0 + webpack-sources: 3.2.3 + transitivePeerDependencies: + - '@swc/core' + - esbuild + - uglify-js + dev: true + /webpack/5.86.0_esbuild@0.17.16: resolution: {integrity: sha512-3BOvworZ8SO/D4GVP+GoRC3fVeg5MO4vzmq8TJJEkdmopxyazGDxN8ClqN12uzrZW9Tv8EED8v5VSb6Sqyi0pg==} engines: {node: '>=10.13.0'} @@ -23034,7 +23985,6 @@ packages: - '@swc/core' - esbuild - uglify-js - dev: true /webpack/5.88.2_pur5qe7dhbhqwjtj2daaog4n7u: resolution: {integrity: sha512-JmcgNZ1iKj+aiR0OvTYtWQqJwq37Pf683dY9bVORwVbUrDhLhdn/PlO2sHsFHPkj7sHNQF3JwaAkp49V+Sq1tQ==} From 6198eea61a459636aaee0452864ee3b519374705 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B0=B4=E6=BE=9C?= <shuilan.cj@taobao.com> Date: Thu, 26 Oct 2023 14:58:37 +0800 Subject: [PATCH 14/17] fix: changeset (#6612) --- .changeset/chilled-jars-pump.md | 1 + 1 file changed, 1 insertion(+) diff --git a/.changeset/chilled-jars-pump.md b/.changeset/chilled-jars-pump.md index 4d27994b22..379c54982c 100644 --- a/.changeset/chilled-jars-pump.md +++ b/.changeset/chilled-jars-pump.md @@ -4,6 +4,7 @@ '@ice/runtime': minor '@ice/app': minor '@ice/bundles': patch +'@ice/route-manifest': patch --- feat: support react server component From 67dc6e9691a1e14e8847a4b91db9393d62e67d97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B0=B4=E6=BE=9C?= <shuilan.cj@taobao.com> Date: Wed, 1 Nov 2023 10:28:19 +0800 Subject: [PATCH 15/17] fix: content type (#6616) --- packages/runtime/src/runRSCClientApp.tsx | 2 +- packages/runtime/src/runRSCServerApp.tsx | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/runtime/src/runRSCClientApp.tsx b/packages/runtime/src/runRSCClientApp.tsx index 213b32eaee..0dbee8ff32 100644 --- a/packages/runtime/src/runRSCClientApp.tsx +++ b/packages/runtime/src/runRSCClientApp.tsx @@ -61,5 +61,5 @@ export function useRefresh() { } function getReactTree(location) { - return fetch(location + (location.indexOf('?') > -1 ? '&rsc' : '?rsc')); + return fetch(location + (location.indexOf('?') > -1 ? '&rsc=true' : '?rsc=true')); } \ No newline at end of file diff --git a/packages/runtime/src/runRSCServerApp.tsx b/packages/runtime/src/runRSCServerApp.tsx index f39c8ae2ef..43fdd67337 100644 --- a/packages/runtime/src/runRSCServerApp.tsx +++ b/packages/runtime/src/runRSCServerApp.tsx @@ -49,7 +49,7 @@ export async function runRSCServerApp(serverContext: ServerContext, renderOption matches: [], }; - if (req.url?.indexOf('rsc') === -1) { + if (req.url?.indexOf('rsc=true') === -1) { return renderDocument(serverContext, renderOptions, appContext, matches); } @@ -71,6 +71,7 @@ export async function runRSCServerApp(serverContext: ServerContext, renderOption } }); + res.setHeader('Content-Type', 'text/x-component; charset=utf-8'); const { pipe } = renderToPipeableStream( element, clientManifest, From e88c729019566a3cac18e1c53d076f51baf8cf87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B0=B4=E6=BE=9C?= <shuilan.cj@taobao.com> Date: Mon, 27 Nov 2023 14:25:24 +0800 Subject: [PATCH 16/17] feat: render rsc into document (#6653) * feat: render rsc into document * revert: lock file * fix: init rsc data --- .../src/components/RefreshButton.client.tsx | 19 ---- examples/with-rsc/src/pages/about.tsx | 4 - packages/runtime/src/index.ts | 3 +- packages/runtime/src/runRSCClientApp.tsx | 103 ++++++++++++------ packages/runtime/src/runRSCServerApp.tsx | 39 ++++++- 5 files changed, 102 insertions(+), 66 deletions(-) delete mode 100644 examples/with-rsc/src/components/RefreshButton.client.tsx diff --git a/examples/with-rsc/src/components/RefreshButton.client.tsx b/examples/with-rsc/src/components/RefreshButton.client.tsx deleted file mode 100644 index 643ec10bbf..0000000000 --- a/examples/with-rsc/src/components/RefreshButton.client.tsx +++ /dev/null @@ -1,19 +0,0 @@ -'use client'; -import { useRefresh } from '@ice/runtime'; - -export default function Button({ children }) { - const refresh = useRefresh(); - - return ( - <button - className={[ - 'edit-button', - 'edit-button--solid', - ].join(' ')} - onClick={() => refresh()} - role="menuitem" - > - {children} - </button> - ); -} diff --git a/examples/with-rsc/src/pages/about.tsx b/examples/with-rsc/src/pages/about.tsx index 916a34a9ed..76f33efa99 100644 --- a/examples/with-rsc/src/pages/about.tsx +++ b/examples/with-rsc/src/pages/about.tsx @@ -1,6 +1,5 @@ import { useAppContext } from 'ice'; import styles from './about.module.css'; -import RefreshButton from '@/components/RefreshButton.client'; import Counter from '@/components/Counter.client'; if (!global.requestCount) { @@ -18,9 +17,6 @@ export default function Home() { <h2>About Page</h2> <div>server request count: { global.requestCount++ }</div> <Counter /> - <RefreshButton> - Refresh Button - </RefreshButton> </div> ); } diff --git a/packages/runtime/src/index.ts b/packages/runtime/src/index.ts index 9b09642ac8..d579bd8a27 100644 --- a/packages/runtime/src/index.ts +++ b/packages/runtime/src/index.ts @@ -26,7 +26,7 @@ import type { RunClientAppOptions, CreateRoutes } from './runClientApp.js'; import { useAppContext as useInternalAppContext, useAppData, AppContextProvider } from './AppContext.js'; import { getAppData } from './appData.js'; import { useData, useConfig } from './RouteContext.js'; -import { runRSCClientApp, useRefresh } from './runRSCClientApp.js'; +import { runRSCClientApp } from './runRSCClientApp.js'; import { Meta, Title, @@ -145,7 +145,6 @@ export { RouteErrorComponent, runRSCClientApp, - useRefresh, }; export type { diff --git a/packages/runtime/src/runRSCClientApp.tsx b/packages/runtime/src/runRSCClientApp.tsx index 0dbee8ff32..37db3a5fac 100644 --- a/packages/runtime/src/runRSCClientApp.tsx +++ b/packages/runtime/src/runRSCClientApp.tsx @@ -4,10 +4,21 @@ import pkg from 'react-server-dom-webpack/client'; import type { AppConfig } from './types.js'; // @ts-ignore -const { Suspense, use, useState, createContext, useContext, startTransition } = React; -const { createFromFetch } = pkg; +const { Suspense, use } = React; +const { createFromReadableStream } = pkg; export async function runRSCClientApp(appConfig: AppConfig) { + // It's possible that the DOM is already loaded. + if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', DOMContentLoaded, false); + } else { + DOMContentLoaded(); + } + + const rscData = (self as any).__rsc_data = (self as any).__rsc_data || []; + rscData.forEach(serverDataCallback); + rscData.push = serverDataCallback; + const rootId = appConfig.app.rootId || 'app'; const container = document.getElementById(rootId); const root = ReactDOM.createRoot(container); @@ -15,51 +26,71 @@ export async function runRSCClientApp(appConfig: AppConfig) { } function Root() { + const response = useInitialServerResponse(window.location.href); + return ( - <Router /> + <Suspense> + {use(response)} + </Suspense> ); } -const RouterContext = createContext(null); -const initialCache = new Map(); +const rscCache = new Map(); -function Router() { - const [cache, setCache] = useState(initialCache); - const [location] = useState(window.location.href); +function useInitialServerResponse(cacheKey: string): Promise<JSX.Element> { + const response = rscCache.get(cacheKey); + if (response) return response; - let content = cache.get(location); - if (!content) { - content = createFromFetch( - getReactTree(location), - ); - cache.set(location, content); - } + const readable = new ReadableStream({ + start(controller) { + nextServerDataRegisterWriter(controller); + }, + }); + + const newResponse = createFromReadableStream(readable); + + rscCache.set(cacheKey, newResponse); + return newResponse; +} + +let initialServerDataBuffer: string[] | undefined; +let initialServerDataWriter: ReadableStreamDefaultController | undefined; +let initialServerDataLoaded = false; +let initialServerDataFlushed = false; +const encoder = new TextEncoder(); - function refresh() { - startTransition(() => { - const nextCache = new Map(); - const nextContent = createFromFetch( - getReactTree(location), - ); - nextCache.set(location, nextContent); - setCache(nextCache); +function nextServerDataRegisterWriter(ctr: ReadableStreamDefaultController) { + if (initialServerDataBuffer) { + initialServerDataBuffer.forEach((val) => { + ctr.enqueue(encoder.encode(val)); }); + if (initialServerDataLoaded && !initialServerDataFlushed) { + ctr.close(); + initialServerDataFlushed = true; + initialServerDataBuffer = undefined; + } } - return ( - <RouterContext.Provider value={{ location, refresh }}> - <Suspense fallback={<h1>Loading...</h1>}> - {use(content)} - </Suspense> - </RouterContext.Provider> - ); + initialServerDataWriter = ctr; } -export function useRefresh() { - const router = useContext(RouterContext); - return router.refresh; -} +// When `DOMContentLoaded`, we can close all pending writers to finish hydration. +const DOMContentLoaded = function () { + if (initialServerDataWriter && !initialServerDataFlushed) { + initialServerDataWriter.close(); + initialServerDataFlushed = true; + initialServerDataBuffer = undefined; + } + initialServerDataLoaded = true; +}; -function getReactTree(location) { - return fetch(location + (location.indexOf('?') > -1 ? '&rsc=true' : '?rsc=true')); +function serverDataCallback(seg) { + if (initialServerDataWriter) { + initialServerDataWriter.enqueue(encoder.encode(seg)); + } else { + if (!initialServerDataBuffer) { + initialServerDataBuffer = []; + } + initialServerDataBuffer.push(seg); + } } \ No newline at end of file diff --git a/packages/runtime/src/runRSCServerApp.tsx b/packages/runtime/src/runRSCServerApp.tsx index 43fdd67337..0327f05b6b 100644 --- a/packages/runtime/src/runRSCServerApp.tsx +++ b/packages/runtime/src/runRSCServerApp.tsx @@ -1,3 +1,4 @@ +import { TextDecoder, TextEncoder } from 'util'; import * as React from 'react'; import * as ReactDOMServer from 'react-dom/server'; import { renderToPipeableStream } from 'react-server-dom-webpack/server.node'; @@ -17,6 +18,22 @@ import type { ServerRenderOptions as RenderOptions, } from './types.js'; +// This utility is based on https://github.com/zertosh/htmlescape +// License: https://github.com/zertosh/htmlescape/blob/0527ca7156a524d256101bb310a9f970f63078ad/LICENSE +const ESCAPE_LOOKUP: { [match: string]: string } = { + '&': '\\u0026', + '>': '\\u003e', + '<': '\\u003c', + '\u2028': '\\u2028', + '\u2029': '\\u2029', +}; + +const ESCAPE_REGEX = /[&><\u2028\u2029]/g; + +function htmlEscapeJsonString(str: string): string { + return str.replace(ESCAPE_REGEX, (match) => ESCAPE_LOOKUP[match]); +} + export async function runRSCServerApp(serverContext: ServerContext, renderOptions: RenderOptions) { const { req, res } = serverContext; @@ -49,9 +66,7 @@ export async function runRSCServerApp(serverContext: ServerContext, renderOption matches: [], }; - if (req.url?.indexOf('rsc=true') === -1) { - return renderDocument(serverContext, renderOptions, appContext, matches); - } + renderDocument(serverContext, renderOptions, appContext, matches); const routeModules = await loadRouteModules(matches.map(({ route: { id, lazy } }) => ({ id, lazy }))); @@ -71,7 +86,22 @@ export async function runRSCServerApp(serverContext: ServerContext, renderOption } }); - res.setHeader('Content-Type', 'text/x-component; charset=utf-8'); + const decoder = new TextDecoder(); + const encoder = new TextEncoder(); + + res.write('<script>self.__rsc_data=self.__rsc_data||[];</script>'); + + function decorateWrite(write) { + return function (data) { + const chunk = decoder.decode(data, { stream: true }); + const modifiedData = `<script>self.__rsc_data.push(${htmlEscapeJsonString(JSON.stringify([chunk]))})</script>`; + + return write.call(this, encoder.encode(modifiedData)); + }; + } + + res.write = decorateWrite(res.write); + const { pipe } = renderToPipeableStream( element, clientManifest, @@ -116,6 +146,5 @@ function renderDocument(requestContext, renderOptions, appContext, matches) { res.setHeader('Content-Type', 'text/html; charset=utf-8'); res.write(`<!DOCTYPE html>${htmlStr}`); - res.end(); } From c1deba862e6a426e17e5deef0a852a808c266ccd Mon Sep 17 00:00:00 2001 From: ClarkXia <xiawenwu41@gmail.com> Date: Tue, 26 Dec 2023 17:12:34 +0800 Subject: [PATCH 17/17] fix: use compilation api to get assets --- packages/ice/src/webpack/ServerCompilerPlugin.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/ice/src/webpack/ServerCompilerPlugin.ts b/packages/ice/src/webpack/ServerCompilerPlugin.ts index 4579f4fdef..6375baa211 100644 --- a/packages/ice/src/webpack/ServerCompilerPlugin.ts +++ b/packages/ice/src/webpack/ServerCompilerPlugin.ts @@ -40,12 +40,12 @@ export default class ServerCompilerPlugin { if (compilation) { // Option of compilationInfo need to be object, while it may changed during multi-time compilation. this.compilerOptions.compilationInfo.assetsManifest = - JSON.parse(compilation.assets['assets-manifest.json'].source().toString()); + JSON.parse(compilation.getAsset('assets-manifest.json').source.source().toString()); - if (compilation.assets?.['react-client-manifest.json']) { + if (compilation.getAsset('react-client-manifest.json')) { // @ts-ignore this.compilerOptions.compilationInfo.rscManifest = - JSON.parse(compilation.assets['react-client-manifest.json']?.source()?.toString()); + JSON.parse(compilation.getAsset('react-client-manifest.json').source.source().toString()); } } // For first time, we create a new task.