Smarter resources for Angular apps: CSS pruning, bidirectional layouts, SVG & PNG optimization, Sass compilation, locale permutations, automatic reload.
Disclaimer: This is not an official Google product.
All of the following features are lazy (only triggered when needed) and
most of them are disabled or optimized for speed with pub serve in debug mode.
(note: may need pub serve --force-poll on MacOS X)
-
CSS pruning for Angular (see example/angular1, example/angular2):
- Finds which .css rules are not used by Angular templates and removes them.
- Supports
ng-classandclasswith programmatic interpolated fragments (e.g.class="some-{{fragmented}}-class and-some-normal-class",ng-class="{'some-class': isSome}"). - Disabled by default in debug mode.
-
CSS mirroring / bidirectionalization that works with Angular2's transformer:
-
Uses CSSJanus to produce a single CSS file that supports both RTL & LTR layouts!
-
Given
foo { color: blue; float: left }, it generates:foo { color: blue; float: left } :host-context([dir="rtl"]) foo { float: right }
So you just need the supporting code in your
main.dartto support bidirectional layouts (see example/mirroring):document.body.dir = Bidi.isRtlLanguage(Intl.getCurrentLocale()) ? 'rtl' : 'ltr';
-
-
Sass compilation:
- Compiles
*.sassand*.scssfiles withsassc, the lightning-fast C++ port of Ruby Sass. - Rebuilds
.cssfiles whenever their.sasssources are modified.
- Compiles
-
Image inlining:
- Expands inline-image calls in CSS files into data URI links, like Compass does.
- By default in debug mode, links to images instead of inlining them.
-
PNG optimization:
- Calls
pngcrushto remove all metadata that is useless for rendering. - Disabled by default in debug mode.
- Calls
-
SVG optimization:
- Removes comments, doctypes, unused namespaces.
- Disabled by default in debug mode.
-
Locale-specific permutations generation (Optional, see example/permutations):
- Generates one .js per locale (e.g.
main_en.js,main_fr.js...) with the deferred parts needed for that locale, which speeds up load time. - Supports deferred messages and deferred LTR/RTL template caches.
- Optionally optimizes the resulting
.jsfiles with the Closure Compiler.
- Generates one .js per locale (e.g.
-
Automatic reload support (Optional): zero-turnaround for Dart!
sCiSSors is fine-tuned for fast build in debug mode (default for pub serve)
and small code size in release mode (default for pub build).
Its behaviour can be fully customized through transformer settings in
pubspec.yaml.
For instance, to enable PNG optimizations in all modes, and enable SVG
optimizations in debug only:
transformers:
- scissors:
optimizePng: true
release:
optimizeSvg: false
debug:
optimizeSvg: trueIf you checked out scissors's sources, you can run . ./script/install_dependencies.sh to get all the required dependencies, and skip the rest of this section :-)
You'll need a local install of CSSJanus for CSS mirroring.
Note that this transformer uses Google's original cssjanus.py, not its .js port (github.com/cssjanus/cssjanus, which might work if packaged as a binary that consumes css from stdin and outputs mirrored css on stdout).
To install CSSJanus, run the following command in a console (ensure you have something like export PATH=~/bin:$PATH in your ~/.profile or ~/.bashrc):
mkdir ~/bin
curl http://cssjanus.googlecode.com/svn/trunk/cssjanus.py > ~/bin/cssjanus.py
chmod +x ~/bin/cssjanus.py
These packages are quite standard, you can get them with brew install on MacOS X and with sudo apt-get install on Ubuntu:
sasscpngcrush
The default transformer will build Sass files in a blink of an
eye and will optimize CSS, PNG and SVG assets in release mode
(pub build).
Please only setup sCiSSors's transformer on projects you know respect sCiSSors' conventions and limitations (see below).
Examples: see example/angular1, example/angular2).
pubspec.yaml:
dev_dependencies:
scissors: ^0.6.0
transformers:
- scissors
Valid settings:
pruneCss(boolean): by default,trueinreleaseonlyimageInlining: default islinkInlinedImagesindebug,inlineInlinedImagesinreleaseinlineAllUrls: treatsurlasinline-imageinlineInlinedImages: simply honoursinline-imagelinkInlinedImages: replacesinline-imagebyurldisablePass: leavesinline-imageuntouched
optimizePng(boolean): by default,trueinreleaseonlyoptimizeSvg(boolean): by default,trueinreleaseonlysasscPath: default issassccompiledCssExtension: default isappendappend: append the.cssextension to the SASS / SCSS file name:foo.scsswill be compiled tofoo.scss.css.replace: replace the SASS / SCSS file extension by.css:foo.scsswill be compiled tofoo.css.
pngCrushPath: default ispngcrushbidiCss(boolean): default isfalse(note that this istrueby default in thescissors/css_mirroring_transformer, see below)cssJanusPath:cssjanus.pyby default, see prerequisites
- Assumes if foo.html exists, foo.css is only used from there (conventions
matter). This means sCiSSors should be disabled or used with caution when
using Angular2 with
ViewEncapsulation.None(see section below). - Very limited support of CSS rules (naive and hopefully pessimistic matching),
- Bails out of pruning as soon as it doesn't recognize the (map literal)
syntax of an
ng-class(or if the map has non-string-literal keys), - Does not detect direct / handle DOM manipulations done in .dart companion files yet (html:Element.classes, etc).
- No support for XML namespaces in CSS3 attribute selectors.
- No CSS renaming yet (just pruning for now),
- No Polymer.dart support yet.
Angular(1,2) provide the following strategies:
- Shadow DOM (default in AngularDart 1.x), implemented by
ShadowDomComponentFactoryin AngularDart 1.x andViewEncapsulation.Nativein Angular2 - Shadow DOM emulation with "transclusion" (default in Angular2) implemented by
TranscludingComponentFactoryin AngularDart 1.x andViewEncapsulation.Emulatedin Angular2 - Unscoped / no Shadow DOM, implemented by
ViewEncapsulation.Nonein Angular2
The first two strategies (Shadow DOM & its transcluded emulation) provide strict encapsulation of style at the component level: styles defined in a component do not leak to any of its sub-components or parent components. This is the assumption by which sCiSSors lives, so you're safe with it.
The last "unscoped" strategy means there's no file- or component-local way of deciding if a style could be used elsewhere. You should not use sCiSSors on packages / projects with that strategy.
See BidirectionalCss for more details.
Example: see example/mirroring.
pubspec.yaml:
dev_dependencies:
scissors
transformers:
- scissors/css_mirroring_transformer
Valid settings:
bidiCss(boolean):trueby default (Note: this is not the same default as in thescissorstransformer)originalCssDirection(ltrorrtl):ltrby default, defines the direction of input css.cssJanusPath:cssjanus.pyby default.
- The standalone
scissors/css_mirroring_transformertransformer only consumes CSS files. If you need Sass support, please use thescissorstransformer withbidiCss: true. - Does not handle directives like
@keyframesand@page.
Example: see example/permutations.
pubspec.yaml:
dev_dependencies:
scissors
transformers:
- scissors/permutations_transformer
Valid settings:
generatePermutations:trueby defaultltrImportandrtlImport: unset by default. If you're deferred-loading LTR/RTL-specific template caches, these settings should take the alias you're importing them under. See example/permutations for a concrete example.expectedPartCounts(map of .dart.js artifact to number of expected parts): unset by default. For instance:{ web/main.dart.js: 3 }.stripSourceMaps:falseby default. Removes thesourceMappingURLlinks from all generated.jsfiles, to avoid provoking 404s in production when sourcemaps aren't served (relevant only when the$dart2jstransformer has settingsourceMaps: true).reoptimizePermutations:falseby default. Whether to optimize permutations with the Closure Compiler.closureCompilerJarPath:compiler.jarby defaultjavaPath:javaby default.
This provides an amazing development turnaround experience, whether you're using the other sCiSSors transformers or not.
With pub serve --force-poll, as soon as you save an asset (say, foo.scss)
and it finished building the dependent assets (say, foo.scss.css), the app
will reload. That's typically before you even have the time to tab-switch to
the browser (+ no need to Ctrl+R).
The transformer ensures the automatic reload logic is removed in release
builds (pub build), without interfering with source maps.
Example: see example/permutations.
Just edit pubspec.yaml (note: it's in dev_dependencies, not dependencies):
dev_dependencies:
scissors
transformers:
- scissors/reloader/transformer
And edit main.dart:
import 'package:scissors/reloader/reloader.dart';
main() {
setupReloader();
...
}Valid settings:
serveTimestamps(boolean): by default,trueindebugonlyremoveReloader(boolean): by default,trueinreleaseonly
For things to do, please see issues.
To setup dependencies, please run:
. scripts/install_dependencies.sh
This will download some executables used by Scissors and will export the following environment vars
SASSC_BINCSSJANUS_BINCLOSURE_COMPILER_JARPNGCRUSH_BIN
Please run the following command to test your changes + reformat + analyze sources:
./scripts/presubmit.sh
Please never force-push to master: use git revert to revert changes.