HighlightJS's Themes Not Working

Consider this code:
function App() {
// ...

hljs.registerLanguage('java', java);
hljs.registerLanguage('gradle', gradle);
hljs.registerLanguage('css', css);

createEffect(() => {
const theme = getTheme();
document.documentElement.setAttribute("theme", theme);
hljs.highlightAll();
})

const themeMapToHighlightJS = new Map<Theme, string>();
themeMapToHighlightJS.set(Theme.DARK, "atom-one-dark.min");
themeMapToHighlightJS.set(Theme.LIGHT, "atom-one-light.min");

return (
<div>
<NavbarComponent />
<div class={"content-container"}>
<Router root={props => (
<MetaProvider>
<Title>APEL Website</Title>
{(() => {
let arr: JSXElement[] = [];
for (const [currTheme, highlightTheme] of themeMapToHighlightJS.entries()) {
arr.push(
<Link
media={"all"}
rel={"stylesheet"}
disabled={getTheme() !== currTheme}
href={`https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/styles/${highlightTheme}.css`}
/>
)
}
return arr;
})()}
<Suspense>{props.children}</Suspense>
</MetaProvider>
)}>
<FileRoutes />
</Router>
</div>
<FooterComponent />
</div>
)
}
function App() {
// ...

hljs.registerLanguage('java', java);
hljs.registerLanguage('gradle', gradle);
hljs.registerLanguage('css', css);

createEffect(() => {
const theme = getTheme();
document.documentElement.setAttribute("theme", theme);
hljs.highlightAll();
})

const themeMapToHighlightJS = new Map<Theme, string>();
themeMapToHighlightJS.set(Theme.DARK, "atom-one-dark.min");
themeMapToHighlightJS.set(Theme.LIGHT, "atom-one-light.min");

return (
<div>
<NavbarComponent />
<div class={"content-container"}>
<Router root={props => (
<MetaProvider>
<Title>APEL Website</Title>
{(() => {
let arr: JSXElement[] = [];
for (const [currTheme, highlightTheme] of themeMapToHighlightJS.entries()) {
arr.push(
<Link
media={"all"}
rel={"stylesheet"}
disabled={getTheme() !== currTheme}
href={`https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/styles/${highlightTheme}.css`}
/>
)
}
return arr;
})()}
<Suspense>{props.children}</Suspense>
</MetaProvider>
)}>
<FileRoutes />
</Router>
</div>
<FooterComponent />
</div>
)
}
The highlightjs themes are not working on page load. When i highlight nothing gets colored, tho for some odd reason doing a hot reload remedies this issue
8 Replies
Madaxen86
Madaxen862w ago
not sure how highlight.js works, but just a guess: createEffect runs before mount meaning before all elements are mounted. So maybe adding
onMount(()=> hljs.highlightAll());
onMount(()=> hljs.highlightAll());
will do it. Would also explain why hot reload fixes it, because the dom elements are already mounted. Are the code blocks mounted conditionally? Made this stackblitz to showcase what happens if there's a condition and code blocks get rendered after the highlightAll() is called. https://stackblitz.com/edit/github-l3ak3iob-jzvjqhdg?file=src%2Fapp.tsx,src%2Fapp.css,src%2Fentry-server.tsx
McBrincie212
McBrincie212OP2w ago
doesn't work and by conditionally wdym? i think i found something registering them on the server as normal link elements work tho it only works on the first load changing the theme will not change the link elements disable stat the more i think about it the more ik where the issue is SSR stuff bc its set to render server-side, maybe the signals don't get updated or smth
Madaxen86
Madaxen862w ago
What’s the implementation of getTheme? Like in the stackblitz wrapped in a Show component. Doesn’t need to be conditionally. Could also be client only / lazy loaded. If hljs.hihglightAll() is called before the pre code elements are in the Dom highlighting doesn’t work.
McBrincie212
McBrincie212OP2w ago
its a signal the codeblocks are not conditionally rendered tbh i think i should wrap the link components as a client one i feel like i've got the hugest brain of mankind when i solved this bug lmao the way i patched it is like so
const HighlightThemes = clientOnly(() => import("~/utils/HighlightThemes"));

// @ts-ignore
export enum Theme {
DARK = "dark",
LIGHT = "light"
}

export const [getTheme, setTheme] = createSignal(Theme.DARK);

export default function App() {
hljs.registerLanguage('java', java);
hljs.registerLanguage('gradle', gradle);
hljs.registerLanguage('css', css);

createEffect(() => {
const theme = getTheme();
document.documentElement.setAttribute("theme", theme);
hljs.highlightAll();
})

return (
<div>
<NavbarComponent />
<div class={"content-container"}>
<Router root={props => (
<MetaProvider>
<Title>APEL Website</Title>
<Suspense>{props.children}</Suspense>
<HighlightThemes />
</MetaProvider>
)}>
<FileRoutes />
</Router>
</div>
<FooterComponent />
</div>
)
}
const HighlightThemes = clientOnly(() => import("~/utils/HighlightThemes"));

// @ts-ignore
export enum Theme {
DARK = "dark",
LIGHT = "light"
}

export const [getTheme, setTheme] = createSignal(Theme.DARK);

export default function App() {
hljs.registerLanguage('java', java);
hljs.registerLanguage('gradle', gradle);
hljs.registerLanguage('css', css);

createEffect(() => {
const theme = getTheme();
document.documentElement.setAttribute("theme", theme);
hljs.highlightAll();
})

return (
<div>
<NavbarComponent />
<div class={"content-container"}>
<Router root={props => (
<MetaProvider>
<Title>APEL Website</Title>
<Suspense>{props.children}</Suspense>
<HighlightThemes />
</MetaProvider>
)}>
<FileRoutes />
</Router>
</div>
<FooterComponent />
</div>
)
}
where
export default function HighlightThemes() {
const themeMapToHighlightJS = new Map<Theme, string>();
themeMapToHighlightJS.set(Theme.DARK, "atom-one-dark");
themeMapToHighlightJS.set(Theme.LIGHT, "atom-one-light");

return (
<For each={themeMapToHighlightJS.entries().toArray()}>
{([themeCondition, highlightTheme]) => {
return (
<link rel={"stylesheet"} disabled={getTheme() !== themeCondition}
href={`https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/styles/${highlightTheme}.min.css`}/>
);
}}
</For>
);
}
export default function HighlightThemes() {
const themeMapToHighlightJS = new Map<Theme, string>();
themeMapToHighlightJS.set(Theme.DARK, "atom-one-dark");
themeMapToHighlightJS.set(Theme.LIGHT, "atom-one-light");

return (
<For each={themeMapToHighlightJS.entries().toArray()}>
{([themeCondition, highlightTheme]) => {
return (
<link rel={"stylesheet"} disabled={getTheme() !== themeCondition}
href={`https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/styles/${highlightTheme}.min.css`}/>
);
}}
</For>
);
}
i import it client-side instead of server-side so that the client gets to decide how to highlight the themes
McBrincie212
McBrincie212OP2w ago
tho when i open the docs page i am greeted with this
No description
McBrincie212
McBrincie212OP2w ago
this only is triggered when i reload the page and its caused in
export default function DocumentationItem(props: {
title: string;
sectionContent: () => JSXElement;
itemContent?: () => JSXElement;
}) {
const id = createUniqueId();
const commonDocContext = useCommonsDocumentationContext();

return (
<li class={`${styles["documentation-item"]} ${id === commonDocContext.getActiveDocItemID() ? styles["documentation-item-active"] : ""} unselectable`}
onclick={() => {
commonDocContext.setActiveDocItemID(id);
commonDocContext.setDocumentationSection(() => props.sectionContent);
}}
>
<div class={styles["documentation-item-title"]}># {props.title}</div>
{(props.itemContent || "") as unknown as JSXElement}
</li>
);
}
export default function DocumentationItem(props: {
title: string;
sectionContent: () => JSXElement;
itemContent?: () => JSXElement;
}) {
const id = createUniqueId();
const commonDocContext = useCommonsDocumentationContext();

return (
<li class={`${styles["documentation-item"]} ${id === commonDocContext.getActiveDocItemID() ? styles["documentation-item-active"] : ""} unselectable`}
onclick={() => {
commonDocContext.setActiveDocItemID(id);
commonDocContext.setDocumentationSection(() => props.sectionContent);
}}
>
<div class={styles["documentation-item-title"]}># {props.title}</div>
{(props.itemContent || "") as unknown as JSXElement}
</li>
);
}
oh fixed same technique
Madaxen86
Madaxen862w ago
Here's a working example in stackblitz https://stackblitz.com/edit/github-l3ak3iob-jzvjqhdg?file=src%2Fcomponents%2FHighlightedCode.tsx 1. Link from @sokidjs/meta does not work - normal link does !? (SSR works and also client side navigation and theme change). 2. added location.pathname to createEffect which calls hljs.highlightAll() to also trigger hljs to add the classes to the pre and code elements. Necessary as hljs manipulates the DOM so it's necessary to call the update everytime the DOM changes (e.g. route change). Reduced example for css (note remove the theme toggle) Just added it for testing:
import { useLocation } from '@solidjs/router';
import hljs from 'highlight.js';
import css from 'highlight.js/lib/languages/css';
import { createEffect, createSignal, ParentProps } from 'solid-js';

export default function CodeHighlightProvider(props: ParentProps) {
const [getTheme, setTheme] = createSignal<'dark' | 'light'>('dark');

hljs.registerLanguage('css', css);

const location = useLocation();

createEffect(() => {
location.pathname;
const theme = getTheme();
document.documentElement.setAttribute('theme', theme);
hljs.highlightAll();
});
return (
<>
<link
media={'all'}
rel={'stylesheet'}
disabled={getTheme() !== 'dark'}
href={`https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/styles/atom-one-dark.css`}
/>
<link
media={'all'}
rel={'stylesheet'}
disabled={getTheme() !== 'light'}
href={`https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/styles/atom-one-light.css`}
/>
<button
style={{
padding: '.5rem 1rem',
background: 'purple',
}}
onClick={() => setTheme((prev) => (prev === 'dark' ? 'light' : 'dark'))}
>
Swtich to {getTheme() === 'dark' ? 'light' : 'dark'} themes
</button>
{props.children}
</>
);
}
import { useLocation } from '@solidjs/router';
import hljs from 'highlight.js';
import css from 'highlight.js/lib/languages/css';
import { createEffect, createSignal, ParentProps } from 'solid-js';

export default function CodeHighlightProvider(props: ParentProps) {
const [getTheme, setTheme] = createSignal<'dark' | 'light'>('dark');

hljs.registerLanguage('css', css);

const location = useLocation();

createEffect(() => {
location.pathname;
const theme = getTheme();
document.documentElement.setAttribute('theme', theme);
hljs.highlightAll();
});
return (
<>
<link
media={'all'}
rel={'stylesheet'}
disabled={getTheme() !== 'dark'}
href={`https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/styles/atom-one-dark.css`}
/>
<link
media={'all'}
rel={'stylesheet'}
disabled={getTheme() !== 'light'}
href={`https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/styles/atom-one-light.css`}
/>
<button
style={{
padding: '.5rem 1rem',
background: 'purple',
}}
onClick={() => setTheme((prev) => (prev === 'dark' ? 'light' : 'dark'))}
>
Swtich to {getTheme() === 'dark' ? 'light' : 'dark'} themes
</button>
{props.children}
</>
);
}
McBrincie212
McBrincie212OP2w ago
mhm, yho i found it and fixed it as said above wasn't nesscarry

Did you find this page helpful?