Skip to content

Commit f684e6e

Browse files
committed
feat(snippets): seperate nodejs snippet, add corepack installation
1 parent 9f16142 commit f684e6e

File tree

10 files changed

+102
-85
lines changed

10 files changed

+102
-85
lines changed

apps/site/components/Downloads/Release/ReleaseCodeBox.tsx

Lines changed: 98 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {
1616
ReleaseContext,
1717
ReleasesContext,
1818
} from '#site/providers/releaseProvider';
19+
import type { DownloadSnippet } from '#site/types/download';
1920
import type { ReleaseContextType } from '#site/types/release';
2021
import { INSTALL_METHODS } from '#site/util/download';
2122

@@ -26,80 +27,109 @@ import { INSTALL_METHODS } from '#site/util/download';
2627
// by Shiki to render the highlighted syntax. Hence XSS attacks or JavaScript injections are not possible.
2728
const interpreter = createSval({}, 'script');
2829

29-
const parseSnippet = (s: string, releaseContext: ReleaseContextType) => {
30-
// Adds the release context to the interpreter context
30+
/**
31+
* Parses a snippet string using the interpreter with the given release context
32+
*/
33+
const parseSnippet = (snippet: string, releaseContext: ReleaseContextType) => {
3134
interpreter.import({ props: releaseContext });
32-
33-
// Evaluates the JavaScript code applying the release context to the code
34-
interpreter.run(`exports.content = \`${s}\``);
35-
36-
// Sets the parsed raw string to be used by the JSX CodeBox
37-
return String(interpreter.exports.content);
35+
interpreter.run(`exports.content = \`${snippet}\``);
36+
return interpreter.exports.content;
3837
};
3938

40-
const ReleaseCodeBox: FC = () => {
41-
const { snippets } = useContext(ReleasesContext);
39+
/**
40+
* Custom hook to handle snippet processing logic
41+
*/
42+
const useSnippetProcessor = (
43+
snippets: Array<DownloadSnippet>,
44+
context: ReleaseContextType
45+
) => {
46+
return useMemo(() => {
47+
// Find relevant snippets
48+
const installMethodSnippet = snippets.find(
49+
({ name }) => name === context.installMethod.toLowerCase()
50+
);
4251

43-
const { installMethod, os, packageManager, release } =
44-
useContext(ReleaseContext);
52+
const packageManagerSnippet = snippets.find(
53+
({ name }) => name === context.packageManager.toLowerCase()
54+
);
4555

46-
const t = useTranslations();
56+
// Only process if both snippets are available
57+
if (!installMethodSnippet || !packageManagerSnippet) {
58+
return '';
59+
}
4760

48-
// Retrieves the current platform (Dropdown Item) based on the selected platform value
49-
const currentPlatform = useMemo(
50-
() => INSTALL_METHODS.find(({ value }) => value === installMethod),
51-
[installMethod]
52-
);
61+
const verifyNodeSnippet = snippets.find(({ name }) => name === 'node');
62+
63+
const installCorepackSnippet =
64+
context.packageManager !== 'NPM' &&
65+
// Corepack is no longer distributed with Node.js v25
66+
context.release.major >= 25 &&
67+
snippets.find(({ name }) => name === 'corepack');
68+
69+
// Combine and parse snippets
70+
const parsedContent = parseSnippet(
71+
[
72+
installMethodSnippet,
73+
verifyNodeSnippet,
74+
installCorepackSnippet,
75+
packageManagerSnippet,
76+
]
77+
.filter(Boolean)
78+
.map(snippet => (snippet as DownloadSnippet).content)
79+
.join('\n'),
80+
context
81+
);
5382

54-
// Parses the snippets based on the selected platform, package manager, and release context
55-
const parsedSnippets = useMemo(() => {
56-
// Retrieves a snippet for the given Installation Method (aka Platform)
57-
const installMethodSnippet = snippets.find(
58-
({ name }) => name === installMethod.toLowerCase()
83+
// Convert to HTML using Shiki's highlighter
84+
// This is faster than JSX rendering as it avoids React runtime overhead
85+
return highlightToHtml(
86+
parsedContent,
87+
context.os === 'WIN' ? 'ps1' : 'bash'
5988
);
89+
}, [snippets, context]);
90+
};
6091

61-
// Retrieves a snippet for the given Package Manager to be bundled with the Platform snippet
62-
const packageManagerSnippet = snippets.find(
63-
({ name }) => name === packageManager.toLowerCase()
92+
/**
93+
* Custom hook to get current platform information
94+
*/
95+
const usePlatformInfo = (installMethod: string) => {
96+
return useMemo(() => {
97+
const platform = INSTALL_METHODS.find(
98+
({ value }) => value === installMethod
6499
);
65100

66-
// Prevents numerous recalculations of `sval` and `Shiki` when not necessary
67-
// As we only want to parse the snippets when both the Platform and Package Manager snippets are available
68-
if (installMethodSnippet && packageManagerSnippet) {
69-
const content = parseSnippet(
70-
// Bundles the Platform and Package Manager snippets
71-
`${installMethodSnippet.content}\n${packageManagerSnippet.content}`,
72-
// Passes a partial state of only the things we need to the parser
73-
{ release, os } as ReleaseContextType
74-
);
75-
76-
// We use Shikis's `hast-util-to-html` to convert the highlighted code into plain HTML (Pretty much using Rehype)
77-
// This is actually faster than using `hast-util-to-jsx-runtime` and then rendering the JSX
78-
// As it requires React's runtime to interpolate and build these components dynamically
79-
// Which also leads to a lot o GC being emitted. (Tested via Profiling)
80-
return highlightToHtml(content, os === 'WIN' ? 'ps1' : 'bash');
81-
}
101+
// Provide defaults for destructuring
102+
return {
103+
label: platform?.label || '',
104+
url: platform?.url || '',
105+
info: platform?.info || 'layouts.download.codeBox.platformInfo.default',
106+
recommended: platform?.recommended || false,
107+
exists: !!platform,
108+
};
109+
}, [installMethod]);
110+
};
82111

83-
return '';
84-
// Only change to these specific properties which are relevant for the re-rendering of the CodeBox
85-
// eslint-disable-next-line react-hooks/exhaustive-deps
86-
}, [release.versionWithPrefix, installMethod, os, packageManager]);
112+
/**
113+
* ReleaseCodeBox component displays installation instructions based on platform and context
114+
*/
115+
const ReleaseCodeBox: FC = () => {
116+
const { snippets } = useContext(ReleasesContext);
117+
const context = useContext(ReleaseContext);
118+
const t = useTranslations();
87119

88-
// Determines the code language based on the OS
89-
const displayName = os === 'WIN' ? 'PowerShell' : 'Bash';
120+
// Process platform information
121+
const platformInfo = usePlatformInfo(context.installMethod);
90122

91-
// Determines if the code box should render the skeleton loader
92-
const renderSkeleton = os === 'LOADING' || installMethod === '';
123+
// Process snippets
124+
const parsedSnippets = useSnippetProcessor(snippets, context);
93125

94-
// Defines fallbacks for the currentPlatform object
95-
const {
96-
label = '',
97-
url = '',
98-
info = 'layouts.download.codeBox.platformInfo.default',
99-
} = currentPlatform ?? {};
126+
// UI state calculations
127+
const displayLanguage = context.os === 'WIN' ? 'PowerShell' : 'Bash';
128+
const isLoading = context.os === 'LOADING' || context.installMethod === '';
100129

101130
return (
102131
<div className="mb-6 mt-4 flex flex-col gap-2">
132+
{/* NoScript warning */}
103133
<noscript>
104134
<AlertBox
105135
title={t('components.common.alertBox.warning')}
@@ -116,9 +146,11 @@ const ReleaseCodeBox: FC = () => {
116146
</AlertBox>
117147
</noscript>
118148

119-
<WithReleaseAlertBox status={release.status} />
149+
{/* Release status alert */}
150+
<WithReleaseAlertBox status={context.release.status} />
120151

121-
{!currentPlatform || currentPlatform.recommended || (
152+
{/* Community platform notice */}
153+
{platformInfo.exists && !platformInfo.recommended && (
122154
<AlertBox
123155
title={t('components.common.alertBox.info')}
124156
level="info"
@@ -128,19 +160,21 @@ const ReleaseCodeBox: FC = () => {
128160
</AlertBox>
129161
)}
130162

131-
<Skeleton loading={renderSkeleton}>
132-
<CodeBox language={displayName} className="min-h-[16.5rem]">
163+
{/* Code display with skeleton loading */}
164+
<Skeleton loading={isLoading}>
165+
<CodeBox language={displayLanguage} className="min-h-[16.5rem]">
133166
<code dangerouslySetInnerHTML={{ __html: parsedSnippets }} />
134167
</CodeBox>
135168
</Skeleton>
136169

170+
{/* Platform info footer */}
137171
<span className="text-center text-xs text-neutral-800 dark:text-neutral-200">
138-
<Skeleton loading={renderSkeleton} hide={!currentPlatform}>
139-
{t(info, { platform: label })}{' '}
172+
<Skeleton loading={isLoading} hide={!platformInfo.exists}>
173+
{t(platformInfo.info, { platform: platformInfo.label })}{' '}
140174
{t.rich('layouts.download.codeBox.externalSupportInfo', {
141-
platform: label,
175+
platform: platformInfo.label,
142176
link: text => (
143-
<LinkWithArrow href={url}>
177+
<LinkWithArrow href={platformInfo.url}>
144178
<b>{text}</b>
145179
</LinkWithArrow>
146180
),

apps/site/snippets/en/download/brew.bash

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,3 @@ curl -o- https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh | ba
33

44
# Download and install Node.js:
55
brew install node@${props.release.major}
6-
7-
# Verify the Node.js version:
8-
node -v # Should print "${props.release.versionWithPrefix}".

apps/site/snippets/en/download/choco.bash

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,3 @@ powershell -c "irm https://community.chocolatey.org/install.ps1|iex"
33

44
# Download and install Node.js:
55
choco install nodejs --version="${props.release.version}"
6-
7-
# Verify the Node.js version:
8-
node -v # Should print "${props.release.versionWithPrefix}".
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# Install Corepack
2+
npm install -g corepack

apps/site/snippets/en/download/devbox.bash

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,3 @@ devbox add node@${props.release.major}
99

1010
# Open a Devbox shell
1111
devbox shell
12-
13-
# Verify the Node.js version:
14-
node -v # Should print "${props.release.versionWithPrefix}".

apps/site/snippets/en/download/docker.bash

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,3 @@ docker pull node:${props.release.major}-${props.release.major >= 4 ? 'alpine' :
66

77
# Create a Node.js container and start a Shell session:
88
docker run -it --rm --entrypoint sh node:${props.release.major}-${props.release.major >= 4 ? 'alpine' : 'slim'}
9-
10-
# Verify the Node.js version:
11-
node -v # Should print "${props.release.versionWithPrefix}".

apps/site/snippets/en/download/fnm.bash

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,3 @@ ${props.os === 'WIN' ?
66

77
# Download and install Node.js:
88
fnm install ${props.release.major}
9-
10-
# Verify the Node.js version:
11-
node -v # Should print "${props.release.versionWithPrefix}".

apps/site/snippets/en/download/n.bash

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,3 @@ curl -fsSL https://raw.githubusercontent.com/mklement0/n-install/stable/bin/n-in
33

44
# Node.js already installs during n-install, but you can also install it manually:
55
# n install ${props.release.major}
6-
7-
# Verify the Node.js version:
8-
node -v # Should print "${props.release.versionWithPrefix}".
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# Verify the Node.js version:
2+
node -v # Should print "${props.release.versionWithPrefix}".

apps/site/snippets/en/download/volta.bash

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,3 @@ ${props.os === 'WIN' ?
66

77
# Download and install Node.js:
88
volta install node@${props.release.major}
9-
10-
# Verify the Node.js version:
11-
node -v # Should print "${props.release.versionWithPrefix}".

0 commit comments

Comments
 (0)