sync-directory
v6.0.5
Published
sync two directories by copying or creating hardlink
Downloads
54,655
Maintainers
Readme
Description
sync-directory
can sync files from src directory to target directory.
CLI and API are supported.
We have two ways to sync files: hardlink
and copy
.
If type is copy
, sync-directory
will copy files from src directory to target directory.
If type is hardlink
, sync-directory
can create hardlink files in target directory from src directory.
sync-directory
uses copy
by default for safety. (hardlink
will be quicker but some watchers can't trigger change event for target files.)
Cli
npm i sync-directory -g
syncdir <from> <to> [options]
Example: syncdir aaa bbb -w
options:
-w, --watch
Watch changes.
false
as default.Same as config
watch
.--quiet
Disable unnecessary logs.
--exclude <strings...>
Exclude some path. Such as
syncdir a b --exclude node_modules package-lock.json
.Same as config
exclude
-si, --skipInitialSync
Skip the first time sync actions when it's
true
. It's useful when you just want the srcFolder to be watched.false
as default.Same as config
skipInitialSync
.-nd, --nodeep
Just walk the first level sub files/folders. Avoids deep scanning of big folders.
Same as config
nodeep
.-do, --deleteOrphaned
Delete orphaned or
excluded
(when using API) files/folders in target folder.false
as default.Same as config
deleteOrphaned
.-hardlink, --hardlink
Sync with type
hardlink
,copy
as default.Same as config
type: 'hardlink'
.-symlink, --symlink
support symlink while sync running.
false
as default.Same as config
staySymlink
.
API (commonjs and esm are supported)
sync
commonjs
const syncDirectory = require('sync-directory');
esm
import syncDirectory from 'sync-directory/index.mjs'
syncDirectory(srcDir, targetDir, {
afterEachSync({ eventType, nodeType, relativePath, srcPath, targetPath }) {
},
});
async
commonjs
const { async } = require('sync-directory');
esm
import { async } from 'sync-directory/index.mjs'
(async () => {
const delay = (time = 2000) => new Promise(r => setTimeout(r, time));
console.log('start'); // time a
// wait several 2s: 2 * file number
await async(srcDir, targetDir, {
async afterEachSync({ eventType, nodeType, relativePath, srcPath, targetPath }) {
await delay(2000); // delay 2s after one file/folder was synced
},
});
console.log('end'); // time a + 2 * (file number)
})()
Pick Your API
commonjs
const syncDirectory = require('sync-directory');
esm
import syncDirectory from 'sync-directory/index.mjs';
syncDirectory(srcDir, targetDir[, config]);
Syntax
Function | Returns | Syntax | Block the thread?
---- | ---- | ---- | ----
syncDirectory()
syncDirectory.sync()
| undefined
or chokidar watcher | Synchronous | Yes
syncDirectory.async()
| Promise
| async / await
Promise.then()
| No
Returns
const watcher = syncDirectory(A, B);
watcher
is undefined
.
const watcher = syncDirectory(A, B, {
watch: true
});
watcher
is a chokidar watcher.
Params
Params Overview
name | description | type | values | default | can be async
?
---- | ---- | ---- | ---- | ---- | ----
srcDir
| src directory | String | absolute or relative path | - | -
targetDir
| target directory | String | absolute or relative path | - | -
config.cwd
| when srcDir or targetDir is a relative path, they will be formatted to absolute path by path.join(cwd, srcDir | targetDir)
| string | - | process.cwd()
| -
config.watch
| watch file changes | Boolean | - | false | -
config.chokidarWatchOptions
| watch options (chokidar is used for watching) | Object | - | {}
| -
config.type
| way to sync files | String | 'copy' \| 'hardlink'
| 'copy'
| -
config.skipInitialSync
| skip the first time sync actions when it's true
. It's useful when you just want the srcFolder to be watched. | Boolean | true \| false
| false
| -
config.deleteOrphaned
| delete orphaned or excluded
(API using) files/folders in target folder. false
as default. | Boolean | - | false
| -
config.afterEachSync
| callback function when every file synced | Function | - | blank function | Yes when syncDirectory.async()
config.staySymlink
| if src folder "A/" is a symlink, the target folder "A/" will also be the same symlink. | Boolean | - | false | -
config.stayHardlink
| only worked when type: 'hardlink'
. When stayHardlink: true
, if src file is "src/a.js", the target file "target/a.js" will be a hardlink of "src/a.js". | Boolean | - | true
| -
config.exclude
| Priority: forceSync > exclude
. Filter which src files should not be synced. | RegExp / String / Array (item is RegExp / String) | - | null | -
config.forceSync
| Priority: forceSync > exclude
. Force sync some files even though they are excluded
. | RegExp / String / Array (item is RegExp / String) | - | (file) => { return false }
| No
config.nodeep
| Just walk the first level sub files/folders. | Boolean | - | false
| -
config.onError
| callback function when something wrong | Function | - | (err) => { throw new Error(err) }
| Yes when syncDirectory.async()
Some confusing params
Params Details
cwd
Type:
String
Default:
process.cwd()
For: format
srcDir | targetDir
to absolute path when they are relative pathssyncDirectory(srcDir, targetDir, { cwd: __dirname });
watch
Type:
true | false
Default:
false
For: watch file changes.
syncDirectory(srcDir, targetDir, { watch: true });
chokidarWatchOptions
Type:
Object
Default:
{}
For: watch options (chokidar is used for watching).
syncDirectory(srcDir, targetDir, { chokidarWatchOptions: { awaitWriteFinish: { stabilityThreshold: 2000, pollInterval: 100 } }, });
afterEachSync
Type:
Function
Default:
() => {}
For: callback function when every file synced.
syncDirectory.sync(srcDir, targetDir, { afterEachSync({ eventType, nodeType, relativePath, srcPath, targetPath }) { } }); await syncDirectory.async(srcDir, targetDir, { async afterEachSync({ eventType, nodeType, relativePath, srcPath, targetPath }) { } });
eventType
:"init:hardlink"
/"init:copy"
/"add"
/"change"
/"unlink"
/"unlinkDir"
/"addDir"
nodeType
:"file"
/"dir"
relativePath
: relative file/folder pathsrcPath
: absolute or relative src file/folder pathtargetPath
: absolute or relative target file/folder path
type
Type:
'copy' | 'hardlink'
Default:
'copy'
For: way to sync files.
copy
(default)syncDirectory(srcDir, targetDir);
hardlink
syncDirectory(srcDir, targetDir, { type: 'hardlink' });
skipInitialSync
Type:
true | false
Default:
false
For: enhance the performance
It's for enhancing the sync performance when you just want
srcDir
to be watched.syncDirectory(srcDir, targetDir, { skipInitialSync: true, watch: true, })
The
srcDir
won't be synced totargetDir
whenskipInitialSync: true
and thesrcDir
's file changes will be watched and synced totargetDir
.stayHardlink
Type:
true | false
Default:
true
Only works when
type: 'hardlink'
.When
stayHardlink: true
, if src file is "src/a.js", the target file "target/a.js" will be a hardlink of "src/a.js".Then when "src/a.js" changed, "target/a.js" will remain a hardlink. Otherwise will be a copied file.
Some watchers will not be able to watch changes of "target/a.js".
nodeep
Type:
true | false
Default:
false
Just walk the first level sub files/folders. Avoids deep scanning of big folders.
The reason why
deep
was not used is that cli options is--nodeep
. Just keep this two the same.// srcFolder: // a/ a is symlink // 1.js // targetFolder: // a/ syncDirectory(srcDir, targetDir, { nodeep: true, // 1.js will be ignored });
deleteOrphaned
Type:
true | false
Default:
false
Delete orphaned or
excluded
(when using API) files/folders in target folder.false
as default.For instance:
srcDir: dir1/ 1.js 2.js targetDir: dir2/ 1.js 2.js 3.js
syncDirectory(srcDir, targetDir, { deleteOrphaned: true, excluded: [ '2.js' ] }); // dir2/3.js will be removed because dir1/3.js does not exist. // dir2/2.js will be removed because dir1/2.js is excluded.
exclude
Type: Function / RegExp / String / Array (item is RegExp / String)
Priority:
forceSync > exclude
.Default:
null
For: declare files that should not sync to target directory.
Function
syncDirectory(srcDir, targetDir, { exclude(filePath) { return /node_modules/.test(filePath); } });
String
syncDirectory(srcDir, targetDir, { exclude: 'node_modules' });
RegExp
syncDirectory(srcDir, targetDir, { exclude: /node\_modules/ });
Array
syncDirectory(srcDir, targetDir, { exclude: [/node\_modules/] });
syncDirectory(srcDir, targetDir, { exclude: ['node_modules'] });
forceSync
Type: Function / RegExp / String / Array (item is RegExp / String)
Priority:
forceSync > exclude
.Default:
null
For: some files must be synced even though 'excluded'.
Function
syncDirectory(srcDir, targetDir, { exclude: ['node_modules'], forceSync(filePath) { return /node_modules\/jquery/.test(filePath); } });
String
syncDirectory(srcDir, targetDir, { exclude: ['node_modules'], forceSync: 'node_modules/jquery' });
RegExp
syncDirectory(srcDir, targetDir, { exclude: ['node_modules'], forceSync: /node_modules\/jquery/ });
Array
syncDirectory(srcDir, targetDir, { exclude: ['node_modules'], forceSync: [/node_modules\/jquery/] });
syncDirectory(srcDir, targetDir, { exclude: ['node_modules'], forceSync: ['node_modules/jquery'] });
staySymlink
Type:
true | false
Default:
false
If src folder "A/" is a symlink, the target folder "A/" will also be the same symlink.
// srcFolder: // a/ a is symlink // 1.js // targetFolder: // a/ a is not symlink // 1.js syncDirectory(srcDir, targetDir, { staySymlink: false, });
// srcFolder: // a/ a is symlink // 1.js // targetFolder: // a/ a is the same symlink // 1.js syncDirectory(srcDir, targetDir, { staySymlink: true, });
onError
Type:
Function
Default:
(err) => { throw new Error(err) }
For: callback function when something wrong.
syncDirectory(srcDir, targetDir, { onError(err) { console.log(err.message); }, });
LICENSE
MIT