feat(output): add the output.copy option - #1
anurag6569201 wants to merge 1 commit into
Conversation
Source PR: webpack#21938 Source head: 06195d8
|
| .sort((a, b) => (a.name < b.name ? -1 : 1)); | ||
| if (assets.length === 0) return; | ||
|
|
||
| // the merged content carries the name of every part as well as its |
There was a problem hiding this comment.
Shipwright · HIGH
The example's 'MergeCopiedAssetsPlugin' caches the merged asset under a key built from 'filename' and asset names, with an etag over asset sources.
Impact: The example's 'MergeCopiedAssetsPlugin' caches the merged asset under a key built from 'filename' and asset names, with an etag over asset sources. If 'merge' behavior changes without changing the key or etag, stale cached output is served. The example documents caching but does not include a cache-busting version key, so a reader copying this pattern can ship stale merged output after changing 'merge'.
Suggested fix: Review the cited evidence, fix the risk if confirmed, and rerun Shipwright.
| }, | ||
| // content rewritten on the way through, cached on what it reads | ||
| { | ||
| from: "config.json", |
There was a problem hiding this comment.
Shipwright · HIGH
The 'to' function example routes '.css' files to 'css' and everything else to 'media', but the source directory is named 'img' and contains 'theme.css'.
Impact: The 'to' function example routes '.css' files to 'css' and everything else to 'media', but the source directory is named 'img' and contains 'theme.css'. This is surprising and likely to confuse a new contributor about whether 'to' receives the source-relative path or the destination filename; the type name 'CopiedFileData.filename' is ambiguous without reading the implementation.
Suggested fix: Review the cited evidence, fix the risk if confirmed, and rerun Shipwright.
| ); | ||
| fs.symlinkSync(source, path.join(source, "real/loop"), "junction"); | ||
| // relative, so it still resolves once the link and its target are copied | ||
| fs.symlinkSync("real/a.txt", path.join(source, "relative.txt"), "file"); |
There was a problem hiding this comment.
Shipwright · HIGH
The symlink test fixture builds a symlink loop ('real/loop' points back at the source base) and the default 'followSymlinks: true' path must walk it.
Impact: The symlink test fixture builds a symlink loop ('real/loop' points back at the source base) and the default 'followSymlinks: true' path must walk it. If the implementation lacks cycle detection or a visited-set, this can recurse until stack overflow or copy unboundedly. The fixture itself proves the loop exists, but no assertion in the visible diff verifies termination or bounded output for the follow-symlinks case.
Suggested fix: Review the cited evidence, fix the risk if confirmed, and rerun Shipwright.
Summary
Copying static files into the output directory needs
copy-webpack-plugintoday, sooutput.copybrings it into core: a pattern is afromplus an optionalto,filenameandtransform, glob matching reuses webpack's ownlib/util/globUtils.js, and every copied file is cached behind a file system snapshot so a rebuild re-reads only what changed.The option surface is deliberately smaller than the plugin's, calibrated against Vite's
publicDir,vite-plugin-static-copy,rollup-plugin-copyandesbuild-plugin-copy:tois a destination directory (never a dir/file/template guess, sotoTypeis gone),filenameis a webpack filename template within it (default[path][base], so it renames, flattens and hashes), a pattern that copies nothing warns rather than failing the build (sonoErrorOnMissingis gone, andignoreWarningssilences it), a later pattern replaces an earlier one (soforceis gone), andfromis the only file selector.output.copyalso accepts a bare string or an array of strings.What kind of change does this PR introduce?
feat
Did you add tests for your changes?
Yes —
test/configCases/copy/{basic,glob,shorthand,transform,to-option,missing,errors}, plustest/watchCases/copy/{copy,clean}for rebuilds andoutput.clean, andtest/hotCases/copy/copyfor HMR.Does this PR introduce a breaking change?
No, it is a new option.
If relevant, what needs to be documented once your changes are merged or what have you already documented?
output.copyneeds a page on webpack.js.org: the pattern shape (from,to,filename,transform), the[path][base]default, the warning on a pattern that copies nothing, and a migration note fromcopy-webpack-plugin(to: "dir"keeps working;toType/filter/force/priority/info/noErrorOnMissinghave no equivalent).Use of AI
AI was used throughout, under review at each step: it wrote the implementation and tests, ran the option surface against the other bundlers' copy plugins to decide what to keep, and measured the claims made above (glob base extraction against
glob-parent, the exclusion and re-emit behaviour, watch rebuilds). Every design decision here was made or confirmed by me.🤖 Generated with Claude Code
https://claude.ai/code/session_012Bq1dTfsXi8stgF7XQsyEg
Generated by Claude Code
Summary by CodeRabbit
output.copyfor copying files and directories into build output.Source merge-base:
9cb49ef1474b807fbc0b852611610eb24289eee5Source head:
06195d8ac727be35ce6acbe3fca7cf518fc33fa6