This issue was originally identified in voxpelli/voxpelli.github.com#32
Problem
The --copy flag only accepts directories. Individual root-level files that need to end up in the build output require a manual post-build shell command. Any file that lives outside src/ but must appear in the output directory — service workers, Netlify _redirects, _headers, .well-known/* files, etc. — cannot be handled by the DomStack build pipeline alone.
These files cannot live inside src/ because DomStack treats .js files there as page modules, layout modules, or template modules based on naming conventions.
Expected: --copy sw.js copies a single file into the output root, just as --copy images copies a directory.
Actual: --copy calls getCopyDirs() which unconditionally appends /** to every path, treating all arguments as directories. A file path like sw.js becomes the glob sw.js/**, which matches nothing.
Current behavior
// lib/build-copy/index.js
export function getCopyDirs (copy = []) {
const copyGlobs = copy?.map((dir) => join(dir, '**'))
return copyGlobs
}
For sw.js, the glob sw.js/** matches nothing — cpx2 silently produces no output.
Real-world workaround
"build": "domstack --copy images --copy media && cp sw.js public/sw.js",
"dev": "domstack --watch --copy images --copy media"
Note: the dev (watch) script does not include the cp sw.js step. This means changes to sw.js during watch mode are never copied — the service worker is stale or missing during local development.
Proposed solution
Option A: Let --copy accept both files and directories (recommended)
Detect whether the argument is a file or directory and handle accordingly:
import { stat } from 'node:fs/promises';
export async function getCopyGlobs (copy = []) {
const globs = await Promise.all(copy.map(async (entry) => {
try {
const stats = await stat(entry);
if (stats.isDirectory()) {
return join(entry, '**');
} else if (stats.isFile()) {
return entry;
}
} catch {
// Path doesn't exist yet — treat as glob pattern
}
return entry;
}));
return globs;
}
Usage unchanged:
domstack --copy images --copy media --copy sw.js --copy _redirects
Option B: Add a --copy-file flag for explicit semantics
Option C: Support a static/ directory convention
A static/ directory at the project root whose contents are copied verbatim to the output root, similar to Astro's public/, Vite's public/, or Next.js's public/.
Recommendation: Option A is the smallest useful change. Option C could be added later as a complementary feature.
Common files that would benefit
sw.js / service workers
_redirects (Netlify/Cloudflare Pages)
_headers (Netlify/Cloudflare Pages)
.well-known/webfinger (Fediverse discovery)
ads.txt, security.txt, browserconfig.xml
See also: issue #34 (Service worker support).
Problem
The
--copyflag only accepts directories. Individual root-level files that need to end up in the build output require a manual post-build shell command. Any file that lives outsidesrc/but must appear in the output directory — service workers, Netlify_redirects,_headers,.well-known/*files, etc. — cannot be handled by the DomStack build pipeline alone.These files cannot live inside
src/because DomStack treats.jsfiles there as page modules, layout modules, or template modules based on naming conventions.Expected:
--copy sw.jscopies a single file into the output root, just as--copy imagescopies a directory.Actual:
--copycallsgetCopyDirs()which unconditionally appends/**to every path, treating all arguments as directories. A file path likesw.jsbecomes the globsw.js/**, which matches nothing.Current behavior
For
sw.js, the globsw.js/**matches nothing —cpx2silently produces no output.Real-world workaround
Note: the
dev(watch) script does not include thecp sw.jsstep. This means changes tosw.jsduring watch mode are never copied — the service worker is stale or missing during local development.Proposed solution
Option A: Let
--copyaccept both files and directories (recommended)Detect whether the argument is a file or directory and handle accordingly:
Usage unchanged:
Option B: Add a
--copy-fileflag for explicit semanticsOption C: Support a
static/directory conventionA
static/directory at the project root whose contents are copied verbatim to the output root, similar to Astro'spublic/, Vite'spublic/, or Next.js'spublic/.Recommendation: Option A is the smallest useful change. Option C could be added later as a complementary feature.
Common files that would benefit
sw.js/ service workers_redirects(Netlify/Cloudflare Pages)_headers(Netlify/Cloudflare Pages).well-known/webfinger(Fediverse discovery)ads.txt,security.txt,browserconfig.xmlSee also: issue #34 (Service worker support).