singlePageApp function
Serves one file for every document request, for a single-page application.
A client-side router owns the path, so the server answers the same document whatever the browser asks for. Register it as a fallback, after the routes that should still win:
final app = Router()
..mount('/api', apiRoutes)
..fallback(singlePageApp('web/index.html'));
This answers one file and nothing else. For a whole build directory, which
is the usual case, use staticFiles(directory, html: true) instead — it
serves the assets beside the document and gets the cache policy right.
Only GET and HEAD are answered. A POST to a path nothing matched is a
wrong request, not a page view, and handing it an HTML document would hide
that.
Implementation
Handler singlePageApp(String file) {
final url = file.split('/').last;
final inner = shelf_static.createFileHandler(file, url: url);
return (Request request) {
if (request.method != 'GET' && request.method != 'HEAD') {
return Response.notFound('no route for /${request.url.path}');
}
// `createFileHandler` only answers at the file's own URL, so the request is
// pointed at it; the client-side route stays in the browser's address bar.
return inner(
Request(
request.method,
request.requestedUri.replace(path: '/$url'),
headers: request.headers,
context: request.context,
),
);
};
}