Skip to content

Conversation

@antfitch
Copy link
Collaborator

@antfitch antfitch commented Dec 4, 2025

Description:

This PR refactors the changelog implementation to use a hybrid static/dynamic architecture and migrates the Dart SDK Chagelog, Breaking Changes page, Language Evolution page to this new system.

Preview:

https://dart-dev--pr7056-breaking-changes-migration-9su53cep.web.app/changelog

Stages for this PR before we merge:

This PR has a few stages. This is the workflow I plan to follow:

  • First batch of commits: code quality review, make sure nothing is missing that was in Breaking Changes, Language Evolution, Dart SDK Changelog.

  • Second batch of commits: @antfitch to remove Breaking Changes, Language Evolution, and Dart SDK Changelog from the TOC (please note that we will not be removing the CHANGELOG.md from it's repo, but we will no longer directly link to it in our TOC)

Key Changes:

  • Architecture: Implemented a new hybrid architecture where changelog content is rendered statically (SSG) for SEO and performance, while client-side filtering is handled via a lightweight JavaScript layer.

  • Components:

    • Created ChangelogIndex as the main server component.
    • Implemented ChangelogFilters and ChangelogFiltersSidebar for client-side interactivity.
    • Added shared filtering components (CheckboxFilterGroup, FilterToolbar).
  • Data Model: Introduced ChangelogEntry model that parses data from YAML on the server and re-hydrates from DOM data- attributes on the client.

  • Documentation: Added site/doc/changelog_architecture.md detailing the new architecture, data flow, and maintenance guide.

  • Content: Migrated content to src/data/changelog.yml.

What's after this PR:

After this PR is merged, I will move the Dart doc site changes into the new Changelog system.

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @antfitch, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly refactors the changelog system for Dart documentation, moving from disparate pages to a unified, interactive experience. The new system leverages a hybrid static and client-side approach to ensure optimal performance and search engine visibility while providing users with dynamic filtering and search capabilities. This change centralizes content management and introduces a robust, well-documented architecture for future maintainability.

Highlights

  • New Changelog Architecture: Implemented a hybrid static/dynamic architecture for the changelog page, combining static-site generation (SSG) for SEO and initial load performance with client-side JavaScript for interactive filtering and searching.
  • Content Migration: Migrated existing changelog content, including the Dart SDK Changelog, Breaking Changes page, and Language Evolution page, to this new centralized system, with content now stored in src/data/changelog.yml.
  • New Components and Data Model: Introduced several new components: ChangelogIndex (main server component), ChangelogFilters and ChangelogFiltersSidebar (client-side interactivity), and shared filtering UI components. A new ChangelogEntry data model was created to parse YAML data server-side and re-hydrate from DOM data- attributes client-side.
  • Comprehensive Documentation: Added a detailed site/doc/changelog_architecture.md document, outlining the new architecture, data flow, and a maintenance guide for managing changelog entries.
  • Improved Markdown Parsing: Enhanced the DashMarkdown component to support inline parsing and more robustly handle text content within nodes, improving markdown rendering capabilities.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@antfitch antfitch self-assigned this Dec 4, 2025
@antfitch antfitch added the infra.design Relates to the design of docs.Dart.dev label Dec 4, 2025
Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a new changelog system for Dart documentation, featuring a hybrid static/dynamic architecture for improved SEO and user experience. The changes include new Dart components for filtering and displaying changelog entries, along with corresponding SCSS for styling and a detailed architecture document. The implementation appears well-structured, leveraging client-side interactivity for filtering while maintaining static rendering for initial load performance. The new system also includes a clear data model and management guide for changelog entries. Overall, the changes are comprehensive and well-executed, enhancing the usability and maintainability of the changelog page.

@dart-github-bot
Copy link
Collaborator

dart-github-bot commented Dec 4, 2025

Visit the preview URL for this PR (updated for commit b61f136):

https://dart-dev--pr7056-breaking-changes-migration-9su53cep.web.app

@antfitch
Copy link
Collaborator Author

antfitch commented Dec 5, 2025

/gemini review

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a well-architected changelog system using a hybrid static/dynamic approach, which is a great improvement for both SEO and user experience. The new architecture is thoroughly documented, and the migration of existing content into the new YAML-based system is a significant step forward. My review focuses on improving the maintainability of the new CSS, ensuring the correctness of the generated HTML, and refining some of the Dart implementation details. Overall, this is a solid contribution.

@antfitch antfitch marked this pull request as ready for review December 5, 2025 23:03
@antfitch
Copy link
Collaborator Author

antfitch commented Dec 5, 2025

This is ready for review. @parlough, @ericwindmill, and @kevmoo if you need any changes, let me know.

@kevmoo
Copy link
Member

kevmoo commented Dec 6, 2025

I didn't review the code, but I noticed the staged version:

image

See the double title thingy?

Copy link
Contributor

@ericwindmill ericwindmill left a comment

Choose a reason for hiding this comment

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

I left a few comments, all of which are small and/or just style opinions.

I am not a web expert or Jaspr expert, so @parlough's opinion would be valuable here.

Comment on lines 111 to 113
// pattern: RegExp('LearningResourceIndex', caseSensitive: false),
// builder: (_, _, _) => LearningResourceIndex(),
// ),
Copy link
Contributor

Choose a reason for hiding this comment

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

We shouldn't leave commented out code in the codebase

Copy link
Collaborator Author

@antfitch antfitch Dec 12, 2025

Choose a reason for hiding this comment

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

Removing.

deprecated('deprecated', 'Deprecated'),
removed('removed', 'Removed'),
none('none', 'None')
;
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: This semicolon on it's own line is weird? Maybe run dart fmt

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The dart formatter is doing this automatically. Here's the message I get back about why this is here:

The standard Dart formatter (dart format) places this semicolon on its own line to clearly distinguish the list of enum cases from the class-like logic that follows. If you didn't have the constructor or fields, the semicolon wouldn't be necessary at all.

And yeah, that's all I've got. So leaving for now, but maybe something to ask the Dart team to reconsider if it seems too weird?

box-shadow: 0 4px 24px rgba(0, 0, 0, 0.2);
width: 90%;
max-width: 600px;
max-height: 90vh;
Copy link
Contributor

Choose a reason for hiding this comment

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

I think the max-width should have a larger max width, it looks cramped when the desktop window is full screen.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Aye! I last tested on mobile and forgot to test again on desktop. Changed the desktop version to 900px. Hope that's enough.


dl {
display: grid;
grid-template-columns: max-content 1fr;
Copy link
Contributor

Choose a reason for hiding this comment

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

Similar to my above comment, I think this should be something like 2fr 3fr. The content looks cramped because the first column takes up most of the space, but has less content. Alternatively, you could explicitly make the content in column 1 be on two lines, so the max-content width isn't so long.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Added a media query to deal with screen width larger than 600px. Added 2fr 3fr to that.

}

dl {
display: grid;
Copy link
Contributor

Choose a reason for hiding this comment

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

The legend popup is pretty is hard to read on mobile. Consider using grid-template-area to make the grid shape change based on the width of the screen. For example, the "type of change" could be listed above the paragraph of explainer text on mobile, and in columns (as it is now) on larger screens

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This should be fixed now. Can you take another look?

@antfitch
Copy link
Collaborator Author

antfitch commented Dec 8, 2025

Let's choose a data serialization strategy for Dash sites before committing this.

Copy link
Member

@parlough parlough left a comment

Choose a reason for hiding this comment

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

This is exciting @antfitch! Thanks for diving into this.

I haven't had a chance to do a full review, but thought I would leave my in-progress comments. I'll finish up soon.

}
}

// Helper functions for definition list elements if not available in jaspr
Copy link
Member

Choose a reason for hiding this comment

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

In the latest release (v0.22) of Jaspr (which we use after 97c6cdd), I added supported for these dom components. So once you update with main, you can remove these functions and use the built-in ones :)

Comment on lines 72 to 73
print('Error rendering markdown: $e\n$st');
return text('Error rendering markdown');
Copy link
Member

Choose a reason for hiding this comment

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

I'd prefer if we don't catch errors here as it might cause issues to be lost. If some Markdown fails to be parsed, we likely should fix it right away rather than potentially not noticing.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Check out my update. Does it work?

markdown: ^7.3.0
path: ^1.9.1
yaml: ^3.1.3
yaml_edit: ^2.2.2
Copy link
Member

Choose a reason for hiding this comment

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

It seems this dependency isn't used:

Suggested change
yaml_edit: ^2.2.2

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

deleted

Comment on lines 23 to 28
for (final entry in _liquidVariables.entries) {
description = description.replaceAll(entry.key, entry.value);
if (link != null) {
link = link.replaceAll(entry.key, entry.value);
}
}
Copy link
Member

Choose a reason for hiding this comment

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

This manual replacement of Liquid variables doesn't feel too great and I worry it'll cause confusion around why some are working while others aren't.

Since it likely doesn't make sense to run the full templating logic over these strings either, perhaps it's best to just avoid using the template variables in the data and just use the expected values.

I don't expect the current variables used here to change much and if ever needed, they are pretty easy to update with find and replace.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Had Antigravity clean this up. How did it do?

}
}
}
} No newline at end of file
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
}
}

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

My IDE was deleting these by default on safe. face palm. Should be fixed now.

Comment on lines 96 to 98
if (entry.link != null)
div(classes: 'read-more', [
a(href: entry.link!, target: Target.blank, [
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
if (entry.link != null)
div(classes: 'read-more', [
a(href: entry.link!, target: Target.blank, [
if (entry.link case final entryLink?)
div(classes: 'read-more', [
a(href: entryLink, target: Target.blank, [

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I ended up having Antigravity fix this. I'm actually worried that we may need to update our documentation to make sure we have the most recent information and we're using the more modern pattern that you suggested. Capturing this here so I can find this comment later.

Comment on lines 100 to 102
span(classes: 'material-symbols-outlined', [
text('open_in_new'),
]),
Copy link
Member

Choose a reason for hiding this comment

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

We have a shared component for this.

Suggested change
span(classes: 'material-symbols-outlined', [
text('open_in_new'),
]),
MaterialIcon('open_in_new'),

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Also flagging Antigravity here. We need to circle back and make sure it's suggesting the most up-to-date solutions.

]),
DashMarkdown(content: entry.description),
if (entry.link != null)
div(classes: 'read-more', [
Copy link
Member

Choose a reason for hiding this comment

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

Consider updating this to use the already existing Button component. If not, consider adding the text-button class to make the styling and interaction handling more consistent.

Copy link
Collaborator Author

@antfitch antfitch Dec 12, 2025

Choose a reason for hiding this comment

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

Updated! Part of this update included adding a trailing icon to the Button class. Look closely.

if (entry.subArea != null) 'data-subarea': entry.subArea!,
'data-tags': entry.tags.map((t) => t.id).join(','),
// Store description for client-side search.
// Warning: This might be large.
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 not sure we should do this. It bloats the page size quite a bit since everything is loaded.

Could the search instead check the already existing content? If we do keep it in the data, we need to escape any potential HTML in the description.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Removed the 'data-description' attribute which should help with page size bloat and updated the search logic in changelog_model.dart. Take a close look.

ChangelogEntry.fromMap(change as Map<String, Object?>),
);
}
}
Copy link
Member

Choose a reason for hiding this comment

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

Currently this will silently fail if there are no changelog entries, rendering an empty index.

Since that likely indicates a mistake or other regression, consider adding a check that if changesData is null or is empty, throws an error.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Double-check my change. Is it what you need?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

infra.design Relates to the design of docs.Dart.dev

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants