Skip to content

Commit

Permalink
wip: sourcemap
Browse files Browse the repository at this point in the history
  • Loading branch information
hi-ogawa committed Nov 15, 2024
1 parent 39fdabd commit 770b456
Show file tree
Hide file tree
Showing 10 changed files with 208 additions and 11 deletions.
31 changes: 31 additions & 0 deletions viteroll/examples/ssr-simple/e2e/basic.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { expect, test } from "@playwright/test";
import { createEditor, testNoJs } from "../../../e2e/helper";

testNoJs("ssr", async ({ page }) => {
await page.goto("/");
await page.getByText("hydrated: false").click();
});

test("csr", async ({ page }) => {
await page.goto("/");
await page.getByText("hydrated: true").click();
});

test("hmr", async ({ page, request }) => {
await page.goto("/");
await page.getByText("hydrated: true").click();

await page.getByRole("button", { name: "Count: 0" }).click();

using file = createEditor("./src/app.tsx");
file.edit((s) => s.replace("Count:", "Count-EDIT:"));

await page.getByRole("button", { name: "Count-EDIT: 1" }).click();

file.edit((s) => s.replace("Count-EDIT:", "Count-EDIT-EDIT:"));
await page.getByRole("button", { name: "Count-EDIT-EDIT: 2" }).click();

// server module is also invalidated
const res = await request.get("/");
expect(await res.text()).toContain("Count-EDIT-EDIT");
});
17 changes: 17 additions & 0 deletions viteroll/examples/ssr-simple/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"name": "@hiogawa/viteroll-example-ssr",
"private": true,
"type": "module",
"scripts": {
"dev": "vite",
"test-e2e": "playwright test"
},
"dependencies": {
"react": "latest",
"react-dom": "latest"
},
"devDependencies": {
"@types/react": "latest",
"@types/react-dom": "latest"
}
}
1 change: 1 addition & 0 deletions viteroll/examples/ssr-simple/playwright.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from "../../playwright.config.ts";
21 changes: 21 additions & 0 deletions viteroll/examples/ssr-simple/src/app.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import React from "react";

export function App() {
const [count, setCount] = React.useState(0);
return (
<div>
<h1>Rolldown SSR</h1>
<Hydrated />
<button onClick={() => setCount((c) => c + 1)}>Count: {count}</button>
</div>
);
}

function Hydrated() {
const hydrated = React.useSyncExternalStore(
React.useCallback(() => () => {}, []),
() => true,
() => false,
);
return <p>hydrated: {String(hydrated)}</p>;
}
7 changes: 7 additions & 0 deletions viteroll/examples/ssr-simple/src/entry-client.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import React from "react";
import ReactDOMClient from "react-dom/client";
import { App } from "./app";

React.startTransition(() => {
ReactDOMClient.hydrateRoot(document.getElementById("root")!, <App />);
});
24 changes: 24 additions & 0 deletions viteroll/examples/ssr-simple/src/entry-server.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import type { Connect } from "vite";

const handler: Connect.SimpleHandleFunction = (req, res) => {
const url = new URL(req.url ?? "/", "https://vite.dev");
console.log(`[SSR] ${req.method} ${url.pathname}`);
if (url.pathname === "/crash-ssr") {
throw new Error("crash-ssr");
}
res.setHeader("content-type", "text/html");
// TODO: transformIndexHtml?
res.end(`\
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
</head>
<body>
Test SSR
</body>
</html>
`);
};

export default handler;
16 changes: 16 additions & 0 deletions viteroll/examples/ssr-simple/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"include": ["src", "*.ts"],
"compilerOptions": {
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"verbatimModuleSyntax": true,
"allowImportingTsExtensions": true,
"moduleResolution": "Bundler",
"module": "ESNext",
"target": "ESNext",
"lib": ["ESNext", "DOM"],
"jsx": "react-jsx",
"noEmit": true
}
}
54 changes: 54 additions & 0 deletions viteroll/examples/ssr-simple/vite.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { defineConfig } from "vite";
import { RolldownEnvironment, viteroll } from "../../viteroll";

process.setSourceMapsEnabled(true);

export default defineConfig({
environments: {
client: {
build: {
outDir: "dist/client",
rollupOptions: {
input: "./src/entry-client",
},
},
},
ssr: {
build: {
outDir: "dist/server",
rollupOptions: {
input: {
index: "./src/entry-server",
},
},
},
},
},
plugins: [
viteroll({
reactRefresh: true,
ssrModuleRunner: true,
}),
{
name: "ssr-middleware",
config() {
return {
appType: "custom",
};
},
configureServer(server) {
return () => {
const devEnv = server.environments.ssr as RolldownEnvironment;
server.middlewares.use(async (req, res, next) => {
try {
const mod = (await devEnv.import("src/entry-server.tsx")) as any;
await mod.default(req, res);
} catch (e) {
next(e);
}
});
};
},
},
],
});
3 changes: 3 additions & 0 deletions viteroll/examples/ssr/src/entry-server.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ import { App } from "./app";
const handler: Connect.SimpleHandleFunction = (req, res) => {
const url = new URL(req.url ?? "/", "https://vite.dev");
console.log(`[SSR] ${req.method} ${url.pathname}`);
if (url.pathname === "/crash-ssr") {
throw new Error("crash-ssr");
}
const ssrHtml = ReactDOMServer.renderToString(<App />);
res.setHeader("content-type", "text/html");
// TODO: transformIndexHtml?
Expand Down
45 changes: 34 additions & 11 deletions viteroll/viteroll.ts
Original file line number Diff line number Diff line change
Expand Up @@ -342,16 +342,36 @@ class RolldownModuleRunner {
self: this.context,
...this.context,
};
// TODO: sourcemap
code = code.replace(/^\/\/# sourceMapping.*$/m, "");
const wrapped = `'use strict';(${Object.keys(context).join(",")})=>{{
${code};
// TODO: need to re-expose runtime utilities for now
self.__toCommonJS = __toCommonJS;
self.__export = __export;
self.__toESM = __toESM;
}}`;
const fn = (0, eval)(wrapped);
// TODO: sourcemap not working?
// extract sourcemap
const sourcemap = code.match(/^\/\/# sourceMappingURL=.*/m)?.[0] ?? "";
if (sourcemap) {
code = code.replace(sourcemap, "");
}
// as eval
code = `\
'use strict';(${Object.keys(context).join(",")})=>{{${code}
// TODO: need to re-expose runtime utilities for now
self.__toCommonJS = __toCommonJS;
self.__export = __export;
self.__toESM = __toESM;
}}
//# sourceMappingSource=rolldown-module-runner
${sourcemap}
`;
// as new Function
// code = `\
// ${code}
// // TODO: need to re-expose runtime utilities for now
// self.__toCommonJS = __toCommonJS;
// self.__export = __export;
// self.__toESM = __toESM;
// //# sourceMappingSource=rolldown-module-runner
// ${sourcemap}
// `;
fs.writeFileSync("dump.js", code);
const fn = (0, eval)(code);
// const fn = new Function(...Object.keys(context), code);
try {
fn(...Object.values(context));
} catch (e) {
Expand Down Expand Up @@ -440,7 +460,10 @@ function viterollEntryPlugin(
if (viterollOptions.reactRefresh) {
output.prepend(getReactRefreshRuntimeCode());
}
return { code: output.toString(), map: output.generateMap() };
return {
code: output.toString(),
map: output.generateMap({ hires: "boundary" }),
};
}
},
generateBundle(_options, bundle) {
Expand Down

0 comments on commit 770b456

Please sign in to comment.