From 3da1c00b130c31f4f0a3cbed478809408e98793c Mon Sep 17 00:00:00 2001 From: EGOIST Date: Tue, 15 Nov 2022 00:18:31 +0800 Subject: [PATCH] feat: add `--publicDir [dir]` flag --- docs/README.md | 6 ++++++ src/cli-main.ts | 1 + src/fs.ts | 19 +++++++++++++++++++ src/index.ts | 14 +++++++++++++- src/lib/public-dir.ts | 22 ++++++++++++++++++++++ src/options.ts | 4 ++++ 6 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 src/lib/public-dir.ts diff --git a/docs/README.md b/docs/README.md index 2cbe384af..1cfcebf57 100644 --- a/docs/README.md +++ b/docs/README.md @@ -522,6 +522,12 @@ export default defineConfig({ - When building the cjs bundle, it will compile `import.meta.url` as `typeof document === "undefined" ? new URL("file:" + __filename).href : document.currentScript && document.currentScript.src || new URL("main.js", document.baseURI).href` - When building the esm bundle, it will compile `__dirname` as `path.dirname(fileURLToPath(import.meta.url))` +### Copy files to output directory + +Use `--publicDir` flag to copy files inside `./public` folder to the output directory. + +You can also specify a custom directory using `--publicDir another-directory`. + ## Troubleshooting ### error: No matching export in "xxx.ts" for import "xxx" diff --git a/src/cli-main.ts b/src/cli-main.ts index 9e36ff864..ad3284be6 100644 --- a/src/cli-main.ts +++ b/src/cli-main.ts @@ -90,6 +90,7 @@ export async function main(options: Options = {}) { '--treeshake [strategy]', 'Using Rollup for treeshaking instead, "recommended" or "smallest" or "safest"' ) + .option('--publicDir [dir]', 'Copy public directory to output directory') .action(async (files: string[], flags) => { const { build } = await import('.') Object.assign(options, { diff --git a/src/fs.ts b/src/fs.ts index f498cadeb..9a20522f0 100644 --- a/src/fs.ts +++ b/src/fs.ts @@ -9,3 +9,22 @@ export const outputFile = async ( await fs.promises.mkdir(path.dirname(filepath), { recursive: true }) await fs.promises.writeFile(filepath, data, options) } + +export function copyDirSync(srcDir: string, destDir: string): void { + if (!fs.existsSync(srcDir)) return + + fs.mkdirSync(destDir, { recursive: true }) + for (const file of fs.readdirSync(srcDir)) { + const srcFile = path.resolve(srcDir, file) + if (srcFile === destDir) { + continue + } + const destFile = path.resolve(destDir, file) + const stat = fs.statSync(srcFile) + if (stat.isDirectory()) { + copyDirSync(srcFile, destFile) + } else { + fs.copyFileSync(srcFile, destFile) + } + } +} diff --git a/src/index.ts b/src/index.ts index 4efe90392..9552ebbc0 100644 --- a/src/index.ts +++ b/src/index.ts @@ -19,6 +19,7 @@ import { PluginContainer } from './plugin' import { es5 } from './plugins/es5' import { sizeReporter } from './plugins/size-reporter' import { treeShakingPlugin } from './plugins/tree-shaking' +import { copyPublicDir, isInPublicDir } from './lib/public-dir' export type { Format, Options, NormalizedOptions } @@ -122,7 +123,7 @@ const normalizeOptions = async ( if (!options.target) { options.target = 'node14' } - + return options as NormalizedOptions } @@ -328,6 +329,16 @@ export async function build(_options: Options) { }) watcher.on('all', async (type, file) => { file = slash(file) + + if ( + options.publicDir && + isInPublicDir(options.publicDir, file) + ) { + logger.info('CLI', `Change in public dir: ${file}`) + copyPublicDir(options.publicDir, options.outDir) + return + } + // By default we only rebuild when imported files change // If you specify custom `watch`, a string or multiple strings // We rebuild when those files change @@ -355,6 +366,7 @@ export async function build(_options: Options) { logger.info('CLI', `Target: ${options.target}`) await buildAll() + copyPublicDir(options.publicDir, options.outDir) startWatcher() } diff --git a/src/lib/public-dir.ts b/src/lib/public-dir.ts new file mode 100644 index 000000000..7179d467b --- /dev/null +++ b/src/lib/public-dir.ts @@ -0,0 +1,22 @@ +import path from 'path' +import { copyDirSync } from '../fs' +import { slash } from '../utils' + +export const copyPublicDir = ( + publicDir: string | boolean | undefined, + outDir: string +) => { + if (!publicDir) return + copyDirSync(path.resolve(publicDir === true ? 'public' : publicDir), outDir) +} + +export const isInPublicDir = ( + publicDir: string | boolean | undefined, + filePath: string +) => { + if (!publicDir) return false + const publicPath = slash( + path.resolve(publicDir === true ? 'public' : publicDir) + ) + return slash(path.resolve(filePath)).startsWith(`${publicPath}/`) +} diff --git a/src/options.ts b/src/options.ts index e17333d83..d99a1bb17 100644 --- a/src/options.ts +++ b/src/options.ts @@ -181,6 +181,10 @@ export type Options = { * This can result in smaller bundle size */ treeshake?: TreeshakingStrategy + /** + * Copy the files inside `publicDir` to output directory + */ + publicDir?: string | boolean } export type NormalizedOptions = Omit<