mirror of
https://github.com/shishantbiswas/bknd.git
synced 2026-03-16 04:27:21 +00:00
fix CodePreview shiki dynamic load for frameworks like Next.js
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { useTheme } from "ui/client/use-theme";
|
import { useTheme } from "ui/client/use-theme";
|
||||||
import { cn } from "ui/lib/utils";
|
import { cn, importDynamicBrowserModule } from "ui/lib/utils";
|
||||||
|
|
||||||
export type CodePreviewProps = {
|
export type CodePreviewProps = {
|
||||||
code: string;
|
code: string;
|
||||||
@@ -30,8 +30,10 @@ export const CodePreview = ({
|
|||||||
async function highlightCode() {
|
async function highlightCode() {
|
||||||
try {
|
try {
|
||||||
// Dynamically import Shiki from CDN
|
// Dynamically import Shiki from CDN
|
||||||
// @ts-expect-error - Dynamic CDN import
|
const { codeToHtml } = await importDynamicBrowserModule(
|
||||||
const { codeToHtml } = await import("https://esm.sh/shiki@3.13.0");
|
"shiki",
|
||||||
|
"https://esm.sh/shiki@3.13.0",
|
||||||
|
);
|
||||||
|
|
||||||
if (cancelled) return;
|
if (cancelled) return;
|
||||||
|
|
||||||
|
|||||||
@@ -3,3 +3,30 @@ import { type ClassNameValue, twMerge } from "tailwind-merge";
|
|||||||
export function cn(...inputs: ClassNameValue[]) {
|
export function cn(...inputs: ClassNameValue[]) {
|
||||||
return twMerge(inputs);
|
return twMerge(inputs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dynamically import a module from a URL in the browser in a way compatible with all react frameworks (nextjs doesn't support dynamic imports)
|
||||||
|
*/
|
||||||
|
export async function importDynamicBrowserModule<T = any>(name: string, url: string): Promise<T> {
|
||||||
|
if (!(window as any)[name]) {
|
||||||
|
const script = document.createElement("script");
|
||||||
|
script.type = "module";
|
||||||
|
script.async = true;
|
||||||
|
script.textContent = `import * as ${name} from '${url}';window.${name} = ${name};`;
|
||||||
|
document.head.appendChild(script);
|
||||||
|
|
||||||
|
// poll for the module to be available
|
||||||
|
const maxAttempts = 50; // 5s
|
||||||
|
let attempts = 0;
|
||||||
|
while (!(window as any)[name] && attempts < maxAttempts) {
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, 100));
|
||||||
|
attempts++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(window as any)[name]) {
|
||||||
|
throw new Error(`Browser module "${name}" failed to load`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (window as any)[name] as T;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user