From bb0e705d3373f1ecd66e7efc04be42cdd3b30770 Mon Sep 17 00:00:00 2001 From: Karel-Jan Van Haute Date: Thu, 24 Nov 2022 12:11:56 +0100 Subject: [PATCH] Issue-36 --- src/options.ts | 9 +++++- src/serve.ts | 85 ++++++++++++++++++++++++++++++++++++++++++++++++-- src/utils.ts | 70 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 160 insertions(+), 4 deletions(-) diff --git a/src/options.ts b/src/options.ts index aa4a9fd..5e56495 100644 --- a/src/options.ts +++ b/src/options.ts @@ -87,6 +87,11 @@ export type ViteStaticCopyOptions = { * @default false */ reloadPageOnChange?: boolean + /** + * Copy files to the dist on change + * @default false + */ + copyToDest?: boolean } } @@ -96,6 +101,7 @@ export type ResolvedViteStaticCopyOptions = { watch: { options: WatchOptions reloadPageOnChange: boolean + copyToDest: boolean } } @@ -106,6 +112,7 @@ export const resolveOptions = ( flatten: options.flatten ?? true, watch: { options: options.watch?.options ?? {}, - reloadPageOnChange: options.watch?.reloadPageOnChange ?? false + reloadPageOnChange: options.watch?.reloadPageOnChange ?? false, + copyToDest: options.watch?.copyToDest ?? false } }) diff --git a/src/serve.ts b/src/serve.ts index d79b501..49f9851 100644 --- a/src/serve.ts +++ b/src/serve.ts @@ -5,7 +5,11 @@ import { collectCopyTargets, updateFileMapFromTargets, outputCollectedLog, - formatConsole + formatConsole, + copyAll, + copyFile, + removeFile, + outputCopyLog } from './utils' import { debounce } from 'throttle-debounce' import chokidar from 'chokidar' @@ -56,6 +60,14 @@ export const servePlugin = ({ ws.send({ type: 'full-reload', path: '*' }) } + if (watch.copyToDest) { + copyAll(config.root, config.build.outDir, targets, flatten).then( + copyCount => { + outputCopyLog(config.logger, copyCount) + } + ) + } + // cannot use server.watcher since disableGlobbing is true watcher = chokidar.watch( targets.flatMap(target => target.src), @@ -73,11 +85,78 @@ export const servePlugin = ({ } ) await collectFileMapDebounce() - if (watch.reloadPageOnChange) { + if (watch.copyToDest) { + const dest = await copyFile( + path, + config.root, + config.build.outDir, + targets, + flatten + ) + config.logger.info( + formatConsole( + `${pc.green('file added and copied')} ${path} ${pc.green( + '->' + )} ${dest.join(pc.green(', '))}` + ), + { + timestamp: true + } + ) + if (watch.reloadPageOnChange) { + reloadPage() + } + } + if (watch.reloadPageOnChange && !watch.copyToDest) { reloadPage() } }) - if (watch.reloadPageOnChange) { + if (watch.copyToDest) { + watcher.on('change', async path => { + const dest = await copyFile( + path, + config.root, + config.build.outDir, + targets, + flatten + ) + if (watch.reloadPageOnChange) { + reloadPage() + } + config.logger.info( + formatConsole( + `${pc.green('file changed and copied')} ${path} ${pc.green( + '->' + )} ${dest.join(pc.green(', '))}` + ), + { + timestamp: true + } + ) + }) + watcher.on('unlink', async path => { + const dest = await removeFile( + path, + config.root, + config.build.outDir, + targets, + flatten + ) + if (dest.length) { + config.logger.info( + formatConsole( + `${pc.green('file deleted and removed')} ${path} ${pc.green( + 'and' + )} ${dest.join(pc.green(', '))}` + ), + { + timestamp: true + } + ) + } + }) + } + if (watch.reloadPageOnChange && !watch.copyToDest) { watcher.on('change', path => { config.logger.info( formatConsole(`${pc.green('file changed')} ${path}`), diff --git a/src/utils.ts b/src/utils.ts index 7e50a50..5484f9e 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -135,6 +135,76 @@ export const copyAll = async ( return copyTargets.length } +export const copyFile = async ( + file: string, + rootSrc: string, + rootDest: string, + targets: Target[], + flatten: boolean +) => { + const copyTargets = await collectCopyTargets(rootSrc, targets, flatten) + const changedFiles: string[] = [] + for (const copyTarget of copyTargets) { + const { src, dest, transform, preserveTimestamps, dereference } = copyTarget + const relative = path.relative(file, src) + if ( + relative.length == 0 || + (relative.startsWith('..') && relative.endsWith('..')) + ) { + const resolvedSrc = path.resolve(rootSrc, file) + let resolvedDest = path.resolve(rootSrc, rootDest, dest) + const transformOption = resolveTransformOption(transform) + if (fs.statSync(resolvedDest).isDirectory()) { + resolvedDest = resolvedDest + '/' + path.relative(src, file) + } + + if (transformOption) { + await transformCopy(transformOption, resolvedSrc, resolvedDest) + } else { + await fs.copy(resolvedSrc, resolvedDest, { + preserveTimestamps, + dereference + }) + } + + changedFiles.push( + path.normalize(rootDest + '/' + dest + '/' + path.relative(src, file)) + ) + } + } + return changedFiles +} + +export const removeFile = async ( + file: string, + rootSrc: string, + rootDest: string, + targets: Target[], + flatten: boolean +) => { + const copyTargets = await collectCopyTargets(rootSrc, targets, flatten) + const changedFiles: string[] = [] + for (const copyTarget of copyTargets) { + const { src, dest } = copyTarget + const relative = path.relative(file, src) + if ( + relative.length == 0 || + (relative.startsWith('..') && relative.endsWith('..')) + ) { + let resolvedDest = path.resolve(rootSrc, rootDest, dest) + if (fs.statSync(resolvedDest).isDirectory()) { + resolvedDest = resolvedDest + '/' + path.relative(src, file) + } + await fs.remove(resolvedDest) + + changedFiles.push( + path.normalize(rootDest + '/' + dest + '/' + path.relative(src, file)) + ) + } + } + return changedFiles +} + export const updateFileMapFromTargets = ( targets: SimpleTarget[], fileMap: FileMap