fix: make the published packages Fable-consumable - #78
Merged
Conversation
Fable compiles a package from the F# sources under fable/, not from the DLL, so a package without them silently produces nothing: it type-checks under `dotnet build` and emits no code under `dotnet fable`. All three packages were broken, in two different ways. Fable.Giraffe.Beam shipped no sources at all -- it never had the Content item that js and python have. Those two had one, but its `**\*.fs` glob is project-relative, so none of the 14 shared files one level up were included: the packaged fsproj pointed at ../Core.fs and friends that were not in the package. The same glob also swept obj/ AssemblyInfo into the package. The fix is structural, not a missing line. Fable resolves the packaged fsproj at fable/ and requires every source to live beneath it -- packing the shared files at the package root instead fails with "expected output path to contain a fable_modules/<package> segment". Since the fsproj's own Compile paths have to resolve inside the packed tree, no fsproj can reference sources outside its own directory. Fable.Beam and Fable.Actor both satisfy this already, one by having self-contained packages and the other by being a single multi-target project. So the three backend projects move from src/<target>/ up to src/, where the shared files are. Only the fsprojs move; the backend .fs files stay in src/beam, src/js and src/python and are now referenced as beam/WebHost.fs and so on. Every Compile path is project-relative, and each project packs its own sources with an explicit per-backend glob rather than `**\*.fs`, so the three packages no longer swallow each other's files. Generated BEAM module names change again as a result (fable_giraffe_beam_beam_ middleware under the package). Nothing needs updating for it: the handler names itself via ?MODULE as of #76. Verified by packing Fable.Giraffe.Beam to a local feed and consuming it from a throwaway project: Fable parses 71 source files, the same as the ProjectReference path, and the compiled result serves 200 OK on BEAM. Giraffe lands as its own OTP app in fable_modules rather than being inlined into the consumer, which is also an improvement over the ProjectReference path. All three suites unchanged: BEAM 94 passed / 7 skipped, JS 100 / 1, Python 101. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Beam and js never carried the ecosystem tags; python already had them. All three now follow the shape the sibling repos use, fsharp;fable;fable-library;fable-<target> followed by domain tags. fable-library rather than fable-binding: Fable.Python and Fable.Beam are bindings to platform APIs, while Fable.Logging and Fable.Reactive are F# libraries compiled to several targets. Giraffe is the latter. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fable compiles a package from the F# sources under
fable/, not from the DLL. A package without them fails silently — it type-checks underdotnet buildand emits no code underdotnet fable. All three packages were broken, in two different ways.Fable.Giraffe.Beamshipped no sources at all. It never had theContentitem that js and python have.**\*.fsis project-relative, so none of the 14 shared files one level up were included — the packaged fsproj pointed at../Core.fsand friends that weren't in the package. The same glob sweptobj/AssemblyInfo in.Why this isn't a missing line
Three attempts, each ruled out empirically:
fable/beam/, shared atfable/fable/, shared at package rooterror FABLE: Cannot locate the OTP app directory ... expected output path to contain a 'fable_modules/<package>' segmentfable/The third requires every
Compilepath to resolve inside the packed tree, which means no fsproj can reference sources outside its own directory. Both sibling repos already satisfy this —Fable.Beamby having self-contained packages with no shared sources,Fable.Actorby being a single multi-target project. Giraffe was the only one violating it, and the only one whose package didn't work.The change
The three backend projects move from
src/<target>/up tosrc/, where the shared files already are. Only the fsprojs move — the backend.fsfiles stay insrc/beam,src/js,src/pythonand are now referenced asbeam/WebHost.fsetc. EveryCompilepath becomes project-relative, and each project packs its own sources with an explicit per-backend glob rather than**\*.fs, so the three packages no longer swallow each other's files:Generated BEAM module names change again as a result (
fable_giraffe_beam_beam_middlewareunder the package). Nothing needs updating for it — the handler names itself via?MODULEas of #76. That's now four distinct names the same source has produced; pinning it by hand was never going to hold.Testing
Packed
Fable.Giraffe.Beamto a local feed and consumed it from a throwaway project:rebar3 compileclean, and the result serves200 OKon BEAM withWebHost - Giraffe listening on port 8080.fable_modules/rather than being inlined into the consumer — also an improvement over the ProjectReference path, which duplicates it into every consuming app.All three suites unchanged: BEAM 94 passed / 7 skipped, JS 100 / 1 skipped, Python 101.
dotnet buildclean on all three projects.Notes
PackageTagsare normalised in a follow-up commit. Beam and js never carried the ecosystem tags; python already had them. All three now readfsharp;fable;fable-library;fable-<target>;....fable-libraryrather thanfable-binding: Fable.Python and Fable.Beam bind platform APIs, while Fable.Logging and Fable.Reactive are F# libraries compiled to several targets — Giraffe is the latter. Purely nuget.org discovery metadata; no effect on the fix above.src/. Legal, and the Justfile addresses them by explicit path, butdotnet build src/is no longer unambiguous.🤖 Generated with Claude Code