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,