Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial docs for app profiling #1075

Merged
merged 8 commits into from
May 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 34 additions & 33 deletions src/features/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,47 +79,48 @@ parcel

These parameters are supported by all Parcel commands.

| Format | Description |
| -------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
| `--target [name]` | Specifies the targets to build. May be specified multiple times. See [Targets](/features/targets/). |
| `--dist-dir <dir>` | Output directory to write to when unspecified by targets. <br> Default value for the [`distDir`](/features/targets/#distdir) option in package.json `targets`. |
| `--public-url <url>` | The path prefix for absolute urls. <br> Default value for the [`publicUrl`](/features/targets/#publicurl) option in package.json `targets`. |
| `--no-source-maps` | Disables sourcemaps, <br> Overrides the [`sourceMap`](/features/targets/#sourcemap) option in package.json `targets`. |
| Format | Description |
| -------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `--target [name]` | Specifies the targets to build. May be specified multiple times. See [Targets](/features/targets/). |
| `--dist-dir <dir>` | Output directory to write to when unspecified by targets. <br> Default value for the [`distDir`](/features/targets/#distdir) option in package.json `targets`. |
| `--public-url <url>` | The path prefix for absolute urls. <br> Default value for the [`publicUrl`](/features/targets/#publicurl) option in package.json `targets`. |
| `--no-source-maps` | Disables sourcemaps, <br> Overrides the [`sourceMap`](/features/targets/#sourcemap) option in package.json `targets`. |
| `--config <path>` | Specify which Parcel config to use. <br> Can be a file path or package name. Defaults to `@parcel/config-default`. See [Parcel configuration](/features/plugins/). |
| `--reporter <package name>` | Run the specified reporter plugin in addition to the ones specified in the `.parcelrc`. Can be specified multiple times. |
| `--log-level (none/error/warn/info/verbose)` | Sets the log level. |
| `--cache-dir <path>` | Sets the cache directory. Defaults to `.parcel-cache`. See [Caching](/features/development/#caching).
| `--no-cache` | Disables reading from the filesystem cache. See [Caching](/features/development/#caching). | |
| `--profile` | Profiles the build (a flamechart can be generated). |
| `-V, --version` | Outputs the version number. |
| `--reporter <package name>` | Run the specified reporter plugin in addition to the ones specified in the `.parcelrc`. Can be specified multiple times. |
| `--log-level (none/error/warn/info/verbose)` | Sets the log level. |
| `--cache-dir <path>` | Sets the cache directory. Defaults to `.parcel-cache`. See [Caching](/features/development/#caching). |
| `--no-cache` | Disables reading from the filesystem cache. See [Caching](/features/development/#caching). |
| `--profile` | Runs a CPU Sampling profile during the build (a flamechart can be generated). |
| `--trace` | Runs a [trace](/features/profiling) during the build. |
| `-V, --version` | Outputs the version number. |

### Parameters specific to `serve` and `watch`

| Format | Description |
| ------------------- | ------------------------------------------------------------------------------------- |
| `-p, --port <port>` | The port for the dev server and HMR (the default port is `process.env.PORT` or 1234). See [Dev server](/features/development/#dev-server). |
| `--host <host>` | Sets the host to listen on, defaults to listening on all interfaces |
| `--https` | Runs the dev server and HMR server over [HTTPS](/features/development/#https). |
| `--cert <path>` | Path to a certificate to use. See [HTTPS](/features/development/#https). |
| `--key <path>` | Path to a private key to use. See [HTTPS](/features/development/#https). |
| `--no-hmr` | Disables [hot reloading](/features/development/#hot-reloading). |
| `--hmr-port <port>` | The port for the HMR server (defaults to the dev server's port). See [Hot reloading](/features/development/#hot-reloading).
| `--hmr-host <host>` | The host for the HMR server (defaults to the dev server's host). See [Hot reloading](/features/development/#hot-reloading). |
| `--no-autoinstall` | Disables [auto install](/features/development/#auto-install). |
| `--watch-for-stdin` | Stop Parcel once stdin is closed. |
| Format | Description |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
| `-p, --port <port>` | The port for the dev server and HMR (the default port is `process.env.PORT` or 1234). See [Dev server](/features/development/#dev-server). |
| `--host <host>` | Sets the host to listen on, defaults to listening on all interfaces |
| `--https` | Runs the dev server and HMR server over [HTTPS](/features/development/#https). |
| `--cert <path>` | Path to a certificate to use. See [HTTPS](/features/development/#https). |
| `--key <path>` | Path to a private key to use. See [HTTPS](/features/development/#https). |
| `--no-hmr` | Disables [hot reloading](/features/development/#hot-reloading). |
| `--hmr-port <port>` | The port for the HMR server (defaults to the dev server's port). See [Hot reloading](/features/development/#hot-reloading). |
| `--hmr-host <host>` | The host for the HMR server (defaults to the dev server's host). See [Hot reloading](/features/development/#hot-reloading). |
| `--no-autoinstall` | Disables [auto install](/features/development/#auto-install). |
| `--watch-for-stdin` | Stop Parcel once stdin is closed. |

### Parameters specific to `serve`

| Format | Description |
| ------------------ | ------------------------------------------------------------------------------ |
| Format | Description |
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------ |
| `--open [browser]` | Automatically opens the entry in your browser. Defaults to the default browser. See [Dev server](/features/development/#dev-server). |
| `--lazy` | Only builds bundles requested by the dev server. See [Lazy mode](/features/development/#lazy-mode). |
| `--lazy` | Only builds bundles requested by the dev server. See [Lazy mode](/features/development/#lazy-mode). |

### Parameters specific to `build`

| Format | Description |
| --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `--no-optimize` | Disables optimizations such as minification. <br> Overrides the [`optimize`](/features/targets/#optimize) option of package.json `targets`. See [Production](/features/production/). |
| `--no-scope-hoist` | Disables scope hoisting. <br> Overrides the [`scopeHoist`](/features/targets/#scopehoist) option of package.json `targets`. See [Scope hoisting](/features/scope-hoisting/).
| `--no-content-hash` | Disables content hashing of output file names. <br> Bundle names may still include hashes, but they will not change on each build. See [Content hashing](/features/production/#content-hashing). | |
| `--detailed-report [depth]` | Displays the largest 10 (number configurable with `depth`) assets per bundle in the CLI report. See [Detailed report](/features/production/#detailed-report). |
| Format | Description |
| --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `--no-optimize` | Disables optimizations such as minification. <br> Overrides the [`optimize`](/features/targets/#optimize) option of package.json `targets`. See [Production](/features/production/). |
| `--no-scope-hoist` | Disables scope hoisting. <br> Overrides the [`scopeHoist`](/features/targets/#scopehoist) option of package.json `targets`. See [Scope hoisting](/features/scope-hoisting/). |
| `--no-content-hash` | Disables content hashing of output file names. <br> Bundle names may still include hashes, but they will not change on each build. See [Content hashing](/features/production/#content-hashing). |
| `--detailed-report [depth]` | Displays the largest 10 (number configurable with `depth`) assets per bundle in the CLI report. See [Detailed report](/features/production/#detailed-report). |
5 changes: 2 additions & 3 deletions src/features/plugins.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ title: Plugins
eleventyNavigation:
key: features-plugins
title: 🔌 Plugins
order: 11
order: 12
---

Parcel works out of the box for many projects with zero configuration. But if you want more control, or need to extend or override Parcel’s defaults, you can do so by creating a `.parcelrc` file in your project.
Expand Down Expand Up @@ -375,7 +375,7 @@ If `"..."` is omitted, your namer must be able to handle naming all bundles or t
"compressors": {
"*.{js,html,css}": [
"...",
"@parcel/compressor-gzip",
"@parcel/compressor-gzip",
"@parcel/compressor-brotli"
]
}
Expand Down Expand Up @@ -486,4 +486,3 @@ In your root package.json, you can define a dependency on the `parcel-transforme
{% endsample %}

Then, in your `.parcelrc` you can reference `parcel-transformer-foo` as you would a published package. Whenever you update the code for your plugin, Parcel will rebuild your project.

109 changes: 109 additions & 0 deletions src/features/profiling.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
---
layout: layout.njk
title: Profiling and tracing
eleventyNavigation:
key: features-profiling
title: 📈 Profiling and tracing
order: 11
---

## Tracing

CPU profiling or sampling profiling generates a profile which tracks execution of JavaScript during the build, and can be used to identify parts of the codebase and where time was spent in it during the build. Tracing is a higher level profile, that tracks specific phases of Parcel's execution, which plugins were called into, and how long is spent in each.

A Parcel trace can help you to optimize your build by answering questions such as, "Which plugin is taking the most time during my build?" or "Which file in my project takes the longest to transform?". These questions are not as easy to answer with the data provided by a CPU sampling profile, but can be answered with a Parcel trace.

The overhead of running a trace is relatively minimal, but is non-zero - it's certainly less expensive than running a sampling profile during the build. In particular, the JSON file produced can be quite large depending on the numbers of plugins you are using and the size of your build. Consider these factors when deciding when to enable tracing.

### Usage

#### CLI

To generate a trace with the CLI, start Parcel with the `--trace` CLI argument. Parcel will generate a [trace JSON](#format) file in the root of your project. Parcel will log the filename it is writing the trace to when the build starts.

#### API

To generate a trace when using the API, you must pass `shouldTrace: true` with the Parcel options in order to enable the tracing events. In addition, you will need to add the tracer reporter via `additionalReporters` to have Parcel create the trace JSON file. For example:

```js
import {Parcel} from '@parcel/core';

let bundler = new Parcel({
// ...
shouldTrace: true,
additionalReporters: [{
packageName: '@parcel/reporter-tracer',
resolveFrom: __dirname,
}],
});
```

### Format

The tracing JSON file uses the [Chrome Tracing Format](https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/preview), similar to CPU profiles, but analysing it is a little bit different.

The Parcel trace consists only of type `X` Complete Events. The raw events look like this:

```json
{"ts":6020131,"pid":11738,"tid":4,"ph":"X","name":"@parcel/transformer-js","cat":"transform","args":{"name":"src/index.html"},"dur":11642},
```

### Analysing traces

While you can load a Parcel trace into Chrome Dev Tools, the analysis options for this kind of profile in that tool is fairly limited. This is because the data is not typical data that Dev Tools is designed for. The trace events, for example, contain metadata that can be useful for deeper analysis and this metadata is not accessible through Dev Tools. In addition, a medium to large sized build may produce a volume of data that is not feasible to load into Chrome Dev Tools due to it's size.

The recommended tool for analysing Parcel traces is [Perfetto](https://ui.perfetto.dev/), which is also built by Google, but specifically designed for dealing with large traces, and non-browser traces. In particular, the most useful part of Perfetto for analysing these traces is that it loads the data into an [SQLite](https://www.sqlite.org/index.html) database that can be queried via the UI - this allows us to answer the kinds of questions that were mentioned earlier.

#### Example queries

Here are some example queries you can enter into the "Query (SQL)" function in Perfetto to generate some useful statistics about your Parcel builds. Keep in mind that the durations in these results are total sampled time - given Parcel's multi-threaded implementation, some of these total times may exceed the wall time of your Parcel build.

##### What is the breakdown of my build by phase?

This is a high level query that provides a breakdown by the main phases of your build - building, bundling, packaging - and can help to identify at a high level if any particular phase stands out as taking longer than expected.

```sql
select
name, SUM(CAST(dur AS double)/1000/1000) as dur_ms
from
slice s
where
s.category = "Core"
group by name
order by dur_ms desc
```

##### What are the plugins in my build that take the most time?

This can be useful to identify at a high level which plugins Parcel spends the most time in. While some of these are going to be core plugins, in a build where you are using custom plugins, or other third-party plugins, this can be a useful query to identify if any of these plugins stand out as taking an unexpected amount of time - which can be useful for identifying optimisation opportunities.

```sql
select
s.category, name, SUM(CAST(dur AS double)/1000/1000) as dur_ms
from
slice s
left join
args using(arg_set_id)
where
args.flat_key = "args.name"
group by s.category, name
order by dur_ms desc
```

##### Which Babel plugins are ones are taking the most time in my build?

This can be useful to identify which Babel plugins that are still needed in your build, and executed by `@parcel/transform-babel`, take the most time and so can be prioritised to be removed or replaced with Parcel transforms.

```sql
select
name, SUM(CAST(dur AS double)/1000/1000) as dur_ms
from
slice s
left join
args using(arg_set_id)
where
args.flat_key = "args.name" AND
s.category LIKE "transform:@parcel/transformer-babel%"
group by name
order by dur_ms desc
```