Skip to content

fix(embed): untrack web/frontend/dist/* and serve a fallback stub on bare go builds#473

Merged
Dumbris merged 1 commit into
smart-mcp-proxy:mainfrom
HaloCollar:upstream-fix/untrack-web-frontend
May 17, 2026
Merged

fix(embed): untrack web/frontend/dist/* and serve a fallback stub on bare go builds#473
Dumbris merged 1 commit into
smart-mcp-proxy:mainfrom
HaloCollar:upstream-fix/untrack-web-frontend

Conversation

@electrolobzik
Copy link
Copy Markdown
Contributor

Summary

The .gitignore already declares web/frontend/ "auto-generated":

# Embedded frontend assets (auto-generated)
web/frontend/

But 39+ files under web/frontend/dist/ have been tracked since a27d360 (“chore: regenerate OpenAPI spec and frontend build”, Spec 031). The make frontend-build target does rm -rf web/frontend && cp -r frontend/dist web/frontend/, and Vite's content-hashed output filenames change with bundle content. The result: every make build produces a flood of “deleted old-hash” + “untracked-but-gitignored new-hash” entries in git status, on main today.

This PR aligns the tracked state with the maintainers' stated intent.

What changes

  1. git rm --cached -r web/frontend/ — untracks the previously-tracked Vite output.
  2. Track web/frontend/dist/.gitkeep (empty) — gives //go:embed something to embed on a fresh module fetch (go install …@latest), before any real UI has been produced.
  3. Track web/embedded_fallback/index.html — a small stub page shown when no real Vite bundle is present. It tells the user how to get the real UI (release artifacts or make build).
  4. web/web.go — changes the embed pattern to //go:embed all:frontend/dist (required to pick up the dotfile placeholder), adds a second embed for the fallback, and adjusts the handler to fall back to the stub when frontend/dist/index.html isn't found in the embedded FS.
  5. .gitignore — explicit re-includes for !web/frontend/dist/ and !web/frontend/dist/.gitkeep so they survive the generic dist/ ignore rule earlier in the file.
  6. Makefilefrontend-build now cp -r frontend/dist/. web/frontend/dist/ (copy contents, not the directory) and touch web/frontend/dist/.gitkeep so the placeholder survives subsequent rebuilds.

User-visible behavior

Flow Before After
make build from a clean tree dirty tree after clean tree after
make build re-run dirty tree after clean tree after
Bare go build ./cmd/mcpproxy stale-bundle UI from last a27d360-era commit (broken: index.html references different asset hashes than the binary actually serves) clean fallback stub at /ui/ with build-from-source instructions
go install …@latest (no npm available) same stale-bundle UI same fallback stub
Docker / .deb / DMG / Homebrew release always uses make build unchanged
release.yml / pr-build.yml CI always regenerates web/frontend/ from frontend/ unchanged

The trade-off is the bare-Go-toolchain install paths (go install, go build without make). Those previously produced a binary with a technically embedded stale UI bundle whose index.html referenced assets the binary doesn't actually contain after subsequent feature PRs landed Vue code without re-committing web/frontend/dist/*. After this PR, those paths produce a small, intentional fallback page instead. The REST API, MCP endpoints, and CLI are untouched — only /ui/ changes.

Verification (all three install paths)

  1. make build from clean tree → clean tree after.

    make frontend-build  # the part that touches web/frontend/
    git status --porcelain   # ⇒ empty
    

    Re-running make frontend-build repeatedly continues to produce a clean status.

  2. Bare go build ./cmd/mcpproxy from a fresh-clone-shaped tree.

    rm -rf web/frontend/dist/assets web/frontend/dist/favicon.svg web/frontend/dist/index.html
    ls web/frontend/dist/    # ⇒ only .gitkeep
    go build -o /tmp/mcpproxy-stub ./cmd/mcpproxy   # compiles
    /tmp/mcpproxy-stub serve --listen 127.0.0.1:18099 --config … &
    curl -s http://127.0.0.1:18099/ui/ | grep '<title>'
    # ⇒ <title>MCPProxy — Web UI not built</title>
    

    Including SPA routes:

    curl -s http://127.0.0.1:18099/ui/foo/bar | grep '<title>'
    # ⇒ <title>MCPProxy — Web UI not built</title>
    
  3. go install …@latest simulated via the actual module zip pkg.go.dev would serve.

    git archive HEAD | tar -x -C /tmp/install-sim
    ls /tmp/install-sim/web/frontend/dist   # ⇒ only .gitkeep
    cd /tmp/install-sim && go build ./cmd/mcpproxy   # compiles
    # /ui/ ⇒ same fallback stub as scenario 2
    

What this PR is not

This PR does not touch cmd/generate-types/main.go or frontend/src/types/contracts.ts. The independent contracts.ts churn (where the hardcoded TS string in cmd/generate-types has drifted from the actual file) is fixed in #472, which can land independently in either order.

🤖 Generated with Claude Code

The .gitignore already declares `web/frontend/` "auto-generated", and
every documented build path (`make build`, `make build-server`, the
release.yml + pr-build.yml CI workflows, the frontend/README.md
"Production Deployment" recipe) regenerates the bundle from source.
But the 39+ files under web/frontend/dist/ have been tracked since
a27d360, which means every `make frontend-build` produces a flood of
"deleted old-hash" + "untracked-but-gitignored new-hash" entries in
`git status`.

This commit brings the tracked state in line with the maintainers'
stated intent.

Changes:

1. `git rm --cached -r web/frontend/` removes the tracked Vite output.
2. Track `web/frontend/dist/.gitkeep` so //go:embed has at least one
   file to embed on a fresh module fetch.
3. Track `web/embedded_fallback/index.html`, a small stub UI shown
   when no real Vite bundle is present.
4. Change the embed directive in web/web.go to `all:frontend/dist`
   (required to pick up the dotfile placeholder) and add a second
   embed for the fallback. The handler falls back to the stub when
   index.html isn't found in the real bundle.
5. `.gitignore` gains explicit re-include lines so the new .gitkeep
   survives the generic `dist/` ignore rule earlier in the file.
6. Makefile's `frontend-build` recreates `.gitkeep` after copying the
   freshly built dist into web/frontend/, so subsequent rebuilds
   leave a clean `git status`.

User-visible behavior:

| Flow                                    | Before              | After                  |
|-----------------------------------------|---------------------|------------------------|
| `make build` from a clean tree          | dirty tree after    | clean tree after       |
| `make build` re-run                     | dirty tree after    | clean tree after       |
| Bare `go build ./cmd/mcpproxy`          | stale embedded UI   | fallback stub at /ui/  |
| `go install …@latest` (no npm)          | stale embedded UI   | fallback stub at /ui/  |
| Docker / .deb / DMG release             | uses `make build`   | unchanged              |
| CI release.yml / pr-build.yml           | always rebuilds     | unchanged              |

The trade-off is that bare-Go-toolchain users (no npm) now get a stub
UI with a "build from source for the real UI" message instead of a
silently-stale bundle. The REST API, MCP endpoints, and CLI are
unaffected — only the `/ui/` route changes.

Verified:
- `go build ./...` succeeds
- `make frontend-build` produces a clean `git status`
- After wiping web/frontend/dist/* except .gitkeep, bare
  `go build ./cmd/mcpproxy` compiles and the binary serves the
  fallback HTML at /ui/
- `git archive HEAD | tar -x -C tmp && cd tmp && go build ./cmd/mcpproxy`
  (the `go install` module-fetch simulation) produces the same fallback
  behaviour
electrolobzik added a commit to HaloCollar/mcpproxy-go that referenced this pull request May 16, 2026
…proxy#473)

Brings in the embed untrack + fallback stub:
- e46d3d7 fix(embed): untrack web/frontend/dist/* and serve a fallback stub

After this merge:
- web/frontend/dist/* is no longer tracked (only .gitkeep remains as a
  placeholder so //go:embed all:frontend/dist still compiles on a fresh
  module fetch).
- web/web.go embeds a small fallback HTML page at web/embedded_fallback/
  that is served when no real Vite bundle is present (e.g.
  `go install …@latest` users who don't run npm).
- Makefile's `frontend-build` recreates .gitkeep after copying the
  freshly built dist, so subsequent rebuilds leave a clean working tree.

All three documented install paths verified end-to-end (see PR smart-mcp-proxy#473).
@Dumbris
Copy link
Copy Markdown
Member

Dumbris commented May 17, 2026

Thank you, @HaloCollar! 🙏 Untracking the generated web/frontend/dist/ bundle (it was already .gitignored yet still tracked) plus the honest embedded fallback stub for bare go build/go install is a clean, well-scoped fix for a long-standing dirty-tree annoyance — and the .gitkeep + //go:embed all: handling is exactly right. CI is green; merging for v0.31.1. A small follow-up (#474) aligns the release/PR workflows' copy step with your new Makefile form so there's a single canonical form. Great contribution! 🎉

@Dumbris Dumbris merged commit 7a1f6fd into smart-mcp-proxy:main May 17, 2026
22 checks passed
Dumbris added a commit that referenced this pull request May 17, 2026
…474)

PR #473 changed the Makefile `frontend-build` target to copy into
`web/frontend/dist/` and `touch web/frontend/dist/.gitkeep` (so the
`//go:embed all:frontend/dist` directive always has something to embed).
The release.yml and pr-build.yml "Copy frontend dist" steps still used
the older `cp -r frontend/dist web/frontend/` form.

Both forms place a real index.html under web/frontend/dist/ so release
artifacts were never broken, but the divergent forms are confusing and
the workflow steps did not recreate the tracked .gitkeep. This aligns
both workflows with the Makefile so there is a single canonical form.

Follow-up to #473. No functional change to release/CI artifacts.

Co-authored-by: Claude Code <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants