-
Notifications
You must be signed in to change notification settings - Fork 616
ui: encapsulate Perfetto UI start-up in a new API class #3275
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
base: main
Are you sure you want to change the base?
Conversation
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]>
|
Hi @stevegolton this is a new PR to supersede #2267, as promised. This new approach reworks the current 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. |
|
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. |
stevegolton
left a comment
There was a problem hiding this 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 |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
Thanks @stevegolton As always, much appreciated.
OK, so the same extension points as in the
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!
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. |
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:
Additionally, in support of incorporating the build output into another application's packaging:
Fixes #2266