-
Notifications
You must be signed in to change notification settings - Fork 142
Structurally refactor Site class into Facade and separate Managers #2775
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
* Decouple monolithic Site god class. * Organize classes in Site/index.ts for git history, tracking before evict to separate files. * Extract responsibilities into dedicated manager classes - `SiteAssetsManager` - `SitePagesManager` (handling page collection and generation logic) - `SiteDeployManager` - `SiteGenerationManager` (orchestrating the build process) - Refactor `Site` class as Facade, delegate logic to underlying managers - Maintain public API compatibility for now.
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## master #2775 +/- ##
==========================================
+ Coverage 62.30% 71.67% +9.37%
==========================================
Files 130 134 +4
Lines 7184 7284 +100
Branches 1580 1514 -66
==========================================
+ Hits 4476 5221 +745
+ Misses 2644 2017 -627
+ Partials 64 46 -18 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
5c66e94 to
3f72158
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR refactors the monolithic Site class into a facade pattern with specialized manager classes, improving code maintainability and separation of concerns without breaking the public API.
Changes:
- Introduced four new manager classes to handle distinct responsibilities:
SiteAssetsManager,SitePagesManager,SiteDeployManager, andSiteGenerationManager - Refactored the
Siteclass as a facade that delegates to these managers while maintaining backward compatibility - Moved constants to a centralized location and reorganized test files to match the new structure
Reviewed changes
Copilot reviewed 12 out of 12 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/core/src/Site/index.ts | Refactored Site class as facade delegating to manager classes |
| packages/core/src/Site/SitePagesManager.ts | New manager handling page creation and collection logic |
| packages/core/src/Site/SiteGenerationManager.ts | New manager orchestrating build process and page generation |
| packages/core/src/Site/SiteDeployManager.ts | New manager handling deployment operations |
| packages/core/src/Site/SiteAssetsManager.ts | New manager handling asset operations (CSS, JS, fonts, images) |
| packages/core/src/Site/constants.ts | Added new constants extracted from Site class |
| packages/core/test/unit/Site.test.ts | Removed old monolithic test file |
| packages/core/test/unit/Site/Site.test.ts | New test file for refactored Site facade |
| packages/core/test/unit/Site/SitePagesManager.test.ts | New test file for SitePagesManager |
| packages/core/test/unit/Site/SiteGenerationManager.test.ts | New test file for SiteGenerationManager |
| packages/core/test/unit/Site/SiteDeployManager.test.ts | New test file for SiteDeployManager |
| packages/core/test/unit/Site/SiteAssetsManager.test.ts | New test file for SiteAssetsManager |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Removed internal and unused delegation methods from Site class. - Methods delegated without being used by CLI or external consumers removed. - Properties representing internal states (getters) removed as they break encapsulation and are unused. - This enforces the Facade pattern by hiding implementation details and ensure Site object does not act as "God Class" exposing internal helpers. - Consumers can now clearly see the key interfaces intended for public use. - Removed associated unit tests and Jest mocks for the deleted facade methods in testcases
When style.codeTheme was set to a value that is not dark or light, it would cause a crash Added validation else set to default.
Encapsulate PagesManager baseUrlMap assign with a setter Standardize AssetsManager.copyTheme to return resolved promise
Caused by conflict of Jest reporter and lerna output streaming. Add --ci flag to jest command to fix
Update `SitePagesManager` test mock with `baseUrlMap` Fix log message spacing.
yihao03
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very welcomed changes to refactor the Site class as it has proven to be difficult to understand when I was studying the codebase.
| * Copies core-web bundles and external assets to the assets output folder | ||
| */ | ||
| copyCoreWebAsset() { | ||
| const coreWebRootPath = path.dirname(require.resolve('@markbind/core-web/package.json')); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
would this be a good opportunity to refactor require.resolve to use ESM alternatives? this applies to other instances of require.resolve() too
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeap, that would be ideal to tackle in the next few PRs
| message: string, | ||
| repo: string, | ||
| remote: string, | ||
| user?: { name: string; email: string; }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there already a user type defined somewhere? should we define it in a types.ts or a types/user.ts assuming that this type will show up often?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it seems that the defined type is only used in this specific component's logic, especially since the cli package which interfaces with core is also not in TS and has no type annotations
The types are not consolidated together probably because it was infeasible to do so when past developers were working to migrate the core file by file, but now that core has almost entirely been migrated to TS, we can definitely consider some form of consolidation of types, how to organize them, pros and cons.
Feel free to raise an issue if you have any good ideas / to facilitate discussion!
| if (ciTokenVar) { | ||
| const ciToken = _.isBoolean(ciTokenVar) ? 'GITHUB_TOKEN' : ciTokenVar; | ||
| if (!process.env[ciToken]) { | ||
| throw new Error(`The environment variable ${ciToken} does not exist.`); | ||
| } | ||
| const githubToken = process.env[ciToken]; | ||
| let repoSlug; | ||
|
|
||
| if (process.env.TRAVIS) { | ||
| repoSlug = SiteDeployManager.extractRepoSlug(options.repo, process.env.TRAVIS_REPO_SLUG); | ||
|
|
||
| options.user = { | ||
| name: 'Deployment Bot', | ||
| email: 'deploy@travis-ci.org', | ||
| }; | ||
| } else if (process.env.APPVEYOR) { | ||
| repoSlug = SiteDeployManager.extractRepoSlug(options.repo, process.env.APPVEYOR_REPO_NAME); | ||
|
|
||
| options.user = { | ||
| name: 'AppVeyorBot', | ||
| email: 'deploy@appveyor.com', | ||
| }; | ||
| } else if (process.env.GITHUB_ACTIONS) { | ||
| // Set cache folder to a location Github Actions can find. | ||
| process.env.CACHE_DIR = path.join(process.env.GITHUB_WORKSPACE || '.cache'); | ||
| repoSlug = SiteDeployManager.extractRepoSlug(options.repo, process.env.GITHUB_REPOSITORY); | ||
|
|
||
| options.user = { | ||
| name: 'github-actions', | ||
| email: 'github-actions@github.com', | ||
| }; | ||
| } else if (process.env.CIRCLECI) { | ||
| repoSlug = SiteDeployManager.extractRepoSlug( | ||
| options.repo, | ||
| `${process.env.CIRCLE_PROJECT_USERNAME}/${process.env.CIRCLE_PROJECT_REPONAME}`, | ||
| ); | ||
|
|
||
| options.user = { | ||
| name: 'circleci-bot', | ||
| email: 'deploy@circleci.com', | ||
| }; | ||
| } else { | ||
| throw new Error('-c/--ci should only be run in CI environments.'); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
perhaps can use switch case?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good idea, can raise a PR for this
What is the purpose of this pull request?
Overview of changes:
Closes #2774
Closes #1756
Anything you'd like to highlight/discuss:
The
Siteclass had become a "God Class" with many responsibilities, making it hard to maintain and test.This PR refactors and decouples the monolithic Site god class class into a Facade provided by Site/index.ts. It delegates responsibilities to four newly created manager classes (SiteAssetsManager, SitePagesManager, SiteDeployManager, and SiteGenerationManager), which are currently defined within the same file.
SiteAssetsManager: Asset handling (copying, building, removing).SitePagesManager: Page collection and dependency management.SiteDeployManager: GH Pages and others deployment logic.SiteGenerationManager: Core build orchestration (generate, rebuild, lazy loading).Siteclass as Facade, delegate logic to underlying managersAdditionally, using
Siteclass as a Facade now enables us to hide some of the methods that are not used and not overexpose internal methods. Instead, we can easily see the key interfaces thecorepackage (Siteobject) exposes for consumers to use.Testing instructions:
npm run test(Plan to do a merge-commit):
Proposed commit message: (wrap lines at 72 characters)
Refactor Site class into Facade and specialized Managers
Decouples monolithic Site class by extracting logic into Managers
The Site class has too many responsibilities, hard to maintain, test.
Delegate specific responsibilities to created manager classes:
SiteAssetsManager: Handles asset copying, building, and removal.SitePagesManager: Manages page collection, mapping, and dependencies.SiteDeployManager: Handles deployment logic (e.g., GitHub Pages).SiteGenerationManager: Orchestrates build and regenerate processes.The Site class now acts as an entry point (Facade), exposing only the
necessary public API methods while hiding internal state and logic.
This separation of concerns significantly reduces complexity of core
package and improves testability with dedicated test cases for each manager.
Checklist: ☑️
Reviewer checklist:
Indicate the SEMVER impact of the PR:
At the end of the review, please label the PR with the appropriate label:
r.Major,r.Minor,r.Patch.Breaking change release note preparation (if applicable):