S
SolidJSโ€ข2mo ago
Rvespula

Context with Meta

Hi there! ๐Ÿ™‚ I have a problem. It seems that when I try to create a custom MetaTitle with SolidMeta, the language context is not being accessed in SSR. Here is my implementation:
// Component
import { Title } from "@solidjs/meta";
import type { JSX } from "solid-js";

interface IMetaTitle {
children: JSX.Element;
}
export function MetaTitle(props: IMetaTitle) {
return <Title>{`${props.children} | WebsiteName`}</Title>;
}
// Component
import { Title } from "@solidjs/meta";
import type { JSX } from "solid-js";

interface IMetaTitle {
children: JSX.Element;
}
export function MetaTitle(props: IMetaTitle) {
return <Title>{`${props.children} | WebsiteName`}</Title>;
}
import { MetaProvider } from "@solidjs/meta";
import type { Component, JSX } from "solid-js";
import { Suspense } from "solid-js";
import { Toaster } from 'solid-toast';
import { LanguageTagProvider, useLocationLanguageTag } from "~/shared/i18n";
import { sourceLanguageTag } from "~/shared/paraglide/runtime";


interface IProviders {
/** Content that will be wrapped by providers. */
readonly children: JSX.Element;
}

export const Providers: Component<IProviders> = (props) => {
const url_language_tag = useLocationLanguageTag();
const language_tag = url_language_tag ?? sourceLanguageTag;

return (
<LanguageTagProvider value={language_tag}>
<MetaProvider>
<Suspense>{props.children}</Suspense>
<Toaster />
</MetaProvider>
</LanguageTagProvider>
);
};
import { MetaProvider } from "@solidjs/meta";
import type { Component, JSX } from "solid-js";
import { Suspense } from "solid-js";
import { Toaster } from 'solid-toast';
import { LanguageTagProvider, useLocationLanguageTag } from "~/shared/i18n";
import { sourceLanguageTag } from "~/shared/paraglide/runtime";


interface IProviders {
/** Content that will be wrapped by providers. */
readonly children: JSX.Element;
}

export const Providers: Component<IProviders> = (props) => {
const url_language_tag = useLocationLanguageTag();
const language_tag = url_language_tag ?? sourceLanguageTag;

return (
<LanguageTagProvider value={language_tag}>
<MetaProvider>
<Suspense>{props.children}</Suspense>
<Toaster />
</MetaProvider>
</LanguageTagProvider>
);
};
// route
import { MetaTitle } from "~/shared/components/metatitle";
import * as m from "~/shared/paraglide/messages.js";

export default function EmailValidationRoute() {
return (
<>
<MetaTitle>{m.meta_route_email_validation()}</MetaTitle>
</>
);
}
// route
import { MetaTitle } from "~/shared/components/metatitle";
import * as m from "~/shared/paraglide/messages.js";

export default function EmailValidationRoute() {
return (
<>
<MetaTitle>{m.meta_route_email_validation()}</MetaTitle>
</>
);
}
ERROR:
throw new Error("LanguageTagCtx not found");
^

Error: LanguageTagCtx not found
throw new Error("LanguageTagCtx not found");
^

Error: LanguageTagCtx not found
this is the context for paraglide: https://github.com/thetarnav/paraglide-solidstart-hackernews/blob/main/src/i18n/adapter.ts
GitHub
paraglide-solidstart-hackernews/src/i18n/adapter.ts at main ยท theta...
Example hackernews app built with SolidStart and Paraglide-js for i18n. - thetarnav/paraglide-solidstart-hackernews
5 Replies
peerreynders
peerreyndersโ€ข2mo ago
First thing I'd check is whether adapter.createI18n() is actually executed in your server side implementation. And given the source is in your project find out if/when the initialization goes off the rails.
GitHub
paraglide-solidstart-hackernews/src/i18n/index.tsx at b3b28ff610f61...
Example hackernews app built with SolidStart and Paraglide-js for i18n. - thetarnav/paraglide-solidstart-hackernews
peerreynders
peerreyndersโ€ข2mo ago
One thing I'd note is that this import is probably the one responsible for loading the module on the server for the first time.
GitHub
paraglide-solidstart-hackernews/src/entry-server.tsx at b3b28ff610f...
Example hackernews app built with SolidStart and Paraglide-js for i18n. - thetarnav/paraglide-solidstart-hackernews
Rvespula
Rvespulaโ€ข2mo ago
This is running on the server. If I remove the MetaTitle, it works. I'm not sure what could be wrong with the Title component from SolidMeta.
Rvespula
Rvespulaโ€ข2mo ago
i found this issue in solid-meta: https://github.com/solidjs/solid-meta/issues/41
GitHub
[Bug?]: Cannot access context when read in Meta content prop. ยท Iss...
If you try to read context inside content prop of Meta component provided by start, the context will not be available, which is not expected as it's used directly under the provider. <Ctx.Pr...
peerreynders
peerreyndersโ€ข2mo ago
Based on that issue, this crashes:
import { createContext, useContext } from 'solid-js';
import { Title, Meta } from '@solidjs/meta';
import Counter from '~/components/Counter';

const Ctx = createContext<{ text: string }>();

export default function Home() {
return (
<Ctx.Provider value={{ text: 'you should see this' }}>
<main>
<Title>{useContext(Ctx)!.text}</Title>
<h1>Hello world!</h1>
<Counter />
<p>
Visit{' '}
<a href="https://start.solidjs.com" target="_blank">
start.solidjs.com
</a>{' '}
to learn how to build SolidStart apps.
</p>
</main>
</Ctx.Provider>
);
}
import { createContext, useContext } from 'solid-js';
import { Title, Meta } from '@solidjs/meta';
import Counter from '~/components/Counter';

const Ctx = createContext<{ text: string }>();

export default function Home() {
return (
<Ctx.Provider value={{ text: 'you should see this' }}>
<main>
<Title>{useContext(Ctx)!.text}</Title>
<h1>Hello world!</h1>
<Counter />
<p>
Visit{' '}
<a href="https://start.solidjs.com" target="_blank">
start.solidjs.com
</a>{' '}
to learn how to build SolidStart apps.
</p>
</main>
</Ctx.Provider>
);
}
But this works:
import {
createContext,
createUniqueId,
mergeProps,
splitProps,
useContext,
} from 'solid-js';
import { useHead } from '@solidjs/meta';
import Counter from '~/components/Counter';

const Ctx = createContext<{ text: string }>();

const MyTitle = (props: { [k: string]: any }) => {
const text = useContext(Ctx)!.text;
const [children, rest] = splitProps(props, ['children']);
const merged = mergeProps({ children: `${children.children} ${text}` }, rest);

useHead({
tag: 'title',
props: merged,
setting: { escape: true, close: true },
id: createUniqueId(),
get name() {
return props.name || props.property;
},
});

return null;
};

export default function Home() {
return (
<Ctx.Provider value={{ text: 'you should see this' }}>
<main>
<MyTitle>Hello world</MyTitle>
<h1>Hello world!</h1>
<Counter />
<p>
Visit{' '}
<a href="https://start.solidjs.com" target="_blank">
start.solidjs.com
</a>{' '}
to learn how to build SolidStart apps.
</p>
</main>
</Ctx.Provider>
);
}
import {
createContext,
createUniqueId,
mergeProps,
splitProps,
useContext,
} from 'solid-js';
import { useHead } from '@solidjs/meta';
import Counter from '~/components/Counter';

const Ctx = createContext<{ text: string }>();

const MyTitle = (props: { [k: string]: any }) => {
const text = useContext(Ctx)!.text;
const [children, rest] = splitProps(props, ['children']);
const merged = mergeProps({ children: `${children.children} ${text}` }, rest);

useHead({
tag: 'title',
props: merged,
setting: { escape: true, close: true },
id: createUniqueId(),
get name() {
return props.name || props.property;
},
});

return null;
};

export default function Home() {
return (
<Ctx.Provider value={{ text: 'you should see this' }}>
<main>
<MyTitle>Hello world</MyTitle>
<h1>Hello world!</h1>
<Counter />
<p>
Visit{' '}
<a href="https://start.solidjs.com" target="_blank">
start.solidjs.com
</a>{' '}
to learn how to build SolidStart apps.
</p>
</main>
</Ctx.Provider>
);
}
Only you know how you plan to use your MetaTitle. Perhaps you can construct it in such a way that the context is accessed outside of useHead().