
=head1 NAME

Mojolicious::Plugin::AssetPack::Guides::Tutorial - AssetPack tutorial

=head1 OVERVIEW

This guide will give detailed information about how to define assets and
include them into your templates.

See L<Mojolicious::Plugin::AssetPack/DESCRIPTION> for a short description of
AssetPack.

=head1 GUIDE

=head2 Loading the plugin

The plugin needs to be installed an loaded before any assets can be defined:

  $app->plugin(AssetPack => \%args);

Details about C<%args> can be found under
L<Mojolicious::Plugin::AssetPack/register>, but there is one mandatory
argument worth noting: "pipes". "pipes" need to be a list of all the pipes
you need to process your assets. Example:

  $app->plugin(AssetPack => {pipes => [qw(Sass Css Combine)]});

Loading the plugin with the list above will enable AssetPack to process Sass
and Css files, minify them and combine them into a single asset in production.

=head2 Optional dependencies

AssetPack has only optional dependencies. The reason for that is that the
dependencies should only be required while developing, and not for running
the application. See L<https://github.com/jhthorsen/mojolicious-plugin-assetpack/blob/v2/cpanfile>
for a complete list, but here are the current list:

=over 2

=item * L<CSS::Minifier::XS> 0.09

Used to minify CSS.

=item * L<CSS::Sass> 3.3.0

Used to process and minify CSS.

=item * L<Imager::File::PNG> 0.90

TODO: Used to generate CSS sprites.

=item * L<JavaScript::Minifier::XS> 0.11

Used to minify JavaScript.

=back

=head2 Pipes

AssetPack does not do any heavy lifting itself: All the processing is left to
the L<pipe objects|Mojolicious::Plugin::AssetPack::Pipe>.

=over 2

=item * L<Mojolicious::Plugin::AssetPack::Pipe::CoffeeScript>

Process CoffeeScript coffee files. Should be loaded before
L<Mojolicious::Plugin::AssetPack::Pipe::JavaScript>.

=item * L<Mojolicious::Plugin::AssetPack::Pipe::Combine>

Combine multiple assets to one. Should be loaded last.

=item * L<Mojolicious::Plugin::AssetPack::Pipe::Css>

Minify CSS.

=item * L<Mojolicious::Plugin::AssetPack::Pipe::Favicon>

There is a special topic called "favicon.ico", combined with the
L<Mojolicious::Plugin::AssetPack::Pipe::Favicon> pipe which can be used to
describe favicons, touch icons and tile icons.

=item * L<Mojolicious::Plugin::AssetPack::Pipe::Fetch>

Will look for "url(...)" in CSS files and download the related assets.

=item * L<Mojolicious::Plugin::AssetPack::Pipe::JavaScript>

Minify JavaScript.

=item * L<Mojolicious::Plugin::AssetPack::Pipe::Jpeg>

Used to crush "jpeg" image files.

=item * L<Mojolicious::Plugin::AssetPack::Pipe::Less>

Process Less CSS files. Should be loaded before
L<Mojolicious::Plugin::AssetPack::Pipe::Css>.

=item * L<Mojolicious::Plugin::AssetPack::Pipe::Png>

Used to crush "png" image files.

=item * L<Mojolicious::Plugin::AssetPack::Pipe::Riotjs>

Process L<http://riotjs.com/> tag files. Should be loaded before
L<Mojolicious::Plugin::AssetPack::Pipe::JavaScript>.

=item * L<Mojolicious::Plugin::AssetPack::Pipe::Sass>

Process sass and scss files. Should be loaded before
L<Mojolicious::Plugin::AssetPack::Pipe::Css>.

=back

=head2 Where to place source files

The source/input files that make up a virtual asset (topic) can come from
either...

=head3 On disk

AssetPack will look for source files in the "assets" directory, relative to the
application L<home|Mojo/home>. Unlike the "public" directory, this directory is
not shared on the internet, but the generated assets will still be available
thanks to a custom L<route|Mojolicious::Plugin::AssetPack/route>.

L<Mojolicious::Plugin::AssetPack::Store> is a sub class of
L<Mojolicious::Static>, allowing it to find files relative to
L<Mojolicious::Static/paths>. For example, to change asset search paths, you
can do:

    $app->asset->store->paths(["/some/new/location", "/other/location"]);

=head3 DATA section

L<Mojolicious::Plugin::AssetPack::Store> is a sub class of
L<Mojolicious::Static>, allowing it to look for files in DATA sections of
L<Mojolicious::Static/classes>.

The DATA section can also be used to lookup "@import" files. (Currently only
supported by L<Mojolicious::Plugin::AssetPack::Pipe::Sass>)

=head3 Web

Any file starting with "http" or "https" will be downloaded from web using
L<Mojolicious::Plugin::AssetPack/ua>.

It will also parse recursively "@import" files and download those as well.
(Currently only supported by L<Mojolicious::Plugin::AssetPack::Pipe::Sass>)

Assets from web will be cached locally to prevent downloading new and untested
assets on each application startup.

=head3 Current Mojolicious application

See L<Mojolicious::Plugin::Assets::Guides::Cookbook/DYNAMIC ASSETS>.

=head2 Process assets

Assets should be defined when you application starts. This can either be done
using a L<definition file|Mojolicious::Plugin::AssetPack/process> or inside you
application.

=head3 Defining assets in the application

Assets can be defined using the L<Mojolicious::Plugin::AssetPack/process>
method:

  $app->asset->process(
    "app.css" => (
      "sass/bar.scss",
      "foo/bar.css",
      "https://github.com/Dogfalo/materialize/blob/master/sass/materialize.scss",
    )
  );

In the example above we have defined a topic named "app.css" which
later can be included in L<templates|/Using assets>. The list of files
following are the source files which will make up the final asset.

=head3 Defining assets in a definition file

Moving the definition to an external file can be useful for keeping the
application code tidy. The definition file should be located in the
L<assets|Mojolicious::Plugin::AssetPack::Store/paths> directory, or optionally
defined it in the "DATA" section. The default file is called
"assetpack.def" and will be looked up if
L<Mojolicious::Plugin::AssetPack/process> is called without arguments. Example
file:

  ! app.css
  < sass/bar.scss
  << https://github.com/Dogfalo/materialize/blob/master/sass/materialize.scss
  < sass/main.scss

Empty lines and lines starting with "#" will be skipped. Each line starting
with "!" will be used to define a topic (virtual asset name), and "E<lt>" will
define a source file. This means that the file above will result in (almost)
the same as in the L<example above|/Defining assets in the application>.

The idea of the line starting with "<<" is to download an external (remote)
file for your convenience, which can be imported in your SASS/LESS files. The
downloaded file is not included in the output asset. For example, you have
"sass/main.scss" which depends on "materialize.scss" (remote file) and you need
this "materialize.scss" file locally available to be imported in
"sass/main.scss".  If you want to include a remote file in your output asset,
use '<' insteaf of '<<'.

It is also possible to add conditions:

  ! app.css
  < development.css [mode==development] [minify==0]
  < production.css  [mode!=development]

"development.css" will be processed if L<Mojolicious/mode> is "development" and
L<Mojolicious::Plugin::AssetPack/minify> is "0". "production.css" will be
processed if L<Mojolicious/mode> is something else than "development". This is
especially useful if you want to include a JavaScript with debug flags set
while developing, but switch to a smaller version without debug in production.

=head2 Using assets

Any processed asset can be accessed by referring to a topic.

=head3 Template

An asset can be included in a template using the
L<Mojolicious::Plugin::AssetPack/asset> helper:

  <head>
    %= asset "app.css"
    %= asset "app.js"
  </head>

The L<Mojolicious::Plugin::AssetPack/asset> helper takes additional arguments
which will be passed on directly to either the
L<Mojolicious::Plugin::TagHelpers/javascript> helper or
L<Mojolicious::Plugin::TagHelpers/stylesheet> helper. Example:

    %= asset "app.css", media => "print"

In production mode, the helper above will just result in one "link" tag. On the
other hand, if you are in "development" mode, it will result in on "link" tag
per source asset.

=head3 Asset objects

It is also possible to retrieve the processed asset objects. The example
below will retrieve a L<Mojo::Collection> object holding zero or more
L<Mojolicious::Plugin::AssetPack::Asset> objects:

  my $collection = $app->asset->processed("app.css");
  print $collection->map("checksum")->join(", ");

This can also be used to inline assets in a template:

  %= stylesheet sub { asset->processed('app.css')->map('content')->join }

=head2 Application mode

The application L<mode|Mojolicious/mode> will define if the assets should be
combined and minified. The L<Mojolicious::Plugin::AssetPack/minify> attribute
can also be set manually if you have special needs.

=head3 Development

The assets will be processed, but not minified/combined if L<MOJO_MODE> or
L<Mojolicious/mode> is set to "development". This is to make it easier to
map JavaScript or CSS bugs to a specific file and line. "development" is
the default mode while running L<morbo|Mojo::Server::Morbo>:

  $ morbo -w assets/ -w lib/ -w templates/ script/myapp

=head3 Any other mode

Any "production" mode will result in one combined and minified asset. This will
save bandwidth and roundtrip time to the server.

=head2 Caching

Processed assets will be cached to disk when possible. The process step is run
so if such a processed asset exists, the process step will not be run again.
Again, the external tools (less, coffee, ...) and modules
(L<JavaScript::Minifier::XS>, L<CSS::Sass>) will only be required while
developing, but can be skipped when installing an already built application.

=head2 Assets without topics

One nifty feature is to use L<Mojolicious::Plugin::AssetPack> for assets which
do not have any pipe to process them. The reason why this comes in handy is to
avoid cache issues, since changing the file on disk will generate a new URL.

These assets can also be defined directly in the templates, without having to
be defined in the application startup process. Examples:

  # <img src="/asset/52e98718f0/foo.gif">
  %= asset "/image/foo.gif"

  # <img src="/asset/87652910af/baz.svg">
  %= asset "/image/baz.svg"

  # <link rel="icon" href="/asset/65428718f1/bar.ico">
  %= asset "/image/bar.ico"

  # <source src="/asset/87652718f0/baz.mp3" type="audio/mpeg">
  %= asset "/audio/baz.mp3"

  # <source src="/asset/52e87652f0/foo.mp4" type="video/mp4">
  %= asset "/video/foo.mp4"

  # <source src="/asset/52eaz7613a/bar.ogg" type="audio/ogg">
  %= asset "/audio/bar.ogg"

  # <source src="/asset/baf72618f1/foo.ogv" type="audio/ogv">
  %= asset "/video/foo.ogv"

  # <source src="/asset/92118711f0/bar.webm" type="audio/webm">
  %= asset "/video/bar.webm"

=head1 SEE ALSO

L<Mojolicious::Plugin::AssetPack>,
L<Mojolicious::Plugin::AssetPack::Guides::Developing> and
L<Mojolicious::Plugin::AssetPack::Guides::Cookbook>.

=cut
