Skip to content

Commit

Permalink
feat: official vs community and instructions for downloads page
Browse files Browse the repository at this point in the history
  • Loading branch information
ovflowd committed Dec 28, 2024
1 parent 1ef006f commit ca999cd
Show file tree
Hide file tree
Showing 19 changed files with 184 additions and 50 deletions.
111 changes: 111 additions & 0 deletions COLLABORATOR_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@
- [Best practices when creating a Component](#best-practices-when-creating-a-component)
- [How a new Component should look like when freshly created](#how-a-new-component-should-look-like-when-freshly-created)
- [Best practices for Component development in general](#best-practices-for-component-development-in-general)
- [The new Downloads page](#the-new-downloads-page)
- [Adding a Download Installation Method](#adding-a-download-installation-method)
- [Adding a Download Package Manager](#adding-a-download-package-manager)
- [Unit Tests and Storybooks](#unit-tests-and-storybooks)
- [General Guidelines for Unit Tests](#general-guidelines-for-unit-tests)
- [General Guidelines for Storybooks](#general-guidelines-for-storybooks)
Expand Down Expand Up @@ -259,6 +262,114 @@ export default MyComponent;
Use utilities or Hooks when you need a Reactive state
- Avoid making your Component too big. Deconstruct it into smaller Components/Hooks whenever possible

## The new Downloads page

### Adding a Download Installation Method

To add a new download installation method, follow these steps:

1. **Update `INSTALL_METHODS` in `apps/site/utils/downloadUtils.tsx`:**

- Add a new entry to the `INSTALL_METHODS` array.
- Each entry should have the following properties:
- `iconImage`: The path to the icon image for the installation method. This should be an SVG component stored within `apps/site/components/Icons/InstallationMethod` and must follow the other icon component references (being a `FC` supporting `SVGSVGElement` props).
- `recommended`: A boolean indicating if this method is recommended. This property is available only for official installation methods.
- `url`: The URL for the installation method.
- `value`: The key of the installation method, which must be unique.

Example:

```javascript
// filepath: /nodejs.org/apps/site/utils/downloadUtils.tsx
export const INSTALL_METHODS = [
// ...existing methods...
{
iconImage: 'path/to/icon.svg',
url: 'https://example.com/install',
value: 'exampleMethod',
},
];
```

2. **Add translation key in `packages/i18n/locales/en.json`:**

- Add an entry under `layouts.download.codeBox.platformInfo` for the `info` property of the new installation method.

Example:

```json
// filepath: /nodejs.org/packages/i18n/locales/en.json
{
"layouts": {
"download": {
"codeBox": {
"platformInfo": {
"exampleMethod": "Example installation method description."
}
}
}
}
}
```

3. **Update `InstallationMethodLabel` and `InstallationMethod` in `@/types/release.ts`:**

- Add the new method to the `InstallationMethodLabel` and `InstallationMethod` types.

Example:

```typescript
// filepath: /nodejs.org/apps/site/types/release.ts
export type InstallationMethod = 'exampleMethod' | 'anotherMethod' | ...;

export const InstallationMethodLabel: Record<InstallationMethod, string> = {
exampleMethod: 'Example Method',
anotherMethod: 'Another Method',
// ...existing methods...
};
```

4. **Add a snippet in `apps/site/snippets/download`:**

- Create a new file with the same key as the `value` property (e.g., `exampleMethod.bash`).
- Add the installation instructions in this file.
- The snippet file can use JavaScript template syntax and has access to a `props` variable of type `ReleaseContextType`.

Example:

```bash
// filepath: /nodejs.org/apps/site/snippets/download/exampleMethod.bash
echo "Installing Node.js version ${props.version} using Example Method"
```

5. **Configure `compatbility` within the `INSTALL_METHODS` object in `downloadUtils.ts`:**

- Use the `compatbility` property to enable/list the installation method for specific OSs, Node.js version ranges, or architectures/platforms.

Example:

```javascript
// filepath: /nodejs.org/apps/site/utils/downloadUtils.tsx
export const INSTALL_METHODS = [
{
iconImage: 'path/to/icon.svg',
url: 'https://example.com/install',
value: 'exampleMethod',
compatibility: {
os: ['linux', 'macos'],
semver: ['>=14.0.0'],
platform: ['x64', 'arm64'],
},
},
];
```

By following these steps, you can successfully add a new download installation method to the Node.js website.

### Adding a Download Package Manager

You can add a PACKAGE_MANAGER the same way as adding an INSTALLATION_METHOD (from the section above, "Adding a Download Installation Method") but it should be added to the PACKAGE_MANAGERS object in `apps/site/utils/downloadUtils.tsx`.

## Unit Tests and Storybooks

Each new feature or bug fix should be accompanied by a unit test (when deemed valuable).
Expand Down
34 changes: 20 additions & 14 deletions apps/site/components/Downloads/DownloadReleasesTable.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { getTranslations } from 'next-intl/server';
import type { FC } from 'react';

import LinkWithArrow from '@/components/LinkWithArrow';
import getReleaseData from '@/next-data/releaseData';
import { getNodeApiLink } from '@/util/getNodeApiLink';
import { getNodeJsChangelog } from '@/util/getNodeJsChangelog';
Expand All @@ -17,11 +18,12 @@ const DownloadReleasesTable: FC = async () => {
<table id="tbVersions" className="download-table full-width">
<thead>
<tr>
<th>Node.js Version</th>
<th>Module Version</th>
<th>Codename</th>
<th>Release Date</th>
<th colSpan={2}>npm</th>
<th>{t('components.downloadReleasesTable.version')}</th>
<th>{t('components.downloadReleasesTable.nApiVersion')}</th>
<th>{t('components.downloadReleasesTable.codename')}</th>
<th>{t('components.downloadReleasesTable.releaseDate')}</th>
<th>{t('components.downloadReleasesTable.npmVersion')}</th>
<th></th>
</tr>
</thead>
<tbody>
Expand All @@ -35,17 +37,21 @@ const DownloadReleasesTable: FC = async () => {
</td>
<td data-label="npm">v{release.npm}</td>
<td className="download-table-last">
<a
<LinkWithArrow
href={`https://nodejs.org/download/release/${release.versionWithPrefix}/`}
>
{t('components.downloadReleasesTable.releases')}
</a>
<a href={getNodeJsChangelog(release.versionWithPrefix)}>
{t('components.downloadReleasesTable.changelog')}
</a>
<a href={getNodeApiLink(release.versionWithPrefix)}>
{t('components.downloadReleasesTable.docs')}
</a>
{t('components.downloadReleasesTable.actions.releases')}
</LinkWithArrow>

<LinkWithArrow
href={getNodeJsChangelog(release.versionWithPrefix)}
>
{t('components.downloadReleasesTable.actions.changelog')}
</LinkWithArrow>

<LinkWithArrow href={getNodeApiLink(release.versionWithPrefix)}>
{t('components.downloadReleasesTable.actions.docs')}
</LinkWithArrow>
</td>
</tr>
))}
Expand Down
2 changes: 1 addition & 1 deletion apps/site/components/Downloads/Release/BlogPostLink.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import type { FC, PropsWithChildren } from 'react';
import { useContext } from 'react';

import LinkWithArrow from '@/components/Downloads/Release/LinkWithArrow';
import LinkWithArrow from '@/components/LinkWithArrow';
import { ReleaseContext } from '@/providers/releaseProvider';

const BlogPostLink: FC<PropsWithChildren> = ({ children }) => {
Expand Down
2 changes: 1 addition & 1 deletion apps/site/components/Downloads/Release/ChangelogLink.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
import type { FC, PropsWithChildren } from 'react';
import { useContext } from 'react';

import LinkWithArrow from '@/components/Downloads/Release/LinkWithArrow';
import Link from '@/components/Link';
import LinkWithArrow from '@/components/LinkWithArrow';
import { BASE_CHANGELOG_URL } from '@/next.constants.mjs';
import { ReleaseContext } from '@/providers/releaseProvider';

Expand Down
3 changes: 1 addition & 2 deletions apps/site/components/Downloads/Release/ReleaseCodeBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,13 @@ import AlertBox from '@/components/Common/AlertBox';
import CodeBox from '@/components/Common/CodeBox';
import Skeleton from '@/components/Common/Skeleton';
import Link from '@/components/Link';
import LinkWithArrow from '@/components/LinkWithArrow';
import { createSval } from '@/next.jsx.compiler.mjs';
import { ReleaseContext, ReleasesContext } from '@/providers/releaseProvider';
import type { ReleaseContextType } from '@/types/release';
import { INSTALL_METHODS } from '@/util/downloadUtils';
import { highlightToHtml } from '@/util/getHighlighter';

import LinkWithArrow from './LinkWithArrow';

// Creates a minimal JavaScript interpreter for parsing the JavaScript code from the snippets
// Note: that the code runs inside a sandboxed environment and cannot interact with any code outside of the sandbox
// It also does not have access to any Global or Window objects, nor it can execute code on the end-user's browser
Expand Down
File renamed without changes.
File renamed without changes.
7 changes: 7 additions & 0 deletions apps/site/components/Icons/InstallationMethod/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import Choco from '@/components/Icons/InstallationMethod/Choco';
import Docker from '@/components/Icons/InstallationMethod/Docker';
import FNM from '@/components/Icons/InstallationMethod/FNM';
import Homebrew from '@/components/Icons/InstallationMethod/Homebrew';
import NVM from '@/components/Icons/InstallationMethod/NVM';

export default { Choco, Docker, FNM, Homebrew, NVM };
7 changes: 0 additions & 7 deletions apps/site/components/Icons/Platform/index.ts

This file was deleted.

File renamed without changes.
10 changes: 5 additions & 5 deletions apps/site/components/__design__/platform-logos.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { Meta as MetaObj, StoryObj } from '@storybook/react';

import InstallMethodIcons from '@/components/Icons/InstallationMethod';
import OSIcons from '@/components/Icons/OperatingSystem';
import PlatformIcons from '@/components/Icons/Platform';

export const PlatformLogos: StoryObj = {
render: () => (
Expand All @@ -13,12 +13,12 @@ export const PlatformLogos: StoryObj = {
<OSIcons.AIX width={64} height={64} />
</div>
<div className="flex flex-col items-center gap-4">
<PlatformIcons.Docker width={64} height={64} />
<PlatformIcons.Homebrew width={64} height={64} />
<PlatformIcons.NVM width={64} height={64} />
<InstallMethodIcons.Docker width={64} height={64} />
<InstallMethodIcons.Homebrew width={64} height={64} />
<InstallMethodIcons.NVM width={64} height={64} />
</div>
<div className="flex flex-col items-center gap-4">
<PlatformIcons.Choco width={64} height={64} />
<InstallMethodIcons.Choco width={64} height={64} />
</div>
</div>
),
Expand Down
9 changes: 2 additions & 7 deletions apps/site/i18n.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { importLocale } from '@node-core/website-i18n';
import defaultMessages from '@node-core/website-i18n/locales/en.json';
import { getRequestConfig } from 'next-intl/server';

import { availableLocaleCodes, defaultLocale } from '@/next.locales.mjs';
Expand All @@ -7,20 +8,14 @@ import deepMerge from './util/deepMerge';

// Loads the Application Locales/Translations Dynamically
const loadLocaleDictionary = async (locale: string) => {
// This enables HMR on the English Locale, so that instant refresh
// happens while we add/change texts on the source locale
const defaultMessages = await import(
'@node-core/website-i18n/locales/en.json'
).then(f => f.default);

if (locale === defaultLocale.code) {
return defaultMessages;
}

if (availableLocaleCodes.includes(locale)) {
// Other languages don't really require HMR as they will never be development languages
// so we can load them dynamically
const messages = await importLocale(locale);
const messages = importLocale(locale);

// Use default messages as fallback
return deepMerge(defaultMessages, messages);
Expand Down
2 changes: 1 addition & 1 deletion apps/site/next.mdx.use.client.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@ import DownloadLink from './components/Downloads/DownloadLink';
import BlogPostLink from './components/Downloads/Release/BlogPostLink';
import ChangelogLink from './components/Downloads/Release/ChangelogLink';
import InstallationMethodDropdown from './components/Downloads/Release/InstallationMethodDropdown';
import LinkWithArrow from './components/Downloads/Release/LinkWithArrow';
import OperatingSystemDropdown from './components/Downloads/Release/OperatingSystemDropdown';
import PackageManagerDropdown from './components/Downloads/Release/PackageManagerDropdown';
import PlatformDropdown from './components/Downloads/Release/PlatformDropdown';
import PrebuiltDownloadButtons from './components/Downloads/Release/PrebuiltDownloadButtons';
import ReleaseCodeBox from './components/Downloads/Release/ReleaseCodeBox';
import VersionDropdown from './components/Downloads/Release/VersionDropdown';
import Link from './components/Link';
import LinkWithArrow from './components/LinkWithArrow';
import MDXCodeBox from './components/MDX/CodeBox';
import MDXCodeTabs from './components/MDX/CodeTabs';
import MDXImage from './components/MDX/Image';
Expand Down
22 changes: 19 additions & 3 deletions apps/site/pages/en/about/previous-releases.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,28 @@ Production applications should only use _Active LTS_ or _Maintenance LTS_ releas

![Releases](https://raw.githubusercontent.com/nodejs/Release/main/schedule.svg?sanitize=true)

Full details regarding Node.js release schedule are available [on GitHub](https://github.com/nodejs/release#release-schedule).
Full details regarding the Node.js release schedule are available [on GitHub](https://github.com/nodejs/release#release-schedule).

### Commercial Support

Commercial support for versions past Maintenance phase is available through our OpenJS Ecosystem Sustainability Program partner [HeroDevs](https://herodevs.com/).
Commercial support for versions past the Maintenance phase is available through our OpenJS Ecosystem Sustainability Program partner [HeroDevs](https://herodevs.com/).

## Looking for latest release of a version branch?
## Looking for the latest release of a version branch?

<DownloadReleasesTable />

## Official versus Community

The Node.js website offers numerous installation methods that allow Node.js to be installed in a non-interactive manner,
for example, via CLIs, OS package managers (such as `apt`), or Node.js version managers (such as `nvm`).

The Node.js project, in an attempt to popularize and advertise community efforts, has introduced a new Downloads page that lists both Official and Community installation methods, providing more versatility and options for users.
With this change, we introduced the concept of "Official" and "Community" installation methods, which have the following key differences:

| | Official | Community |
| ------------------------------------------------------------------------------------------------------ | -------- | --------- |
| New Node.js releases are available simultaneously when Node.js releases come out |||
| Project maintainers have a close relationship with Node.js, at least a direct communication way |||
| Installation method downloads the official binaries bundled by the Node.js project |||
| Installation method builds from source and/or modifies what gets bundled (SSL version, Corepack, etc.) |||
| Installation method is the default recommendation for supported environments |||
12 changes: 6 additions & 6 deletions apps/site/util/downloadUtils.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import satisfies from 'semver/functions/satisfies';

import type { SelectValue } from '@/components/Common/Select';
import InstallMethodIcons from '@/components/Icons/InstallationMethod';
import OSIcons from '@/components/Icons/OperatingSystem';
import PackageManagerIcons from '@/components/Icons/PackageManager';
import PlatformIcons from '@/components/Icons/Platform';
import type { NodeReleaseStatus } from '@/types';
import type * as Types from '@/types/release';
import type { UserOS, UserPlatform } from '@/types/userOS';
Expand Down Expand Up @@ -162,7 +162,7 @@ export const INSTALL_METHODS: Array<
label: InstallationMethodLabel.NVM,
value: 'NVM',
compatibility: { os: ['MAC', 'LINUX', 'OTHER'] },
iconImage: <PlatformIcons.NVM width={16} height={16} />,
iconImage: <InstallMethodIcons.NVM width={16} height={16} />,
recommended: true,
url: 'https://github.com/nvm-sh/nvm',
info: 'layouts.download.codeBox.platformInfo.nvm',
Expand All @@ -171,31 +171,31 @@ export const INSTALL_METHODS: Array<
label: InstallationMethodLabel.FNM,
value: 'FNM',
compatibility: { os: ['MAC', 'LINUX', 'WIN'] },
iconImage: <PlatformIcons.FNM width={16} height={16} />,
iconImage: <InstallMethodIcons.FNM width={16} height={16} />,
url: 'https://github.com/Schniz/fnm',
info: 'layouts.download.codeBox.platformInfo.fnm',
},
{
label: InstallationMethodLabel.BREW,
value: 'BREW',
compatibility: { os: ['MAC', 'LINUX'], releases: ['Current', 'LTS'] },
iconImage: <PlatformIcons.Homebrew width={16} height={16} />,
iconImage: <InstallMethodIcons.Homebrew width={16} height={16} />,
url: 'https://brew.sh/',
info: 'layouts.download.codeBox.platformInfo.brew',
},
{
label: InstallationMethodLabel.CHOCO,
value: 'CHOCO',
compatibility: { os: ['WIN'] },
iconImage: <PlatformIcons.Choco width={16} height={16} />,
iconImage: <InstallMethodIcons.Choco width={16} height={16} />,
url: 'https://chocolatey.org/',
info: 'layouts.download.codeBox.platformInfo.choco',
},
{
label: InstallationMethodLabel.DOCKER,
value: 'DOCKER',
compatibility: { os: ['WIN', 'MAC', 'LINUX'] },
iconImage: <PlatformIcons.Docker width={16} height={16} />,
iconImage: <InstallMethodIcons.Docker width={16} height={16} />,
recommended: true,
url: 'https://docs.docker.com/get-started/get-docker/',
info: 'layouts.download.codeBox.platformInfo.docker',
Expand Down
Loading

0 comments on commit ca999cd

Please sign in to comment.