Skip to content

Commit 9711c95

Browse files
committed
feat(shiki): add twoslash support
1 parent 5140729 commit 9711c95

File tree

21 files changed

+399
-188
lines changed

21 files changed

+399
-188
lines changed

apps/site/mdx/components.mjs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@
33
import BadgeGroup from '@node-core/ui-components/Common/BadgeGroup';
44
import Blockquote from '@node-core/ui-components/Common/Blockquote';
55
import MDXCodeTabs from '@node-core/ui-components/MDX/CodeTabs';
6+
import {
7+
MDXTooltip,
8+
MDXTooltipContent,
9+
MDXTooltipTrigger,
10+
} from '@node-core/ui-components/MDX/Tooltip';
611

712
import Button from '#site/components/Common/Button';
813
import LinkWithArrow from '#site/components/Common/LinkWithArrow';
@@ -48,6 +53,10 @@ export default {
4853
img: MDXImage,
4954
// Renders MDX CodeTabs
5055
CodeTabs: MDXCodeTabs,
56+
// Renders Tooltips
57+
MDXTooltip,
58+
MDXTooltipContent,
59+
MDXTooltipTrigger,
5160
// Renders a Download Button
5261
DownloadButton,
5362
// Renders a stateless Release Select Component

apps/site/mdx/plugins.mjs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,12 @@ import readingTime from 'remark-reading-time';
99

1010
import remarkTableTitles from '../util/table';
1111

12+
// TODO(@avivkeller): When available, use `OPEN_NEXT_CLOUDFLARE` environment
13+
// variable for detection instead of current method, which will enable better
14+
// tree-shaking.
15+
// Reference: https://github.com/nodejs/nodejs.org/pull/7896#issuecomment-3009480615
16+
const OPEN_NEXT_CLOUDFLARE = 'Cloudflare' in global;
17+
1218
/**
1319
* Provides all our Rehype Plugins that are used within MDX
1420
*/
@@ -19,7 +25,21 @@ export const rehypePlugins = [
1925
[rehypeAutolinkHeadings, { behavior: 'wrap' }],
2026
// Transforms sequential code elements into code tabs and
2127
// adds our syntax highlighter (Shikiji) to Codeboxes
22-
rehypeShikiji,
28+
[
29+
rehypeShikiji,
30+
{
31+
// We use the faster WASM engine on the server instead of the web-optimized version.
32+
//
33+
// Currently we fall back to the JavaScript RegEx engine
34+
// on Cloudflare workers because `shiki/wasm` requires loading via
35+
// `WebAssembly.instantiate` with custom imports, which Cloudflare doesn't support
36+
// for security reasons.
37+
wasm: !OPEN_NEXT_CLOUDFLARE,
38+
39+
// TODO(@avivkeller): Find a way to enable Twoslash w/ a VFS on Cloudflare
40+
twoslash: !OPEN_NEXT_CLOUDFLARE,
41+
},
42+
],
2343
];
2444

2545
/**

apps/site/next.config.mjs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,16 @@ const nextConfig = {
5151
},
5252
],
5353
},
54+
serverExternalPackages: ['twoslash'],
55+
outputFileTracingIncludes: {
56+
// Twoslash needs TypeScript declarations to function, and, by default,
57+
// Next.js strips them for brevity. Therefore, they must be explicitly
58+
// included.
59+
'/*': [
60+
'../../node_modules/.pnpm/typescript@*/node_modules/typescript/lib/*.d.ts',
61+
'./node_modules/@types/node/**/*',
62+
],
63+
},
5464
// On static export builds we want the output directory to be "build"
5565
distDir: ENABLE_STATIC_EXPORT ? 'build' : undefined,
5666
// On static export builds we want to enable the export feature

apps/site/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@
7474
"semver": "~7.7.2",
7575
"sval": "^0.6.3",
7676
"tailwindcss": "catalog:",
77+
"twoslash": "^0.3.4",
7778
"unist-util-visit": "^5.0.0",
7879
"vfile": "~6.0.3",
7980
"vfile-matter": "~5.0.1"

apps/site/pages/en/learn/typescript/introduction.md

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -70,16 +70,15 @@ npm add --save-dev @types/node
7070

7171
These type definitions allow TypeScript to understand Node.js APIs and provide proper type checking and autocompletion when you use functions like `fs.readFile` or `http.createServer`. For example:
7272

73-
```js
74-
import * as fs from 'fs';
75-
76-
fs.readFile('example.txt', 'foo', (err, data) => {
77-
// ^^^ Argument of type '"foo"' is not assignable to parameter of type …
78-
if (err) {
79-
throw err;
80-
}
81-
console.log(data);
82-
});
73+
<!-- prettier-ignore -->
74+
```ts
75+
// @noErrors
76+
/* eslint-disable */
77+
// ---cut---
78+
import fs from 'fs';
79+
80+
fs.read
81+
// ^|
8382
```
8483

8584
Many popular JavaScript libraries have their type definitions available under the `@types` namespace, maintained by the DefinitelyTyped community. This enables seamless integration of existing JavaScript libraries with TypeScript projects.

apps/site/pages/en/learn/typescript/publishing-a-ts-package.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,9 +126,9 @@ A note about directory organisation: There are a few common practices for placin
126126
The purpose of types is to warn an implementation will not work:
127127

128128
```ts
129+
// @errors: 2322
129130
const foo = 'a';
130131
const bar: number = 1 + foo;
131-
// ^^^ Type 'string' is not assignable to type 'number'.
132132
```
133133

134134
TypeScript has warned that the above code will not behave as intended, just like a unit test warns that code does not behave as intended. They are complementary and verify different things—you should have both.

apps/site/pages/en/learn/typescript/transpile.md

Lines changed: 1 addition & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ If you have type errors in your TypeScript code, the TypeScript compiler will ca
7171
We will modify our code like this, to voluntarily introduce a type error:
7272

7373
```ts
74+
// @errors: 2322 2554
7475
type User = {
7576
name: string;
7677
age: number;
@@ -88,31 +89,4 @@ const justine: User = {
8889
const isJustineAnAdult: string = isAdult(justine, "I shouldn't be here!");
8990
```
9091

91-
And this is what TypeScript has to say about this:
92-
93-
```console
94-
example.ts:12:5 - error TS2322: Type 'string' is not assignable to type 'number'.
95-
96-
12 age: 'Secret!',
97-
~~~
98-
99-
example.ts:3:5
100-
3 age: number;
101-
~~~
102-
The expected type comes from property 'age' which is declared here on type 'User'
103-
104-
example.ts:15:7 - error TS2322: Type 'boolean' is not assignable to type 'string'.
105-
106-
15 const isJustineAnAdult: string = isAdult(justine, "I shouldn't be here!");
107-
~~~~~~~~~~~~~~~~
108-
109-
example.ts:15:51 - error TS2554: Expected 1 arguments, but got 2.
110-
111-
15 const isJustineAnAdult: string = isAdult(justine, "I shouldn't be here!");
112-
~~~~~~~~~~~~~~~~~~~~~~
113-
114-
115-
Found 3 errors in the same file, starting at: example.ts:12
116-
```
117-
11892
As you can see, TypeScript is very helpful in catching bugs before they even happen. This is one of the reasons why TypeScript is so popular among developers.

apps/site/styles/index.css

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,5 @@
77
*/
88

99
@import '@node-core/ui-components/styles/index.css';
10+
@import '@node-core/rehype-shiki/index.css';
1011
@import './locales.css';

packages/rehype-shiki/package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
{
22
"name": "@node-core/rehype-shiki",
3-
"version": "1.1.0",
3+
"version": "1.2.0",
44
"type": "module",
55
"exports": {
66
".": "./src/index.mjs",
7+
"./index.css": "./src/index.css",
78
"./*": "./src/*.mjs"
89
},
910
"repository": {
@@ -23,6 +24,7 @@
2324
"@shikijs/core": "^3.12.0",
2425
"@shikijs/engine-javascript": "^3.12.0",
2526
"@shikijs/engine-oniguruma": "^3.12.0",
27+
"@shikijs/twoslash": "^3.12.2",
2628
"classnames": "catalog:",
2729
"hast-util-to-string": "^3.0.1",
2830
"shiki": "~3.12.0",

packages/rehype-shiki/src/__tests__/highlighter.test.mjs

Lines changed: 1 addition & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -20,33 +20,7 @@ mock.module('shiki/themes/nord.mjs', {
2020
});
2121

2222
describe('createHighlighter', async () => {
23-
const { createHighlighter } = await import('../highlighter.mjs');
24-
25-
describe('getLanguageDisplayName', () => {
26-
it('returns display name for known languages', () => {
27-
const langs = [
28-
{ name: 'javascript', displayName: 'JavaScript', aliases: ['js'] },
29-
];
30-
const highlighter = createHighlighter({ langs });
31-
32-
assert.strictEqual(
33-
highlighter.getLanguageDisplayName('javascript'),
34-
'JavaScript'
35-
);
36-
assert.strictEqual(
37-
highlighter.getLanguageDisplayName('js'),
38-
'JavaScript'
39-
);
40-
});
41-
42-
it('returns original name for unknown languages', () => {
43-
const highlighter = createHighlighter({ langs: [] });
44-
assert.strictEqual(
45-
highlighter.getLanguageDisplayName('unknown'),
46-
'unknown'
47-
);
48-
});
49-
});
23+
const { default: createHighlighter } = await import('../highlighter.mjs');
5024

5125
describe('highlightToHtml', () => {
5226
it('extracts inner HTML from code tag', () => {

0 commit comments

Comments
 (0)