Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable multi page app #88

Merged
merged 14 commits into from
Nov 2, 2023
30 changes: 24 additions & 6 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,23 @@ function isIgnoredPath(path: string, req: express.Request) {
: Config.ignorePaths(path, req);
}

function findClosestIndexToRoot(
reqPath: string,
root: string
): string | undefined {
const basePath = reqPath.slice(0, reqPath.lastIndexOf("/"));
const dirs = basePath.split("/");

while (dirs.length > 0) {
const pathToTest = path.join(root, ...dirs, "index.html");
if (fs.existsSync(pathToTest)) {
return pathToTest;
}
dirs.pop();
}
return undefined;
}

async function injectViteIndexMiddleware(
app: core.Express,
server: ViteDevServer
Expand All @@ -199,13 +216,12 @@ async function injectViteIndexMiddleware(
app.get("/*", async (req, res, next) => {
if (isIgnoredPath(req.path, req)) return next();

const template = fs.readFileSync(
path.resolve(config.root, "index.html"),
"utf8"
);

if (isStaticFilePath(req.path)) next();
else {
const indexPath = findClosestIndexToRoot(req.path, config.root);
if (indexPath === undefined) return next();

const template = fs.readFileSync(indexPath, "utf8");
const html = await server.transformIndexHtml(req.originalUrl, template);
res.send(getTransformedHTML(html, req));
}
Expand All @@ -218,8 +234,10 @@ async function injectIndexMiddleware(app: core.Express) {
app.use("*", (req, res, next) => {
if (isIgnoredPath(req.baseUrl, req)) return next();

const html = fs.readFileSync(path.resolve(distPath, "index.html"), "utf-8");
const indexPath = findClosestIndexToRoot(req.originalUrl, distPath);
if (indexPath === undefined) return next();

const html = fs.readFileSync(indexPath, "utf8");
res.send(getTransformedHTML(html, req));
});
}
Expand Down
12 changes: 12 additions & 0 deletions tests/env/dist/subpath/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<h1>subpath</h1>
</body>
</html>
12 changes: 12 additions & 0 deletions tests/noIndexEnv/dist/subpath/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<h1>subpath</h1>
</body>
</html>
12 changes: 12 additions & 0 deletions tests/noIndexEnv/subpath/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<h1>subpath</h1>
</body>
</html>
106 changes: 104 additions & 2 deletions tests/server.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,26 @@ test("Express app", async (done) => {
it("get api routes work");

response = await request(app).get("/");
expect(response.text).toMatch(/<body>/);
expect(response.text).toMatch(/<h1>index<\/h1>/);
response = await request(app).get("/route");
expect(response.text).toMatch(/<body>/);
expect(response.text).toMatch(/<h1>index<\/h1>/);

it("html is served correctly");

response = await request(app).get("/subpath/");
expect(response.text).toMatch(/<h1>subpath<\/h1>/);
response = await request(app).get("/subpath/route");
expect(response.text).toMatch(/<h1>subpath<\/h1>/);

it("subpath html is served correctly");

response = await request(app).get("/some/path/route");
expect(response.text).toMatch(/<h1>index<\/h1>/);
response = await request(app).get("/subpath/to/some/route");
expect(response.text).toMatch(/<h1>subpath<\/h1>/);

it("fallback to closest index toward root");

response = await request(app).get("/test.txt");
expect(response.text).toBe("Hello from test.txt");

Expand Down Expand Up @@ -86,9 +100,23 @@ test("Express app with explicit static middleware", async (done) => {

it("html is served correctly");

response = await request(app).get("/subpath/");
expect(response.text).toMatch(/<h1>subpath<\/h1>/);
response = await request(app).get("/subpath/route");
expect(response.text).toMatch(/<h1>subpath<\/h1>/);

it("subpath html is served correctly");

expect(response.headers.before).toBe("1");
expect(response.headers.after).toBe("1");

response = await request(app).get("/some/path/route");
expect(response.text).toMatch(/<h1>index<\/h1>/);
response = await request(app).get("/subpath/to/some/route");
expect(response.text).toMatch(/<h1>subpath<\/h1>/);

it("fallback to closest index toward root");

response = await request(app).get("/test.txt");
expect(response.text).toBe("Hello from test.txt");

Expand Down Expand Up @@ -136,6 +164,20 @@ test("Express app with custom http server", async (done) => {

it("html is served correctly");

response = await request(app).get("/subpath/");
expect(response.text).toMatch(/<h1>subpath<\/h1>/);
response = await request(app).get("/subpath/route");
expect(response.text).toMatch(/<h1>subpath<\/h1>/);

it("subpath html is served correctly");

response = await request(app).get("/some/path/route");
expect(response.text).toMatch(/<h1>index<\/h1>/);
response = await request(app).get("/subpath/to/some/route");
expect(response.text).toMatch(/<h1>subpath<\/h1>/);

it("fallback to closest index toward root");

response = await request(app).get("/test.txt");
expect(response.text).toBe("Hello from test.txt");

Expand Down Expand Up @@ -209,6 +251,24 @@ test("Express app with transformer function", async (done) => {

it("html is transformed correctly");

response = await request(app).get("/subpath/");
expect(response.text).toMatch(/<h1>subpath<\/h1>/);
response = await request(app).get("/subpath/route");
expect(response.text).toMatch(/<h1>subpath<\/h1>/);

it("subpath html is served correctly");

expect(response.text).toMatch(/<meta name="test"\/>/);

it("subpath html is transformed correctly");

response = await request(app).get("/some/path/route");
expect(response.text).toMatch(/<h1>index<\/h1>/);
response = await request(app).get("/subpath/to/some/route");
expect(response.text).toMatch(/<h1>subpath<\/h1>/);

it("fallback to closest index toward root");

response = await request(app).get("/test.txt");
expect(response.text).toBe("Hello from test.txt");

Expand Down Expand Up @@ -236,6 +296,20 @@ test("Express app with ignored paths", async (done) => {

it("html is served correctly");

response = await request(app).get("/subpath/");
expect(response.text).toMatch(/<h1>subpath<\/h1>/);
response = await request(app).get("/subpath/route");
expect(response.text).toMatch(/<h1>subpath<\/h1>/);

it("subpath html is served correctly");

response = await request(app).get("/some/path/route");
expect(response.text).toMatch(/<h1>index<\/h1>/);
response = await request(app).get("/subpath/to/some/route");
expect(response.text).toMatch(/<h1>subpath<\/h1>/);

it("fallback to closest index toward root");

response = await request(app).get("/ignored");
expect(response.text).toMatch(/Cannot GET \/ignored/);

Expand All @@ -262,4 +336,32 @@ test("Express app with ignored paths", async (done) => {
});
});

test("Express with no index at root", async (done) => {
const app = express();

process.chdir(path.join(__dirname, "noIndexEnv"));

const server = ViteExpress.listen(app, 3000, async () => {
// default middleware fallback will respond with 404
let response = await request(app).get("/");
expect(response.status).toBe(404);
response = await request(app).get("/route");
expect(response.status).toBe(404);
response = await request(app).get("/some/path/route");
expect(response.status).toBe(404);

it("fallback with next middleware if no index found");

response = await request(app).get("/subpath/route");
expect(response.text).toMatch(/<h1>subpath<\/h1>/);

it("html is served correctly");

server.close(() => {
process.chdir(baseDir);
done();
});
});
});

run();