From b023ac9e34b3a493c20534f4212b5f5128b823b6 Mon Sep 17 00:00:00 2001 From: MUI bot <2109932+Janpot@users.noreply.github.com> Date: Wed, 24 Jan 2024 18:50:01 +0100 Subject: [PATCH 01/19] WIP --- examples/custom-server-nextjs/app/layout.tsx | 16 ++ .../app/my-toolpad/[[...path]]/page.tsx | 6 + examples/custom-server-nextjs/next-env.d.ts | 1 + examples/custom-server-nextjs/next.config.mjs | 8 + examples/custom-server-nextjs/package.json | 10 +- examples/custom-server-nextjs/tsconfig.json | 10 +- packages/toolpad-app/cli/index.ts | 2 +- packages/toolpad-app/package.json | 7 +- .../toolpad-app/src/exports/next-client.tsx | 3 + packages/toolpad-app/src/exports/next.tsx | 33 ++++ packages/toolpad-app/src/packageInfo.ts | 2 +- .../toolpad-app/src/runtime/ToolpadApp.tsx | 2 + .../src/server/FunctionsManager.ts | 4 +- .../src/server/functionsRuntime.ts | 2 +- packages/toolpad-app/src/server/index.ts | 2 +- .../src/server/toolpadAppBuilder.ts | 2 +- packages/toolpad-app/tsup.config.ts | 2 +- pnpm-lock.yaml | 155 ++++++++++++++++++ pnpm-workspace.yaml | 1 + 19 files changed, 252 insertions(+), 16 deletions(-) create mode 100644 examples/custom-server-nextjs/app/layout.tsx create mode 100644 examples/custom-server-nextjs/app/my-toolpad/[[...path]]/page.tsx create mode 100644 packages/toolpad-app/src/exports/next-client.tsx create mode 100644 packages/toolpad-app/src/exports/next.tsx diff --git a/examples/custom-server-nextjs/app/layout.tsx b/examples/custom-server-nextjs/app/layout.tsx new file mode 100644 index 00000000000..a14e64fcd5e --- /dev/null +++ b/examples/custom-server-nextjs/app/layout.tsx @@ -0,0 +1,16 @@ +export const metadata = { + title: 'Next.js', + description: 'Generated by Next.js', +} + +export default function RootLayout({ + children, +}: { + children: React.ReactNode +}) { + return ( + + {children} + + ) +} diff --git a/examples/custom-server-nextjs/app/my-toolpad/[[...path]]/page.tsx b/examples/custom-server-nextjs/app/my-toolpad/[[...path]]/page.tsx new file mode 100644 index 00000000000..ec61262d2ca --- /dev/null +++ b/examples/custom-server-nextjs/app/my-toolpad/[[...path]]/page.tsx @@ -0,0 +1,6 @@ +import * as React from 'react'; +import { ToolpadApp } from '@mui/toolpad/next'; + +export default function ToolpadPage() { + return ; +} diff --git a/examples/custom-server-nextjs/next-env.d.ts b/examples/custom-server-nextjs/next-env.d.ts index 4f11a03dc6c..fd36f9494e2 100644 --- a/examples/custom-server-nextjs/next-env.d.ts +++ b/examples/custom-server-nextjs/next-env.d.ts @@ -1,5 +1,6 @@ /// /// +/// // NOTE: This file should not be edited // see https://nextjs.org/docs/basic-features/typescript for more information. diff --git a/examples/custom-server-nextjs/next.config.mjs b/examples/custom-server-nextjs/next.config.mjs index 39cb507f56b..dc0f85c7d04 100644 --- a/examples/custom-server-nextjs/next.config.mjs +++ b/examples/custom-server-nextjs/next.config.mjs @@ -1,4 +1,12 @@ /** @type {import('next').NextConfig} */ export default { + webpack: (config) => { + config.externals.push({ + fsevents: 'commonjs fsevents', + chokidar: 'commonjs chokidar', + }); + config.resolve.alias['@mui/icons-material'] = ['@mui/icons-material/esm']; + return config; + }, basePath: '/my-next-app', }; diff --git a/examples/custom-server-nextjs/package.json b/examples/custom-server-nextjs/package.json index 0a2425215d7..52bf8d3e136 100644 --- a/examples/custom-server-nextjs/package.json +++ b/examples/custom-server-nextjs/package.json @@ -10,7 +10,13 @@ }, "dependencies": { "@mui/toolpad": "0.1.46", - "next": "14.0.2" + "chokidar": "3.5.3", + "express": "4.18.2", + "next": "14.1.0", + "react": "18.2.0", + "react-dom": "18.2.0" }, - "devDependencies": {} + "devDependencies": { + "@types/react": "18.2.48" + } } diff --git a/examples/custom-server-nextjs/tsconfig.json b/examples/custom-server-nextjs/tsconfig.json index 1c4f693a991..f7ebea61fe5 100644 --- a/examples/custom-server-nextjs/tsconfig.json +++ b/examples/custom-server-nextjs/tsconfig.json @@ -11,8 +11,14 @@ "moduleResolution": "node", "resolveJsonModule": true, "isolatedModules": true, - "jsx": "preserve" + "jsx": "preserve", + "plugins": [ + { + "name": "next" + } + ], + "strictNullChecks": true }, - "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], + "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], "exclude": ["node_modules"] } diff --git a/packages/toolpad-app/cli/index.ts b/packages/toolpad-app/cli/index.ts index 2d0fed10e51..a6e62dfb509 100644 --- a/packages/toolpad-app/cli/index.ts +++ b/packages/toolpad-app/cli/index.ts @@ -14,7 +14,7 @@ export interface RunOptions { base: string; } -import.meta.url ??= url.pathToFileURL(__filename).toString(); +// import.meta.url ??= url.pathToFileURL(__filename).toString(); const currentDirectory = url.fileURLToPath(new URL('.', import.meta.url)); async function runCommand( diff --git a/packages/toolpad-app/package.json b/packages/toolpad-app/package.json index fe6a7230b0d..d3b73a6c990 100644 --- a/packages/toolpad-app/package.json +++ b/packages/toolpad-app/package.json @@ -29,6 +29,7 @@ "server", "runtime" ], + "type": "module", "exports": { "./package.json": "./package.json", "./cli": { @@ -36,13 +37,11 @@ }, ".": { "types": "./dist/exports/index.d.ts", - "import": "./dist/exports/index.mjs", - "require": "./dist/exports/index.js" + "import": "./dist/exports/index.js" }, "./*": { "types": "./dist/exports/*.d.ts", - "import": "./dist/exports/*.mjs", - "require": "./dist/exports/*.js" + "import": "./dist/exports/*.js" } }, "dependencies": { diff --git a/packages/toolpad-app/src/exports/next-client.tsx b/packages/toolpad-app/src/exports/next-client.tsx new file mode 100644 index 00000000000..e7c04561a81 --- /dev/null +++ b/packages/toolpad-app/src/exports/next-client.tsx @@ -0,0 +1,3 @@ +'use client'; + +export { default } from '../runtime/ToolpadApp'; diff --git a/packages/toolpad-app/src/exports/next.tsx b/packages/toolpad-app/src/exports/next.tsx new file mode 100644 index 00000000000..294a7d60b24 --- /dev/null +++ b/packages/toolpad-app/src/exports/next.tsx @@ -0,0 +1,33 @@ +'use server'; + +import * as React from 'react'; +import * as appDom from '@mui/toolpad-core/appDom'; +import ToolpadAppClient from './next-client'; +import { initProject } from '../server/localMode'; +import createRuntimeState from '../runtime/createRuntimeState'; + +export interface ToolpadAppServerProps { + base: string; + dir: string; +} + +let dom = appDom.createDom(); +dom = appDom.addNode( + dom, + appDom.createNode(dom, 'page', { attributes: {} }), + appDom.getRoot(dom), + 'pages', +); + +export async function ToolpadApp({ base, dir = './toolpad' }: ToolpadAppServerProps) { + const project = await initProject({ + dev: false, + dir, + base, + }); + // + // const dom = await project.loadDom(); + const initialState = createRuntimeState({ dom }); + + return ; +} diff --git a/packages/toolpad-app/src/packageInfo.ts b/packages/toolpad-app/src/packageInfo.ts index 8d0ce5017a7..46a15020195 100644 --- a/packages/toolpad-app/src/packageInfo.ts +++ b/packages/toolpad-app/src/packageInfo.ts @@ -2,7 +2,7 @@ import * as path from 'path'; import * as url from 'node:url'; import * as fs from 'fs'; -const currentDirectory = url.fileURLToPath(new URL('.', import.meta.url)); +const currentDirectory = url.fileURLToPath(new URL('.', String(import.meta.url))); const pkgJsonContent = fs.readFileSync(path.resolve(currentDirectory, '../../package.json'), { encoding: 'utf-8', diff --git a/packages/toolpad-app/src/runtime/ToolpadApp.tsx b/packages/toolpad-app/src/runtime/ToolpadApp.tsx index 581de553e2a..7545a21eda4 100644 --- a/packages/toolpad-app/src/runtime/ToolpadApp.tsx +++ b/packages/toolpad-app/src/runtime/ToolpadApp.tsx @@ -1,3 +1,5 @@ +'use client'; + import * as React from 'react'; import { Stack, diff --git a/packages/toolpad-app/src/server/FunctionsManager.ts b/packages/toolpad-app/src/server/FunctionsManager.ts index af7ed4953ff..a9f958e4735 100644 --- a/packages/toolpad-app/src/server/FunctionsManager.ts +++ b/packages/toolpad-app/src/server/FunctionsManager.ts @@ -31,8 +31,8 @@ export interface CreateDataProviderOptions { paginationMode: PaginationMode; } -import.meta.url ??= url.pathToFileURL(__filename).toString(); -const currentDirectory = url.fileURLToPath(new URL('.', import.meta.url)); +// import.meta.url ??= url.pathToFileURL(__filename).toString(); +const currentDirectory = url.fileURLToPath(new URL('.', String(import.meta.url))); async function createDefaultFunction(filePath: string): Promise { const result = await format( diff --git a/packages/toolpad-app/src/server/functionsRuntime.ts b/packages/toolpad-app/src/server/functionsRuntime.ts index 9270891a9d0..c7da6f42c46 100644 --- a/packages/toolpad-app/src/server/functionsRuntime.ts +++ b/packages/toolpad-app/src/server/functionsRuntime.ts @@ -6,7 +6,7 @@ import * as z from 'zod'; import { fromZodError } from 'zod-validation-error'; import * as crypto from 'crypto'; -import.meta.url ??= url.pathToFileURL(__filename).toString(); +// import.meta.url ??= url.pathToFileURL(__filename).toString(); async function loadExports(filePath: string): Promise> { const fullPath = path.resolve(filePath); diff --git a/packages/toolpad-app/src/server/index.ts b/packages/toolpad-app/src/server/index.ts index 7b1f377facb..d0c95d5a916 100644 --- a/packages/toolpad-app/src/server/index.ts +++ b/packages/toolpad-app/src/server/index.ts @@ -29,7 +29,7 @@ import { createRpcServer as createProjectRpcServer } from './projectRpcServer'; import { createRpcServer as createRuntimeRpcServer } from './runtimeRpcServer'; import { createAuthHandler, createRequireAuthMiddleware } from './auth'; -import.meta.url ??= url.pathToFileURL(__filename).toString(); +// import.meta.url ??= url.pathToFileURL(__filename).toString(); const currentDirectory = url.fileURLToPath(new URL('.', import.meta.url)); const DEFAULT_PORT = 3000; diff --git a/packages/toolpad-app/src/server/toolpadAppBuilder.ts b/packages/toolpad-app/src/server/toolpadAppBuilder.ts index b49fa1d76d3..11bb6a36e63 100644 --- a/packages/toolpad-app/src/server/toolpadAppBuilder.ts +++ b/packages/toolpad-app/src/server/toolpadAppBuilder.ts @@ -9,7 +9,7 @@ import { INITIAL_STATE_WINDOW_PROPERTY } from '../constants'; import { pathToNodeImportSpecifier } from '../utils/paths'; import viteVirtualPlugin, { VirtualFileContent, replaceFiles } from './viteVirtualPlugin'; -import.meta.url ??= url.pathToFileURL(__filename).toString(); +// import.meta.url ??= url.pathToFileURL(__filename).toString(); const currentDirectory = url.fileURLToPath(new URL('.', import.meta.url)); const MAIN_ENTRY = '/main.tsx'; diff --git a/packages/toolpad-app/tsup.config.ts b/packages/toolpad-app/tsup.config.ts index 0def9bd3bad..2d060baa374 100644 --- a/packages/toolpad-app/tsup.config.ts +++ b/packages/toolpad-app/tsup.config.ts @@ -54,7 +54,7 @@ export default defineConfig((options) => [ tsconfig: './tsconfig.runtime.json', sourcemap: true, esbuildPlugins: [cleanFolderOnFailure(path.resolve(__dirname, 'dist/runtime'))], - external: [/.*\.(svg|png|jpe?g|gif|ico|webp)$/], + external: [/.*\.(svg|png|jpe?g|gif|ico|webp)$/, './next-client'], async onSuccess() { // eslint-disable-next-line no-console console.log('runtime: build successful'); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 722b869feb8..37baf409517 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -422,6 +422,31 @@ importers: specifier: 2.2.1 version: 2.2.1 + examples/custom-server-nextjs: + dependencies: + '@mui/toolpad': + specifier: 0.1.46 + version: link:../../packages/toolpad-app + chokidar: + specifier: 3.5.3 + version: 3.5.3 + express: + specifier: 4.18.2 + version: 4.18.2 + next: + specifier: 14.1.0 + version: 14.1.0(react-dom@18.2.0)(react@18.2.0) + react: + specifier: 18.2.0 + version: 18.2.0 + react-dom: + specifier: 18.2.0 + version: 18.2.0(react@18.2.0) + devDependencies: + '@types/react': + specifier: 18.2.48 + version: 18.2.48 + packages/create-toolpad-app: dependencies: '@mui/toolpad-utils': @@ -3131,6 +3156,10 @@ packages: resolution: {integrity: sha512-FsAT5x0jF2kkhNkKkukhsyYOrRqtSxrEhfliniIq0bwWbuXLgyt3Gv0Ml+b91XwjwArmuP7NxCiGd++GGKdNMQ==} dev: false + /@next/env@14.1.0: + resolution: {integrity: sha512-Py8zIo+02ht82brwwhTg36iogzFqGLPXlRGKQw5s+qP/kMNc4MAyDeEwBKDijk6zTIbegEgu8Qy7C1LboslQAw==} + dev: false + /@next/eslint-plugin-next@14.1.0: resolution: {integrity: sha512-x4FavbNEeXx/baD/zC/SdrvkjSby8nBn8KcCREqk6UuwvwoAPZmaV8TFCAuo/cpovBRTIY67mHhe86MQQm/68Q==} dependencies: @@ -3146,6 +3175,15 @@ packages: dev: false optional: true + /@next/swc-darwin-arm64@14.1.0: + resolution: {integrity: sha512-nUDn7TOGcIeyQni6lZHfzNoo9S0euXnu0jhsbMOmMJUBfgsnESdjN97kM7cBqQxZa8L/bM9om/S5/1dzCrW6wQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: false + optional: true + /@next/swc-darwin-x64@13.4.19: resolution: {integrity: sha512-jyzO6wwYhx6F+7gD8ddZfuqO4TtpJdw3wyOduR4fxTUCm3aLw7YmHGYNjS0xRSYGAkLpBkH1E0RcelyId6lNsw==} engines: {node: '>= 10'} @@ -3155,6 +3193,15 @@ packages: dev: false optional: true + /@next/swc-darwin-x64@14.1.0: + resolution: {integrity: sha512-1jgudN5haWxiAl3O1ljUS2GfupPmcftu2RYJqZiMJmmbBT5M1XDffjUtRUzP4W3cBHsrvkfOFdQ71hAreNQP6g==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: false + optional: true + /@next/swc-linux-arm64-gnu@13.4.19: resolution: {integrity: sha512-vdlnIlaAEh6H+G6HrKZB9c2zJKnpPVKnA6LBwjwT2BTjxI7e0Hx30+FoWCgi50e+YO49p6oPOtesP9mXDRiiUg==} engines: {node: '>= 10'} @@ -3164,6 +3211,15 @@ packages: dev: false optional: true + /@next/swc-linux-arm64-gnu@14.1.0: + resolution: {integrity: sha512-RHo7Tcj+jllXUbK7xk2NyIDod3YcCPDZxj1WLIYxd709BQ7WuRYl3OWUNG+WUfqeQBds6kvZYlc42NJJTNi4tQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: false + optional: true + /@next/swc-linux-arm64-musl@13.4.19: resolution: {integrity: sha512-aU0HkH2XPgxqrbNRBFb3si9Ahu/CpaR5RPmN2s9GiM9qJCiBBlZtRTiEca+DC+xRPyCThTtWYgxjWHgU7ZkyvA==} engines: {node: '>= 10'} @@ -3173,6 +3229,15 @@ packages: dev: false optional: true + /@next/swc-linux-arm64-musl@14.1.0: + resolution: {integrity: sha512-v6kP8sHYxjO8RwHmWMJSq7VZP2nYCkRVQ0qolh2l6xroe9QjbgV8siTbduED4u0hlk0+tjS6/Tuy4n5XCp+l6g==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: false + optional: true + /@next/swc-linux-x64-gnu@13.4.19: resolution: {integrity: sha512-htwOEagMa/CXNykFFeAHHvMJeqZfNQEoQvHfsA4wgg5QqGNqD5soeCer4oGlCol6NGUxknrQO6VEustcv+Md+g==} engines: {node: '>= 10'} @@ -3182,6 +3247,15 @@ packages: dev: false optional: true + /@next/swc-linux-x64-gnu@14.1.0: + resolution: {integrity: sha512-zJ2pnoFYB1F4vmEVlb/eSe+VH679zT1VdXlZKX+pE66grOgjmKJHKacf82g/sWE4MQ4Rk2FMBCRnX+l6/TVYzQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: false + optional: true + /@next/swc-linux-x64-musl@13.4.19: resolution: {integrity: sha512-4Gj4vvtbK1JH8ApWTT214b3GwUh9EKKQjY41hH/t+u55Knxi/0wesMzwQRhppK6Ddalhu0TEttbiJ+wRcoEj5Q==} engines: {node: '>= 10'} @@ -3191,6 +3265,15 @@ packages: dev: false optional: true + /@next/swc-linux-x64-musl@14.1.0: + resolution: {integrity: sha512-rbaIYFt2X9YZBSbH/CwGAjbBG2/MrACCVu2X0+kSykHzHnYH5FjHxwXLkcoJ10cX0aWCEynpu+rP76x0914atg==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: false + optional: true + /@next/swc-win32-arm64-msvc@13.4.19: resolution: {integrity: sha512-bUfDevQK4NsIAHXs3/JNgnvEY+LRyneDN788W2NYiRIIzmILjba7LaQTfihuFawZDhRtkYCv3JDC3B4TwnmRJw==} engines: {node: '>= 10'} @@ -3200,6 +3283,15 @@ packages: dev: false optional: true + /@next/swc-win32-arm64-msvc@14.1.0: + resolution: {integrity: sha512-o1N5TsYc8f/HpGt39OUQpQ9AKIGApd3QLueu7hXk//2xq5Z9OxmV6sQfNp8C7qYmiOlHYODOGqNNa0e9jvchGQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: false + optional: true + /@next/swc-win32-ia32-msvc@13.4.19: resolution: {integrity: sha512-Y5kikILFAr81LYIFaw6j/NrOtmiM4Sf3GtOc0pn50ez2GCkr+oejYuKGcwAwq3jiTKuzF6OF4iT2INPoxRycEA==} engines: {node: '>= 10'} @@ -3209,6 +3301,15 @@ packages: dev: false optional: true + /@next/swc-win32-ia32-msvc@14.1.0: + resolution: {integrity: sha512-XXIuB1DBRCFwNO6EEzCTMHT5pauwaSj4SWs7CYnME57eaReAKBXCnkUE80p/pAZcewm7hs+vGvNqDPacEXHVkw==} + engines: {node: '>= 10'} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: false + optional: true + /@next/swc-win32-x64-msvc@13.4.19: resolution: {integrity: sha512-YzA78jBDXMYiINdPdJJwGgPNT3YqBNNGhsthsDoWHL9p24tEJn9ViQf/ZqTbwSpX/RrkPupLfuuTH2sf73JBAw==} engines: {node: '>= 10'} @@ -3218,6 +3319,15 @@ packages: dev: false optional: true + /@next/swc-win32-x64-msvc@14.1.0: + resolution: {integrity: sha512-9WEbVRRAqJ3YFVqEZIxUqkiO8l1nool1LmNxygr5HWF8AcSYsEpneUDhmjUVJEzO2A04+oPtZdombzzPPkTtgg==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: false + optional: true + /@nodelib/fs.scandir@2.1.5: resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} @@ -3918,6 +4028,12 @@ packages: tslib: 2.6.2 dev: false + /@swc/helpers@0.5.2: + resolution: {integrity: sha512-E4KcWTpoLHqwPHLxidpOqQbcrZVgi0rsmmZXUle1jXmJfuIf/UWpczUJ7MZZ5tlxytgJXyp0w4PGkkeLiuIdZw==} + dependencies: + tslib: 2.6.2 + dev: false + /@szmarczak/http-timer@5.0.1: resolution: {integrity: sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==} engines: {node: '>=14.16'} @@ -10672,6 +10788,45 @@ packages: - babel-plugin-macros dev: false + /next@14.1.0(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-wlzrsbfeSU48YQBjZhDzOwhWhGsy+uQycR8bHAOt1LY1bn3zZEcDyHQOEoN3aWzQ8LHCAJ1nqrWCc9XF2+O45Q==} + engines: {node: '>=18.17.0'} + hasBin: true + peerDependencies: + '@opentelemetry/api': ^1.1.0 + react: ^18.2.0 + react-dom: ^18.2.0 + sass: ^1.3.0 + peerDependenciesMeta: + '@opentelemetry/api': + optional: true + sass: + optional: true + dependencies: + '@next/env': 14.1.0 + '@swc/helpers': 0.5.2 + busboy: 1.6.0 + caniuse-lite: 1.0.30001579 + graceful-fs: 4.2.11 + postcss: 8.4.31 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + styled-jsx: 5.1.1(@babel/core@7.23.7)(babel-plugin-macros@3.1.0)(react@18.2.0) + optionalDependencies: + '@next/swc-darwin-arm64': 14.1.0 + '@next/swc-darwin-x64': 14.1.0 + '@next/swc-linux-arm64-gnu': 14.1.0 + '@next/swc-linux-arm64-musl': 14.1.0 + '@next/swc-linux-x64-gnu': 14.1.0 + '@next/swc-linux-x64-musl': 14.1.0 + '@next/swc-win32-arm64-msvc': 14.1.0 + '@next/swc-win32-ia32-msvc': 14.1.0 + '@next/swc-win32-x64-msvc': 14.1.0 + transitivePeerDependencies: + - '@babel/core' + - babel-plugin-macros + dev: false + /nice-napi@1.0.2: resolution: {integrity: sha512-px/KnJAJZf5RuBGcfD+Sp2pAKq0ytz8j+1NehvgIGFkvtvFrDM3T8E4x/JJODXK9WZow8RRGrbA9QQ3hs+pDhA==} os: ['!win32'] diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 6e7e91713fc..989ef66e332 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -2,3 +2,4 @@ packages: - 'packages/*' - 'docs' - 'test' + - 'examples/custom-server-nextjs' From 97fe280541aaf254296d95a5dbad850f41200a8c Mon Sep 17 00:00:00 2001 From: MUI bot <2109932+Janpot@users.noreply.github.com> Date: Thu, 25 Jan 2024 09:18:06 +0100 Subject: [PATCH 02/19] remove --- packages/toolpad-app/cli/index.ts | 1 - packages/toolpad-app/src/server/FunctionsManager.ts | 1 - packages/toolpad-app/src/server/functionsRuntime.ts | 3 --- packages/toolpad-app/src/server/index.ts | 1 - packages/toolpad-app/src/server/toolpadAppBuilder.ts | 1 - 5 files changed, 7 deletions(-) diff --git a/packages/toolpad-app/cli/index.ts b/packages/toolpad-app/cli/index.ts index a6e62dfb509..b86a8de3043 100644 --- a/packages/toolpad-app/cli/index.ts +++ b/packages/toolpad-app/cli/index.ts @@ -14,7 +14,6 @@ export interface RunOptions { base: string; } -// import.meta.url ??= url.pathToFileURL(__filename).toString(); const currentDirectory = url.fileURLToPath(new URL('.', import.meta.url)); async function runCommand( diff --git a/packages/toolpad-app/src/server/FunctionsManager.ts b/packages/toolpad-app/src/server/FunctionsManager.ts index a9f958e4735..dfc2cd311a4 100644 --- a/packages/toolpad-app/src/server/FunctionsManager.ts +++ b/packages/toolpad-app/src/server/FunctionsManager.ts @@ -31,7 +31,6 @@ export interface CreateDataProviderOptions { paginationMode: PaginationMode; } -// import.meta.url ??= url.pathToFileURL(__filename).toString(); const currentDirectory = url.fileURLToPath(new URL('.', String(import.meta.url))); async function createDefaultFunction(filePath: string): Promise { diff --git a/packages/toolpad-app/src/server/functionsRuntime.ts b/packages/toolpad-app/src/server/functionsRuntime.ts index c7da6f42c46..e7b0ee4b52a 100644 --- a/packages/toolpad-app/src/server/functionsRuntime.ts +++ b/packages/toolpad-app/src/server/functionsRuntime.ts @@ -1,13 +1,10 @@ import * as path from 'path'; import * as fs from 'fs/promises'; -import * as url from 'node:url'; import { TOOLPAD_DATA_PROVIDER_MARKER, ToolpadDataProvider } from '@mui/toolpad-core/server'; import * as z from 'zod'; import { fromZodError } from 'zod-validation-error'; import * as crypto from 'crypto'; -// import.meta.url ??= url.pathToFileURL(__filename).toString(); - async function loadExports(filePath: string): Promise> { const fullPath = path.resolve(filePath); const content = await fs.readFile(fullPath, 'utf-8'); diff --git a/packages/toolpad-app/src/server/index.ts b/packages/toolpad-app/src/server/index.ts index d0c95d5a916..14480d712e6 100644 --- a/packages/toolpad-app/src/server/index.ts +++ b/packages/toolpad-app/src/server/index.ts @@ -29,7 +29,6 @@ import { createRpcServer as createProjectRpcServer } from './projectRpcServer'; import { createRpcServer as createRuntimeRpcServer } from './runtimeRpcServer'; import { createAuthHandler, createRequireAuthMiddleware } from './auth'; -// import.meta.url ??= url.pathToFileURL(__filename).toString(); const currentDirectory = url.fileURLToPath(new URL('.', import.meta.url)); const DEFAULT_PORT = 3000; diff --git a/packages/toolpad-app/src/server/toolpadAppBuilder.ts b/packages/toolpad-app/src/server/toolpadAppBuilder.ts index 11bb6a36e63..fb15db5a9a3 100644 --- a/packages/toolpad-app/src/server/toolpadAppBuilder.ts +++ b/packages/toolpad-app/src/server/toolpadAppBuilder.ts @@ -9,7 +9,6 @@ import { INITIAL_STATE_WINDOW_PROPERTY } from '../constants'; import { pathToNodeImportSpecifier } from '../utils/paths'; import viteVirtualPlugin, { VirtualFileContent, replaceFiles } from './viteVirtualPlugin'; -// import.meta.url ??= url.pathToFileURL(__filename).toString(); const currentDirectory = url.fileURLToPath(new URL('.', import.meta.url)); const MAIN_ENTRY = '/main.tsx'; From e2795722a7dd6ce013666a01bbc7d3ad9f682903 Mon Sep 17 00:00:00 2001 From: MUI bot <2109932+Janpot@users.noreply.github.com> Date: Thu, 25 Jan 2024 09:33:35 +0100 Subject: [PATCH 03/19] make server work --- packages/toolpad-app/src/exports/next.tsx | 19 ++----------------- packages/toolpad-app/src/server/localMode.ts | 7 ++++++- 2 files changed, 8 insertions(+), 18 deletions(-) diff --git a/packages/toolpad-app/src/exports/next.tsx b/packages/toolpad-app/src/exports/next.tsx index 294a7d60b24..b32a4fa0326 100644 --- a/packages/toolpad-app/src/exports/next.tsx +++ b/packages/toolpad-app/src/exports/next.tsx @@ -1,9 +1,8 @@ 'use server'; import * as React from 'react'; -import * as appDom from '@mui/toolpad-core/appDom'; import ToolpadAppClient from './next-client'; -import { initProject } from '../server/localMode'; +import { loadDom } from '../server/localMode'; import createRuntimeState from '../runtime/createRuntimeState'; export interface ToolpadAppServerProps { @@ -11,22 +10,8 @@ export interface ToolpadAppServerProps { dir: string; } -let dom = appDom.createDom(); -dom = appDom.addNode( - dom, - appDom.createNode(dom, 'page', { attributes: {} }), - appDom.getRoot(dom), - 'pages', -); - export async function ToolpadApp({ base, dir = './toolpad' }: ToolpadAppServerProps) { - const project = await initProject({ - dev: false, - dir, - base, - }); - // - // const dom = await project.loadDom(); + const dom = await loadDom(dir); const initialState = createRuntimeState({ dom }); return ; diff --git a/packages/toolpad-app/src/server/localMode.ts b/packages/toolpad-app/src/server/localMode.ts index 643266ffdb7..434660a6b0f 100644 --- a/packages/toolpad-app/src/server/localMode.ts +++ b/packages/toolpad-app/src/server/localMode.ts @@ -911,7 +911,7 @@ async function loadProjectFolder(root: string): Promise { return readProjectFolder(root); } -export async function loadDomFromDisk(root: string): Promise { +async function loadDomFromDisk(root: string): Promise { const projectFolder = await loadProjectFolder(root); return projectFolderToAppDom(projectFolder); @@ -1439,3 +1439,8 @@ async function buildPagesManifest(root: string): Promise { return { pages }; } + +export async function loadDom(root: string) { + const resolvedRoot = resolveProjectDir(root); + return loadDomFromDisk(resolvedRoot); +} From aa364fa807fa42a35c114f201a44109674bf3945 Mon Sep 17 00:00:00 2001 From: MUI bot <2109932+Janpot@users.noreply.github.com> Date: Thu, 25 Jan 2024 10:46:06 +0100 Subject: [PATCH 04/19] bindings --- .../toolpad/application.yml | 3 ++ .../toolpad/pages/page/page.yml | 14 ++++++++- .../toolpad/resources/functions2.ts | 7 +++++ .../toolpad-app/src/exports/next-client.tsx | 17 +++++++++- .../toolpad-app/src/runtime/AppContext.tsx | 8 +++++ .../toolpad-app/src/runtime/PreviewHeader.tsx | 11 ++++--- .../toolpad-app/src/runtime/ToolpadApp.tsx | 31 +++++++++++++------ packages/toolpad-app/src/runtime/constants.ts | 2 -- packages/toolpad-app/src/runtime/index.tsx | 13 +++++++- .../toolpad-core/src/jsBrowserRuntime.tsx | 22 ++++++++----- 10 files changed, 103 insertions(+), 25 deletions(-) create mode 100644 examples/custom-server-nextjs/toolpad/application.yml create mode 100644 examples/custom-server-nextjs/toolpad/resources/functions2.ts create mode 100644 packages/toolpad-app/src/runtime/AppContext.tsx diff --git a/examples/custom-server-nextjs/toolpad/application.yml b/examples/custom-server-nextjs/toolpad/application.yml new file mode 100644 index 00000000000..6b008228134 --- /dev/null +++ b/examples/custom-server-nextjs/toolpad/application.yml @@ -0,0 +1,3 @@ +apiVersion: v1 +kind: application +spec: {} diff --git a/examples/custom-server-nextjs/toolpad/pages/page/page.yml b/examples/custom-server-nextjs/toolpad/pages/page/page.yml index 3e9c960bca7..cd43a3f6595 100644 --- a/examples/custom-server-nextjs/toolpad/pages/page/page.yml +++ b/examples/custom-server-nextjs/toolpad/pages/page/page.yml @@ -1,4 +1,4 @@ -# yaml-language-server: $schema=https://raw.githubusercontent.com/mui/mui-toolpad/v0.1.40/docs/schemas/v1/definitions.json#properties/Page +# yaml-language-server: $schema=https://raw.githubusercontent.com/mui/mui-toolpad/v0.1.46/docs/schemas/v1/definitions.json#properties/Page apiVersion: v1 kind: page @@ -16,3 +16,15 @@ spec: mode: link value: To the Next.js app href: /my-next-app + - component: Text + name: text1 + props: + mode: null + value: + $$jsExpression: query.data + queries: + - name: query + mode: query + query: + function: functions2.ts#default + kind: local diff --git a/examples/custom-server-nextjs/toolpad/resources/functions2.ts b/examples/custom-server-nextjs/toolpad/resources/functions2.ts new file mode 100644 index 00000000000..2750f3f5977 --- /dev/null +++ b/examples/custom-server-nextjs/toolpad/resources/functions2.ts @@ -0,0 +1,7 @@ +/** + * Toolpad handlers file. + */ + +export default async function handler(message: string) { + return `Hello ${message}`; +} diff --git a/packages/toolpad-app/src/exports/next-client.tsx b/packages/toolpad-app/src/exports/next-client.tsx index e7c04561a81..2678c131ffe 100644 --- a/packages/toolpad-app/src/exports/next-client.tsx +++ b/packages/toolpad-app/src/exports/next-client.tsx @@ -1,3 +1,18 @@ 'use client'; -export { default } from '../runtime/ToolpadApp'; +import * as React from 'react'; +import ToolpadApp, { ToolpadAppProps } from '../runtime/ToolpadApp'; +import { AppContext, AppContextValue } from '../runtime/AppContext'; + +const appContext: AppContextValue = { + isPreview: false, + isCustomServer: true, +}; + +export default function ToolpadAppClient(props: ToolpadAppProps) { + return ( + + + + ); +} diff --git a/packages/toolpad-app/src/runtime/AppContext.tsx b/packages/toolpad-app/src/runtime/AppContext.tsx new file mode 100644 index 00000000000..2d8cde66551 --- /dev/null +++ b/packages/toolpad-app/src/runtime/AppContext.tsx @@ -0,0 +1,8 @@ +import * as React from 'react'; + +export interface AppContextValue { + isPreview: boolean; + isCustomServer: boolean; +} + +export const AppContext = React.createContext(null); diff --git a/packages/toolpad-app/src/runtime/PreviewHeader.tsx b/packages/toolpad-app/src/runtime/PreviewHeader.tsx index 8398de74491..da431f350f6 100644 --- a/packages/toolpad-app/src/runtime/PreviewHeader.tsx +++ b/packages/toolpad-app/src/runtime/PreviewHeader.tsx @@ -17,7 +17,8 @@ import { import EditIcon from '@mui/icons-material/Edit'; import { useMatch } from 'react-router-dom'; import ContentCopyIcon from '@mui/icons-material/ContentCopy'; -import { IS_CUSTOM_SERVER, PREVIEW_HEADER_HEIGHT } from './constants'; +import { PREVIEW_HEADER_HEIGHT } from './constants'; +import { AppContext } from './AppContext'; interface CopyToClipboardButtonProps extends IconButtonProps { content: string; @@ -178,7 +179,9 @@ export default function PreviewHeader({ basename }: PreviewHeaderProps) { const theme = useTheme(); - return ( + const appContext = React.useContext(AppContext); + + return appContext ? ( ) : ( - ); + ) : null; } diff --git a/packages/toolpad-app/src/runtime/ToolpadApp.tsx b/packages/toolpad-app/src/runtime/ToolpadApp.tsx index 7545a21eda4..a685ef07103 100644 --- a/packages/toolpad-app/src/runtime/ToolpadApp.tsx +++ b/packages/toolpad-app/src/runtime/ToolpadApp.tsx @@ -85,7 +85,7 @@ import evalJsBindings, { EvaluatedBinding, ParsedBinding, } from './evalJsBindings'; -import { HTML_ID_EDITOR_OVERLAY, IS_PREVIEW, PREVIEW_HEADER_HEIGHT } from './constants'; +import { HTML_ID_EDITOR_OVERLAY, PREVIEW_HEADER_HEIGHT } from './constants'; import { layoutBoxArgTypes } from './toolpadComponents/layoutBox'; import { useDataQuery, UseFetch } from './useDataQuery'; import { CanvasHooksContext, NavigateToPage } from './CanvasHooksContext'; @@ -96,6 +96,7 @@ import api, { queryClient } from './api'; import { AuthContext, useAuth } from './useAuth'; import { RequireAuthorization } from './auth'; import SignInPage from './SignInPage'; +import { AppContext } from './AppContext'; const browserJsRuntime = getBrowserRuntime(); @@ -104,8 +105,6 @@ export const IS_RENDERED_IN_CANVAS = ? false : !!(window.frameElement as HTMLIFrameElement)?.dataset?.toolpadCanvas; -const SHOW_PREVIEW_HEADER = IS_PREVIEW && !IS_RENDERED_IN_CANVAS; - export type PageComponents = Partial>; export const componentsStore = createGlobalState({}); @@ -188,7 +187,6 @@ const AppRoot = styled('div')({ minHeight: '100vh', display: 'flex', flexDirection: 'column', - paddingTop: SHOW_PREVIEW_HEADER ? PREVIEW_HEADER_HEIGHT : 0, }); const EditorOverlay = styled('div')({ @@ -1559,9 +1557,10 @@ function AppError({ error }: FallbackProps) { export interface ToolpadAppLayoutProps { dom: appDom.RenderTree; basename: string; + clipped: boolean; } -function ToolpadAppLayout({ dom, basename }: ToolpadAppLayoutProps) { +function ToolpadAppLayout({ dom, basename, clipped }: ToolpadAppLayoutProps) { const root = appDom.getApp(dom); const { pages = [] } = appDom.getChildNodes(dom, root); @@ -1586,7 +1585,7 @@ function ToolpadAppLayout({ dom, basename }: ToolpadAppLayoutProps) { pages={navEntries} hasNavigation={!IS_RENDERED_IN_CANVAS} hasHeader={hasAuthentication && !IS_RENDERED_IN_CANVAS} - clipped={SHOW_PREVIEW_HEADER} + clipped={clipped} > @@ -1621,13 +1620,21 @@ export default function ToolpadApp({ rootRef, basename, state }: ToolpadAppProps const authContext = useAuth({ dom, basename }); + const appContext = React.useContext(AppContext); + const showPreviewHeader: boolean = !!appContext?.isPreview && !IS_RENDERED_IN_CANVAS; + return ( - {SHOW_PREVIEW_HEADER ? : null} - + {showPreviewHeader ? : null} + @@ -1639,7 +1646,13 @@ export default function ToolpadApp({ rootRef, basename, state }: ToolpadAppProps } /> } + element={ + + } /> diff --git a/packages/toolpad-app/src/runtime/constants.ts b/packages/toolpad-app/src/runtime/constants.ts index ea8366fca87..d11b874574c 100644 --- a/packages/toolpad-app/src/runtime/constants.ts +++ b/packages/toolpad-app/src/runtime/constants.ts @@ -1,4 +1,2 @@ export const HTML_ID_EDITOR_OVERLAY = 'editor-overlay'; -export const IS_PREVIEW = process.env.NODE_ENV !== 'production'; -export const IS_CUSTOM_SERVER = process.env.TOOLPAD_CUSTOM_SERVER === 'true'; export const PREVIEW_HEADER_HEIGHT = 52; diff --git a/packages/toolpad-app/src/runtime/index.tsx b/packages/toolpad-app/src/runtime/index.tsx index 4e673ae26c4..c86982e007d 100644 --- a/packages/toolpad-app/src/runtime/index.tsx +++ b/packages/toolpad-app/src/runtime/index.tsx @@ -13,6 +13,10 @@ import RuntimeToolpadApp, { pageComponentsStore, } from './ToolpadApp'; import { RuntimeState } from './types'; +import { AppContext } from './AppContext'; + +const IS_PREVIEW = process.env.NODE_ENV !== 'production'; +const IS_CUSTOM_SERVER = process.env.TOOLPAD_CUSTOM_SERVER === 'true'; const cache = createCache({ key: 'css', @@ -39,13 +43,20 @@ export interface RootProps { ToolpadApp: React.ComponentType; } +const appContext = { + isPreview: IS_PREVIEW, + isCustomServer: IS_CUSTOM_SERVER, +}; + function Root({ ToolpadApp, initialState, base }: RootProps) { return ( {/* For some reason this helps with https://github.com/vitejs/vite/issues/12423 */}