## Summary
Fix https://github.com/elastic/kibana/issues/89340
Implements a third option, `system`, for the `theme:darkMode`
uiSettings, which will follow the system's theme preference (light/dark)
when Kibana loads.
82078697-8bf5-41df-add1-4ecfed6e1dea
**Note: system theme refresh still requires the user to reload Kibana -
please see the next section for the reasons if you're interested**
## How theming works in Kibana, again?
This is an excellent question, thanks for asking. And the answer is,
"well, it's complicated".
We have multiples sources of "themed" styles in Kibana, ordered from
"best" to "worse":
#### 1. the EUI/JSS Theming
It was initially implemented in
https://github.com/elastic/kibana/pull/117368. All react applications
and react mountpoints are supposed to be wrapped by a
`KibanaThemeProvider` that bridges core's `theme$` values to the
`EuiProvider`.
477505a2dd/packages/core/theme/core-theme-browser-internal/src/core_theme_provider.tsx (L11)
This one was already dynamic and just works perfectly. If
`core.theme.theme$` changes, the new values is received by the theme
provider, which automatically changes the styles accordingly, creating
this sexy "it just works" effect:
f3e61ca7-f3ed-4c37-aa46-76ee68c1a628
If everything theme-related was using this approach, dynamic theme
reload would have been possible. However, Kibana has a lot of legacy, so
as you can imagine, it wasn't that easy.
So, **don't get false hopes** (as I did when I tried it...) from this
video. Dynamic theme swap **could not** be implemented in this PR. And
the reasons are just below.
#### 2. Per-theme css files
6443b57164/packages/core/rendering/core-rendering-server-internal/src/render_utils.ts (L40-L54)
We have a bunch of dark/light variations of some css files that are
computed in the rendering service, server-side, to be injected into the
page template.
Of course, this doesn't play well with dynamic theming, given the UI
then doesn't know which css should be swapped, and which one should be
added instead.
However, porting the responsibilities of which theme css files to load
to the browser was achievable, and done in this PR. core's browser-side
`theme` provider now receives the list of theme files for both light and
dark theme (via the injected metadata), and inject them in the document
(instead of having them pre-injected in the page template by the
rendering service server-side).
So this one wasn't a blocker for dynamic theme reload.
#### 3. Plugin styles
This is where the problems start.
Plugins can ship their own styles too, by importing them from components
or from their entrypoint.
E.g this component
f1dc1e1869/src/plugins/controls/public/control_group/component/control_group_component.tsx (L9)
importing this file:
bafb23580b/src/plugins/controls/public/control_group/control_group.scss (L107-L110)
Which relies on a theme variable, `$euiFormBackgroundColor`
So how does it works under the hood? How is that
`$euiFormBackgroundColor` variable interpolated? Using which theme?
Well, technically, how the styles are effectively loaded differs
slightly between dev and production (different webpack loaders/config),
but in both cases, it depends on the `__kbnThemeTag__` variable that is
injected to the global scope by the `bootstrap.js` script.
This `__kbnThemeTag__` tag (apparently) **can** be modified after page
load. However it doesn't magically reload everything, so styles already
loaded for one theme will not reload. If a component and its imported
styles were already compiled / injected, then they won't reload
As a short video is better than 3 blocks of text, just see:
3087ffd6-80d8-42bf-ab17-691ec408ea6f
That was the first blocker for supporting "dynamic" reloads of the
system theme.
#### 4. Static inline styles
Last but not least, we have some static style injected in the template,
that also depend on the current theme.
6443b57164/packages/core/rendering/core-rendering-server-internal/src/views/styles.tsx (L52-L54)
Of course this plays very badly with dynamic theming. And worth noting,
those styles are used by the "Loading Elastic" screen, where Core (and
therefore Core's theming service) isn't loaded yet, which made the
things even more complicated.
This was the second blocker for supporting "dynamic" reloads of the
system theme.
#### 5. `euiThemeVars`
Actually TIL (not that I was asking for it)
We're exposing the EUI theme variable via the `euiThemeVars` of the
`@kbn/ui-theme` package:
E.g.
c7e785383a/src/plugins/chart_expressions/expression_metric/public/components/metric_vis.tsx (L41)c7e785383a/src/plugins/chart_expressions/expression_metric/public/components/metric_vis.tsx (L50)
So I did my best, and made it that this export was a proxy, and that
Core's theme service was dynamically swapping the target of the proxy
depending on the system's theme...
b0a0017811/packages/kbn-ui-theme/src/theme.ts (L30-L42)
Unfortunately it doesn't fully work for dynamic system theme switch,
given modules/code can keep references of the property directly (e.g.
the snippet a few lines on top), and there's nothing to dynamically
reload components when the proxy changes.
So yet another blocker for dynamic theme switch.
## Release Notes
Add a new option, `system`, to the `theme:darkMode` Kibana advanced
setting, that can be used to have Kibana's theme follow the system's
(light or dark)
---------
Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
## Dearest Reviewers 👋
I've been working on this branch with @mistic and @tylersmalley and
we're really confident in these changes. Additionally, this changes code
in nearly every package in the repo so we don't plan to wait for reviews
to get in before merging this. If you'd like to have a concern
addressed, please feel free to leave a review, but assuming that nobody
raises a blocker in the next 24 hours we plan to merge this EOD pacific
tomorrow, 12/22.
We'll be paying close attention to any issues this causes after merging
and work on getting those fixed ASAP. 🚀
---
The operations team is not confident that we'll have the time to achieve
what we originally set out to accomplish by moving to Bazel with the
time and resources we have available. We have also bought ourselves some
headroom with improvements to babel-register, optimizer caching, and
typescript project structure.
In order to make sure we deliver packages as quickly as possible (many
teams really want them), with a usable and familiar developer
experience, this PR removes Bazel for building packages in favor of
using the same JIT transpilation we use for plugins.
Additionally, packages now use `kbn_references` (again, just copying the
dx from plugins to packages).
Because of the complex relationships between packages/plugins and in
order to prepare ourselves for automatic dependency detection tools we
plan to use in the future, this PR also introduces a "TS Project Linter"
which will validate that every tsconfig.json file meets a few
requirements:
1. the chain of base config files extended by each config includes
`tsconfig.base.json` and not `tsconfig.json`
1. the `include` config is used, and not `files`
2. the `exclude` config includes `target/**/*`
3. the `outDir` compiler option is specified as `target/types`
1. none of these compiler options are specified: `declaration`,
`declarationMap`, `emitDeclarationOnly`, `skipLibCheck`, `target`,
`paths`
4. all references to other packages/plugins use their pkg id, ie:
```js
// valid
{
"kbn_references": ["@kbn/core"]
}
// not valid
{
"kbn_references": [{ "path": "../../../src/core/tsconfig.json" }]
}
```
5. only packages/plugins which are imported somewhere in the ts code are
listed in `kbn_references`
This linter is not only validating all of the tsconfig.json files, but
it also will fix these config files to deal with just about any
violation that can be produced. Just run `node scripts/ts_project_linter
--fix` locally to apply these fixes, or let CI take care of
automatically fixing things and pushing the changes to your PR.
> **Example:** [`64e93e5`
(#146212)](64e93e5806)
When I merged main into my PR it included a change which removed the
`@kbn/core-injected-metadata-browser` package. After resolving the
conflicts I missed a few tsconfig files which included references to the
now removed package. The TS Project Linter identified that these
references were removed from the code and pushed a change to the PR to
remove them from the tsconfig.json files.
## No bazel? Does that mean no packages??
Nope! We're still doing packages but we're pretty sure now that we won't
be using Bazel to accomplish the 'distributed caching' and 'change-based
tasks' portions of the packages project.
This PR actually makes packages much easier to work with and will be
followed up with the bundling benefits described by the original
packages RFC. Then we'll work on documentation and advocacy for using
packages for any and all new code.
We're pretty confident that implementing distributed caching and
change-based tasks will be necessary in the future, but because of
recent improvements in the repo we think we can live without them for
**at least** a year.
## Wait, there are still BUILD.bazel files in the repo
Yes, there are still three webpack bundles which are built by Bazel: the
`@kbn/ui-shared-deps-npm` DLL, `@kbn/ui-shared-deps-src` externals, and
the `@kbn/monaco` workers. These three webpack bundles are still created
during bootstrap and remotely cached using bazel. The next phase of this
project is to figure out how to get the package bundling features
described in the RFC with the current optimizer, and we expect these
bundles to go away then. Until then any package that is used in those
three bundles still needs to have a BUILD.bazel file so that they can be
referenced by the remaining webpack builds.
Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
* [packages] add kibana.jsonc files
* auto-migrate to kibana.jsonc
* support interactive pkg id selection too
* remove old codeowners entry
* skip codeowners generation when .github/CODEOWNERS doesn't exist
* fall back to format validation if user is offline
* update question style
* [CI] Auto-commit changed files from 'node scripts/eslint --no-cache --fix'
Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
* refact(NA): apply root_input_dir=src to each already created pkg
* refact(NA): update package generator
* fix(NA): correctly use rootDir
* fix(NA): use root input dir on latest introduced pkgs for jsts_transpiler macro
* chore(NA): merge with main
Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
* [type-summarizer] reimplement for broader support
* Enable sourceMaps in all packages
* include naming collision in summarizePackage test
* fix readmes
* remove unnecessary transient dependency
* remove code that was commented out
* remove outdated todo comment
* ensure errors triggered by untyped-exports are ligible
* remove unused import
* break out snippet generation from AstIndexer
* refactor several massive files into smaller pieces and add more inline docs
* fix typos
* update jest snapshots
* add sections to readme that points people to the useful parts of the source code along with a high-level overview of how the type-summarizer works
* remove --dump flag, it doesn't work
* use decName instead of calling names.get a second time
* include `export` as invalid name