=head1 NAME

Mojolicious::Plugin::AssetPack::Guides::Cookbook - AssetPack recipes

=head1 OVERVIEW

This guide will provide recipes for cooking with
L<Mojolicious::Plugin::AssetPack>.

=head1 ASSETS FROM CUSTOM DOMAIN

You might want to serve the assets from a domain different from where the main
app is running. The reasons for that might be:

=over 2

=item *

No cookies send on each request. This is especially useful when you use
L<Mojolicious> sessions as they are stored in cookies and clients send whole
session with every request.

=item *

More requests done in parallel. Browsers have limits for sending parallel
request to one domain. With separate domain static files can be loaded in
parallel.

=item *

Serve files directly (by absolute url) from CDN (or Amazon S3).

=back

=head2 Synopsis

You need to customize L<Mojolicious::Plugin::AssetPack/route> to accomplish
this:

  $app->asset->route->to(base_url => "http://cdn.example.com/my-assets/");

=head2 Caveat

Many recent browsers blocks mixed content, meaning if your HTML is served over
HTTPS, then you can't serve the assets over HTTP. One way to fix this is by
using "//" instead of a scheme specific URL. Example:

  base_url => "//cdn.example.com/my-assets/"

This will tell the browser to use the same scheme for fetching assets, as it
did fetching the web page.

=head2 See also

L<https://developers.google.com/speed/docs/best-practices/request#ServeFromCookielessDomain>.

=head1 DYNAMIC ASSETS

Any L<web|Mojolicious::Plugin::AssetPack::Guides::Tutorial/Web> asset with the
hostname "local" will be routed to the current L<Mojolicious> application.
Example:

  $ cat assetpack.def
  ! app.js
  < http://local/some/resource.js

The above URL will make AssetPack issue a request to the current Mojolicious
application, allowing it to render dynamic JavaScript. Example Mojolicious
resource:

  get "/some/resource" => [format => "js"], sub {
    my $c = shift;
    $c->render(text => sprintf "rand = %s\n", rand);
  };

=head2 Sass

Sass files can also be generated dynamically. Here is an example Sass file:

  @import "http://local/sass/dynamic";
  $color: red !default;
  body { color: $color; }

Normally, the C<@import> statement would be left untouched, but AssetPack will
(in the special case where the host is "local") inline the result from that
resource. This allow C<$color> to be set from the application and override the
default C<$color> in the file above. Example:

  get "/sass/_dynamic" => [format => "scss"], sub {
    my $c = shift;
    $c->render(text => "\$color: black;\n");
  };

Note that this feature is EXPERIMENTAL and not compatible with standard Sass
rules.

=head1 ONLINE ASSETS

Instead of making custom AssetPack plugins, it is possible to simply include
projects such as Bootstrap, FontAwesome or jQuery directly from the web
instead.

=head2 Bootstrap

The SASS version of L<http://getbootstrap.com> can easily be included by defining it
in the L<assetspack.def|Mojolicious::Plugin::AssetPack::Guides::Tutorial/Defining assets in a definition file>
file:

  $ cat - > assets/assetpack.def
  ! app.css
  < https://github.com/twbs/bootstrap-sass/raw/master/assets/stylesheets/_bootstrap.scss

After that, you might want to customize bootstrap. This can then be done by changing
"assetpack.def" to:

  ! app.css
  << https://github.com/twbs/bootstrap-sass/raw/master/assets/stylesheets/_bootstrap.scss
  < sass/main.scss

"assets/sass/main.scss" should then have a modified version of
L<https://github.com/twbs/bootstrap-sass/raw/master/assets/stylesheets/_bootstrap.scss>:

  @import "variables.scss";
  @import "../cache/github.com/twbs/bootstrap-sass/raw/master/assets/stylesheets/bootstrap/mixins";
  @import "../cache/github.com/twbs/bootstrap-sass/raw/master/assets/stylesheets/bootstrap/normalize";
  @import "../cache/github.com/twbs/bootstrap-sass/raw/master/assets/stylesheets/bootstrap/print";
  ...

The file "_variables.scss" should also be copied to "assets/sass".

(Note that the rest of the example file above is truncated)

=head2 Font awesome

L<https://fortawesome.github.io/Font-Awesome/> can be included with the snippet
below:

  $app->asset->process(
    "app.css" => (
      "https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css",
    )
  );

See also L<Mojolicious::Plugin::AssetPack::Pipe::Fetch> for information about
automatically fetching related font files.

=head2 Google fonts

L<https://www.google.com/fonts> can be included with this snippet:

  $app->asset->process(
    "app.css" => (
      "https://fonts.googleapis.com/css?family=Roboto:400,700",
      "your-app.css",
    )
  );

=head2 JavaScript polyfills

L<https://github.com/Modernizr/Modernizr> contains a list of many shims which
can be included. Here is just one example:

  $app->asset->process(
    "app.js" => (
      "http://cdnjs.cloudflare.com/ajax/libs/es5-shim/2.3.0/es5-shim.js",
      "http://cdnjs.cloudflare.com/ajax/libs/es5-shim/2.3.0/es5-sham.js",
      "your-app.js",
    )
  );

=head2 jQuery

L<http://jquery.com> can easily be included by refering to a CDN:

  $app->asset->process(
    "app.js" => (
      "http://code.jquery.com/jquery-1.12.0.js",
      "your-app.js",
    )
  );

=head2 Materialize CSS

L<http://materializecss.com/> can be included by defining it
in the L<assetspack.def|Mojolicious::Plugin::AssetPack::Guides::Tutorial/Defining assets in a definition file>
file. L<Mojolicious::Plugin::AssetPack::Pipe::Sass> will also discover all
the "@import" files and download those recusively as well.

  $ cat - > assets/assetpack.def
  ! app.css
  < https://raw.githubusercontent.com/Dogfalo/materialize/master/sass/materialize.scss
  < https://fonts.googleapis.com/icon?family=Material+Icons

After that, you might want to customize Materialize. This can then be done by changing
"assetpack.def" to:

  ! app.css
  << https://raw.githubusercontent.com/Dogfalo/materialize/master/sass/materialize.scss
  < https://fonts.googleapis.com/icon?family=Material+Icons
  < sass/main.scss

"assets/sass/main.scss" should then have a modified version of
L<https://raw.githubusercontent.com/Dogfalo/materialize/master/sass/materialize.scss>:

  @charset "UTF-8";
  @import "../cache/raw.githubusercontent.com/Dogfalo/materialize/master/sass/components/prefixer";
  @import "../cache/raw.githubusercontent.com/Dogfalo/materialize/master/sass/components/mixins";
  @import "../cache/raw.githubusercontent.com/Dogfalo/materialize/master/sass/components/color";
  @import "variables.scss";
  ...

The file "_variables.scss" should also be copied to "assets/sass".

(Note that the rest of the example file above is truncated)

=head1 BUILDING PRODUCTION ASSETS

To be sure that production assets are alwasy built, you can add a unit test
like the one below:

  use Test::Mojo;
  use Test::More;

  $ENV{MOJO_MODE} = "production";
  my $t = Test::Mojo->new("MyApp");

  $t->get_ok("/")
    ->element_exists(q(head link[href$="/app.css"]))
    ->element_exists(q(body script[src$="/app.js"]));

  done_testing;

The C<element_exists()> tests should match the topics defined when defining the
different assets.

=head1 SEE ALSO

L<Mojolicious::Plugin::AssetPack> and
L<Mojolicious::Plugin::AssetPack::Guides::Tutorial>.

=cut
