Git Product home page Git Product logo

dart-scissors's Introduction

sCiSSors Build Status Pub Package

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.

Features

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-class and class with 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; }
      :host-context([dir="ltr"]) foo { float: left }
      :host-context([dir="rtl"]) foo { float: right }

      So you just need the supporting code in your main.dart to support bidirectional layouts (see example/mirroring):

      document.body.dir = Bidi.isRtlLanguage(Intl.getCurrentLocale()) ? 'rtl' : 'ltr';
  • Sass compilation:

    • Compiles *.sass and *.scss files with sassc, the lightning-fast C++ port of Ruby Sass.
    • Rebuilds .css files whenever their .sass sources are modified.
  • 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 pngcrush to remove all metadata that is useless for rendering.
    • Disabled by default in debug mode.
  • 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 .js files with the Closure Compiler.
  • Automatic reload support (Optional): zero-turnaround for Dart!

  • Experimental static checker that detects unawaited futures (a common cause of sneaky bugs in async code):

Usage

Defaults vs. debug vs. release

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: true

Prerequisites

If 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 :-)

Installing CSSJanus

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

Other deps: SassC, pngcrush...

These packages are quite standard, you can get them with brew install on MacOS X and with sudo apt-get install on Ubuntu:

  • sassc
  • pngcrush

Using the scissors transformer

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): false by default
  • imageInlining: default is inlineInlinedImages
    • inlineAllUrls: treats url as inline-image
    • inlineInlinedImages: simply honours inline-image
    • linkInlinedImages: replaces inline-image by url
    • disablePass: leaves inline-image untouched
  • optimizePng (boolean): by default, true in release only
  • optimizeSvg (boolean): by default, true in release only
  • sasscPath: default is sassc
  • compiledCssExtension: default is append
    • append: append the .css extension to the SASS / SCSS file name: foo.scss will be compiled to foo.scss.css.
    • replace: replace the SASS / SCSS file extension by .css: foo.scss will be compiled to foo.css.
  • pngCrushPath: default is pngcrush
  • bidiCss (boolean): default is false (note that this is true by default in the scissors/css_mirroring_transformer, see below)
  • cssJanusPath: cssjanus.py by default, see prerequisites

Limitations

  • 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.

Style Isolation in Angular

Angular(1,2) provide the following strategies:

  • Shadow DOM (default in AngularDart 1.x), implemented by ShadowDomComponentFactory in AngularDart 1.x and ViewEncapsulation.Native in Angular2
  • Shadow DOM emulation with "transclusion" (default in Angular2) implemented by TranscludingComponentFactory in AngularDart 1.x and ViewEncapsulation.Emulated in Angular2
  • Unscoped / no Shadow DOM, implemented by ViewEncapsulation.None in 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.

Using scissors/css_mirroring_transformer

See BidirectionalCss for more details.

Example: see example/mirroring.

pubspec.yaml:

dev_dependencies:
  scissors
transformers:
- scissors/css_mirroring_transformer

Valid settings:

  • bidiCss (boolean): true by default (Note: this is not the same default as in the scissors transformer)
  • originalCssDirection (ltr or rtl): ltr by default, defines the direction of input css.
  • cssJanusPath: cssjanus.py by default.

Limitations

  • The standalone scissors/css_mirroring_transformer transformer only consumes CSS files. If you need Sass support, please use the scissors transformer with bidiCss: true.
  • Does not handle directives like @keyframes and @page.

Using scissors/permutations_transformer

Example: see example/permutations.

pubspec.yaml:

dev_dependencies:
  scissors
transformers:
- scissors/permutations_transformer

Valid settings:

  • generatePermutations: true by default
  • ltrImport and rtlImport: 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: false by default. Removes the sourceMappingURL links from all generated .js files, to avoid provoking 404s in production when sourcemaps aren't served (relevant only when the $dart2js transformer has setting sourceMaps: true).
  • reoptimizePermutations: false by default. Whether to optimize permutations with the Closure Compiler.
  • closureCompilerJarPath: compiler.jar by default
  • javaPath: java by default.

Using scissors/reloader/transformer

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, true in debug only
  • removeReloader (boolean): by default, true in release only

Using scissors/src/checker/transformer to detect unawaited futures

See UnawaitedFutures for more details.

Keep in mind that this transformer is very experimental, and slow. It aims to complement Dart's new strong-mode analyzer with more static checks, some of which could eventually graduate to the analyzer itself.

Example:

pubspec.yaml:

dev_dependencies:
  scissors
transformers:
- scissors/src/checker/transformer:
  unawaitedFutures: error

Valid settings:

  • unawaitedFutures (ignore, warning or error): warning by default

Development

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_BIN
  • CSSJANUS_BIN
  • CLOSURE_COMPILER_JAR
  • PNGCRUSH_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.

dart-scissors's People

Contributors

artichokes avatar cbracken avatar chenjm8683 avatar creisman avatar davidmorgan avatar ddrone avatar har79 avatar keertip avatar leafpetersen avatar monamagarwal avatar munificent avatar nex3 avatar ochafik avatar srawlins avatar stereotype441 avatar tvolkert avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

dart-scissors's Issues

Image inlining broken by /deep/ selectors

Same issue as #38 (csslib doesn't parse deprecated /deep/ selectors and al., see dart-lang/csslib#23), but this is a bigger issue as image inlining is enabled by default + used in binary entry point bin/sassc_with_compass_functions.dart...

Definitely need a workaround asap (text-based image-inlining fallback?)

provide a more convenient way to set `load-path` option

I'm trying to port the material2 repo to dart.

I saw that they do some magic so that you more easily can import scss files in your component stylesheet. See this line;
https://github.com/angular/material2/blob/master/src/components/button/button.scss#L1

So basically they resolve imports not relative to the component itself, but relative to the src/core/style directory.

Now I was also able to do this with scissors as well:

transformers:
- scissors:
    sasscArgs:
    - '--load-path'
    - '/Users/kasper/Code/DartProjects/material2/lib/core/style'

But I would like to do it for example like this:

transformers:
- scissors:
    sasscArgs:
    - '--load-path'
    - 'lib/core/style'

Or maybe there could be some convention? For how to import scss files?

Parser fails to compile code containing legacy IE functions, such as progid:DXImageTransform.Microsoft.gradient

The following fails with errors (given below). Interestingly, it still seems to find the asset name and attempt to look it up, because if it doesn't exist it throws another error, but even if it finds the asset it doesn't replace it in the output.

.classname {
-ms-filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#f8f8f8, endColorstr=#f1f1f1);
}
.otherclassname::after {
content: inline-image("path/to/inline/image.png");
}

error on line 1, column 29 of file|path/to/file.scss.css: expected }, but found :
.classname{-ms-filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#f8f8f8, endColorstr=#f1f1f1)}.otherclassname::after{content:inline-image("path/to/inline/image.png")}

error on line 1, column 65 of file|path/to/file.scss.css: expected {, but found (
.classname{-ms-filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#f8f8f8, endColorstr=#f1f1f1)}.otherclassname::after{content:inline-image("path/to/inline/image.png")}

error on line 1, column 79 of file|path/to/file.scss.css: expected :, but found =
.classname{-ms-filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#f8f8f8, endColorstr=#f1f1f1)}.otherclassname::after{content:inline-image("path/to/inline/image.png")}

error on line 1, column 100 of file|path/to/file.scss.css: expected }, but found =
.classname{-ms-filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#f8f8f8, endColorstr=#f1f1f1)}.otherclassname::after{content:inline-image("path/to/inline/image.png")}

error on line 1, column 108 of file|path/to/file.scss.css: expected {, but found )
.classname{-ms-filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#f8f8f8, endColorstr=#f1f1f1)}.otherclassname::after{content:inline-image("path/to/inline/image.png")}

Support plain mirroring of CSS

Right now, the mirrorCss: true option creates "bidirectionalized" CSS (see issue #4). There might be cases where we'd want plain CssJanus transformation with no added magic, to help with some migrations.

sassc and pngcrush not available on Ubuntu 16.04 LTS

The README states Ubuntu users can just apt-get install required dependencies but sassc and pngcrush is not available in default Ubuntu repositories. At least not on latest 16.04 LTS.

Is there a secret Ubuntu repository somewhere? Any alternatives to the two dependencies?

css pruning fails with /deep/ and ::shadow

These selectors (including deep's alias >>>) are deprecated: https://code.google.com/p/chromium/issues/detail?id=489954
however there isn't a replacement yet and there are still discussions what form that will take so they'll likely be around for quite a while.

The bug appears to be in csslib; errors are of the form:
"error on line 33, column 17 of foo.css: expected {, but found /
foo /deep/ #bar {"
Message comes from https://github.com/dart-lang/csslib/blob/master/lib/parser.dart#L307
and forwarded by SCiSSors: https://github.com/google/dart-scissors/blob/master/lib/src/css_pruning/css_pruning.dart#L121

I've filed an issue with csslib (dart-lang/csslib#23) and will work on a patch.

Perform RTL mirroring of CSS

There are two options:

  • Fork out to cssjanus (demo) when some transformer setting says so (requires a build per direction).

  • Perform ad-hoc transform using css direction tricks (single build for both ltr & rtl)

    a {
      foo: bar;
      margin-left: 1em;
    }

    To the following (edited with :host-context, see spec and see thread below):

    a {
      foo: bar;
    }
    :host-context([dir="ltr"]) a {
      margin-left: 1em;
    }
    :host-context([dir="rtl"]) a {
      margin-right: 1em;
    }

    (this would also use cssjanus, with extra logic to know which properties are flippable and to recombine the three portions: orientation-neutral, non-flipped orientation-specific, flipped orientation-specific)

Simplify bidirectionalization scheme

We should consider a simplification of the bidirectionalization scheme (see issue #4), to output smaller css code. The following example:

  a {
    foo: bar;
    margin-left: 1em;
  }

Is currently transformed into:

  a {
    foo: bar;
  }
  :host-context([dir="ltr"]) a {
    margin-left: 1em;
  }
  :host-context([dir="rtl"]) a {
    margin-right: 1em;
  }

But could be shorter with:

  a {
    foo: bar;
    margin-left: 1em;
  }
  :host-context([dir="rtl"]) a {
    margin-right: 1em;
  }

Handle :host selectors

Short of performing whole-world analysis of where a component is used, such selectors must trigger a bail out of pruning.

Output css sourcemaps

If the input css has a sourcemap (for instance, output of SASS), we should also use it as input / chain sourcemaps.

The resulting sourcemap combination code should be contributed back to the source_maps package.

Bad state: Setting sasscArgs wasn't read yet

Hi,

I have an issue while running pub serve. I get this error:

$ pub serve
Loading source assets... 
Loading scissors, scissors/reloader/transformer, angular2 and dart_to_js_script_rewriter transformers... (3.9s) 
in ShutdownIsolate: Unhandled exception:
Bad state: Setting sasscArgs wasn't read yet.
#0      checkState (package:quiver/check.dart:71:5)
#1      Setting.value (package:scissors/src/utils/setting.dart:25:5)
#2      SettingsBase&SvgOptimizationSettings&PngOptimizationSettings&SassSettings.sasscSettings.<anonymous closure>.<<anonymous closure>_async_body> (package:scissors/src/sass/settings.dart:53:26)
#3      Future.Future.microtask.<anonymous closure> (dart:async/future.dart:144)
#4      _microtaskLoop (dart:async/schedule_microtask.dart:41)
#5      _startMicrotaskLoop (dart:async/schedule_microtask.dart:50)
#6      _runPendingImmediateCallback (dart:isolate-patch/isolate_patch.dart:96)
#7      _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:149)

This is my yaml file:

environment:
  sdk: '>=1.13.0 <2.0.0'
dependencies:
  angular2: 2.0.0-beta.6
  browser: ^0.10.0
dev_dependencies:
  scissors: ^0.4.1
  dart_to_js_script_rewriter: ^0.1.0
  func: "^0.1.0"
transformers:
- scissors:
    verbose: true
    bidiCss: false
    compiledCssExtension: replace
    sasscArgs:
      - --load-path
      - lib/client/css
- scissors/reloader/transformer
- angular2:
    generate_template_cache: true
    platform_directives:
      - 'package:angular2/common.dart#COMMON_DIRECTIVES'
    platform_pipes:
      - 'package:angular2/common.dart#COMMON_PIPES'
    entry_points: web/main.dart
- $dart2js:
    commandLineOptions:
      - --trust-type-annotations
      - --trust-primitives
      - --enable-experimental-mirrors
      - --dump-info
- dart_to_js_script_rewriter

I'm not sure what is causing this problem. I copied example script, I have /lib/client/css folder and some file in it.. I also tried without sasscArgs in yaml file, but I get the same error.

Thanks in advance.

Bidi CSS broken

In versions up to 0.6.0+1 (issue #23), the following snippet:

foo { margin-left: 1px }

Is bidirectionalized to:

foo { margin-left: 1px }
:host-context([dir="rtl"]) foo { margin-right: 1px }

Which is incorrect (a margin-left does not counteract a margin-right). It should be the following instead:

:host-context([dir="ltr"]) foo { margin-left: 1px }
:host-context([dir="rtl"]) foo { margin-right: 1px }

Already fixed by @MonamAgarwal in 2873219, now need a new release.

Dart 2 runtime failures in tests

When running tests in Dart 2 mode, see failures like

Failed to load "/scissors/test/checker/transformer_test.dart":
type '_ImmutableMap<String, dynamic>' is not a subtype of type 'Map<String, String>' of 'other' where
_ImmutableMap is from dart:core
String is from dart:core
Map is from dart:core
String is from dart:core
String is from dart:core
dart:collection __InternalLinkedHashMap&_HashVMBase&MapMixin.addAll
package:scissors/src/utils/settings_base.dart 61:12 new SettingsBase
../../scissors/lib/src/checker/settings.dart new CheckerSettings
package:scissors/src/checker/transformer.dart 50:25 new CheckerTransformer.asPlugin
../..//scissors/test/checker/transformer_test.dart 9:13 makePhases

type '_InternalLinkedHashMap<dynamic, dynamic>' is not a subtype of type 'Map<String, dynamic>' in type cast where
_InternalLinkedHashMap is from dart:collection
Map is from dart:core
String is from dart:core
dart:core Object._as
package:scissors/src/utils/settings_base.dart 60:42 new SettingsBase
../scissors/lib/src/css_pruning/settings.dart new __CssPruningSettings&SettingsBase&CssPruningSettings
../../tmp/archives/third_party/dart/scissors/lib/src/css_pruning/settings.dart new _CssPruningSettings
package:scissors/src/css_pruning/transformer.dart 35:18 new CssPruningTransformer.asPlugin
../../scissors/test/css_pruning/transformer_test.dart 23:13 makePhases

and more ....

Analyze companion .dart files to support inlined templates

sCiSSors should extract inline templates from Angular 1 & 2 component / view annotations (implies loading up the .dart file through code transformers).

Another thing we could do is detect manual DOM class manipulations to bail out of some/all of the pruning.

Enable + address more lints

Example content for .analysis_options:

analyzer:
  strong-mode: true
  exclude:
    - test/**
linter:
  rules:
    - always_declare_return_types
    - always_specify_types
    - annotate_overrides
    - avoid_as
    - avoid_empty_else
    - avoid_init_to_null
    - avoid_return_types_on_setters
    - await_only_futures
    - camel_case_types
    - comment_references
    - constant_identifier_names
    - control_flow_in_finally
    - dont_compare_unrelated_types_for_equality
    - empty_constructor_bodies
    - hash_and_equals
    - implementation_imports
    - iterable_contains_unrelated_type
    - library_names
    - library_prefixes
    - non_constant_identifier_names
    - one_member_abstracts
    - overriden_field
    - package_api_docs
    - package_prefixed_library_names
    - prefer_is_not_empty
    - pub/package_names
    - public_member_api_docs
    - slash_for_doc_comments
    - sort_constructors_first
    - sort_unnamed_constructors_first
    - super_goes_last
    - test_types_in_equals
    - throw_in_finally
    - type_annotate_public_apis
    - type_init_formals
    - unawaited_futures
    - unnecessary_brace_in_string_interp
    - unnecessary_getters_setters
    - unrelated_type_equality_checks

Introduce mechanism to preserve classes

Need to see which of the following options are the most SASS-friendly / most usable:

  • Javadoc-like @retain tags in comments,
  • Special rule scissors { my-class: preserved; },
  • Special property .my-class { scissors: preserved; ... } (my favourite),

sassc temporary folder issue on Mac OSX

OS: Mac OSX Yosemite
Dart Version: Dart VM version: 1.19.1 (Wed Sep 7 08:59:17 2016) on "macos_x64"
Pub Version: Pub 1.19.1

I'm trying to serve a project which contains SASS (scss) files within the lib folder.
This results in the following error message:

[SassC on XYZ|XYZ|lib/components/app.scss]:
Failed to run [/usr/local/bin/sassc, -t, expanded, -m, ../../../../../../Users/Eric/XYZ/lib/components/app.scss, app.scss.css, --load-path, /Users/Eric/XYZ] in /var/folders/pv/1mm2ydkj0414nv110gnr1vvw0000gq/T/pNjrSc:
Internal Error: File to read not found or unreadable: ../../../../../../Users/Eric/XYZ/lib/components/app.scss

Pub serve:

pub serve --force-poll

It seems that the Mac OSX Symlinks cause the issue, because /var/folders/pv/... actually points to /private/var/folders/pv/... .

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.