diff --git a/.yarn/install-state.gz b/.yarn/install-state.gz index 0d32934..58cc032 100644 Binary files a/.yarn/install-state.gz and b/.yarn/install-state.gz differ diff --git a/examples/app-router/next.config.js b/examples/app-router/next.config.js index bec2b4c..77ea0f0 100644 --- a/examples/app-router/next.config.js +++ b/examples/app-router/next.config.js @@ -1,6 +1,6 @@ /** @type {import('next').NextConfig} */ const nextConfig = { - serverExternalPackages: ['@shikijs/twoslash'], + serverExternalPackages: ['@shikijs/twoslash', '@typescript/vfs', 'typescript'], }; module.exports = nextConfig; diff --git a/examples/pages-router/next.config.js b/examples/pages-router/next.config.js index 658404a..77ea0f0 100644 --- a/examples/pages-router/next.config.js +++ b/examples/pages-router/next.config.js @@ -1,4 +1,6 @@ /** @type {import('next').NextConfig} */ -const nextConfig = {}; +const nextConfig = { + serverExternalPackages: ['@shikijs/twoslash', '@typescript/vfs', 'typescript'], +}; module.exports = nextConfig; diff --git a/examples/pages-router/package.json b/examples/pages-router/package.json index 749d9a8..9e4864e 100644 --- a/examples/pages-router/package.json +++ b/examples/pages-router/package.json @@ -10,9 +10,9 @@ }, "dependencies": { "@mintlify/mdx": "workspace:^", - "next": "14.0.4", - "react": "^18", - "react-dom": "^18" + "next": "15.4.2", + "react": "18.3.1", + "react-dom": "18.3.1" }, "devDependencies": { "@tailwindcss/typography": "^0.5.10", diff --git a/packages/mdx/src/plugins/rehype/rehypeSyntaxHighlighting.ts b/packages/mdx/src/plugins/rehype/rehypeSyntaxHighlighting.ts index d803001..d128d7d 100644 --- a/packages/mdx/src/plugins/rehype/rehypeSyntaxHighlighting.ts +++ b/packages/mdx/src/plugins/rehype/rehypeSyntaxHighlighting.ts @@ -1,4 +1,3 @@ -import { transformerTwoslash } from '@shikijs/twoslash'; import type { Element, Root } from 'hast'; import { toString } from 'hast-util-to-string'; import type { MdxJsxFlowElementHast, MdxJsxTextElementHast } from 'mdast-util-mdx-jsx'; @@ -21,10 +20,10 @@ import { SHIKI_TRANSFORMERS, } from './shiki-constants.js'; import { - cdnTransformerTwoslash, - cdnTwoslash, getTwoslashOptions, parseLineComment, + getCdnTwoslashTransformer, + cdnTwoslash, } from './twoslash/config.js'; import { getLanguage } from './utils.js'; @@ -101,9 +100,8 @@ export const rehypeSyntaxHighlighting: Plugin<[RehypeSyntaxHighlightingOptions?] nodesToProcess.push( (async () => { - await cdnTwoslash.prepareTypes(toString(node)); if (!DEFAULT_LANGS.includes(lang)) await highlighter.loadLanguage(lang); - traverseNode({ node, index, parent, highlighter, lang, options }); + await traverseNode({ node, index, parent, highlighter, lang, options }); })() ); }); @@ -111,7 +109,7 @@ export const rehypeSyntaxHighlighting: Plugin<[RehypeSyntaxHighlightingOptions?] }; }; -function traverseNode({ +async function traverseNode({ node, index, parent, @@ -150,7 +148,10 @@ function traverseNode({ code = splitCode.join('\n'); + await cdnTwoslash.init(); + await cdnTwoslash.prepareTypes(code); const twoslashOptions = getTwoslashOptions({ linkMap }); + const cdnTwoslashTransformer = getCdnTwoslashTransformer(twoslashOptions); const hast = highlighter.codeToHast(code, { lang: lang ?? DEFAULT_LANG, @@ -165,11 +166,7 @@ function traverseNode({ colorReplacements: shikiColorReplacements, tabindex: false, tokenizeMaxLineLength: 1000, - transformers: [ - ...SHIKI_TRANSFORMERS, - transformerTwoslash(twoslashOptions), - cdnTransformerTwoslash(twoslashOptions), - ], + transformers: [...SHIKI_TRANSFORMERS, cdnTwoslashTransformer], }); const codeElement = hast.children[0] as Element; diff --git a/packages/mdx/src/plugins/rehype/twoslash/config.ts b/packages/mdx/src/plugins/rehype/twoslash/config.ts index f24ac44..72376e5 100644 --- a/packages/mdx/src/plugins/rehype/twoslash/config.ts +++ b/packages/mdx/src/plugins/rehype/twoslash/config.ts @@ -1,27 +1,81 @@ import { - createTransformerFactory, rendererRich, + createTransformerFactory, type TransformerTwoslashOptions, } from '@shikijs/twoslash'; import type { ElementContent } from 'hast'; import type { ShikiTransformer } from 'shiki/types'; -import { createTwoslashFromCDN, type TwoslashCdnReturn } from 'twoslash-cdn'; -import ts from 'typescript'; +import type { TwoslashInstance } from 'twoslash'; +import { createTwoslashFromCDN } from 'twoslash-cdn'; +import * as ts from 'typescript'; type TransformerFactory = (options?: TransformerTwoslashOptions) => ShikiTransformer; const twoslashCompilerOptions: ts.CompilerOptions = { target: ts.ScriptTarget.ESNext, lib: ['ESNext', 'DOM', 'esnext', 'dom', 'es2020'], + allowJs: true, + allowSyntheticDefaultImports: true, + allowUnreachableCode: true, + alwaysStrict: false, }; -export const cdnTwoslash: TwoslashCdnReturn = createTwoslashFromCDN({ +const fsMap: Map = new Map(); +const twoslashStorageMap = new Map(); + +export const cdnTwoslash = createTwoslashFromCDN({ compilerOptions: twoslashCompilerOptions, + fsMap, + fetcher(input, init) { + console.log(`[GLOBAL__FETCHER] Fetching ${input}`); + return fetch(input, init); + }, + storage: { + getItemRaw(key) { + console.log(`[GLOBAL__STORAGE] Getting ${key}`); + return twoslashStorageMap.get(key); + }, + setItemRaw(key, value) { + console.log(`[GLOBAL__STORAGE] Setting ${key}`); + twoslashStorageMap.set(key, value); + }, + }, }); -export const cdnTransformerTwoslash: TransformerFactory = createTransformerFactory( + +export const cdnTwoslashTransformer: TransformerFactory = createTransformerFactory( cdnTwoslash.runSync ); +export function getCdnTwoslashTransformer(options: TransformerTwoslashOptions): ShikiTransformer { + function getInstance() { + return createTwoslashFromCDN({ + compilerOptions: twoslashCompilerOptions, + fetcher(input, init) { + console.log(`[FETCHER] Fetching ${input}`); + return fetch(input, init); + }, + fsMap, + storage: { + getItemRaw(key) { + console.log(`[STORAGE] Getting ${key}`); + return twoslashStorageMap.get(key); + }, + setItemRaw(key, value) { + console.log(`[STORAGE] Setting ${key}`); + twoslashStorageMap.set(key, value); + }, + }, + }); + } + + return createTransformerFactory( + // lazy load Twoslash instance so it works on serverless platforms + ((...args) => getInstance().runSync(...args)) as TwoslashInstance + )({ + ...options, + }); +} + function onTwoslashError(err: unknown, code: string, lang: string) { console.error(JSON.stringify({ err, code, lang })); } @@ -69,6 +123,7 @@ export function getTwoslashOptions( langs: ['ts', 'typescript', 'js', 'javascript', 'tsx', 'jsx'], explicitTrigger: /mint-twoslash/, twoslashOptions: { + tsModule: ts, compilerOptions: twoslashCompilerOptions, }, }; diff --git a/yarn.lock b/yarn.lock index 18354ac..83c6fbb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -706,13 +706,6 @@ __metadata: languageName: node linkType: hard -"@next/env@npm:14.0.4": - version: 14.0.4 - resolution: "@next/env@npm:14.0.4" - checksum: 10c0/59b893d30aea0556379a24f6e4eac830677feb149bd8416b72383ea2600ce194fa22a79b2dd86e0b295c4a8f0702e461f48edaff1ac9173eddef42a4cce7fd98 - languageName: node - linkType: hard - "@next/env@npm:15.4.2": version: 15.4.2 resolution: "@next/env@npm:15.4.2" @@ -729,13 +722,6 @@ __metadata: languageName: node linkType: hard -"@next/swc-darwin-arm64@npm:14.0.4": - version: 14.0.4 - resolution: "@next/swc-darwin-arm64@npm:14.0.4" - conditions: os=darwin & cpu=arm64 - languageName: node - linkType: hard - "@next/swc-darwin-arm64@npm:15.4.2": version: 15.4.2 resolution: "@next/swc-darwin-arm64@npm:15.4.2" @@ -743,13 +729,6 @@ __metadata: languageName: node linkType: hard -"@next/swc-darwin-x64@npm:14.0.4": - version: 14.0.4 - resolution: "@next/swc-darwin-x64@npm:14.0.4" - conditions: os=darwin & cpu=x64 - languageName: node - linkType: hard - "@next/swc-darwin-x64@npm:15.4.2": version: 15.4.2 resolution: "@next/swc-darwin-x64@npm:15.4.2" @@ -757,13 +736,6 @@ __metadata: languageName: node linkType: hard -"@next/swc-linux-arm64-gnu@npm:14.0.4": - version: 14.0.4 - resolution: "@next/swc-linux-arm64-gnu@npm:14.0.4" - conditions: os=linux & cpu=arm64 & libc=glibc - languageName: node - linkType: hard - "@next/swc-linux-arm64-gnu@npm:15.4.2": version: 15.4.2 resolution: "@next/swc-linux-arm64-gnu@npm:15.4.2" @@ -771,13 +743,6 @@ __metadata: languageName: node linkType: hard -"@next/swc-linux-arm64-musl@npm:14.0.4": - version: 14.0.4 - resolution: "@next/swc-linux-arm64-musl@npm:14.0.4" - conditions: os=linux & cpu=arm64 & libc=musl - languageName: node - linkType: hard - "@next/swc-linux-arm64-musl@npm:15.4.2": version: 15.4.2 resolution: "@next/swc-linux-arm64-musl@npm:15.4.2" @@ -785,13 +750,6 @@ __metadata: languageName: node linkType: hard -"@next/swc-linux-x64-gnu@npm:14.0.4": - version: 14.0.4 - resolution: "@next/swc-linux-x64-gnu@npm:14.0.4" - conditions: os=linux & cpu=x64 & libc=glibc - languageName: node - linkType: hard - "@next/swc-linux-x64-gnu@npm:15.4.2": version: 15.4.2 resolution: "@next/swc-linux-x64-gnu@npm:15.4.2" @@ -799,13 +757,6 @@ __metadata: languageName: node linkType: hard -"@next/swc-linux-x64-musl@npm:14.0.4": - version: 14.0.4 - resolution: "@next/swc-linux-x64-musl@npm:14.0.4" - conditions: os=linux & cpu=x64 & libc=musl - languageName: node - linkType: hard - "@next/swc-linux-x64-musl@npm:15.4.2": version: 15.4.2 resolution: "@next/swc-linux-x64-musl@npm:15.4.2" @@ -813,13 +764,6 @@ __metadata: languageName: node linkType: hard -"@next/swc-win32-arm64-msvc@npm:14.0.4": - version: 14.0.4 - resolution: "@next/swc-win32-arm64-msvc@npm:14.0.4" - conditions: os=win32 & cpu=arm64 - languageName: node - linkType: hard - "@next/swc-win32-arm64-msvc@npm:15.4.2": version: 15.4.2 resolution: "@next/swc-win32-arm64-msvc@npm:15.4.2" @@ -827,20 +771,6 @@ __metadata: languageName: node linkType: hard -"@next/swc-win32-ia32-msvc@npm:14.0.4": - version: 14.0.4 - resolution: "@next/swc-win32-ia32-msvc@npm:14.0.4" - conditions: os=win32 & cpu=ia32 - languageName: node - linkType: hard - -"@next/swc-win32-x64-msvc@npm:14.0.4": - version: 14.0.4 - resolution: "@next/swc-win32-x64-msvc@npm:14.0.4" - conditions: os=win32 & cpu=x64 - languageName: node - linkType: hard - "@next/swc-win32-x64-msvc@npm:15.4.2": version: 15.4.2 resolution: "@next/swc-win32-x64-msvc@npm:15.4.2" @@ -1047,15 +977,6 @@ __metadata: languageName: node linkType: hard -"@swc/helpers@npm:0.5.2": - version: 0.5.2 - resolution: "@swc/helpers@npm:0.5.2" - dependencies: - tslib: "npm:^2.4.0" - checksum: 10c0/b6fa49bcf6c00571d0eb7837b163f8609960d4d77538160585e27ed167361e9776bd6e5eb9646ffac2fb4d43c58df9ca50dab9d96ab097e6591bc82a75fd1164 - languageName: node - linkType: hard - "@tailwindcss/typography@npm:^0.5.10": version: 0.5.15 resolution: "@tailwindcss/typography@npm:0.5.15" @@ -1883,15 +1804,6 @@ __metadata: languageName: node linkType: hard -"busboy@npm:1.6.0": - version: 1.6.0 - resolution: "busboy@npm:1.6.0" - dependencies: - streamsearch: "npm:^1.1.0" - checksum: 10c0/fa7e836a2b82699b6e074393428b91ae579d4f9e21f5ac468e1b459a244341d722d2d22d10920cdd849743dbece6dca11d72de939fb75a7448825cf2babfba1f - languageName: node - linkType: hard - "cacache@npm:^19.0.1": version: 19.0.1 resolution: "cacache@npm:19.0.1" @@ -1958,13 +1870,6 @@ __metadata: languageName: node linkType: hard -"caniuse-lite@npm:^1.0.30001406, caniuse-lite@npm:^1.0.30001646, caniuse-lite@npm:^1.0.30001688": - version: 1.0.30001689 - resolution: "caniuse-lite@npm:1.0.30001689" - checksum: 10c0/51cf99751dddfba24e13556ae0e0f38c062f76d49f2e24cce3d28e71a0325ca6fe04fe51b4a0e8467d601d94e72fea84f160bf577e7cbb5677f14ac673b6da20 - languageName: node - linkType: hard - "caniuse-lite@npm:^1.0.30001579": version: 1.0.30001743 resolution: "caniuse-lite@npm:1.0.30001743" @@ -1972,6 +1877,13 @@ __metadata: languageName: node linkType: hard +"caniuse-lite@npm:^1.0.30001646, caniuse-lite@npm:^1.0.30001688": + version: 1.0.30001689 + resolution: "caniuse-lite@npm:1.0.30001689" + checksum: 10c0/51cf99751dddfba24e13556ae0e0f38c062f76d49f2e24cce3d28e71a0325ca6fe04fe51b4a0e8467d601d94e72fea84f160bf577e7cbb5677f14ac673b6da20 + languageName: node + linkType: hard + "ccount@npm:^2.0.0": version: 2.0.1 resolution: "ccount@npm:2.0.1" @@ -3281,13 +3193,6 @@ __metadata: languageName: node linkType: hard -"glob-to-regexp@npm:^0.4.1": - version: 0.4.1 - resolution: "glob-to-regexp@npm:0.4.1" - checksum: 10c0/0486925072d7a916f052842772b61c3e86247f0a80cc0deb9b5a3e8a1a9faad5b04fb6f58986a09f34d3e96cd2a22a24b7e9882fb1cf904c31e9a310de96c429 - languageName: node - linkType: hard - "glob@npm:7.1.7": version: 7.1.7 resolution: "glob@npm:7.1.7" @@ -3394,7 +3299,7 @@ __metadata: languageName: node linkType: hard -"graceful-fs@npm:^4.1.2, graceful-fs@npm:^4.2.11, graceful-fs@npm:^4.2.4, graceful-fs@npm:^4.2.6": +"graceful-fs@npm:^4.2.4, graceful-fs@npm:^4.2.6": version: 4.2.11 resolution: "graceful-fs@npm:4.2.11" checksum: 10c0/386d011a553e02bc594ac2ca0bd6d9e4c22d7fa8cfbfc448a6d148c59ea881b092db9dbe3547ae4b88e55f1b01f7c4a2ecc53b310c042793e63aa44cf6c257f2 @@ -5347,62 +5252,6 @@ __metadata: languageName: node linkType: hard -"next@npm:14.0.4": - version: 14.0.4 - resolution: "next@npm:14.0.4" - dependencies: - "@next/env": "npm:14.0.4" - "@next/swc-darwin-arm64": "npm:14.0.4" - "@next/swc-darwin-x64": "npm:14.0.4" - "@next/swc-linux-arm64-gnu": "npm:14.0.4" - "@next/swc-linux-arm64-musl": "npm:14.0.4" - "@next/swc-linux-x64-gnu": "npm:14.0.4" - "@next/swc-linux-x64-musl": "npm:14.0.4" - "@next/swc-win32-arm64-msvc": "npm:14.0.4" - "@next/swc-win32-ia32-msvc": "npm:14.0.4" - "@next/swc-win32-x64-msvc": "npm:14.0.4" - "@swc/helpers": "npm:0.5.2" - busboy: "npm:1.6.0" - caniuse-lite: "npm:^1.0.30001406" - graceful-fs: "npm:^4.2.11" - postcss: "npm:8.4.31" - styled-jsx: "npm:5.1.1" - watchpack: "npm:2.4.0" - peerDependencies: - "@opentelemetry/api": ^1.1.0 - react: ^18.2.0 - react-dom: ^18.2.0 - sass: ^1.3.0 - dependenciesMeta: - "@next/swc-darwin-arm64": - optional: true - "@next/swc-darwin-x64": - optional: true - "@next/swc-linux-arm64-gnu": - optional: true - "@next/swc-linux-arm64-musl": - optional: true - "@next/swc-linux-x64-gnu": - optional: true - "@next/swc-linux-x64-musl": - optional: true - "@next/swc-win32-arm64-msvc": - optional: true - "@next/swc-win32-ia32-msvc": - optional: true - "@next/swc-win32-x64-msvc": - optional: true - peerDependenciesMeta: - "@opentelemetry/api": - optional: true - sass: - optional: true - bin: - next: dist/bin/next - checksum: 10c0/e6c829fd473d8c3605b2b62d15e1bf41e9d90cf59a2c213b4adeadff2846999bc9a653ffef18f6aa13cc9f5d6de02469c222acf5a4184901a4690a4504bd468f - languageName: node - linkType: hard - "next@npm:15.4.2": version: 15.4.2 resolution: "next@npm:15.4.2" @@ -5693,10 +5542,10 @@ __metadata: autoprefixer: "npm:^10.0.1" eslint: "npm:^8" eslint-config-next: "npm:14.0.4" - next: "npm:14.0.4" + next: "npm:15.4.2" postcss: "npm:^8" - react: "npm:^18" - react-dom: "npm:^18" + react: "npm:18.3.1" + react-dom: "npm:18.3.1" tailwindcss: "npm:^3.3.0" typescript: "npm:^5" languageName: unknown @@ -6072,7 +5921,7 @@ __metadata: languageName: node linkType: hard -"react-dom@npm:18.3.1, react-dom@npm:^18, react-dom@npm:^18.3.1": +"react-dom@npm:18.3.1, react-dom@npm:^18.3.1": version: 18.3.1 resolution: "react-dom@npm:18.3.1" dependencies: @@ -6091,7 +5940,7 @@ __metadata: languageName: node linkType: hard -"react@npm:18.3.1, react@npm:^18, react@npm:^18.3.1": +"react@npm:18.3.1, react@npm:^18.3.1": version: 18.3.1 resolution: "react@npm:18.3.1" dependencies: @@ -6871,13 +6720,6 @@ __metadata: languageName: node linkType: hard -"streamsearch@npm:^1.1.0": - version: 1.1.0 - resolution: "streamsearch@npm:1.1.0" - checksum: 10c0/fbd9aecc2621364384d157f7e59426f4bfd385e8b424b5aaa79c83a6f5a1c8fd2e4e3289e95de1eb3511cb96bb333d6281a9919fafce760e4edb35b2cd2facab - languageName: node - linkType: hard - "string-width-cjs@npm:string-width@^4.2.0, string-width@npm:^4.1.0": version: 4.2.3 resolution: "string-width@npm:4.2.3" @@ -7039,22 +6881,6 @@ __metadata: languageName: node linkType: hard -"styled-jsx@npm:5.1.1": - version: 5.1.1 - resolution: "styled-jsx@npm:5.1.1" - dependencies: - client-only: "npm:0.0.1" - peerDependencies: - react: ">= 16.8.0 || 17.x.x || ^18.0.0-0" - peerDependenciesMeta: - "@babel/core": - optional: true - babel-plugin-macros: - optional: true - checksum: 10c0/42655cdadfa5388f8a48bb282d6b450df7d7b8cf066ac37038bd0499d3c9f084815ebd9ff9dfa12a218fd4441338851db79603498d7557207009c1cf4d609835 - languageName: node - linkType: hard - "styled-jsx@npm:5.1.6": version: 5.1.6 resolution: "styled-jsx@npm:5.1.6" @@ -7613,16 +7439,6 @@ __metadata: languageName: node linkType: hard -"watchpack@npm:2.4.0": - version: 2.4.0 - resolution: "watchpack@npm:2.4.0" - dependencies: - glob-to-regexp: "npm:^0.4.1" - graceful-fs: "npm:^4.1.2" - checksum: 10c0/c5e35f9fb9338d31d2141d9835643c0f49b5f9c521440bb648181059e5940d93dd8ed856aa8a33fbcdd4e121dad63c7e8c15c063cf485429cd9d427be197fe62 - languageName: node - linkType: hard - "web-namespaces@npm:^2.0.0": version: 2.0.1 resolution: "web-namespaces@npm:2.0.1"