dart2js_info 0.6.1

  • Readme
  • Changelog
  • Installing
  • 27

Dart2js Info #

This package contains libraries and tools you can use to process info files produced when running dart2js with --dump-info.

The info files contain data about each element included in the output of your program. The data includes information such as:

  • the size that each function adds to the .dart.js output,
  • dependencies between functions,
  • how the code is clustered when using deferred libraries, and
  • the declared and inferred type of each function argument.

All of this information can help you understand why some piece of code is included in your compiled application, and how far was dart2js able to understand your code. This data can help you make changes to improve the quality and size of your framework or app.

This package focuses on gathering libraries and tools that summarize all of that information. Bear in mind that even with all these tools, it is not trivial to isolate code-size issues. We just hope that these tools make things a bit easier.

Status #

Build Status

Currently, most tools available here can be used to analyze code-size and attribution of code-size to different parts of your app. With time, we hope to add more data to the info files, and include better tools to help understand the results of type inference.

This package is still in flux and we might make breaking changes at any time. Our current goal is not to provide a stable API, we mainly want to expose the functionality and iterate on it. We recommend that you pin a specific version of this package and update when needed.

Tools #

All tools are provided as commands of a single command-line interface. To install:

pub global activate dart2js_info

To run a tool, then run:

dart2js_info <command> [arguments]

There is a short help available on the tool, and more details are provided below.

Format #

There are several formats of info files. Dart2js today produces a JSON format, but very soon will switch to produce a binary format by default.

Info API #

This package also exposes libraries to parse and represent the information from the info files. If there is data that is stored in the info files but not exposed by one of our tools, you may be able to use the info APIs to quickly put together your own tool.

AllInfo exposes a Dart representation of all of the collected information. There are deserialization libraries in this package to decode any info file produced by the dart2js --dump-info option. See lib/binary_serialization.dart and lib/json_info_codec.dart to find the binary and JSON decoders respectively. For convenience, package:dart2js_info/src/io.dart also exposes a helper method that can choose, depending on the extension of the info file, whether to deserialize it using the binary or JSON decoder. For example:

import 'dart:convert';
import 'dart:io';

import 'package:dart2js_info/info.dart';
import 'package:dart2js_info/src/io.dart';

main(args) async {
  var infoPath = args[0];
  var info = await infoFromFile(infoPath);
  ...
}

Available tools #

The following tools are a available today:

  • code_deps: simple tool that can answer queries about the dependency between functions and fields in your program. Currently it only supports the some_path query, which shows a dependency path from one function to another.

  • diff: a tool that diffs two info files and reports which program elements have been added, removed, or changed size. This also tells which elements are no longer deferred or have become deferred.

  • library_size: a tool that shows how much code was attributed to each library. This tool is configurable so it can group data in many ways (e.g. to tally together all libraries that belong to a package, or all libraries that match certain name pattern).

  • deferred_check: a tool that verifies that code was split into deferred parts as expected. This tool takes a specification of the expected layout of code into deferred parts, and checks that the output from dart2js meets the specification.

  • deferred_size: a tool that gives a breakdown of the sizes of the deferred parts of the program. This can show how much of your total code size can be loaded deferred.

  • deferred_layout: a tool that reports which code is included on each output unit.

  • function_size: a tool that shows how much code was attributed to each function. This tool also uses dependency information to compute dominance and reachability data. This information can sometimes help determine how much savings could come if the function was not included in the program.

  • coverage_server and coverage_analysis: dart2js has an experimental feature to gather coverage data of your application. The coverage_log_server can record this data, and live_code_size_analysis can correlate that with the info file, so you determine why code that is not used is being included in your app.

  • convert: a tool that converts info files from one format to another. Accepted inputs are JSON or the internal binary form, outputs can be JSON, backward-compatible JSON, binary, or protobuf schema (as defined in info.proto).

  • show: a tool that dumps info files in a readable text format.

Next we describe in detail how to use each of these tools.

Code deps tool #

This command-line tool can be used to query for code dependencies. Currently this tool only supports the some_path query, which gives you the shortest path for how one function depends on another.

Run this tool as follows:

# activate is only needed once to install the dart2js_info tool
$ pub global activate dart2js_info
$ dart2js_info code_deps some_path out.js.info.data main foo

The arguments to the query are regular expressions that can be used to select a single element in your program. If your regular expression is too general and has more than one match, this tool will pick the first match and ignore the rest. Regular expressions are matched against a fully qualified element name, which includes the library and class name (if any) that contains it. A typical qualified name is of this form:

libraryName::ClassName.elementName

If the name of a function your are looking for is unique enough, it might be sufficient to just write that name as your regular expression.

Diff tool #

This command-line tool shows a diff between two info files. It can be run as follows:

$ pub global activate dart2js_info # only needed once
$ dart2js_info diff old.js.info.data new.js.info.data [--summary]

The tool gives a breakdown of the difference between the two info files. Here's an example output:

total_size_difference -2688
total_added 0
total_removed 2321
total_size_changed -203
total_became_deferred 0
total_no_longer_deferred 0

ADDED (0 bytes)
========================================================================

REMOVED (2321 bytes)
========================================================================
dart:_js_helper::getRuntimeTypeString: 488 bytes
dart:_js_helper::substitute: 479 bytes
dart:_js_helper::TypeImpl.toString: 421 bytes
dart:_js_helper::computeSignature: 204 bytes
dart:_js_helper::getRuntimeTypeArguments: 181 bytes
dart:_js_helper::extractFunctionTypeObjectFrom: 171 bytes
dart:_js_helper::getTypeArgumentByIndex: 147 bytes
dart:_js_helper::runtimeTypeToString: 136 bytes
dart:_js_helper::setRuntimeTypeInfo: 94 bytes
dart:core::Object.runtimeType: 0 bytes
dart:_js_helper::getRawRuntimeType: 0 bytes
dart:_js_helper::invoke: 0 bytes
dart:_js_helper::invokeOn: 0 bytes
dart:_js_helper::getField: 0 bytes
dart:_js_helper::getClassName: 0 bytes
dart:_js_helper::getRuntimeType: 0 bytes
dart:_js_helper::TypeImpl.TypeImpl: 0 bytes

CHANGED SIZE (-203 bytes)
========================================================================
dart:_interceptors::JSUnmodifiableArray: -3 bytes
dart:core::List: -3 bytes
dart:_interceptors::ArrayIterator: -4 bytes
dart:_js_helper::TypeImpl._typeName: -10 bytes
dart:_js_helper::TypeImpl._unmangledName: -15 bytes
dart:_js_names::: -30 bytes
dart:_js_names::extractKeys: -30 bytes
dart:core::StringBuffer: -40 bytes
dart:core::StringBuffer._writeAll: -40 bytes
dart:core::: -43 bytes
dart:_interceptors::JSArray.+: -63 bytes
dart:_interceptors::JSArray: -66 bytes
dart:_interceptors::: -73 bytes
dart:_js_helper::TypeImpl: -481 bytes
dart:_js_helper::: -2445 bytes

BECAME DEFERRED (0 bytes)
========================================================================

NO LONGER DEFERRED (0 bytes)
========================================================================

You can also pass --summary to only show the summary section.

Library size split tool #

This command-line tool shows the size distribution of generated code among libraries. It can be run as follows:

$ pub global activate dart2js_info # only needed once
$ dart2js_info library_size out.js.info.data

Libraries can be grouped using regular expressions. You can specify what regular expressions to use by providing a grouping.yaml file:

$ dart2js_info library_size out.js.info.data grouping.yaml

The format of the grouping.yaml file is as follows:

groups:
- { regexp: "package:(foo)/*.dart", name: "group name 1", cluster: 2}
- { regexp: "dart:.*",              name: "group name 2", cluster: 3}

The file should include a single key groups containing a list of group specifications. Each group is specified by a map of 3 entries:

  • regexp (required): a regexp used to match entries that belong to the group.

  • name (optional): the name given to this group in the output table. If omitted, the name is derived from the regexp as the match's group(1) or group(0) if no group was defined. When names are omitted the group specification implicitly defines several groups, one per observed name.

  • cluster (optional): a clustering index for how data is shown in a table. Groups with higher cluster indices are shown later in the table after a dividing line. If missing, the cluster index defaults to 0.

Here is an example configuration, with comments about what each entry does:

groups:
# This group shows the total size for all libraries that were loaded from
# file:// urls, it is shown in cluster #2, which happens to be the last
# cluster in this example before the totals are shown:
- name: "Loose files"
  regexp: "file://.*"
  cluster: 2

# This group shows the total size of all code loaded from packages:
- { name: "All packages", regexp: "package:.*", cluster: 2}

# This group shows the total size of all code loaded from core libraries:
- { name: "Core libs", regexp: "dart:.*", cluster: 2}

# This group shows the total size of all libraries in a single package. Here
# we omitted the `name` entry, instead we extract it from the regexp
# directly.  In this case, the name will be the package-name portion of the
# package-url (determined by group(1) of the regexp).
- { regexp: "package:([^/]*)", cluster: 1}

# The next two groups match the entire library url as the name of the group.
- regexp: "package:.*"
- regexp: "dart:.*"

# If your code lives under /my/project/dir, this will match any file loaded
from a file:// url, and we use as a name the relative path to it.
- regexp: "file:///my/project/dir/(.*)"

Regardless of the grouping configuration, the tool will display the total code size attributed of all libraries, constants, and the program size.

Note: eventually you should expect all numbers to add up to the program size. Currently dart2js's --dump-info is not complete, so numbers for bootstrapping code and lazy static initializers are missing.

Deferred library verification #

This tool checks that the output from dart2js meets a given specification, given in a YAML file. It can be run as follows:

$ pub global activate dart2js_info # only needed once
$ dart2js_info deferred_check out.js.info.data manifest.yaml

The format of the YAML file is:

main:
  include:
    - some_package
    - other_package
  exclude:
    - some_other_package

foo:
  include:
    - foo
    - bar

baz:
  include:
    - baz
    - quux
  exclude:
    - zardoz

The YAML file consists of a list of declarations, one for each deferred part expected in the output. At least one of these parts must be named "main"; this is the main part that contains the program entrypoint. Each top-level part contains a list of package names that are expected to be contained in that part, a list of package names that are expected to be in another part, or both. For instance, in the example YAML above the part named "baz" is expected to contain the packages "baz" and "quux" and exclude the package "zardoz".

The names for parts given in the specification YAML file (besides "main") are the same as the name given to the deferred import in the dart file. For instance, if you have import 'package:foo/bar.dart' deferred as baz; in your dart file, then the corresponding name in the specification file is 'baz'.

Deferred library size tool #

This tool gives a breakdown of all of the deferred code in the program by size. It can show how much of the total code size is deferred. It can be run as follows:

pub global activate dart2js_info # only needed once
dart2js_info deferred_size out.js.info.data

The tool will output a table listing all of the deferred imports in the program as well as the "main" chunk, which is not deferred. The output looks like:

Size by library
------------------------------------------------
main                                    12345678
foo                                      7654321
bar                                      1234567
------------------------------------------------
Main chunk size                         12345678
Deferred code size                       8888888
Percent of code deferred                  41.86%

Deferred library layout tool #

This tool reports which code is included in each output unit. It can be run as follows:

$ pub global activate dart2js_info # only needed once
$ dart2js_info deferred_layout out.js.info.data

The tool will output a table listing all of the deferred output units or chunks, for each unit it will list the set of libraries that contribute code to this unit. If a library contributes to more than one output unit, the tool lists which elements are in one or another output unit. For example, the output might look like this:

Output unit main:
  loaded by default
  contains:
     - hello_world.dart
     - dart:core
     ...

Output unit 2:
  loaded by importing: [b]
  contains:
     - c.dart:
       - function d
     - b.dart

Output unit 1:
  loaded by importing: [a]
  contains:
     - c.dart:
       - function c
     - a.dart

In this example, all the code of b.dart after tree-shaking was included in the output unit 2, but c.dart was split between output unit 1 and output unit 2.

Function size analysis tool #

This command-line tool presents how much each function contributes to the total code of your application. We use dependency information to compute dominance and reachability data as well.

When you run:

$ pub global activate dart2js_info # only needed once
$ dart2js_info function_size out.js.info.data

the tool produces a table output with lots of entries. Here is an example entry with the corresponding table header:

 --- Results per element (field or function) ---
    element size     dominated size     reachable size Element identifier
    ...
     275   0.01%     283426  13.97%    1506543  74.28% some.library.name::ClassName.myMethodName

Such entry means that the function myMethodName uses 275 bytes, which is 0.01% of the application. That function however calls other functions, which transitively can include up to 74.28% of the application size. Of all those reachable functions, some of them are reachable from other parts of the program, but a subset are dominated by myMethodName, that is, other parts of the program starting from main would first go through myMethodName before reaching those functions. In this example, that subset is 13.97% of the application size. This means that if you somehow can remove your dependency on myMethodName, you will save at least that 13.97%, and possibly some more from the reachable size, but how much of that we are not certain.

Coverage tools #

Coverage information requires a bit more setup and work to get them running. The steps are as follows:

  • Compile an app with dart2js using --dump-info and --experiment-call-instrumentation
$ dart2js --dump-info --experiment-call-instrumentation main.dart

The flag only works dart2js version 2.2.0 or newer.

  • Launch the coverage server tool to serve up the JS code of your app:
$ dart2js_info coverage_server main.dart.js
  • (optional) If you have a complex application setup, you may need to serve an html file or integrate your application server to proxy to the log server any GET request for the .dart.js file and /coverage POST requests that send coverage data.

  • Load your app and use it to exercise the entire code.

  • Shut down the coverage server (Ctrl-C). This will emit a file named mail.dart.js.coverage.json

  • Finally, run the live code analysis tool given it both the info and coverage json files:

$ dart2js_info coverage_analysis main.dart.info.data main.dart.coverage.json

Code location, features and bugs #

This package is developed in github. Please file feature requests and bugs at the issue tracker.

0.6.1 #

  • Move binary subcommands under src folder. Otherwise, pub global activate fails.

0.6.0 #

This release contains several breaking changes:

  • The fields Info.id and Info.serializedId have been removed. These properties were only used for serialization and deserialization. Those values are now computed during the serialization process instead.

  • Added CodeSpan - a representation of code regions referring to output files. This will be used to transition to a lighterweight dump-info that doesn't embed code snippets (since they are duplicated with the output program).

    Encoder produces a new format for code-spans, but for a transitional period a flag is provided to produce the old format. The decoder is still backwards compatible (filling in just the text in CodeSpan where the json contained a String).

  • Deleted unused Measurements.

  • Split the json codec from info.dart.

  • Introduced lib/binary_serialization.dart a lighterweight serialization/deserialization implementation. This will eventually be used by default by dart2js.

  • Added backwards compatibility flag to the JSON codec, to make transition to new tools more gradual.

  • Added a tool to dump info files in a readable text form.

  • Consolidated all binary tools under a single command. Now you can access all tools as follows:

    pub global activate dart2js_info
    dart2js_info <command> [arguments] ...
    

    See updated documentation in README.md

0.5.17 #

  • Make live_code_size_analysis print library URIs and not library names.

0.5.16 #

  • Split out IO dependency from util.dart, so all other utilities can be used on any platform.

0.5.15 #

  • Add BasicInfo.resetIds to free internal cache used for id uniqueness.

0.5.14 #

  • Updates coverage_log_server.dart and live_code_size_analysis.dart to make them strong clean and match the latest changes in dart2js.

0.5.13 #

  • Use a more efficient Map implementation for decoding existing info files.

  • Use a relative path when generating unique IDs for elements in non-package sources.

0.5.12 #

  • Improved output of dart2js_info_diff by sorting the diffs by size and outputting the summary in full output mode.

0.5.11 #

  • Added --summary option to dart2js_info_diff tool.

0.5.10 #

  • Set max SDK version to <3.0.0, and adjust other dependencies.

0.5.6+4 #

  • Changes to make the library strong mode (runtime) clean.

0.5.6 #

  • Added isRuntimeTypeUsed, isIsolateInUse, isFunctionApplyUsed and isMirrorsUsed to ProgramInfo.

0.5.5+1 #

  • Support the latest versions of shelf and args packages.

0.5.5 #

  • Added diff tool.

0.5.4+2 #

  • Updated minimum SDK dependency to align with package dependencies.
  • Allowed the latest version of pkg/quiver.
  • Updated the homepage.
  • Improved the stability and eliminated duplicates in "holding" dump info output.

0.5.4+1 #

  • Remove files published accidentally.

0.5.4 #

  • Added script to show inferred types of functions and fields on the command line.

0.5.3+1 #

  • Improved the stability of ConstantInfo.id.

0.5.3 #

  • Made IDs in the JSON format stable. Improves plain text diffing.

0.2.7 #

  • Make dart2js_info strong-mode clean.

0.2.6 #

  • Add tool to get breakdown of deferred libraries by size.

0.2.5 #

  • Changed the deferred_library_check tool to allow parts to exclude packages and to not assume that unspecified packages are in the main part.

0.2.4 #

  • Added imports field for OutputUnitInfo

0.2.3 #

  • Moved deferred_library_check functionality to a library

0.2.2 #

  • Added deferred_libary_check tool

0.2.1 #

  • Merged verify_deps tool into debug_info tool

0.2.0 #

  • Added AllInfoJsonCodec
  • Added verify_deps tool

0.1.0 #

  • Added ProgramInfo.entrypoint.
  • Added experimental information about calls in function bodies. This will likely change again in the near future.

0.0.3 #

  • Added executable names

0.0.2 #

  • Add support for ConstantInfo

0.0.1 #

  • Initial version

Use this package as an executable

1. Install it

You can install the package from the command line:


$ pub global activate dart2js_info

2. Use it

The package has the following executables:


$ dart2js_info

Use this package as a library

1. Depend on it

Add this to your package's pubspec.yaml file:


dependencies:
  dart2js_info: ^0.6.1

2. Install it

You can install packages from the command line:

with pub:


$ pub get

with Flutter:


$ flutter pub get

Alternatively, your editor might support pub get or flutter pub get. Check the docs for your editor to learn more.

3. Import it

Now in your Dart code, you can use:


import 'package:dart2js_info/binary_serialization.dart';
import 'package:dart2js_info/deferred_library_check.dart';
import 'package:dart2js_info/info.dart';
import 'package:dart2js_info/json_info_codec.dart';
import 'package:dart2js_info/proto_info_codec.dart';
  
Popularity:
Describes how popular the package is relative to other packages. [more]
16
Health:
Code health derived from static analysis. [more]
11
Maintenance:
Reflects how tidy and up-to-date the package is. [more]
80
Overall:
Weighted score of the above. [more]
27
Learn more about scoring.

We analyzed this package on Nov 11, 2019, and provided a score, details, and suggestions below. Analysis was completed with status completed using:

  • Dart: 2.6.0
  • pana: 0.12.21

Platforms

Detected platforms: Flutter, web, other

No platform restriction found in libraries.

Health suggestions

Fix lib/src/proto/info.pbjson.dart. (-42.96 points)

Analysis of lib/src/proto/info.pbjson.dart reported 112 hints, including:

line 7 col 31: Avoid const keyword.

line 9 col 8: Avoid const keyword.

line 10 col 5: Avoid const keyword.

line 11 col 5: Avoid const keyword.

line 15 col 24: Avoid const keyword.

Fix lib/src/proto/info.pb.dart. (-29.95 points)

Analysis of lib/src/proto/info.pb.dart reported 71 hints, including:

line 14 col 37: Unnecessary new keyword.

line 27 col 31: Unnecessary new keyword.

line 31 col 39: Unnecessary new keyword.

line 33 col 7: Unnecessary new keyword.

line 59 col 37: Unnecessary new keyword.

Fix lib/json_info_codec.dart. (-15.25 points)

Analysis of lib/json_info_codec.dart reported 33 hints, including:

line 21 col 38: Unnecessary new keyword.

line 26 col 18: Unnecessary new keyword.

line 57 col 22: Unnecessary new keyword.

line 181 col 23: Unnecessary new keyword.

line 200 col 11: Unnecessary new keyword.

Fix additional 29 files with analysis or formatting issues. (-106.74 points)

Additional issues in the following files:

  • lib/proto_info_codec.dart (26 hints)
  • lib/binary_serialization.dart (21 hints)
  • bin/src/coverage_log_server.dart (16 hints)
  • lib/src/graph.dart (16 hints)
  • bin/src/debug_info.dart (15 hints)
  • lib/src/binary/sink.dart (15 hints)
  • bin/tools.dart (14 hints)
  • lib/src/binary/source.dart (13 hints)
  • lib/info.dart (9 hints)
  • lib/src/diff.dart (9 hints)
  • bin/src/library_size_split.dart (7 hints)
  • lib/deferred_library_check.dart (7 hints)
  • bin/src/code_deps.dart (6 hints)
  • lib/src/string_edit_buffer.dart (6 hints)
  • bin/src/function_size_analysis.dart (5 hints)
  • lib/src/util.dart (5 hints)
  • bin/src/text_print.dart (4 hints)
  • lib/src/table.dart (4 hints)
  • bin/src/convert.dart (3 hints)
  • bin/src/deferred_library_size.dart (3 hints)
  • bin/src/to_json.dart (3 hints)
  • bin/src/to_proto.dart (3 hints)
  • bin/src/deferred_library_layout.dart (2 hints)
  • bin/src/to_binary.dart (2 hints)
  • lib/src/io.dart (2 hints)
  • bin/src/deferred_library_check.dart (1 hint)
  • bin/src/inject_text.dart (1 hint)
  • bin/src/live_code_size_analysis.dart (1 hint)
  • bin/src/show_inferred_types.dart (1 hint)

Maintenance issues and suggestions

Support latest dependencies. (-10 points)

The version constraint in pubspec.yaml does not support the latest published versions for 1 dependency (protobuf).

Maintain an example. (-10 points)

Create a short demo in the example/ directory to show how to use this package.

Common filename patterns include main.dart, example.dart, and dart2js_info.dart. Packages with multiple examples should provide example/README.md.

For more information see the pub package layout conventions.

Dependencies

Package Constraint Resolved Available
Direct dependencies
Dart SDK >=2.0.0-dev.17.0 <3.0.0
args ^1.4.3 1.5.2
charcode ^1.1.0 1.1.2
collection ^1.10.1 1.14.12
fixnum ^0.10.5 0.10.11
path ^1.3.6 1.6.4
protobuf ^0.10.0 0.10.8 1.0.1
quiver >=0.29.0 <3.0.0 2.1.2+1
shelf ^0.7.3 0.7.5
shelf_static ^0.2.4 0.2.8
yaml ^2.1.0 2.2.0
Transitive dependencies
async 2.4.0
convert 2.1.1
http_parser 3.1.3
matcher 0.12.6
meta 1.1.8
mime 0.9.6+3
source_span 1.5.5
stack_trace 1.9.3
stream_channel 2.0.0
string_scanner 1.0.5
term_glyph 1.1.0
typed_data 1.1.6
Dev dependencies
test ^1.2.0