diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..66bca2d4 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,2 @@ +# 1.0.0 +* Initial release. \ No newline at end of file diff --git a/README.md b/README.md index 09970539..4c365cc7 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,45 @@ # seo -Helpers for building SEO-friendly Web pages in Angel. +Helpers for building SEO-friendly Web pages in Angel. The goal of +`package:angel_seo` is to speed up perceived client page loads, prevent +the infamous +[flash of unstyled content](https://en.wikipedia.org/wiki/Flash_of_unstyled_content), +and other SEO optimizations that can easily become tedious to perform by hand. + +## `inlineAssets` +This function is a simple one; it wraps a `VirtualDirectory` to patch the way it sends +`.html` files. + +In any `.html` file sent down, `link` and `script` elements that point to internal resources +will have the contents of said file read, and inlined into the HTML page itself. + +In this case, "internal resources" refers to a URI *without* a scheme, i.e. `/site.css` or +`foo/bar/baz.js`. + +```dart +import 'package:angel_framework/angel_framework.dart'; +import 'package:angel_seo/angel_seo.dart'; +import 'package:angel_static/angel_static.dart'; +import 'package:file/local.dart'; + +main() async { + var app = new Angel()..lazyParseBodies = true; + var fs = const LocalFileSystem(); + var http = new AngelHttp(app); + + var vDir = inlineAssets( + new VirtualDirectory( + app, + fs, + source: fs.directory('web'), + ), + ); + + app.use(vDir.handleRequest); + + app.use(() => throw new AngelHttpException.notFound()); + + var server = await http.startServer('127.0.0.1', 3000); + print('Listening at http://${server.address.address}:${server.port}'); +} + +``` \ No newline at end of file diff --git a/analysis_options.yaml b/analysis_options.yaml new file mode 100644 index 00000000..0ac20d6b --- /dev/null +++ b/analysis_options.yaml @@ -0,0 +1,3 @@ +analyzer: + strong-mode: + implicit-cast: false \ No newline at end of file diff --git a/example/main.dart b/example/main.dart new file mode 100644 index 00000000..8d7d82d1 --- /dev/null +++ b/example/main.dart @@ -0,0 +1,25 @@ +import 'package:angel_framework/angel_framework.dart'; +import 'package:angel_seo/angel_seo.dart'; +import 'package:angel_static/angel_static.dart'; +import 'package:file/local.dart'; + +main() async { + var app = new Angel()..lazyParseBodies = true; + var fs = const LocalFileSystem(); + var http = new AngelHttp(app); + + var vDir = inlineAssets( + new VirtualDirectory( + app, + fs, + source: fs.directory('web'), + ), + ); + + app.use(vDir.handleRequest); + + app.use(() => throw new AngelHttpException.notFound()); + + var server = await http.startServer('127.0.0.1', 3000); + print('Listening at http://${server.address.address}:${server.port}'); +} diff --git a/example/web/index.html b/example/web/index.html new file mode 100644 index 00000000..50161197 --- /dev/null +++ b/example/web/index.html @@ -0,0 +1,18 @@ + + +
+ + + + + + + +Embrace the power of inlined styles, etc.
+ + \ No newline at end of file diff --git a/example/web/not-inlined.css b/example/web/not-inlined.css new file mode 100644 index 00000000..ab2a12a3 --- /dev/null +++ b/example/web/not-inlined.css @@ -0,0 +1,3 @@ +p { + font-style: italic; +} \ No newline at end of file diff --git a/example/web/not-inlined.js b/example/web/not-inlined.js new file mode 100644 index 00000000..6a8ad492 --- /dev/null +++ b/example/web/not-inlined.js @@ -0,0 +1,3 @@ +window.addEventListener('load', function() { + console.log('THIS message was not from an inlined file.'); +}); \ No newline at end of file diff --git a/example/web/site.css b/example/web/site.css new file mode 100644 index 00000000..acbbda4b --- /dev/null +++ b/example/web/site.css @@ -0,0 +1,3 @@ +h1 { + color: pink; +} \ No newline at end of file diff --git a/example/web/site.js b/example/web/site.js new file mode 100644 index 00000000..283b1eff --- /dev/null +++ b/example/web/site.js @@ -0,0 +1,3 @@ +window.addEventListener('load', function() { + console.log('Hello, inline world!'); +}); \ No newline at end of file diff --git a/lib/angel_seo.dart b/lib/angel_seo.dart new file mode 100644 index 00000000..8288ada9 --- /dev/null +++ b/lib/angel_seo.dart @@ -0,0 +1 @@ +export 'src/inline_assets.dart'; \ No newline at end of file diff --git a/lib/src/inline_assets.dart b/lib/src/inline_assets.dart new file mode 100644 index 00000000..2e33b36f --- /dev/null +++ b/lib/src/inline_assets.dart @@ -0,0 +1,81 @@ +import 'dart:async'; +import 'package:angel_framework/angel_framework.dart'; +import 'package:angel_static/angel_static.dart'; +import 'package:dart2_constant/convert.dart'; +import 'package:file/file.dart'; +import 'package:html/dom.dart' as html; +import 'package:html/parser.dart' as html; +import 'package:path/path.dart' as p; + +VirtualDirectory inlineAssets(VirtualDirectory vDir) => new _InlineAssets(vDir); + +class _InlineAssets extends VirtualDirectory { + final VirtualDirectory inner; + + _InlineAssets(this.inner) + : super(inner.app, inner.fileSystem, + source: inner.source, + indexFileNames: inner.indexFileNames, + publicPath: inner.publicPath, + callback: inner.callback, + allowDirectoryListing: inner.allowDirectoryListing); + + @override + Future