Assets and Transformers

The pub serve, pub build and pub run commands use transformers to prepare a package’s assets before serving the app, building the app for deployment, or executing the command-line app, as the case may be.

Use the pubspec.yaml file to specify which transformers your package uses and, if necessary, to configure the transformers. (See Specifying transformers for details.) For example:

name: myapp
dependencies:
  polymer: any
transformers:
- polymer:
    entry_points:
    - web/index.html
    - web/index2.html

A package’s assets can be in any directory in the root package. However, if you want to make an asset available publicly (to other packages, or to multiple directories within your package), it needs to be in lib.

After transformation by pub build, assets are available somewhere under build. For example, consider the following directory structure:

myapp/
  example/
    foo/
      bar.txt

When you build this example (pub build example), you end up with build/example/foo/bar.txt.

Assets generated from files in a package’s lib directory appear under a directory named packages/<pkg_name>. For details, see Where to put assets and How to refer to assets.

How transformers work

Here are some examples of transformers:

  • The dart2js transformer, which reads in all of the .dart files for a program and compiles them to a single .js file.
  • The polymer transformer, which converts HTML and Dart files into optimized HTML and Dart files.
  • A linter that reads in files and produces warnings but no actual file.

Although you specify which transformers to use, you don’t explicitly say which transformers should be applied to which assets. Instead, each transformer determines which assets it can apply itself to. For pub serve, the transformers run when the dev server starts up and whenever a source asset changes. The pub build and pub run commands run the transformers once and then exit.

As the following figure shows, source assets can pass through, untransformed, and become generated assets. Or a source asset can be transformed, such as a .dart file (along with the .dart files that it refers to) that is compiled to .js.

a figure showing source assets and generated assets; the .html, .css, and .png files pass through, untransformed; the .dart file is transformed into a .js file (and, for pub serve only, the .dart file is passed through, as well)

Dart files are a special case. The pub build command doesn’t produce .dart files because browsers in the wild don’t support Dart natively. The pub serve command, on the other hand, does generate .dart assets, because you can use Dartium while you’re developing your app.

Specifying transformers

To tell pub to apply a transformer to your package’s assets, specify the transformer, as well as the package that contains the transformer, in your package’s pubspec.yaml file. In the following pubspec, the highlighted lines specify that this package requires the polymer transformer, which is in the polymer package (along with the rest of polymer.dart):

name: myapp
dependencies:
  polymer: any
transformers:
- polymer:
    entry_points: web/index.html

The following example configures the dart2js transformer, which is used by pub serve, pub build, and pub run, to analyze the code:

transformers:
- $dart2js:
  analyzeAll: true

For more information, see Configuring the Built-in dart2js Transformer.

We expect more transformers to be available in the future. You can specify multiple transformers, to run either in parallel (if they’re independent of each other) or in separate phases. To specify that transformers run in parallel, use [transformer_1, ..., transformer_n]. If order matters, put the transformers on separate lines.

For example, consider three transformers, specified as follows:

transformers:
- [t1, t2]
- t3

The t1 and t2 transformers run first, in parallel. The t3 transformer runs in a separate phase, after t1 and t2 are finished, and can see the outputs of t1 and t2.

Pub build implicitly appends a transformer that converts your Dart code to JavaScript, so your code can run in any modern browser.

Where to put assets

An asset can be in any root-level directory of your package. However, assets located under the lib directory have additional visibilty:

  • Assets that other packages depend on need to be in lib.

  • Assets in your package that you want to access from other directories within your package need to be in your package’s lib directory.

  • Assets in lib/src are invisible to other packages.

The following picture shows how you might structure your app’s source assets, with your main Dart file under web and additional Dart files under lib.

app/
  lib/
    *.dart
    *.png
    *.html
    ...
  packages/
    pck/
      lib/
        *.dart
        *.js
  web/
    app.dart
    *.html
    *.css
    *.png
    ...

After transformation, pub build places generated assets under a directory named build. Underneath build, pub creates a directory of the same name as the root directory containing the source files. For example, for a web app (where the source files are in /web), pub creates a build/web directory.

The following is an example of a build command for a more complex package layout:

$ pub build test example/one example/two

The resulting build directory looks like:

build/
  example/
    one/
      packages/
    two/
      packages/
  test/
    packages/

The dev server simulates this hierarchy without generating files.

How to refer to assets

Here’s how source asset locations correlate to generated asset locations, for untransformed files:

Source asset location Generated asset location
(under build)
.../<your_pkg>/web/<path> /web/<path>
.../<your_pkg>/lib/<path> /packages/<pkg_name>/<path>

For example, consider a helloworld app’s HTML file, which is in the helloworld directory at web/helloworld.html. Running pub build produces a copy at build/web/helloworld.html. In the dev server, you can get the HTML file contents by using the URL http://localhost:8080/helloworld.html.

Or, perhaps you are compiling the source for a my_game web app that includes a drawing library in the lib/draw directory. If you build the web directory, the result is build/web/packages/my_game/draw/....

Transformers might change any part of <path>, especially the filename, but they can’t change the directory structure above <path>.

How to control which assets are processed

You can use $exclude to tell a transformer not to process one or more assets. You can use $include to tell a transformer to process only one or more assets. You can use glob syntax to make it easier to include, or exclude, a group of assets, including entire directories.

Excluding assets

If you have an asset that you do not want a transformer to process, you can exclude it, by name, in the pubspec. For example, a transformer named simple_transformer operates on HTML files, but you do not want it to process your lib/README.html file. You can exclude it by using the $exclude tag. The following example tells pub to run the transformer on everything it would normally process except for lib/foo.html:

transformers:
- simple_transformer:
    $exclude: "lib/foo.html"

You must provide the file’s location from the top of the package.

Processing specific assets

If you want a transformer to run only on a particular file, you can use $include. The following example tells pub to run the transformer only on lib/foo.html, assuming that foo.html is a file type that it would operate on under normal conditions:

transformers:
- simple_transformer:
    $include: "lib/foo.html"

You can’t use the include tag to force a transformer to operate on a file type that it would not otherwise process.

Using glob syntax

You can specify a list of files for the include or exclude tags:

$exclude: ["lib/foo.html", "lib/bar.html"]

Or you can use glob syntax to specify a group of files.

For example, you can instruct the transformer to process any file that ends with .txt, across all directories in the package, using **.txt:

transformers:
- my_transformer:
    $include: **.txt

You can also specify an entire directory for inclusion or exclusion. For example, you can instruct the transformer to ignore any files in the lib/untransformed directory like this:

transformers:
- my_transformer:
    $exclude: lib/untransformed

For more information on how to use glob syntax, see the glob package.

If you publish a package that uses the glob syntax, be aware that earlier versions of pub will not understand. To ensure that a compatible version of pub is used, add an SDK contraint to your pubspec:

environment:
    sdk: ">=1.8.0 <2.0.0"

How to configure assets

You can use include and exclude to make a transformer, such as dart2js, treat certain assets in a special way.

For example, say that your project includes a Dart file that was written by another programmer who wasn’t as careful as you are about cleaning up compiler warnings. You want to suppress the warnings from the dart2js compiler for this particular file when running pub build or pub serve. The offending code is in the lib/lax_code.dart file. You can disable the warnings only on that file by using the following:

transformers:
- $dart2js:
    suppressWarnings: true
    $include: "lib/lax_code.dart"
- $dart2js:
    suppressWarnings: false
    $exclude: "lib/lax_code.dart"

This suppresses warnings when processing lib/lax_code.dart, but allows warnings when compiling all other Dart files.

Writing a transformer

To write a transformer, see Writing a Pub Transformer.