Skip to content

Conversation

@cdamus
Copy link
Contributor

@cdamus cdamus commented Oct 13, 2025

Define a new Frontend API class that encapsulates the Perfetto UI initialization logic with sufficient factorization of the start-up sequence to allow an embedding application to override and customize the Perfetto UI behavior. This includes hooks to override/customize capabilities such as:

  • adjust routing to work with applications that use hashes already for their own incompatible routing requirements
  • customization of the content security policy
  • allow to control cache keys for browser restrictions on caching
  • allow file CORS origins for desktop-style applications
  • scope key handling to the viewer page so that it doesn't get key events from other UI elements in the host application
  • current script is null also in some embedder apps, not just in tests, so allow an application to set its own assets root URL
  • suppressing the dialog that prompts to open a trace already loaded in the trace_processor_shell, for apps that manage this a priori
  • suppressing registration of error handlers. An embedding application often has its own error handling

Additionally, in support of incorporating the build output into another application's packaging:

  • make @types/mithril a dev dependency
  • remove unused dependencies from package.json

Fixes #2266

Define a new Frontend API class that encapsulates the Perfetto UI
initialization logic with sufficient factorization of the start-up
sequence to allow an embedding application to override and customize
the Perfetto UI behavior. This includes hooks to override/customize
capabilities such as:

- adjust routing to work with applications that use hashes already
  for their own incompatible routing requirements
- customization of the content security policy
- allow to control cache keys for browser restrictions on caching
- allow file CORS origins for desktop-style applications
- scope key handling to the viewer page so that it doesn't get key
  events from other UI elements in the host application
- current script is null also in some embedder apps, not just in tests,
  so allow an application to set its own assets root URL
- suppressing the dialog that prompts to open a trace already loaded
  in the trace_processor_shell, for apps that manage this a priori
- suppressing registration of error handlers. An embedding
  application often has its own error handling

Additionally, in support of incorporating the build output into another
application's packaging:

- make @types/mithril a dev dependency
- remove unused dependencies from package.json

Fixes google#2266

Co-authored-by: Johannes Faltermeier <[email protected]>
Co-authored-by: Martin Fleck <[email protected]>
Co-authored-by: Warren Paul <[email protected]>
Co-authored-by: Daniel Friederich <[email protected]>
Co-authored-by: Andrew Levans <[email protected]>
Signed-off-by: Christian W. Damus <[email protected]>
@cdamus
Copy link
Contributor Author

cdamus commented Oct 13, 2025

Hi @stevegolton this is a new PR to supersede #2267, as promised.

This new approach reworks the current frontend/index.ts script as an API class named Frontend that can be specialized by embedding applications to alter the core application behaviours of the Perfetto UI. Overall I think it's a cleaner solution as it doesn't require any components of the UI to reach into the ether for a magical context object that may or may not exist. A few tweaks are separately injected into modules that currently don't provide API objects (notably as cache_manager.ts and http_utils.ts.

This new PR works well for my application, in conjunction with the several others currently proposed in other PRs, including:

I hope this is closer to the kind of approach you're looking for. Any and all suggestions for improvement are, of course, welcome. Including further refactorings that this may inspire and/or breakdown into smaller incremental changes as feasible. I do understand that this is a significant change that bears some risk and effort to review.

@stevegolton stevegolton self-requested a review October 22, 2025 14:34
@stevegolton
Copy link
Member

Hi @cdamus, apologies again for the delay. Thanks for adding a doc and a thorough description - I'll aim to take a proper look through this tomorrow.

Copy link
Member

@stevegolton stevegolton left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So I've taken a look through the PR. It's definitely an improvement, however what I had in mind explicit configuration through data rather than implicit configuration through code execution.

What I was thinking was this: break off a minimal kernel of functionality that works for embedded and standalone applications, which can be configured with a simple configuration object that provides config and callbacks for customization.

An utterly minimal example might look something like this:

// No config options - a lot of functionality is stubbed
const app = createPerfettoApp();

// Render the main component, injecting the configured app
m.render(targetElement, m(Perfetto, {app}))

Our index.ts will inject all the adapters that communicate with the browser's APIs:

// Configure the app with data and callbacks
const app = createPerfettoApp({
  locationAdapter: {
    getLocation: () => window.location.href,
    navigate: () => ...,
  },
  cacheKey: 'my-cache-key',
  ... etc ...
});

// Register extra settings that only make sense in standalone mode
const setting = app.settings.register({...theme setting...});

// Mount and maybe add some more wrapper components for theming etc
m.mount(targetElement, {
  view: function() {
    return m(ThemeProvider, {theme: setting.get()},
      m(Perfetto, {app}),
    );
  }
});

Yours can configure as you need for your embedded usecase.

To be clear, this is a massively invasive refactor and by no means a small task, and ultimately achieves the same thing as your PR just arranged slightly differently and in my opinion is clearer, though feel free to disagree with me here.

I have some time allocate to work on this this quarter. I suggest breaking it up into smaller chunks might also be a good idea, but we can work together.

I think this might be a good opportunity to test out our new RFC process too, I'll start one next week and we can start getting feedback.


Suppose you have an application integrating Perfetto:

```typescript
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you share your Frontend implementation? I'd be interested to see what parts of the code you override and what you keep. In essence, it'd be interesting to see what your embeddability requirements are so I can get a better understanding of your challenges.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My application is not open-source so I cannot post code here, but perhaps there are other ways. I shall follow that up.

At any rate, we do customize every one of the extension points currently defined in the Frontend class (and previously in the EmbedderContext) as otherwise they wouldn't be defined. And for the most part the customizations address three peculiarities of our application as compared to the SPA deployment of Perfetto UI:

  • our application is a developer workbench, deployable either as an Electron application (primary target) or as a browser application accessing shared developer workspaces on a server. Interactions with the browser window — especially dealing with location, navigation, and messaging — are different to how an SPA like Perfetto UI would operate and they are the responsibility of the framework on which our application is built
  • our application loads the data from trace files into a number of different views for different analytical purposes, one of which is the Perfetto UI's timeline viewer. Consequently, we load the trace into the trace processor (shell or WASM) a priori, so none of Perfetto UI's trace opening or closing flows apply, including the dialog that detects a running trace processor shell
  • our application loads any number of traces without requiring the user close any of them, especially to enable side-by-side comparison. As the framework on which this application is implemented operates within a single browser window, we do not rely on browser windows or tabs to isolate the timeline viewers from one another

@cdamus
Copy link
Contributor Author

cdamus commented Oct 27, 2025

So I've taken a look through the PR. It's definitely an improvement, however what I had in mind explicit configuration through data rather than implicit configuration through code execution.

Thanks @stevegolton As always, much appreciated.

What I was thinking was this: break off a minimal kernel of functionality that works for embedded and standalone applications, which can be configured with a simple configuration object that provides config and callbacks for customization.

An utterly minimal example might look something like this:

OK, so the same extension points as in the Frontend class except packaged as new parameters for the AppImpl? One thing that I'm not sure about is how many of these extension points are actually reachable from the AppImpl currently. Some of them are in frontend/index.ts and others are in peers of AppImpl that it doesn't already depend on. I may be overthinking that and I would be happy to explore another prototype to see how it shakes out. Perhaps pending further discussion per below.

To be clear, this is a massively invasive refactor and by no means a small task, and ultimately achieves the same thing as your PR just arranged slightly differently and in my opinion is clearer, though feel free to disagree with me here.

Yes this was clear from the start that big change would be implicated. My application has needs that an SPA quite rightly does not. I appreciate all that you've done so far!

I have some time allocate to work on this this quarter. I suggest breaking it up into smaller chunks might also be a good idea, but we can work together.

I think this might be a good opportunity to test out our new RFC process too, I'll start one next week and we can start getting feedback.

An RFC process is a happy development! This does seem like a subject that will benefit from such a process, even if (perhaps especially if) there are no other applications like mine that are looking to integrate Perfetto UI in this way.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ui: rich support for embedding Perfetto UI in other applications

2 participants