Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions apps/site/components/Releases/ReleaseSchedule/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { create } from 'lts';

import provideReleaseSchedule from '#site/next-data/providers/releaseSchedule';

import type { FC } from 'react';

const MONTH = 30 * 24 * 3_600_000;

const ReleaseSchedule: FC = async () => {
const schedule = await provideReleaseSchedule();

// eslint-disable-next-line react-hooks/purity
const now = Date.now();

const threeMonthsAgo = new Date(now - 3 * MONTH);
const sixMonthsFromNow = new Date(now + 6 * MONTH);

const svg = create({
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is showing a warning that I'm not sure how to solve:

@node-core/website:dev: Package jsdom can't be external
@node-core/website:dev: The request jsdom matches serverExternalPackages (or the default list).
@node-core/website:dev: The package resolves to a different version when requested from the project directory (27.4.0) compared to the package requested from the importing module (9.4.1).
@node-core/website:dev: Make sure to install the same version of the package in both locations.

data: schedule,
queryStart: threeMonthsAgo,
queryEnd: sixMonthsFromNow,
animate: true,
excludeMain: false,
projectName: 'Node.js',
currentDateMarker: 'red',
});

return (
<div
dangerouslySetInnerHTML={{ __html: svg.html() }}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While I understand the reason for this, is there a way to avoid this potentially dangerous situation?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not that I'm aware of, svg.html() returns a simple string

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would probably then recommend finding a way to make this return a react node instead of raw html. Who maintains 'lts'? Can we make a @node-core/lts-react?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's on Node.js domain

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can return variables like xScale, yScale, xAxis etc from the lts function and render the SVG inside our component using jsx.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Who maintains 'lts'

build wg but not really maintained. IMO it's can be a good idea to make it live here under web-infra team

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We probably should have co-ownership, but this feels like smth that should be owned by releasers or build primarily.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Who maintains 'lts'

build wg but not really maintained. IMO it's can be a good idea to make it live here under web-infra team

@avivkeller @ovflowd I think @AugustinMauroy has a great point. The @nodejs/releasers showed they already have plans of getting rid of SVG, so maybe it's time for the @nodejs/nodejs-website to create our own version.

Copy link
Member

@ovflowd ovflowd Jan 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@avivkeller I don't think they have plans to get rid of the svg ;) what Richard stated was that the PR Guilherme originally opened didn't make sense for them on their PoV and should be done on our side.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we should have competing repositories for the lts svg source of truth tbh. All I'm saying is we can have shared ownership of the lts package if needed. Or make a new package that extends that one at maximum, but I'd like to avoid that route...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

to be honest, I'm fine with this as long as server-side-rendering works.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Me too. We can refactor this by creating a component that does not use d3-node, but we'll end up with more duplicated code.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm fine too

className="h-auto w-auto"
/>
Comment on lines +28 to +32
Copy link

Copilot AI Jan 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The generated SVG HTML is being directly injected using dangerouslySetInnerHTML without any sanitization. While the content comes from the 'lts' library, this could pose security risks if that library or the data it processes is compromised. Consider:

  1. Validating/sanitizing the SVG output before rendering
  2. Using a safer rendering method if possible
  3. Adding comments explaining why dangerouslySetInnerHTML is necessary here

Copilot uses AI. Check for mistakes.
);
};

export default ReleaseSchedule;
2 changes: 2 additions & 0 deletions apps/site/mdx/components.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import MDXImage from '#site/components/MDX/Image';
import MinorReleasesTable from '#site/components/Releases/MinorReleasesTable';
import PreviousReleasesTable from '#site/components/Releases/PreviousReleasesTable';
import ReleaseOverview from '#site/components/Releases/ReleaseOverview';
import ReleaseSchedule from '#site/components/Releases/ReleaseSchedule';
import WithBadgeGroup from '#site/components/withBadgeGroup';
import WithBanner from '#site/components/withBanner';
import WithDownloadArchive from '#site/components/withDownloadArchive';
Expand Down Expand Up @@ -96,6 +97,7 @@ export default {
BadgeGroup,
ReleaseOverview,
MinorReleasesTable,
ReleaseSchedule,
UpcomingMeetings,
EOLAlertBox,
EOLReleaseTable,
Expand Down
10 changes: 10 additions & 0 deletions apps/site/next-data/generators/releaseSchedule.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { RELEASE_SCHEDULE_URL } from '#site/next.constants.mjs';
import { fetchWithRetry } from '#site/util/fetch';

async function fetchReleaseSchedule() {
const response = await fetchWithRetry(RELEASE_SCHEDULE_URL);

return response.json();
}

export default fetchReleaseSchedule;
5 changes: 5 additions & 0 deletions apps/site/next-data/providers/releaseSchedule.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { cache } from 'react';

import generateReleaseSchdule from '#site/next-data/generators/releaseSchedule.mjs';

export default cache(generateReleaseSchdule);
6 changes: 6 additions & 0 deletions apps/site/next.constants.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -219,3 +219,9 @@ export const VULNERABILITIES_URL =
*/
export const OPENCOLLECTIVE_MEMBERS_URL =
'https://opencollective.com/nodejs/members/all.json';

/**
* The location of the Node.js release schedule JSON.
*/
export const RELEASE_SCHEDULE_URL =
'https://raw.githubusercontent.com/nodejs/Release/refs/heads/main/schedule.json';
1 change: 1 addition & 0 deletions apps/site/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
"feed": "~5.1.0",
"github-slugger": "~2.0.0",
"gray-matter": "~4.0.3",
"lts": "github:araujogui/lts-schedule#refactor-website",
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can use the upstream package once this pr is merged

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding blocked until then

"mdast-util-to-string": "^4.0.0",
"next": "16.0.10",
"next-intl": "~4.5.3",
Expand Down
2 changes: 1 addition & 1 deletion apps/site/pages/en/about/previous-releases.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ Production applications should only use _Active LTS_ or _Maintenance LTS_ releas

## Release Schedule

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

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

Expand Down
Loading
Loading