How to serve "static" files? #157
Comments
var html = new File("web/index.html").readAsStringSync();
return new Response.ok(html)..contentType = ContentType.HTML; |
I'm sure you also can forward requests to certain routes to https://pub.dartlang.org/packages/shelf_static |
Not so fast @joeconwaystk 😸 Based on the two lines from your reply, I made something more generic: import 'package:path/path.dart' as path;
import 'dart:io' as io;
import 'package:mime/mime.dart' as mime;
class StaticFilesController extends HTTPController {
final String basePath;
final String defaultFile;
StaticFilesController({this.basePath: "build/web", this.defaultFile: "index.html"});
// Initially based on https://github.com/stablekernel/aqueduct/issues/157
@httpGet getFile() async {
String realPath = request.path.remainingPath;
if (realPath.length == 0) {
realPath = defaultFile;
}
String filePath = path.join(basePath, realPath);
io.File file = new io.File(filePath);
var fileContents = file.readAsStringSync();
String contentType = mime.lookupMimeType(filePath);
return new Response.ok(fileContents)
..contentType = io.ContentType.parse(contentType);
}
} I'm sending a complete AngularDart app, so just The problem is one of scalability: I don't have images, fonts, etc. in this app for now, but I don't want to have to keep adding encoders as I go. Would it be possible to add a Maybe it also makes sense to include this controller in the framework? This is a rather generic thing, not application-specific. What's your take on this? Thanks, Clément |
@woopla That's a good looking piece of code. I'll reopen this because the real issue sounds like the out of the box behavior for Encoders is cumbersome. I think there can be some more intelligent behavior there. I'm just not sure what it is yet. The default behavior for the underlying HttpResponse object may work, and the encoder should just drop the toString and it's up to the developer to make sure the type they're passing works. w.r.t to adding the static file controller, there's three things to consider. First, there are more ways to store an HTML asset than on the filesystem (e.g. a Redis instance). So, the controller would have to be decoupled from the storage of the assets. Then, it'd likely someone would want to post-process the HTML asset (e.g., some sort of templating). So there would have to be some opportunity to do that. Finally, there would also need to be some sort of in-memory caching that the storage mechanism uses to avoid reading from disk each time; but that may be solved by the decoupling in the first point. |
@joeconwaystk there are some smarts in Shelf to handle chunked encoding (see https://github.com/dart-lang/shelf/blob/master/lib/shelf_io.dart#L137), but apart from that, it seems to rely on For the static file controller, I had not thought about this decoupling aspect. Let me try and see what I can do... Probably not before the end of the week, though. |
Since using Aqueduct + AngularDart should be a common case, a canonical HTTPController that serves static files would be a good addition to the template |
If it helps, the next template version will have the following to support authorization code flow login page: https://github.com/stablekernel/aqueduct/blob/jc/oauth/example/templates/default/lib/utility/html_template.dart |
@woopla will check those out |
So I tried the following:
// Catch-all for static files
router
.route("/*")
.generate(() => new StaticFilesController());
Response.addEncoder(io.ContentType.parse("application/javascript"), (j) => j);
Response.addEncoder(io.ContentType.parse("text/*"), (j) => j); And it doesn't work :( I'm getting arrays of bytes shown as strings in the browser. This kinda works: // Catch-all for static files
router
.route("/*")
.generate(() => new StaticFilesController());
Response.addEncoder(io.ContentType.parse("application/javascript"), (j) => UTF8.decode(j));
Response.addEncoder(io.ContentType.parse("text/*"), (j) => UTF8.decode(j));
Response.addEncoder(io.ContentType.parse("image/*"), (List<int> j) => new List<int>.from(j)); Except for the last part - binary streams are still transformed to strings further down the line (my favicon.ico is not sent as binary data). I also tried the simpler I have a (simple project)[https://github.com/woopla/angueduct] that I use to learn Dart & Angular, it contains the code mentioned here. Any ideas? I mean, without having to modify the Aqueduct code itself to remove the encoders part. Thanks, Clément |
Looks like the body is written using the standard library HttpResponse.write, which automatically does a toString and does some interpretation of the content-type and charset. HttpResponse.add is the generic version that assumes the bytes have been encoded prior to. I think there does need to be a change in the Aqueduct code, but I'd need to spend some time researching it/take some suggestions on that. |
Okay, this is now in 2.2. See the following documentation: https://aqueduct.io/docs/http/request_and_response/#response-objects-and-http-body-encoding |
Hi, router.route('/sounds/*').link(() => FileController('sounds', recursive: true)); Cheers, Chris |
Hi,
I'm trying to write a full stack Dart app, using Aqueduct on the back-end side and Angular Dart on the front-end.
Problem is, how do I serve the files intended for the client using Aqueduct? I.e. everything that's typically in the
build/web
dir (and indirectlybuild/lib
) when runningpub build
.Thanks,
Clément
The text was updated successfully, but these errors were encountered: