Angel is a full-featured, full-stack, server-side framework for Dart language that has been in version 1 since early 2017. One of its main goals is to provide a wide range of functionality out-of-the-box. Thus, Angel ships a static file serving plug-in, which has been present since the project’s inception. package:angel_static is customizable, supports browser caching, and cooperates well with push-state routing.

The Basics

To serve files out of a directory on your filesystem, simply use the bundled VirtualDirectory API:

configureServer(Angel app) async {

await app.configure(new VirtualDirectory());

}

By default, a VirtualDirectory adds a file’s contents to a response buffer, which plays well with the compression functionality exposed by package:angel_compress :

// Serve compressed files out of a directory!!!

configureServer(Angel app) async {

await app.configure(new VirtualDirectory()); // Add GZIP compression to `responseFinalizers`, so that it

// runs *after* every request:

app.responseFinalizers.add(gzip());

}

With the default arguments, VirtualDirectory will assume you are serving a Dart project and guess which directory to serve files out of. If ANGEL_ENV is set to production in your environment, then it will default to a folder at the path build/web . If not, then it serves out of web . The benefit here is that you can serve development assets at development time, and when running in production, serve optimized assets (built with pub build ) without any further application configuration.

Of course, if you are serving from a different directory, you can just provide a source argument:

new VirtualDirectory(source: new Directory('<path>');

Browser Caching Support

Cache-Control headers are used to tell browsers how to cache static assets, and shrink page load time on return visits to your website. To achieve this with package:angel_static , all you have to do is replace VirtualDirectory with CachingVirtualDirectory :

new CachingVirtualDirectory(same args...);

If you were looking to cache responses server-side as well, look into cacheResponses , exported by package:angel_multiserver :

configureServer(Angel app) async {

await app.configure(new CachingVirtualDirectory(...));



// Cache static assets server-side

var rgxStatic = new RegExp(r'\.(html|js|jpg|png)$');

await app.configure(cacheResponses(filters: [rgxStatic]));

}

Supporting Push-State Routing

You’re in luck if you use Angel as the backend for a single-page application. Even if the static server plug-in automatically chose your web root for you, you can still access it via the source property and find a fallback page to serve users of a push-state-enabled application:

configureServer(Angel app) async {

var vDir = new CachingVirtualDirectory();

await app.configure(vDir); var indexPage = new File.fromUri(vDir.source.uri.resolve('index.html'));



// Serve index.html instead of 404 page...

app.after.add((req, res) => res.sendFile(indexPage);

}

Advanced Options

Both VirtualDirectory and CachingVirtualDirectory support a number of additional options in their constructors, including the following three, which are most commonly used:

Virtual Root

In many cases, you’ll want to mount the static server on a different path. For example, if a user visits assets/photos/logo.png , you might want to serve web/photos/logo.png . In this case, your static server should be mounted at /assets , instead of at / .

To handle this relatively common use case, use the publicPath parameter:

new VirtualDirectory(publicPath: '/assets');

Index File Resolution

By default, if a user requests the root of a directory, package:angel_static will attempt to serve an index.html file within that directory, and throw a 404 if it is not found. Use the indexFileNames parameter to override this:

new VirtualDirectory(indexFileNames: ['index.txt', 'index.php']);

Streaming Responses and File Callbacks

As mentioned above, a VirtualDirectory writes the contents of served files to the response buffer. This is perfectly fine for most scenarios, but for large files, you might often run into this error:

Unhandled exception:

HttpException: Headers size exceeded the of '8192' bytes

Combat this by forcing package:angel_static to stream files to the response, instead of buffering all the contents at once:

new VirtualDirectory(streamToIO: true);

Streaming files to IO will skip any responseFinalizers wired to your application, which means that it won’t work with package:angel_compress . However, if streamToIO is true , then all files will be automatically compressed via GZIP .

Conclusion

With its extended support for static files, Angel is definitely a strong choice for your next server-side or full-stack project. Don’t be followed, however — there’s so much more to the framework than just package:angel_static . Go ahead and explore it for yourself. Feedback is greatly appreciated!

Angel Wiki

API Documentation

Chat on Gitter!