Skip to content

Latest commit

 

History

History

esbuild-plugin-copy

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

esbuild-plugin-copy

ESBuild plugin for assets copy.

Features

  • Keep copied assets file structure
  • Control assets destination path freely
  • Support verbose output log
  • Run only once or only when assets changed

Usage

npm install esbuild-plugin-copy --save-dev
pnpm install esbuild-plugin-copy --save-dev
yarn add esbuild-plugin-copy --save-dev
import { build } from 'esbuild';
import { copy } from 'esbuild-plugin-copy';

(async () => {
  const res = await build({
    entryPoints: ['./src/main.ts'],
    bundle: true,
    watch: true,
    outfile: './dist/main.js',
    plugins: [
      copy({
        // this is equal to process.cwd(), which means we use cwd path as base path to resolve `to` path
        // if not specified, this plugin uses ESBuild.build outdir/outfile options as base path.
        resolveFrom: 'cwd',
        assets: {
          from: ['./assets/*'],
          to: ['./assets', './tmp-assets'],
        },
        watch: true,
      }),
    ],
  });
})();

Keep file structure

import { copy } from 'esbuild-plugin-copy';
import { build } from 'esbuild';

(async () => {
  const res = await build({
    entryPoints: ['./src/index.ts'],
    bundle: true,
    // as resolveFrom not set, we use dist as output base dir
    outfile: './dist/main.js',
    watch: true,
    plugins: [
      copy({
        assets: [
          {
            from: ['./node_modules/tinymce/skins/**/*'],
            to: ['./dest/skins'],
          },
        ],
      }),
    ],
  });
})();

File structure will be kept:

|-node_modules/tinymce/skins
|--- content
|----- dark
|----- default
|----- document
|--- ui
|----- oxide
|----- oxide-dark
|- dist/dest/skins
|--- content
|----- dark
|----- default
|----- document
|--- ui
|----- oxide
|----- oxide-dark

You can also use patterns with extension names like ./path/**/*.js.

File Glob

Note: This plugin doesnot expand directories by default, which means when you're using pattern dir/* or dir/*.* , you will only get the file inside dir/ like dir/index.md. If you want to match the nested files like dir/path/to/index.md, you will need to use pattern like dir/**/*.

If you're using dir/* and there are no files under this directory, you will got an warning:

i No files matched using current glob pattern: ./node_modules/tinymce/skins/*, maybe you need to configure globby by options.globbyOptions?

Watching Mode

You can use watch option to enable watching mode, which means this plugin will only copy files when assets changed. Also, you can control using watch mode for all assets pair or only for some of them.

Watching Mode of this plugin is implemented using polling for being consistent with ESBuild Watch Mode, you could change the behavior by setting watch option which will be passed to chokidar under the hood.

Note: To use watching mode, you must also enable ESBuild.build.watch option.

Note: Watching Mode only works for files outside ESBuild.build.absWorkingDir, as if the files inside absWorkingDir changed, ESBuild will re-execute plugin completely so we cannot choose file to copy.

(async () => {
  const res = await build({
    // enable watching mode for all assets pair
    watch: true,
    plugins: [
      copy({
        assets: [
          {
            from: [],
            to: [],
            // disable watching mode for this assets pair only
            watch: false,
          },
        ],
      }),
    ],
  });
})();
(async () => {
  const res = await build({
    // disable watching mode for all assets pair
    watch: false,
    plugins: [
      copy({
        assets: [
          {
            from: [],
            to: [],
            // enable watching mode for this assets pair only
            watch: {
              /** chokidar options */
            },
          },
        ],
      }),
    ],
  });
})();

Configurations

import type { GlobbyOptions } from 'globby';
import type { WatchOptions } from 'chokidar';

export type MaybeArray<T> = T | T[];

// file/folder/globs
export interface AssetPair {
  /**
   * from path is resolved based on `cwd`
   */
  from: MaybeArray<string>;

  /**
   * to path is resolved based on `outdir` or `outfile` in your ESBuild options by default
   * you can also set `resolveFrom` to change the base dir
   */
  to: MaybeArray<string>;

  /**
   * control watch mode for current assets
   *
   * @default false
   */
  watch?: boolean | WatchOptions;
}

export interface Options {
  /**
   * assets pair to copy
   *
   * @default []
   */
  assets: MaybeArray<AssetPair>;

  /**
   * execute copy in `ESBuild.onEnd` hook(recommended)
   *
   * set to true if you want to execute in onStart hook
   *
   * @default false
   */
  copyOnStart: boolean;

  /**
   * enable verbose logging
   *
   * outputs from-path and to-path finally passed to `fs.copyFileSync` method
   *
   * @default false
   */
  verbose: boolean;

  /**
   * options passed to `globby` when we 're globbing for files to copy
   *
   * @default {}
   */
  globbyOptions: GlobbyOptions;

  /**
   * only execute copy operation once
   *
   * useful when you're using ESBuild.build watching mode
   *
   * @default false
   */
  once: boolean;

  /**
   * base path used to resolve relative `assets.to` path
   * by default this plugin use `outdir` or `outfile` in your ESBuild options
   * you can specify "cwd" or process.cwd() to resolve from current working directory,
   * also, you can specify somewhere else to resolve from.
   *
   * @default "out"
   */
  resolveFrom: 'cwd' | 'out' | (string & {});

  /**
   * use dry run mode to see what's happening.
   *
   * by default, enable this option means enable `verbose` option in the same time
   *
   * @default false
   */
  dryRun?: boolean;

  /**
   * control watch mode for all assets pair
   *
   * @default false
   */
  watch?: boolean | WatchOptions;
}