Skip to content

Commit

Permalink
Serve HTML static files on explicit ".html" requests (#110)
Browse files Browse the repository at this point in the history
* Remove staticFilePath check

Removing staticFilePath check, as vite.middlewares are now mounted before the injectViteIndexMiddleware function. This adjustment is made because the staticFilePath check doesn't provide any additional benefits, aside from blocking requests like /index.html on the development server.

* Serve */index.html using IndexMiddlewares

Allowing requests for html files to be transformable. This is achieved by skipping files with .htm or .html in the Static Middleware, allowing them to be handled by the IndexMiddlewares.

* Correction

* Return closest index file if no html file found

Previously, my implementation involved checking if a file ended with the html extension and then verifying its existence. If the file didn't exist, it would trigger next(), eventually resulting in a 404 error. However, I now realize that this approach does not align with the current methodology. The updated approach is to return the closest index file if the requested file does not exist.

* Adding Tests

These tests will ensure serving and transformation of .html and .htm files when request explicitly includes filenames.

* Use only .html files

* Using endsWith instead of match

* Using meaningful variable/function names
  • Loading branch information
rmhaiderali authored Jan 21, 2024
1 parent c9268ce commit 1dd4603
Show file tree
Hide file tree
Showing 5 changed files with 67 additions and 36 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Contributors: [@elturpin](https://github.com/elturpin), [@patreeceeo](https://gi

## 0.11.1 (2023-11-17)

- Mount middlewares that serve HTML at `config.root` instead of `/` ([#91](https://github.com/szymmis/vite-express/pull/91))
- Mount middlewares that serve HTML at `config.base` instead of `/` ([#91](https://github.com/szymmis/vite-express/pull/91))

Contributors: [@rmhaiderali](https://github.com/rmhaiderali)

Expand Down
69 changes: 34 additions & 35 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,6 @@ function info(msg: string) {
);
}

function isStaticFilePath(path: string) {
return path.match(/(\.\w+$)|@vite|@id|@react-refresh/);
}

async function getTransformedHTML(html: string, req: express.Request) {
return Config.transformer ? Config.transformer(html, req) : html;
}
Expand Down Expand Up @@ -108,9 +104,7 @@ async function resolveConfig(): Promise<ViteConfig> {
),
);
}
} catch (e) {
1;
}
} catch (e) {}

try {
const config = fs.readFileSync(getViteConfigPath(), "utf8");
Expand Down Expand Up @@ -176,7 +170,10 @@ async function injectStaticMiddleware(
middleware: RequestHandler,
) {
const config = await getViteConfig();
app.use(config.base, middleware);

app.use(config.base, (req, res, next) =>
req.path.endsWith(".html") ? next() : middleware(req, res, next),
);

const stubMiddlewareLayer = app._router.stack.find(
(layer: { handle?: RequestHandler }) => layer.handle === stubMiddleware,
Expand All @@ -198,24 +195,29 @@ function isIgnoredPath(path: string, req: express.Request) {
: Config.ignorePaths(path, req);
}

function findClosestIndexToRoot(
function findTemplateFilePath(
reqPath: string,
root: string,
): string | undefined {
if (reqPath.endsWith(".html")) {
const pathToTest = path.join(root, reqPath);
if (fs.existsSync(pathToTest)) return pathToTest;
}

// find closest index.html to provided path
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;
}
if (fs.existsSync(pathToTest)) return pathToTest;
dirs.pop();
}

return undefined;
}

async function injectViteIndexMiddleware(
async function injectViteHTMLMiddleware(
app: core.Express,
server: ViteDevServer,
) {
Expand All @@ -226,37 +228,34 @@ async function injectViteIndexMiddleware(

if (isIgnoredPath(req.path, req)) return next();

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

const template = fs.readFileSync(indexPath, "utf8");
let html = await server.transformIndexHtml(req.originalUrl, template);

try {
html = await getTransformedHTML(html, req);
res.send(html);
} catch (e) {
console.error(e);
res.status(500);
return next();
}
const templateFilePath = findTemplateFilePath(req.path, config.root);
if (templateFilePath === undefined) return next();

const template = fs.readFileSync(templateFilePath, "utf8");
let html = await server.transformIndexHtml(req.originalUrl, template);

try {
html = await getTransformedHTML(html, req);
res.send(html);
} catch (e) {
console.error(e);
res.status(500);
return next();
}
});
}

async function injectIndexMiddleware(app: core.Express) {
async function injectHTMLMiddleware(app: core.Express) {
const distPath = await getDistPath();
const config = await getViteConfig();

app.use(config.base, async (req, res, next) => {
if (isIgnoredPath(req.path, req)) return next();

const indexPath = findClosestIndexToRoot(req.path, distPath);
if (indexPath === undefined) return next();
const templateFilePath = findTemplateFilePath(req.path, distPath);
if (templateFilePath === undefined) return next();

let html = fs.readFileSync(indexPath, "utf8");
let html = fs.readFileSync(templateFilePath, "utf8");

try {
html = await getTransformedHTML(html, req);
Expand Down Expand Up @@ -315,10 +314,10 @@ async function bind(
if (Config.mode === "development") {
const vite = await startServer(server);
await injectStaticMiddleware(app, vite.middlewares);
await injectViteIndexMiddleware(app, vite);
await injectViteHTMLMiddleware(app, vite);
} else {
await injectStaticMiddleware(app, await serveStatic());
await injectIndexMiddleware(app);
await injectHTMLMiddleware(app);
}

callback?.();
Expand Down
12 changes: 12 additions & 0 deletions tests/env/dist/main.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>main</h1>
</body>
</html>
12 changes: 12 additions & 0 deletions tests/env/main.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>main</h1>
</body>
</html>
8 changes: 8 additions & 0 deletions tests/server.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ test("Express app", async (done) => {
expect(response.text).toMatch(/<h1>index<\/h1>/);
response = await request(app).get("/route");
expect(response.text).toMatch(/<h1>index<\/h1>/);
response = await request(app).get("/index.html");
expect(response.text).toMatch(/<h1>index<\/h1>/);
response = await request(app).get("/main.html");
expect(response.text).toMatch(/<h1>main<\/h1>/);

it("html is served correctly");

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

it("html is served correctly");

expect(response.text).toMatch(/<meta name="test"\/>/);
response = await request(app).get("/index.html");
expect(response.text).toMatch(/<meta name="test"\/>/);
response = await request(app).get("/main.html");
expect(response.text).toMatch(/<meta name="test"\/>/);

it("html is transformed correctly");
Expand Down

0 comments on commit 1dd4603

Please sign in to comment.