Skip to content

Conversation

@gerteck
Copy link
Member

@gerteck gerteck commented Jan 14, 2026

What is the purpose of this pull request?

  • Documentation update
  • Bug fix
  • Feature addition or enhancement
  • Code maintenance
  • DevOps
  • Improve developer experience
  • Others, please explain:

Overview of changes:

Closes #2774
Closes #1756

Anything you'd like to highlight/discuss:
The Site class 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.

  • Organize classes in Site/index.ts for git history, tracking before evict to separate files.
  • Extract responsibilities into dedicated manager classes
    • SiteAssetsManager: Asset handling (copying, building, removing).
      • Responsibility: Copying fonts, CSS, JS bundles, and bootstrap themes to the output directory. Handling ignore rules for assets.
    • SitePagesManager: Page collection and dependency management.
      • Responsibility: Collecting addressable pages from globs, creating Page objects, parsing frontmatter for configuration, and mapping URLs.
    • SiteDeployManager: GH Pages and others deployment logic.
      • Responsiblity: Pushing the artifacts in _site to a remote git branch (GitHub Pages).
    • SiteGenerationManager: Core build orchestration (generate, rebuild, lazy loading).
      • Responsibility: Orchestrating the build process (generate, buildSourceFiles), managing lazy loading logic, re-building affected pages, and writing site data.
  • Refactor Site class as Facade, delegate logic to underlying managers
  • Maintain public API compatibility for now.
  • Separate testcases for better maintainability.

Additionally, using Site class 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 the core package (Site object) exposes for consumers to use.

  • Previously, the Site class exposed numerous internal methods, allowing external manipulation of internal state and obscuring the actual public API. This change reduces the surface area of the Site class, making the core package easier to maintain and consume.

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: ☑️

  • Updated the documentation for feature additions and enhancements
  • Added tests for bug fixes or features
  • Linked all related issues
  • No unrelated changes

Reviewer checklist:

Indicate the SEMVER impact of the PR:

  • Major (when you make incompatible API changes)
  • Minor (when you add functionality in a backward compatible manner)
  • Patch (when you make backward compatible bug fixes)

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):

  • To be included in the release note for any feature that is made obsolete/breaking

Give a brief explanation note about:

  • what was the old feature that was made obsolete
  • any replacement feature (if any), and
  • how the author should modify his website to migrate from the old feature to the replacement feature (if possible).

* 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
Copy link

codecov bot commented Jan 14, 2026

Codecov Report

❌ Patch coverage is 72.17497% with 229 lines in your changes missing coverage. Please review.
✅ Project coverage is 71.67%. Comparing base (2400af3) to head (8d1ca19).
⚠️ Report is 24 commits behind head on master.

Files with missing lines Patch % Lines
packages/core/src/Site/SiteGenerationManager.ts 59.19% 182 Missing ⚠️
packages/core/src/Site/SitePagesManager.ts 74.54% 27 Missing and 1 partial ⚠️
packages/core/src/Site/SiteDeployManager.ts 89.81% 11 Missing ⚠️
packages/core/src/Site/index.ts 86.04% 6 Missing ⚠️
packages/core/src/Site/SiteAssetsManager.ts 99.03% 1 Missing ⚠️
packages/core/src/Site/SiteConfig.ts 66.66% 1 Missing ⚠️
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.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@gerteck gerteck force-pushed the refactor/coreSiteIndex branch from 5c66e94 to 3f72158 Compare January 14, 2026 09:03
@gerteck gerteck requested a review from Copilot January 14, 2026 11:32
@gerteck gerteck changed the title Refactor structurally Site class into Facade and Managers Structurally refactor Site class into Facade and separate Managers Jan 14, 2026
Copy link

Copilot AI left a 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, and SiteGenerationManager
  • Refactored the Site class 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

This comment was marked as outdated.

This comment was marked as outdated.

Encapsulate PagesManager baseUrlMap assign with a setter Standardize AssetsManager.copyTheme to return resolved promise

This comment was marked as outdated.

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.
Copy link

@yihao03 yihao03 left a 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'));
Copy link

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

Copy link
Member Author

@gerteck gerteck Jan 16, 2026

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; },
Copy link

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?

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 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!

Comment on lines +85 to +128
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.');
}
Copy link

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?

Copy link
Member Author

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

@gerteck gerteck merged commit 277bab1 into MarkBind:master Jan 16, 2026
12 of 13 checks passed
@github-actions github-actions bot added the r.Patch Version resolver: increment by 0.0.1 label Jan 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

r.Patch Version resolver: increment by 0.0.1

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Refactor Core Package, specifically Site/index.ts General Refactoring work

2 participants