You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Fix the transform sourcemap signal and path normalisation
Two hook-contract bugs, plus the CI and script gaps found alongside them.
The transform hook returned `map: null`, which in the Rollup and Vite
contract means "I did not move code, keep the previous mapping". That is
false here — the hook replaces F# with JavaScript — and downstream stages
took it at face value, generating a map whose `sources` named a `.fs`
file while its `sourcesContent` held the compiled JavaScript. Devtools
duly showed an F# filename containing JavaScript, which is worse than no
map at all. `{ mappings: "" }` is how Vite's own plugins say a mapping was
lost. Real F#-to-JS source maps stay blocked on Fable, where
FileWriter.AddSourceMapping is a no-op.
compileProject built its compiled-output map by iterating the source file
list and indexing the daemon's response with an already-normalised path,
while fsharpFileChanged normalised the daemon's keys on the way in. The
two sets are not the same — signature files are reported as sources and
never compiled — and the mismatched lookup would yield undefined for
every entry if the daemon ever reported a non-POSIX path. Both paths now
key off what the daemon returned.
CI ran the plugin tests but never `dotnet test`, so the daemon suite,
including the signature-file test added with the hotUpdate work, was not
running there at all. Added as its own step in both workflows.
Also adds a top-level `ci` script that runs lint, formatting and tests in
parallel, for use before committing.
The roadmap's claim that `.fsx` files are matched but never compiled was
wrong and is dropped rather than acted on: the daemon filters only `.fsi`,
so a script listed in the fsproj compiles like any other file, and one
that is not listed fails exactly as a stray `.fs` would.
Copy file name to clipboardExpand all lines: CHANGELOG.md
+3Lines changed: 3 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -27,6 +27,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
27
27
28
28
### Fixed
29
29
30
+
- The `transform` hook reports `map: { mappings: "" }` instead of `map: null`. `null` claims the previous source mapping still applies, which made later stages emit a map labelling the compiled JavaScript as the contents of a `.fs` file — devtools showed an F# filename containing JavaScript. Real F#-to-JS source maps remain blocked on Fable.
31
+
- Compiled output is now keyed off what the daemon returned rather than looked up per source file. The two sets differ (signature files are never compiled), and indexing the daemon's map with an already-normalised path would have yielded `undefined` for every entry had the daemon ever reported a non-POSIX path.
32
+
- CI runs the daemon test suite; previously only the plugin tests ran.
30
33
- TypeScript `strict` is on. That surfaced a real bug: `configResolved` derived the project directory from `resolvedConfig.configFile`, which is optional, so a project without a Vite config file (or one created programmatically) reached `fs.readdir(undefined)`. It now uses `resolvedConfig.root`, which is always resolved and is also the correct directory when `root` differs from the config file's location. A missing `.fsproj` is now an error rather than a `null` handed to the daemon.
31
34
- oxlint warnings fail the lint instead of being reported and ignored.
32
35
-`sample-project` runs its scripts on the Bun runtime through its own `bunfig.toml` rather than `bunx --bun` in each script, so the scripts are plain `vite`, `vite build` and `vite preview`. Bun only reads the `bunfig.toml` in the directory a command starts from, so the one at the repo root does not cover it.
Copy file name to clipboardExpand all lines: ROADMAP.md
+2-5Lines changed: 2 additions & 5 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -8,14 +8,11 @@ Order is a rough suggestion: 1-3 are contract fixes and design questions, 4-7 ar
8
8
9
9
## 1. Hook-contract fixes
10
10
11
-
-**`map: null` is the wrong signal** (`index.js:454`). In the Rollup/Vite contract `null` means "I did not move code, keep the previous map"; the transform replaces F# with JS. The correct value is `{ mappings: '' }` — what Vite's own plugins use for this case (`plugins/css.ts:583`, `plugins/asset.ts:247`).
12
-
Note: real F# source maps are **blocked upstream**. `FileWriter.AddSourceMapping` in `~/Projects/Fable/src/Fable.Compiler/Library.fs:84-90` is a no-op with the `SourceMapSharp` generator commented out; `CliArgs.SourceMaps` exists but does nothing. Needs a Fable PR first.
13
-
Worth knowing what happens meanwhile: because the plugin returns `map: null`, later stages generate their own map, and the served module ends with a `sourceMappingURL` whose `sources` says `Greeting.fs` while its `sourcesContent` is the compiled **JavaScript**. Devtools therefore shows a file named `.fs` containing JavaScript, which is more misleading than having no map at all. `{ mappings: '' }` fixes that on its own.
11
+
-**Real F# source maps are blocked upstream.**`FileWriter.AddSourceMapping` in `~/Projects/Fable/src/Fable.Compiler/Library.fs:84-90` is a no-op with the `SourceMapSharp` generator commented out; `CliArgs.SourceMaps` exists but does nothing. Needs a Fable PR first.
12
+
The plugin now returns `{ mappings: '' }`, which stops later stages from producing a map that labels the compiled JavaScript as the contents of a `.fs` file, but a real F#-to-JS mapping needs the Fable change first.
14
13
-**No `load` hook.** Vite reads the whole `.fs` file off disk purely so `transform` can discard it. A `load` for ids in `compilableFiles` skips the I/O and states the intent. Return `moduleType: 'js'` too — `vite:oxc` does (`plugins/oxc.ts:330`) — otherwise rolldown infers the type from the `.fs` extension.
15
14
-**`configuration` is derived from `env.MODE`** (`index.js:364`), so `vite build --mode staging` compiles Debug F#. `state.isBuild` is already captured from `command === "build"` (`index.js:365`) but unused for this. Make it an explicit plugin option defaulting to `isBuild ? Release : Debug`, and document it.
16
15
-**`transform.filter` ignores query strings** (`index.js:435`). Vite's convention is `makeIdFiltersToMatchWithQuery` from `@rolldown/pluginutils`, used by Vite itself (`plugins/asset.ts:205`) and by plugin-react. Low impact for the main path — Vite still appends `?import` to bare module URLs (`src/node/utils.ts:308`) but strips it in `transformRequest.ts:497` before the id reaches the plugin container, so `transform` sees a clean absolute path. Explicit queries like `./Component.fs?raw` still fall straight through, and the `compilableFiles.has(id)` lookups should go through `cleanUrl`.
17
-
-**Path normalisation is asymmetric** (`index.js:234-238` vs `282-285`). `fsharpFileChanged` normalises the daemon's keys before storing them; `compileProject` indexes `compiledFSharpFiles` with an already-normalised name instead. If the daemon ever returns a backslash path, every value in `compilableFiles` becomes `undefined`. Normalise on the way in, in one place.
18
-
-**`.fsx` is matched but never compiled** (`index.js:15`). Script files are never in `compilableFiles`, so every `.fsx` import warns and then fails to parse. Either drop `.fsx` from the regex or handle it.
19
16
20
17
## 2. The JSX handoff to plugin-react works by accident
0 commit comments