The index.* rename only saved entry points literally named index — every other glob match still took its own basename, so src/elements/*/theme.scss wrote theme.css once per component and the last one won. A styles or scripts out can now be a template, one token for the match's directory and one for its basename, naming one output per match. And live CSS reload no longer guesses those paths, it reads what the compiler actually wrote.
out can be a template, for styles and scripts alike. v1.9.5 named a
glob-matched index.* after its directory, which fixed the case a component
library actually hits. It did nothing for anything else: point a glob at
src/elements/*/theme.scss and every match still falls back to its own
basename, so the components overwrite each other in the output directory and
the last one to build wins. There was no way to say what you wanted the files
called.
Now there is. An out carrying {{dir}} or
{{name}} resolves per entry point instead of naming one
shared destination:
{
"styles": { "in": "src/elements/*/theme.scss", "out": "dist/css/{{dir}}-{{name}}.css" },
"scripts": { "in": "src/elements/*/widget.ts", "out": "dist/js/{{dir}}-{{name}}.js" }
}
src/elements/accordion/theme.scss → dist/css/accordion-theme.css
src/elements/tabs/theme.scss → dist/css/tabs-theme.css
src/elements/accordion/widget.ts → dist/js/accordion-widget.js
src/elements/tabs/widget.ts → dist/js/tabs-widget.js
{{dir}} is the match's directory relative to the glob's
static prefix — the same name an index.* entry gets, so the two rules
agree on what a component is called, and widening the glob keeps the segments
it no longer pins down. {{name}} is the basename
without its extension. Whitespace inside the braces is fine
({{ dir }}), matching the banner templates.
Tokens work in directory segments too, so the flat layout isn't the only one available:
{ "in": "src/elements/*/theme.scss", "out": "dist/css/{{dir}}/theme.css" }
A literal entry fills {{dir}} with its own directory
name, which keeps mixed arrays of globs and plain paths working:
"out": "dist/css/{{dir}}.css"
src/scss/main.scss → dist/css/scss.css
src/elements/accordion/index.scss → dist/css/accordion.css
For scripts the template's extension is honoured as well, which is the cheap way to ship one format per entry point rather than one bundle per format:
{ "in": "src/elements/*/index.ts", "out": "dist/esm/{{dir}}.mjs",
"options": { "format": "esm" } }
A template wins over the index.* rename — you named these outputs, and
renaming them behind your back is the thing globs were already doing wrong.
It's also exempt from the "more than one entry file needs a directory out"
guard, since a template already resolves to a different file per entry rather
than to one file everything overwrites. What it does not do is invent
uniqueness: "out": "dist/{{name}}.css" across component
directories collides exactly like a plain directory out would, and its
scripts equivalent fails the build outright with esbuild's "Two output files
share the same path". That's what {{dir}} is there
for.
Live CSS reload no longer guesses the output path. The watch chain fed
livereload a path derived from the config — a directory out joined with the
basename of in. For a single named entry point that guess was right. For a
glob it was the pattern's own basename, so src/elements/*/index.scss
reported dist/css/index.css, a file that was never written; a templated
out reported the template verbatim, braces and all. The livereload client
looks for a loaded stylesheet matching the path it is handed and, finding
none, falls back to reloading the whole page — so editing a component's Sass
flashed a full reload instead of swapping the stylesheet in place, and any
scroll position or open state went with it.
The styles compiler now records the files it wrote and the watch chain reloads exactly those. One entry, one glob or twenty templated outputs, the reported paths are the ones on disk, because nothing derives them a second time.
The watcher's output zones understand templates. A compiler writing into
a watched directory must not retrigger itself, which the watcher prevents by
zoning each task's out. A templated out is only a fixed path up to its
first token, so dist//theme.css zoned a directory literally named
, protecting nothing. Zones are now taken from the static prefix.