From ad502dc2b22701d7ff689a731becd8704b0c3003 Mon Sep 17 00:00:00 2001 From: ahuigo <1781999+ahuigo@users.noreply.github.com> Date: Mon, 23 Jan 2023 00:50:40 +0800 Subject: [PATCH] feat: support root src path(`"@/":"/_ultra/compiler/src/"`) 1. Support root src path like `import "@/config.ts"` 2. Add an example and test case about root src path in **examples/with-react/router** --- deno.json | 2 +- examples/with-react-router/importMap.json | 3 ++- examples/with-react-router/server.test.ts | 21 +++++++++++++++++++++ examples/with-react-router/server.tsx | 6 +++++- examples/with-react-router/src/app.tsx | 7 ++++--- lib/server.ts | 4 ++-- lib/ultra.ts | 4 +++- tools/dev.ts | 16 +++++++++++++++- tools/test-examples.ts | 2 +- 9 files changed, 54 insertions(+), 11 deletions(-) create mode 100644 examples/with-react-router/server.test.ts diff --git a/deno.json b/deno.json index 3a6d08a2..3bd5d0ae 100644 --- a/deno.json +++ b/deno.json @@ -4,7 +4,7 @@ "test": "deno task test:unit && deno task test:fixture && deno task test:examples", "test:unit": "deno test -A ./test/unit", "test:fixture": "cd ./test/fixture && deno test -A", - "test:examples": "deno run -A ./tools/test-examples.ts basic with-csr with-unocss with-wouter", + "test:examples": "deno run -A ./tools/test-examples.ts basic with-csr with-unocss with-wouter with-react-router", "version-bump:minor": "deno run -A tools/patch.ts --release=minor", "version-bump:patch": "deno run -A tools/patch.ts --release=patch" }, diff --git a/examples/with-react-router/importMap.json b/examples/with-react-router/importMap.json index ab2b66d5..8aedd2a6 100644 --- a/examples/with-react-router/importMap.json +++ b/examples/with-react-router/importMap.json @@ -7,6 +7,7 @@ "react-dom/client": "https://esm.sh/v106/react-dom@18.2.0/client?dev", "ultra/": "https://deno.land/x/ultra@v2.2.1/", "react-router-dom": "https://esm.sh/v106/react-router-dom@6.3.0?external=react", - "react-router-dom/server": "https://esm.sh/v106/react-router-dom@6.3.0/server?external=react" + "react-router-dom/server": "https://esm.sh/v106/react-router-dom@6.3.0/server?external=react", + "@/": "./src/" } } diff --git a/examples/with-react-router/server.test.ts b/examples/with-react-router/server.test.ts new file mode 100644 index 00000000..f84ac815 --- /dev/null +++ b/examples/with-react-router/server.test.ts @@ -0,0 +1,21 @@ +import { assertEquals } from "https://deno.land/std@0.176.0/testing/asserts.ts"; +import server from "./server.tsx"; + +/** + * This is here as an example of how to test your + * server/rendering. + */ +Deno.test("it works", async (t) => { + await t.step("it can render the AboutPage", async () => { + const response = await server.request("http://localhost/about"); + const content = await response.text(); + + assertEquals(response.status, 200); + assertEquals( + response.headers.get("content-type"), + "text/html; charset=utf-8", + ); + + assertEquals(content.includes(`
About page
`), true); + }); +}); diff --git a/examples/with-react-router/server.tsx b/examples/with-react-router/server.tsx index 4633d292..1a3ed590 100644 --- a/examples/with-react-router/server.tsx +++ b/examples/with-react-router/server.tsx @@ -26,4 +26,8 @@ server.get("*", async (context) => { }); }); -serve(server.fetch); +if (import.meta.main) { + serve(server.fetch); +} + +export default server; diff --git a/examples/with-react-router/src/app.tsx b/examples/with-react-router/src/app.tsx index a690e935..7b1448a4 100644 --- a/examples/with-react-router/src/app.tsx +++ b/examples/with-react-router/src/app.tsx @@ -1,10 +1,10 @@ import { lazy, Suspense } from "react"; import { Route, Routes } from "react-router-dom"; import useServerContext from "ultra/hooks/use-server-context.js"; -import { DefaultLayout } from "./layouts/DefaultLayout.tsx"; +import { DefaultLayout } from "@/layouts/DefaultLayout.tsx"; -const HomePage = lazy(() => import("./pages/Home.tsx")); -const AboutPage = lazy(() => import("./pages/About.tsx")); +const HomePage = lazy(() => import("@/pages/Home.tsx")); +const AboutPage = lazy(() => import("@/pages/About.tsx")); function RouteNotFound() { useServerContext((context) => { @@ -26,6 +26,7 @@ export default function App() { Page is Loading...}> }> + {/** @ts-ignore TS2590 [ERROR]: Expression produces a union type that is too complex to represent: https://github.com/microsoft/TypeScript/issues/42790 */} } /> } /> } /> diff --git a/lib/server.ts b/lib/server.ts index 2655fd88..3730b576 100644 --- a/lib/server.ts +++ b/lib/server.ts @@ -67,7 +67,7 @@ export async function createServer( cache: mode !== "development", })); - // Serve anything else static at "/" + // Serve static at "/ultra/" // deno-fmt-ignore server.get("/ultra/*", ( context: Context, @@ -81,7 +81,7 @@ export async function createServer( })(context,next); }); - // Serve anything else static at "/" + // Serve anything else // deno-fmt-ignore server.get("*", serveStatic({ root: resolve(root, "./"), diff --git a/lib/ultra.ts b/lib/ultra.ts index 71dc2a56..8244c63b 100644 --- a/lib/ultra.ts +++ b/lib/ultra.ts @@ -155,7 +155,7 @@ export class UltraServer extends Hono { #importMapHandler(importMap: ImportMap | undefined) { if (importMap?.imports) { const ultraUrl = importMap.imports["ultra/"]; - // Set importMap for ultra/ framework + //1. Set importMap for ultra/ framework if (ultraUrl && !ultraUrl.startsWith("http")) { if (ultraUrl.startsWith("/")) { this.ultraDir = ultraUrl; @@ -164,6 +164,8 @@ export class UltraServer extends Hono { } importMap.imports["ultra/"] = "/ultra/"; } + //2. @/ path + importMap.imports["@/"] = "/_ultra/compiler/src/"; } } diff --git a/tools/dev.ts b/tools/dev.ts index 4b301618..354b3912 100644 --- a/tools/dev.ts +++ b/tools/dev.ts @@ -11,13 +11,19 @@ type ImportMap = { * would like to work on, generate a `deno.dev.json` and `importMap.dev.json` * in that examples project directory, and run the ./server.tsx in dev mode. */ +interface DenoConfig { + tasks: Record; + lock?: boolean; + compilerOptions: Record; + importMap: string; +} export async function initExampleConfig(example: string) { try { const examplePath = join("examples", example); const devConfigPath = join(examplePath, "deno.dev.json"); const devImportMapPath = join(examplePath, "importMap.dev.json"); - const config: Record = JSON.parse( + const config: DenoConfig = JSON.parse( await readTextFile(join(examplePath, "deno.json")), ); @@ -28,6 +34,14 @@ export async function initExampleConfig(example: string) { importMap.imports["ultra/"] = `../../`; config.importMap = "importMap.dev.json"; + // Since `deno task -c deno.dev.json dev` doesn't pass `deno.dev.json` to cli by default + if (config.tasks.dev && !config.tasks.dev.includes("deno.dev.json")) { + config.tasks.dev = config.tasks.dev.replace( + /^deno run/, + "deno run -c deno.dev.json", + ); + } + await Deno.writeTextFile(devConfigPath, JSON.stringify(config, null, 2)); await Deno.writeTextFile( devImportMapPath, diff --git a/tools/test-examples.ts b/tools/test-examples.ts index 0da2f8d7..ce3ce0db 100644 --- a/tools/test-examples.ts +++ b/tools/test-examples.ts @@ -4,7 +4,6 @@ import { initExampleConfig } from "./dev.ts"; async function testExample(example: string) { try { const examplePath = join("examples", example); - await initExampleConfig(example); const cmd = [ Deno.execPath(), "test", @@ -13,6 +12,7 @@ async function testExample(example: string) { "-A", ]; console.log("test ", examplePath, cmd); + await initExampleConfig(example); const process = Deno.run({ cmd, cwd: examplePath,