Skip to content

Refactor Core and CLI Packages interaction #2778

@gerteck

Description

@gerteck

Please confirm that you have searched existing issues in the repo

Yes, I have searched the existing issues

Any related issues?

#139

What is the area that this feature belongs to?

No response

Is your feature request related to a problem? Please describe.

Current architectural smells between @markbind/core and @markbind-cli and am wondering if anyone has any ideas, or recommendations to put forth to better organize the codebase and architecture.

Due to legacy reasons, I believe that originally, cli and core were separated to allow for reuse of the core package across different applications or packages. In fact, they were even previously in two separate github repositories, and was merged together in #139 to this repo.

There seem to be several architectural smells that hinder maintainability and developer experience for the interaction between cli and core:

1. Leaky Encapsulation

The CLI is tightly coupled to core's internal implementation, essentially "micromanaging" the build process.

  • Deep Imports: The CLI bypasses the public API (main exports), importing internal utilities (e.g., @markbind/core/src/utils/fsUtil).

  • Leaked Logic: Determining how to handle file changes (e.g., "if site.json changes, reload config; if dependency changes, rebuild affected") is implemented in the CLI (serveUtil.js), not core.

  • Issue & Implications: Renaming internal files in core breaks the cli, making refactoring risky and dangerous. This also makes development prone to bugs. Additionally, this makes it hard to developcore without divided attention on cli. Makes it hard to reason about logic and classes, and goes against single responsibility, encapsulation, etc.

2. Partial Type Safety

  • Mixed Languages: core is TypeScript, but cli is JavaScript.
  • Missing Tooling: There is no compile-time checking for Site API usage in the CLI. Breaking changes in core will only be caught at runtime or via functional tests, and note that our functional tests only test the build command.

Describe the solution you'd like

We can do some refactoring to establish a clean boundary between cli and core.

These can include:

  • Strengthening Encapsulation Move logic ownership to core and remove deep imports. (E.g. Refactor CLI to use only exported members from core/index.ts. Shared utilities should be properly exported or moved to a shared package.)
  • Centralize Watcher Logic: The Site class should expose a high-level watch() API. The CLI shouldn't decide what to rebuild, only that it should start watching.

Other suggestions include:

  • Decoupling "Build" from "Serve": The CLI should be able to do UI/logging/reloading without knowing how the build happened. (Maybe Site instance should emit lifecycle events, etc)

Additionally, a planned suggestion that is related is:

  • Full TypeScript Migration for full type safety. (Migrate cli package to Typescript #2754)
    • Specifically, configure cli to reference core sources directly. This enables "Go to Definition" updates to flow seamlessly from Core to CLI.

Describe alternatives you've considered

As a general guide, we can try to make the code SOLID.

Additional context

No response

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions