feat(v2): add ThemedImage component#3730
Conversation
|
Deploy preview for docusaurus-2 ready! Built with commit 80309ca |
| } | ||
| } | ||
|
|
||
| export default ThemedImage; |
There was a problem hiding this comment.
This component will only render one image (the light one) on the other on server-rendered markup.
See useTheme hook:
const getInitialTheme = () => {
if (!ExecutionEnvironment.canUseDOM) {
return themes.light; // SSR: we don't care
}
return coerceToTheme(document.documentElement.getAttribute('data-theme'));
};On hydration, the light image will be replaced with the dark one, producing an unwanted flash.
The only viable solution to fix the problem is to always render the 2 images, and display one or the other thanks to CSS (which is loaded before the user actually see anything, so there's no flash)
img.themed-image{
display: none;
}
html[data-theme='light'] img.themed-image.themed-image--light {
display: block;
}
html[data-theme='dark'] img.themed-image.themed-image--dark {
display: block;
}Note: it's worth considering that light/dark is common nowadays but the CSS spec says this might be expanded to more values in the future. Having an API surface that is more extensible could be more future-proof (ie user can declare its own theme name, we should rather have sources={dark: darkSrc,light:lightSrc,sepia: sepiaSrc})
slorber
left a comment
There was a problem hiding this comment.
I think it would produce an hydration flash.
Can you add an example somewhere so that we can see it in action in deploy previews? (there an example md page if you want)
You can find the example in the added section on the Markdown Features page. |
| readonly darkSrc?: string; | ||
| } & ComponentProps<'img'>; | ||
|
|
||
| const ThemedImage: () => JSX.Element; |
There was a problem hiding this comment.
shouldn't you use the props here?
There was a problem hiding this comment.
const ThemedImage: (props: Props) => JSX.Element;
There was a problem hiding this comment.
This has been taken from the Tabs component types already in that file (https://github.com/facebook/docusaurus/blob/master/packages/docusaurus-theme-classic/src/types.d.ts#L395):
const Tabs: () => JSX.Element;
export default Tabs;
TS should be happy with that construction because this method only serves as the definition for the returned value.
|
Ah yeah, didn't see, but unfortunately Netlify is failing so can't check the preview
|
@slorber I saw the log, working on this right now. But it is annoying that during the development the app runs correctly and do not fail or warn user in any way, but on build is failing due to some ambiguous errors. Is there any way to improve this processes and make the results of both modes (dev & build/serve) consistent? |
|
Currently CI fail is related to the issue with V1 build (probably caused by mentioned above PR): |
| const {isDarkTheme} = useThemeContext(); | ||
| const {src, darkSrc, lightSrc, alt = '', ...propsRest} = props; | ||
|
|
||
| if (darkSrc && isDarkTheme) { |
There was a problem hiding this comment.
Let's not duplicate essentially the same code, let's use a ternary expression to determine the desired image src?
And why is there a prop just src? In this case need use native <img> element, not ThemedImage.
There was a problem hiding this comment.
Let's not duplicate essentially the same code, let's use a ternary expression to determine the desired image src?
I choose the standard conditional structure for the redability.
And why is there a prop just
src? In this case need use native<img>element, notThemedImage.
Because of TS types inheritance - & ComponentProps<'img'>; - and props passing. It also serves as fallback, if user provide src instead of lightSrc to the themed image.
Most likely the reason for this is Netlify cache, because the tests in the PR with the update deps were successful. |
Hmm, interesting. Can you re-run the pipeline than? |
|
Maybe @slorber can do it, but I don't have access for that :( |
|
@lex111 I have pushed the ternary refactor commit but the CI still fails on the same V1 error. Are you sure it is only the Netlify cache issue? |
| readonly darkSrc?: string; | ||
| } & ComponentProps<'img'>; | ||
|
|
||
| const ThemedImage: () => JSX.Element; |
There was a problem hiding this comment.
despite other examples not declaring components props properly, I think we should do this (cf TabItem, Layout).
We'll make sure all comps have props: Props over time
There was a problem hiding this comment.
I'm not against this change, but this sound like a feature request or a bug fix request, so I think you should handle this for all theme components in the separate PR.
website/docs/markdown-features.mdx
Outdated
|
|
||
| <ThemedImage | ||
| alt="Docusaurus themed image" | ||
| lightSrc={useBaseUrl('img/docusaurus_keytar.svg')} |
There was a problem hiding this comment.
Why don't we just pass the path as regular string? Accordingly, inside the ThemedImage component, apply useBaseUrl to all src paths? Then users would not import useBaseUrl in their MDX doc.
There was a problem hiding this comment.
@lex111 totally agree with that. BTW I imagined we could even have a Docusaurus image component just for this usecase
There was a problem hiding this comment.
I'm not sure if processing the base URL inside the component is a good idea. It can blur the functionality and cause a confusion (why img need useBaseURL when ThemeImage do not need it)? The goal was to create simple helper not the robust, alternative image component.
And again, I have just looked at the way img tag is used on the Docusuaurus V2 website - https://github.com/facebook/docusaurus/blob/master/website/src/pages/index.js#L77.
There was a problem hiding this comment.
My long-term goal is to simply deprecate useBaseUrl(). But this can probably be done later, so if we don't apply it in the component today, it's fine
|
agree, you can remove the bootstrap theme from the netlify scripts and the netlify HTML page. We'll add it back when it's more production ready |
b383945 to
82475a3
Compare
|
It looks like the local rebase and force push of PR branch fixed the V1 CI issue. |
|
@Simek I added an example so that you understand why your js-based solution will not work in all cases: Try refreshing this page, with dark mode, and caching enabled: https://deploy-preview-3730--docusaurus-2.netlify.app/classic/docs/markdown-features/ Here, the images added are cached aggressively. The image being served by the server will appear on the user screen before React has time to hydrate. You didn't see this issue because:
I think the server should always render both images, but only display one thanks to CSS. |
|
@slorber PR has been updated, mostly according to the review suggestions. Feel free to improve or change the docs section (I'm way better at improving the docs rather than creating the initial version). Please remember to remove the SSR example after the successful review, but before the merge. 🙂 |

Motivation
For some websites it is important to be able to switch the image source based on the current theme. This PR introduces the simple theme helper component -
ThemedImage- which allow users to specify thelightSrcanddarkSrcprops and switches the image content dynamically on theme change.The docs has also been updated within this PR.
Have you read the Contributing Guidelines on pull requests?
Yes
Test Plan
Changes has been tested locally using Docusuaurus V2 website.
Preview
Related PRs
None.