Browser Components is the project of continuing to modularize the Chrome codebase. A large project to extract the content module out of the src/chrome/ directory is complete. Despite the efforts of this project, the src/chrome/ directory remains by far the largest inter-dependent block of code in the codebase, so continuing to tease the next largest modules out of that directory is the next step.
The Chrome project has grown a lot over the last few years in both size and complexity. The number of people contributing to the project has increased a lot, the size of the codebase has increased, and we have added many new target platforms and configurations that were not envisioned in the start. It has also become harder for individuals to understand the whole of the architecture, let alone the whole of the codebase.
The Browser Components project is introducing and enforcing modularity, with these objectives in mind:
A: Extracting bits of src/chrome/ into components that are each individual targets, have a separate unit test target, specify their dependencies on each other explicitly, and have no cyclic dependencies.
Q: What do you mean, components that have no cyclic dependencies?
A: They know nothing about their embedder (e.g., src/chrome/). If they need information or services from their embedder they either receive them at initialization time, or retrieve them at runtime via an abstract client interface defined by the component and implemented by the embedder.
Q: What if one component wants to depend on another?
A: It can. However, such dependencies must be acyclic. This precludes the possibility of dependency cycles between two (or any N) components.
Q: Do we want to componentize UI?
A: Not in the sense described above. However, it is fine for components to contain portions of code related to UI. In general, however, components should not bake UI into their core logic in order to allow embedders the freedom to reuse logic while providing their own UI. The UI that components contain should be made available to embedders as optional "add-ons" to the core logic.
Q: What if I’m evaluating some code for componentization and I see that it has dependencies that are currently implemented by the rest of src/chrome/?
A: Usually, that means we first need to componentize those dependencies. There are two exceptions:
Q: Where do components live?
A: In a subdirectory of src/components/, e.g. a component named foo would be contained in the directory src/components/foo/.
Q: Where do components’ client interfaces live?
A: Their declaration lives in the same directory as the component. Their embedder-specific implementation lives in each embedder, wherever the embedder chooses.
Q: Do components provide an API for the embedder to use?
A: Generally speaking, it is fine for the embedder to use the component as a concrete set of C++ classes, in which case the “API” is simply whatever the “entry point” classes are, where the component receives pointers to implementations of its delegate interfaces from its embedder. In certain cases, we may decide to introduce a fully-abstract API for the embedder to use, that hides implementation details of the component, as we did for src/content/. In certain other cases, we might categorize the component’s concrete C++ classes into an internal set and a publicly-usable set. In either of these cases, the API or publicly-usable set of classes should reside in a subdirectory of the component’s directory named public (e.g. src/components/mycomponent/public/). If a public directory is present, the component’s client interfaces should live within that directory.
Q: Is there any further standardization of the structure within a component’s directory?
A: Some components that depend on the src/content/ layer may have bits of code intended to run in different processes of the embedder, e.g. browser or renderer. The convention for these is to place the code in sub-directories with names matching those already used in src/chrome/, so for a component xyz you might have src/components/xyz/browser/ and src/components/xyz/renderer/ directories.
Q: Is this like Microsoft COM or Mozilla XPCOM?
A: No. It is a non-goal to create binary reusable components similar to Microsoft’s COM or Mozilla’s XPCOM mechanisms. We expect the components we are introducing, and all users of the components, to live in a single codebase and be built together, so we do not need complicated registration and discovery mechanisms, or to limit ourselves exclusively to APIs that are pure vtables.
For a step-by-step guide and cookbook-style recipes on how to componentize, see the Browser Components Cookbook.
The content module (
Smaller examples that illustrate how to componentize can be seen in the work done to implement the following issues:
We have also extended DEPS to allow generation of a visual graph of components and their dependencies. This is helpful when trying to find appropriate “leaves” in the dependency graph under src/chrome/, that make for good next things to componentize.
We have surveyed the available automatic refactoring tools for C++; the brief conclusions are:
We also have a tool for doing search-and-replace across the codebase using Python regular expression syntax; see src/tools/git/mffr.py.
We highly encourage the usage of "git cl format" to ease the tedious process of reformatting that often needs to occur when doing refactorings.
Because the Chrome codebase changes so rapidly, we know from prior experience that all of the above needs to be done using rapid-fire incremental changes. The ability to get quick code reviews from multiple owners and, in many cases, the ability to TBR the trivial parts of changes with wide impact, will be key. In many cases the leaders of the componentization effort are made temporary owners of a feature for the duration of its componentization.
Colin Blundell <firstname.lastname@example.org> is leading the effort. Other full-time members are David Roger <email@example.com>, Jean-François Geyelin <firstname.lastname@example.org>, and Sylvain Defresne <email@example.com>. The current goal of the project is to componentize all of the features under //chrome that are used by the iOS port. If you're interested in helping (no contribution is too small!), reach out to firstname.lastname@example.org and/or have a list at available work that is suitable for anyone generally familiar with Chromium to handle. Be sure to mark a bug Started if you're starting work on it!
[following text is out-of-date but retained for historical purposes] The project started in mid-Q3 2012. Our expectation is that we can put at least a man-year or two of fast and furious work into this project before reaching diminishing returns. We will re-evaluate quarterly, involving the Chrome TLs in the discussion. We will also attempt to set quarterly goals that fulfill shorter-term needs while driving us forward on our longer-term goals (e.g. for Q4 2012 we have a goal to help the Android WebView folks reuse functionality from Chrome without depending on anything under src/chrome/).
While a full risk analysis has not yet been done, there are a couple of obvious risks: