Copy files easily via JavaScript or the CLI, it uses tinyglobby internally for glob patterns and cli-nano for the CLI.
The library is very similar to the copyfiles package, at least from the outside; however its internal is very different. It uses more native NodeJS code and a lot fewer dependencies (3 instead of 7), which makes this package a lot smaller compared to the original copyfiles
project (1/3 of its size). The options are nearly the same (except for --soft
, which is not implemented), new options were also added in this project here (mainly the rename feature, see below).
Note: there is 1 noticeable difference with
copyfiles
, any options must be provided as a suffix after the source/target directories command (the originalcopyfiles
project has them as prefix).
This mean calling:copyfiles source target [options]
instead ofcopyfiles [options] source target
npm install native-copyfiles -D
Usage: copyfiles <inFile..> <outDirectory> [options]
Positionals:
inFile Source file(s) [string|string[]]
outDirectory Destination directory [string]
Options:
-u, --up slice a path off the bottom of the paths [number]
-a, --all include files & directories begining with a dot (.) [boolean]
-d, --dry-run show what would be copied, without actually copying anything [boolean]
-f, --flat flatten the output [boolean]
-e, --exclude pattern or glob to exclude (may be passed multiple times) [string|string[]]
-E, --error throw error if nothing is copied [boolean]
-V, --verbose print more information to console [boolean]
-F, --follow follow symbolic links [boolean]
-s, --stat show statistics after execution (time + file count) [boolean]
-v, --version show version number [boolean]
-h, --help show help [boolean]
Note
Options must be provided after the command directories as suffix (the original project has them as prefix)
copy some files, give it a bunch of arguments, (which can include globs), the last one is the out directory (which it will create if necessary). Note: on Windows globs must be double quoted, everybody else can quote however they please.
copyfiles foo foobar foo/bar/*.js out
you now have a directory called out, with the files "foo"
and "foobar"
in it, it also has a directory named "foo"
with a directory named
"bar"
in it that has all the files from "foo/bar"
that match the glob.
If all the files are in a folder that you don't want in the path out path, ex:
copyfiles something/*.js out
which would put all the js files in "out/something"
, you can use the --up
(or -u
) option
copyfiles something/*.js out -u 1
which would put all the js files in out
you can also just do -f
which will flatten all the output into one directory, so with files "./foo/a.txt"
and "./foo/bar/b.txt"
copyfiles ./foo/*.txt ./foo/bar/*.txt out -f
will put "a.txt"
and "b.txt"
into out
if your terminal doesn't support globstars then you can quote them
copyfiles ./foo/**/*.txt out -f
does not work by default on a Mac
but
copyfiles "./foo/**/*.txt" out -f
does.
You could quote globstars as a part of input:
copyfiles some.json "./some_folder/*.json" ./dist/ && echo 'JSON files copied.'
You can use the -e
option to exclude some files from the pattern, so to exclude all files ending in ".test.js"
you could do
copyfiles "**/*.test.js" -f ./foo/**/*.js out -e
Note
By default the .git/
and node_modules/
directories will be excluded.
Other options include
-a
or--all
which includes files that start with a dot.-F
or--follow
which follows symbolic links
You can copy and rename a single file by specifying the source file and the destination filename (not just a directory). For example, to copy input/.env_publish
to output/.env
:
copyfiles input/.env_publish output/.env
This will copy and rename the file in one step.
You can use this for any filename, not just files starting with a dot:
copyfiles input/original.txt output/renamed.txt
If the destination path is a directory, the file will be copied into that directory as usual. If the destination path is a filename, the file will be copied and renamed.
You can use a wildcard (*
) in the destination to rename files dynamically. For example, to copy all .css
files and change their extension to .scss
:
copyfiles "input/**/*.css" "output/*.scss"
This will copy:
input/foo.css
→output/foo.scss
input/bar/baz.css
→output/bar/baz.scss
The *
in the destination is replaced with the base filename from the source.
You can combine this with --flat
or --up
to control the output structure.
For advanced renaming, you can use the rename
callback option in the API.
This function receives the source and destination path and should return the new destination path of each file being processed.
Example: Change extension to .scss
using a callback
import { copyfiles } from 'native-copyfiles';
copyfiles(['input/**/*.css', 'output'], {
flat: true,
rename: (src, dest) => dest.replace(/\.css$/, '.scss')
}, (err) => {
// All files like input/foo.css → output/foo.scss
});
Example: Prefix all filenames with renamed-
but keep the extension
copyfiles(['input/**/*.css', 'output'], {
up: 1,
rename: (src, dest) => dest.replace(/([^/\\]+)\.css$/, 'renamed-$1.css')
}, (err) => {
// input/foo.css → output/renamed-foo.css
// input/bar/baz.css → output/bar/renamed-baz.css
});
The rename
callback gives you full control over the output filename and path.
Tip:
You can use either the wildcard approach or therename
callback, or even combine them for advanced scenarios!
Note
If you use both a destination wildcard approach (e.g. output/*.ext
) and a rename
callback, the wildcard change is applied first and then the rename
callback is executed last on the computed destination path. This allows you to combine both features for advanced renaming scenarios.
import { copyfiles } from 'native-copyfiles';
copyfiles([paths], opt, callback);
The first argument is an array of paths whose last element is assumed the destination path.
The second argument (opt
) being the options argument
and finally the third and last argument is a callback function which is executed after all files copied
{
verbose: bool, // print more information to console
up: number, // slice a path off the bottom of the paths
exclude: string, // exclude pattern
all: bool, // include dot files
dryRun: bool, // show what would be copied, without actually copying anything
follow: bool, // follow symlinked directories when expanding ** patterns
error: bool // raise errors if no files copied
stat: bool // show statistics after execution (time + file count)
rename: (src, dest) => string; // callback to transform the destination filename(s)
}