@talixo-ds/vite-plugin-copy-files 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE.md ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Talixo
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,205 @@
1
+ # @talixo-ds/vite-plugin-copy-files
2
+
3
+ A Vite plugin for copying build artifacts to external directories. Perfect for monorepo setups where you need to copy frontend build outputs to backend static directories (like Django static files).
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install --save-dev @talixo-ds/vite-plugin-copy-files
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ### Basic Setup
14
+
15
+ ```typescript
16
+ // vite.config.ts
17
+ import { defineConfig } from "vite";
18
+ import { copyFilesPlugin } from "@talixo-ds/vite-plugin-copy-files";
19
+
20
+ export default defineConfig({
21
+ plugins: [
22
+ copyFilesPlugin({
23
+ destination: "../backend/static/frontend"
24
+ })
25
+ ]
26
+ });
27
+ ```
28
+
29
+ ### Environment Variable Configuration
30
+
31
+ The plugin supports the `COPY_FILES_PATH` environment variable, which takes precedence over the `destination` option:
32
+
33
+ ```bash
34
+ # Set destination via environment variable
35
+ COPY_FILES_PATH=../backend/static/frontend npm run build
36
+ ```
37
+
38
+ ```typescript
39
+ // vite.config.ts - destination will be overridden by env var
40
+ import { defineConfig } from "vite";
41
+ import { copyFilesPlugin } from "@talixo-ds/vite-plugin-copy-files";
42
+
43
+ export default defineConfig({
44
+ plugins: [
45
+ copyFilesPlugin() // Will use COPY_FILES_PATH env var
46
+ ]
47
+ });
48
+ ```
49
+
50
+ ### Advanced Configuration
51
+
52
+ ```typescript
53
+ import { defineConfig } from "vite";
54
+ import { copyFilesPlugin } from "@talixo-ds/vite-plugin-copy-files";
55
+
56
+ export default defineConfig({
57
+ plugins: [
58
+ copyFilesPlugin({
59
+ source: "dist", // Source directory (default: 'dist')
60
+ destination: "../backend/static/frontend", // Destination directory
61
+ cleanDestination: true, // Clean destination before copying (default: true)
62
+ failOnError: true, // Fail build on copy errors (default: true)
63
+ verbose: true, // Enable verbose logging (default: false)
64
+ envVariableName: "STATIC_FILES_PATH", // Custom env var name (default: 'COPY_FILES_PATH')
65
+ createDestination: true // Create destination if it doesn't exist (default: true)
66
+ })
67
+ ]
68
+ });
69
+ ```
70
+
71
+ ## API Reference
72
+
73
+ ### Plugin Options
74
+
75
+ ```typescript
76
+ interface CopyFilesOptions {
77
+ /**
78
+ * Source directory to copy from
79
+ * @default 'dist'
80
+ */
81
+ source?: string;
82
+
83
+ /**
84
+ * Destination directory to copy to
85
+ * Can be overridden by environment variable
86
+ */
87
+ destination?: string;
88
+
89
+ /**
90
+ * Whether to clean the destination directory before copying
91
+ * @default true
92
+ */
93
+ cleanDestination?: boolean;
94
+
95
+ /**
96
+ * Whether to fail the build on copy errors
97
+ * @default true
98
+ */
99
+ failOnError?: boolean;
100
+
101
+ /**
102
+ * Enable verbose logging
103
+ * @default false
104
+ */
105
+ verbose?: boolean;
106
+
107
+ /**
108
+ * Custom environment variable name for destination path
109
+ * @default 'COPY_FILES_PATH'
110
+ */
111
+ envVariableName?: string;
112
+
113
+ /**
114
+ * Whether to create destination directory if it doesn't exist
115
+ * @default true
116
+ */
117
+ createDestination?: boolean;
118
+ }
119
+ ```
120
+
121
+ ### Functions
122
+
123
+ #### `copyFilesPlugin(options?: CopyFilesOptions): Plugin`
124
+
125
+ Creates the Vite plugin instance.
126
+
127
+ #### `copyFiles(options: CopyFilesOptions, projectRoot: string): Promise<CopyResult>`
128
+
129
+ Programmatically copy files (useful for testing or standalone usage).
130
+
131
+ ## Use Cases
132
+
133
+ ### Monorepo with Django Backend
134
+
135
+ ```typescript
136
+ // Frontend app vite.config.ts
137
+ export default defineConfig({
138
+ plugins: [
139
+ copyFilesPlugin({
140
+ destination: "../../backend/myapp/static/frontend",
141
+ verbose: true
142
+ })
143
+ ]
144
+ });
145
+ ```
146
+
147
+ ### Multiple Environments
148
+
149
+ ```bash
150
+ # Development
151
+ COPY_FILES_PATH=../backend/static/dev npm run build
152
+
153
+ # Production
154
+ COPY_FILES_PATH=/var/www/static npm run build
155
+ ```
156
+
157
+ ### CI/CD Pipeline
158
+
159
+ ```yaml
160
+ # .github/workflows/build.yml
161
+ - name: Build Frontend
162
+ run: npm run build
163
+ env:
164
+ COPY_FILES_PATH: ./deployment/static
165
+ ```
166
+
167
+ ## Error Handling
168
+
169
+ The plugin validates paths and provides clear error messages:
170
+
171
+ - **Source directory doesn't exist**: Build fails with descriptive error
172
+ - **Destination not writable**: Build fails with permission error
173
+ - **No destination specified**: Build fails asking for destination config
174
+
175
+ You can control error behavior with the `failOnError` option:
176
+
177
+ ```typescript
178
+ copyFilesPlugin({
179
+ failOnError: false // Logs warnings instead of failing build
180
+ });
181
+ ```
182
+
183
+ ## Development
184
+
185
+ ### Building
186
+
187
+ ```bash
188
+ npm run build
189
+ ```
190
+
191
+ ### Testing
192
+
193
+ ```bash
194
+ npm test
195
+ ```
196
+
197
+ ### Running Tests in Watch Mode
198
+
199
+ ```bash
200
+ npm run test
201
+ ```
202
+
203
+ ## License
204
+
205
+ MIT
@@ -0,0 +1,2 @@
1
+ import v from"fs";import s from"fs";import p from"path";function d(t,o){let{source:n="dist",destination:r,envVariableName:e="COPY_FILES_PATH",createDestination:i=!0}=t,c=p.resolve(o,n);if(!s.existsSync(c))throw new Error(`Source directory does not exist: ${c}`);if(!s.statSync(c).isDirectory())throw new Error(`Source path is not a directory: ${c}`);let f=process.env[e]||r;if(!f)throw new Error(`Destination not specified. Provide either 'destination' option or set ${e} environment variable.`);let y=p.resolve(o,f),l=p.dirname(y);if(!s.existsSync(l))if(i)s.mkdirSync(l,{recursive:!0});else throw new Error(`Destination directory does not exist: ${l}`);try{s.accessSync(l,s.constants.W_OK)}catch{throw new Error(`Destination directory is not writable: ${l}`)}return{source:c,destination:y}}function m(t){s.existsSync(t)&&s.rmSync(t,{recursive:!0,force:!0}),s.mkdirSync(t,{recursive:!0})}function u(t){let o=0,n=s.readdirSync(t);for(let r of n){let e=p.join(t,r);s.statSync(e).isDirectory()?o+=u(e):o++}return o}function a(t,o=!1){o&&console.log(`[vite-plugin-copy-files] ${t}`)}function g(t={}){let{failOnError:o=!0,verbose:n=!1}=t,r;return{name:"vite-plugin-copy-files",configResolved(e){r=e.root},closeBundle:async()=>{try{let e=await w(t,r);if(e.success)a(`Successfully copied ${e.filesCopied} files from ${e.source} to ${e.destination}`,n);else{if(o)throw e.error;console.warn(`[vite-plugin-copy-files] Copy operation failed: ${e.error?.message}`)}}catch(e){let i=`Copy operation failed: ${e.message}`;if(o)throw new Error(i);console.warn(`[vite-plugin-copy-files] ${i}`)}}}}async function w(t,o){let{cleanDestination:n=!0,verbose:r=!1}=t;try{let{source:e,destination:i}=d(t,o);a("Starting copy operation...",r),a(`Source: ${e}`,r),a(`Destination: ${i}`,r),n&&(a("Cleaning destination directory...",r),m(i)),a("Copying files...",r),v.cpSync(e,i,{recursive:!0});let c=u(i);return{success:!0,source:e,destination:i,filesCopied:c}}catch(e){return{success:!1,source:t.source||"dist",destination:t.destination||"unknown",error:e,filesCopied:0}}}var F=g;export{w as copyFiles,g as copyFilesPlugin,F as default};
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/index.ts","../../src/utils.ts"],"sourcesContent":["import fs from \"fs\";\nimport type { Plugin } from \"vite\";\nimport type { CopyFilesOptions, CopyResult } from \"./types\";\nimport { validatePaths, cleanDirectory, countFiles, log } from \"./utils\";\n\n/**\n * Vite plugin for copying build artifacts to external directories\n */\nexport function copyFilesPlugin(options: CopyFilesOptions = {}): Plugin {\n\tconst { failOnError = true, verbose = false } = options;\n\n\tlet projectRoot: string;\n\n\treturn {\n\t\tname: \"vite-plugin-copy-files\",\n\t\tconfigResolved(config) {\n\t\t\tprojectRoot = config.root;\n\t\t},\n\t\tcloseBundle: async () => {\n\t\t\ttry {\n\t\t\t\tconst result = await copyFiles(options, projectRoot);\n\n\t\t\t\tif (result.success) {\n\t\t\t\t\tlog(\n\t\t\t\t\t\t`Successfully copied ${result.filesCopied} files from ${result.source} to ${result.destination}`,\n\t\t\t\t\t\tverbose\n\t\t\t\t\t);\n\t\t\t\t} else if (failOnError) {\n\t\t\t\t\tthrow result.error;\n\t\t\t\t} else {\n\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t`[vite-plugin-copy-files] Copy operation failed: ${result.error?.message}`\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tconst errorMessage = `Copy operation failed: ${(error as Error).message}`;\n\n\t\t\t\tif (failOnError) {\n\t\t\t\t\tthrow new Error(errorMessage);\n\t\t\t\t} else {\n\t\t\t\t\tconsole.warn(`[vite-plugin-copy-files] ${errorMessage}`);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n}\n\n/**\n * Copies files from source to destination\n */\nexport async function copyFiles(\n\toptions: CopyFilesOptions,\n\tprojectRoot: string\n): Promise<CopyResult> {\n\tconst { cleanDestination = true, verbose = false } = options;\n\n\ttry {\n\t\t// Validate paths\n\t\tconst { source, destination } = validatePaths(options, projectRoot);\n\n\t\tlog(`Starting copy operation...`, verbose);\n\t\tlog(`Source: ${source}`, verbose);\n\t\tlog(`Destination: ${destination}`, verbose);\n\n\t\t// Clean destination if requested\n\t\tif (cleanDestination) {\n\t\t\tlog(`Cleaning destination directory...`, verbose);\n\t\t\tcleanDirectory(destination);\n\t\t}\n\n\t\t// Copy files\n\t\tlog(`Copying files...`, verbose);\n\t\tfs.cpSync(source, destination, { recursive: true });\n\n\t\t// Count copied files\n\t\tconst filesCopied = countFiles(destination);\n\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tsource,\n\t\t\tdestination,\n\t\t\tfilesCopied\n\t\t};\n\t} catch (error) {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\tsource: options.source || \"dist\",\n\t\t\tdestination: options.destination || \"unknown\",\n\t\t\terror: error as Error,\n\t\t\tfilesCopied: 0\n\t\t};\n\t}\n}\n\n// Export types for external usage\nexport type { CopyFilesOptions, CopyResult, ValidatedPaths } from \"./types\";\n\n// Default export for convenience\nexport default copyFilesPlugin;\n","import fs from \"fs\";\nimport path from \"path\";\nimport type { CopyFilesOptions, ValidatedPaths } from \"./types\";\n\n/**\n * Validates and resolves source and destination paths\n */\nexport function validatePaths(\n\toptions: CopyFilesOptions,\n\tprojectRoot: string\n): ValidatedPaths {\n\tconst {\n\t\tsource = \"dist\",\n\t\tdestination,\n\t\tenvVariableName = \"COPY_FILES_PATH\",\n\t\tcreateDestination = true\n\t} = options;\n\n\t// Resolve source path\n\tconst resolvedSource = path.resolve(projectRoot, source);\n\n\tif (!fs.existsSync(resolvedSource)) {\n\t\tthrow new Error(`Source directory does not exist: ${resolvedSource}`);\n\t}\n\n\tif (!fs.statSync(resolvedSource).isDirectory()) {\n\t\tthrow new Error(`Source path is not a directory: ${resolvedSource}`);\n\t}\n\n\t// Resolve destination path (env var takes precedence)\n\tconst envDestination = process.env[envVariableName];\n\tconst finalDestination = envDestination || destination;\n\n\tif (!finalDestination) {\n\t\tthrow new Error(\n\t\t\t`Destination not specified. Provide either 'destination' option or set ${envVariableName} environment variable.`\n\t\t);\n\t}\n\n\tconst resolvedDestination = path.resolve(projectRoot, finalDestination);\n\n\t// Validate destination directory exists or can be created\n\tconst destinationDir = path.dirname(resolvedDestination);\n\tif (!fs.existsSync(destinationDir)) {\n\t\tif (createDestination) {\n\t\t\tfs.mkdirSync(destinationDir, { recursive: true });\n\t\t} else {\n\t\t\tthrow new Error(`Destination directory does not exist: ${destinationDir}`);\n\t\t}\n\t}\n\n\t// Check if destination is writable\n\ttry {\n\t\tfs.accessSync(destinationDir, fs.constants.W_OK);\n\t} catch {\n\t\tthrow new Error(`Destination directory is not writable: ${destinationDir}`);\n\t}\n\n\treturn {\n\t\tsource: resolvedSource,\n\t\tdestination: resolvedDestination\n\t};\n}\n\n/**\n * Cleans a directory by removing all its contents\n */\nexport function cleanDirectory(dirPath: string): void {\n\tif (fs.existsSync(dirPath)) {\n\t\tfs.rmSync(dirPath, { recursive: true, force: true });\n\t}\n\tfs.mkdirSync(dirPath, { recursive: true });\n}\n\n/**\n * Recursively counts files in a directory\n */\nexport function countFiles(dirPath: string): number {\n\tlet count = 0;\n\tconst items = fs.readdirSync(dirPath);\n\n\tfor (const item of items) {\n\t\tconst itemPath = path.join(dirPath, item);\n\t\tconst stats = fs.statSync(itemPath);\n\n\t\tif (stats.isDirectory()) {\n\t\t\tcount += countFiles(itemPath);\n\t\t} else {\n\t\t\tcount++;\n\t\t}\n\t}\n\n\treturn count;\n}\n\n/**\n * Logs message if verbose mode is enabled\n */\nexport function log(message: string, verbose: boolean = false): void {\n\tif (verbose) {\n\t\tconsole.log(`[vite-plugin-copy-files] ${message}`);\n\t}\n}\n"],"mappings":"AAAA,OAAOA,MAAQ,KCAf,OAAOC,MAAQ,KACf,OAAOC,MAAU,OAMV,SAASC,EACfC,EACAC,EACiB,CACjB,GAAM,CACL,OAAAC,EAAS,OACT,YAAAC,EACA,gBAAAC,EAAkB,kBAClB,kBAAAC,EAAoB,EACrB,EAAIL,EAGEM,EAAiBR,EAAK,QAAQG,EAAaC,CAAM,EAEvD,GAAI,CAACL,EAAG,WAAWS,CAAc,EAChC,MAAM,IAAI,MAAM,oCAAoCA,CAAc,EAAE,EAGrE,GAAI,CAACT,EAAG,SAASS,CAAc,EAAE,YAAY,EAC5C,MAAM,IAAI,MAAM,mCAAmCA,CAAc,EAAE,EAKpE,IAAMC,EADiB,QAAQ,IAAIH,CAAe,GACPD,EAE3C,GAAI,CAACI,EACJ,MAAM,IAAI,MACT,yEAAyEH,CAAe,wBACzF,EAGD,IAAMI,EAAsBV,EAAK,QAAQG,EAAaM,CAAgB,EAGhEE,EAAiBX,EAAK,QAAQU,CAAmB,EACvD,GAAI,CAACX,EAAG,WAAWY,CAAc,EAChC,GAAIJ,EACHR,EAAG,UAAUY,EAAgB,CAAE,UAAW,EAAK,CAAC,MAEhD,OAAM,IAAI,MAAM,yCAAyCA,CAAc,EAAE,EAK3E,GAAI,CACHZ,EAAG,WAAWY,EAAgBZ,EAAG,UAAU,IAAI,CAChD,MAAQ,CACP,MAAM,IAAI,MAAM,0CAA0CY,CAAc,EAAE,CAC3E,CAEA,MAAO,CACN,OAAQH,EACR,YAAaE,CACd,CACD,CAKO,SAASE,EAAeC,EAAuB,CACjDd,EAAG,WAAWc,CAAO,GACxBd,EAAG,OAAOc,EAAS,CAAE,UAAW,GAAM,MAAO,EAAK,CAAC,EAEpDd,EAAG,UAAUc,EAAS,CAAE,UAAW,EAAK,CAAC,CAC1C,CAKO,SAASC,EAAWD,EAAyB,CACnD,IAAIE,EAAQ,EACNC,EAAQjB,EAAG,YAAYc,CAAO,EAEpC,QAAWI,KAAQD,EAAO,CACzB,IAAME,EAAWlB,EAAK,KAAKa,EAASI,CAAI,EAC1BlB,EAAG,SAASmB,CAAQ,EAExB,YAAY,EACrBH,GAASD,EAAWI,CAAQ,EAE5BH,GAEF,CAEA,OAAOA,CACR,CAKO,SAASI,EAAIC,EAAiBC,EAAmB,GAAa,CAChEA,GACH,QAAQ,IAAI,4BAA4BD,CAAO,EAAE,CAEnD,CD9FO,SAASE,EAAgBC,EAA4B,CAAC,EAAW,CACvE,GAAM,CAAE,YAAAC,EAAc,GAAM,QAAAC,EAAU,EAAM,EAAIF,EAE5CG,EAEJ,MAAO,CACN,KAAM,yBACN,eAAeC,EAAQ,CACtBD,EAAcC,EAAO,IACtB,EACA,YAAa,SAAY,CACxB,GAAI,CACH,IAAMC,EAAS,MAAMC,EAAUN,EAASG,CAAW,EAEnD,GAAIE,EAAO,QACVE,EACC,uBAAuBF,EAAO,WAAW,eAAeA,EAAO,MAAM,OAAOA,EAAO,WAAW,GAC9FH,CACD,MACM,IAAID,EACV,MAAMI,EAAO,MAEb,QAAQ,KACP,mDAAmDA,EAAO,OAAO,OAAO,EACzE,EAEF,OAASG,EAAO,CACf,IAAMC,EAAe,0BAA2BD,EAAgB,OAAO,GAEvE,GAAIP,EACH,MAAM,IAAI,MAAMQ,CAAY,EAE5B,QAAQ,KAAK,4BAA4BA,CAAY,EAAE,CAEzD,CACD,CACD,CACD,CAKA,eAAsBH,EACrBN,EACAG,EACsB,CACtB,GAAM,CAAE,iBAAAO,EAAmB,GAAM,QAAAR,EAAU,EAAM,EAAIF,EAErD,GAAI,CAEH,GAAM,CAAE,OAAAW,EAAQ,YAAAC,CAAY,EAAIC,EAAcb,EAASG,CAAW,EAElEI,EAAI,6BAA8BL,CAAO,EACzCK,EAAI,WAAWI,CAAM,GAAIT,CAAO,EAChCK,EAAI,gBAAgBK,CAAW,GAAIV,CAAO,EAGtCQ,IACHH,EAAI,oCAAqCL,CAAO,EAChDY,EAAeF,CAAW,GAI3BL,EAAI,mBAAoBL,CAAO,EAC/Ba,EAAG,OAAOJ,EAAQC,EAAa,CAAE,UAAW,EAAK,CAAC,EAGlD,IAAMI,EAAcC,EAAWL,CAAW,EAE1C,MAAO,CACN,QAAS,GACT,OAAAD,EACA,YAAAC,EACA,YAAAI,CACD,CACD,OAASR,EAAO,CACf,MAAO,CACN,QAAS,GACT,OAAQR,EAAQ,QAAU,OAC1B,YAAaA,EAAQ,aAAe,UACpC,MAAOQ,EACP,YAAa,CACd,CACD,CACD,CAMA,IAAOU,EAAQnB","names":["fs","fs","path","validatePaths","options","projectRoot","source","destination","envVariableName","createDestination","resolvedSource","finalDestination","resolvedDestination","destinationDir","cleanDirectory","dirPath","countFiles","count","items","item","itemPath","log","message","verbose","copyFilesPlugin","options","failOnError","verbose","projectRoot","config","result","copyFiles","log","error","errorMessage","cleanDestination","source","destination","validatePaths","cleanDirectory","fs","filesCopied","countFiles","index_default"]}
@@ -0,0 +1,61 @@
1
+ import { Plugin } from 'vite';
2
+
3
+ interface CopyFilesOptions {
4
+ /**
5
+ * Source directory to copy from
6
+ * @default 'dist'
7
+ */
8
+ source?: string;
9
+ /**
10
+ * Destination directory to copy to
11
+ * Can be overridden by COPY_FILES_PATH environment variable
12
+ */
13
+ destination?: string;
14
+ /**
15
+ * Whether to clean the destination directory before copying
16
+ * @default true
17
+ */
18
+ cleanDestination?: boolean;
19
+ /**
20
+ * Whether to fail the build on copy errors
21
+ * @default true
22
+ */
23
+ failOnError?: boolean;
24
+ /**
25
+ * Enable verbose logging
26
+ * @default false
27
+ */
28
+ verbose?: boolean;
29
+ /**
30
+ * Custom environment variable name for destination path
31
+ * @default 'COPY_FILES_PATH'
32
+ */
33
+ envVariableName?: string;
34
+ /**
35
+ * Whether to create destination directory if it doesn't exist
36
+ * @default true
37
+ */
38
+ createDestination?: boolean;
39
+ }
40
+ interface CopyResult {
41
+ success: boolean;
42
+ source: string;
43
+ destination: string;
44
+ error?: Error;
45
+ filesCopied: number;
46
+ }
47
+ interface ValidatedPaths {
48
+ source: string;
49
+ destination: string;
50
+ }
51
+
52
+ /**
53
+ * Vite plugin for copying build artifacts to external directories
54
+ */
55
+ declare function copyFilesPlugin(options?: CopyFilesOptions): Plugin;
56
+ /**
57
+ * Copies files from source to destination
58
+ */
59
+ declare function copyFiles(options: CopyFilesOptions, projectRoot: string): Promise<CopyResult>;
60
+
61
+ export { type CopyFilesOptions, type CopyResult, type ValidatedPaths, copyFiles, copyFilesPlugin, copyFilesPlugin as default };
@@ -0,0 +1,63 @@
1
+ import { Plugin } from 'vite';
2
+
3
+ interface CopyFilesOptions {
4
+ /**
5
+ * Source directory to copy from
6
+ * @default 'dist'
7
+ */
8
+ source?: string;
9
+ /**
10
+ * Destination directory to copy to
11
+ * Can be overridden by COPY_FILES_PATH environment variable
12
+ */
13
+ destination?: string;
14
+ /**
15
+ * Whether to clean the destination directory before copying
16
+ * @default true
17
+ */
18
+ cleanDestination?: boolean;
19
+ /**
20
+ * Whether to fail the build on copy errors
21
+ * @default true
22
+ */
23
+ failOnError?: boolean;
24
+ /**
25
+ * Enable verbose logging
26
+ * @default false
27
+ */
28
+ verbose?: boolean;
29
+ /**
30
+ * Custom environment variable name for destination path
31
+ * @default 'COPY_FILES_PATH'
32
+ */
33
+ envVariableName?: string;
34
+ /**
35
+ * Whether to create destination directory if it doesn't exist
36
+ * @default true
37
+ */
38
+ createDestination?: boolean;
39
+ }
40
+ interface CopyResult {
41
+ success: boolean;
42
+ source: string;
43
+ destination: string;
44
+ error?: Error;
45
+ filesCopied: number;
46
+ }
47
+ interface ValidatedPaths {
48
+ source: string;
49
+ destination: string;
50
+ }
51
+
52
+ /**
53
+ * Vite plugin for copying build artifacts to external directories
54
+ */
55
+ declare function copyFilesPlugin(options?: CopyFilesOptions): Plugin;
56
+ /**
57
+ * Copies files from source to destination
58
+ */
59
+ declare function copyFiles(options: CopyFilesOptions, projectRoot: string): Promise<CopyResult>;
60
+
61
+ // @ts-ignore
62
+ export = copyFilesPlugin;
63
+ export { type CopyFilesOptions, type CopyResult, type ValidatedPaths, copyFiles, copyFilesPlugin };
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";var D=Object.create;var u=Object.defineProperty;var $=Object.getOwnPropertyDescriptor;var x=Object.getOwnPropertyNames;var F=Object.getPrototypeOf,E=Object.prototype.hasOwnProperty;var P=(e,o)=>{for(var r in o)u(e,r,{get:o[r],enumerable:!0})},v=(e,o,r,i)=>{if(o&&typeof o=="object"||typeof o=="function")for(let t of x(o))!E.call(e,t)&&t!==r&&u(e,t,{get:()=>o[t],enumerable:!(i=$(o,t))||i.enumerable});return e};var f=(e,o,r)=>(r=e!=null?D(F(e)):{},v(o||!e||!e.__esModule?u(r,"default",{value:e,enumerable:!0}):r,e)),O=e=>v(u({},"__esModule",{value:!0}),e);var R={};P(R,{copyFiles:()=>h,copyFilesPlugin:()=>C,default:()=>b});module.exports=O(R);var S=f(require("fs"));var s=f(require("fs")),p=f(require("path"));function g(e,o){let{source:r="dist",destination:i,envVariableName:t="COPY_FILES_PATH",createDestination:n=!0}=e,c=p.default.resolve(o,r);if(!s.default.existsSync(c))throw new Error(`Source directory does not exist: ${c}`);if(!s.default.statSync(c).isDirectory())throw new Error(`Source path is not a directory: ${c}`);let d=process.env[t]||i;if(!d)throw new Error(`Destination not specified. Provide either 'destination' option or set ${t} environment variable.`);let m=p.default.resolve(o,d),l=p.default.dirname(m);if(!s.default.existsSync(l))if(n)s.default.mkdirSync(l,{recursive:!0});else throw new Error(`Destination directory does not exist: ${l}`);try{s.default.accessSync(l,s.default.constants.W_OK)}catch{throw new Error(`Destination directory is not writable: ${l}`)}return{source:c,destination:m}}function w(e){s.default.existsSync(e)&&s.default.rmSync(e,{recursive:!0,force:!0}),s.default.mkdirSync(e,{recursive:!0})}function y(e){let o=0,r=s.default.readdirSync(e);for(let i of r){let t=p.default.join(e,i);s.default.statSync(t).isDirectory()?o+=y(t):o++}return o}function a(e,o=!1){o&&console.log(`[vite-plugin-copy-files] ${e}`)}function C(e={}){let{failOnError:o=!0,verbose:r=!1}=e,i;return{name:"vite-plugin-copy-files",configResolved(t){i=t.root},closeBundle:async()=>{try{let t=await h(e,i);if(t.success)a(`Successfully copied ${t.filesCopied} files from ${t.source} to ${t.destination}`,r);else{if(o)throw t.error;console.warn(`[vite-plugin-copy-files] Copy operation failed: ${t.error?.message}`)}}catch(t){let n=`Copy operation failed: ${t.message}`;if(o)throw new Error(n);console.warn(`[vite-plugin-copy-files] ${n}`)}}}}async function h(e,o){let{cleanDestination:r=!0,verbose:i=!1}=e;try{let{source:t,destination:n}=g(e,o);a("Starting copy operation...",i),a(`Source: ${t}`,i),a(`Destination: ${n}`,i),r&&(a("Cleaning destination directory...",i),w(n)),a("Copying files...",i),S.default.cpSync(t,n,{recursive:!0});let c=y(n);return{success:!0,source:t,destination:n,filesCopied:c}}catch(t){return{success:!1,source:e.source||"dist",destination:e.destination||"unknown",error:t,filesCopied:0}}}var b=C;0&&(module.exports={copyFiles,copyFilesPlugin});
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/utils.ts"],"sourcesContent":["import fs from \"fs\";\nimport type { Plugin } from \"vite\";\nimport type { CopyFilesOptions, CopyResult } from \"./types\";\nimport { validatePaths, cleanDirectory, countFiles, log } from \"./utils\";\n\n/**\n * Vite plugin for copying build artifacts to external directories\n */\nexport function copyFilesPlugin(options: CopyFilesOptions = {}): Plugin {\n\tconst { failOnError = true, verbose = false } = options;\n\n\tlet projectRoot: string;\n\n\treturn {\n\t\tname: \"vite-plugin-copy-files\",\n\t\tconfigResolved(config) {\n\t\t\tprojectRoot = config.root;\n\t\t},\n\t\tcloseBundle: async () => {\n\t\t\ttry {\n\t\t\t\tconst result = await copyFiles(options, projectRoot);\n\n\t\t\t\tif (result.success) {\n\t\t\t\t\tlog(\n\t\t\t\t\t\t`Successfully copied ${result.filesCopied} files from ${result.source} to ${result.destination}`,\n\t\t\t\t\t\tverbose\n\t\t\t\t\t);\n\t\t\t\t} else if (failOnError) {\n\t\t\t\t\tthrow result.error;\n\t\t\t\t} else {\n\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t`[vite-plugin-copy-files] Copy operation failed: ${result.error?.message}`\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tconst errorMessage = `Copy operation failed: ${(error as Error).message}`;\n\n\t\t\t\tif (failOnError) {\n\t\t\t\t\tthrow new Error(errorMessage);\n\t\t\t\t} else {\n\t\t\t\t\tconsole.warn(`[vite-plugin-copy-files] ${errorMessage}`);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n}\n\n/**\n * Copies files from source to destination\n */\nexport async function copyFiles(\n\toptions: CopyFilesOptions,\n\tprojectRoot: string\n): Promise<CopyResult> {\n\tconst { cleanDestination = true, verbose = false } = options;\n\n\ttry {\n\t\t// Validate paths\n\t\tconst { source, destination } = validatePaths(options, projectRoot);\n\n\t\tlog(`Starting copy operation...`, verbose);\n\t\tlog(`Source: ${source}`, verbose);\n\t\tlog(`Destination: ${destination}`, verbose);\n\n\t\t// Clean destination if requested\n\t\tif (cleanDestination) {\n\t\t\tlog(`Cleaning destination directory...`, verbose);\n\t\t\tcleanDirectory(destination);\n\t\t}\n\n\t\t// Copy files\n\t\tlog(`Copying files...`, verbose);\n\t\tfs.cpSync(source, destination, { recursive: true });\n\n\t\t// Count copied files\n\t\tconst filesCopied = countFiles(destination);\n\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tsource,\n\t\t\tdestination,\n\t\t\tfilesCopied\n\t\t};\n\t} catch (error) {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\tsource: options.source || \"dist\",\n\t\t\tdestination: options.destination || \"unknown\",\n\t\t\terror: error as Error,\n\t\t\tfilesCopied: 0\n\t\t};\n\t}\n}\n\n// Export types for external usage\nexport type { CopyFilesOptions, CopyResult, ValidatedPaths } from \"./types\";\n\n// Default export for convenience\nexport default copyFilesPlugin;\n","import fs from \"fs\";\nimport path from \"path\";\nimport type { CopyFilesOptions, ValidatedPaths } from \"./types\";\n\n/**\n * Validates and resolves source and destination paths\n */\nexport function validatePaths(\n\toptions: CopyFilesOptions,\n\tprojectRoot: string\n): ValidatedPaths {\n\tconst {\n\t\tsource = \"dist\",\n\t\tdestination,\n\t\tenvVariableName = \"COPY_FILES_PATH\",\n\t\tcreateDestination = true\n\t} = options;\n\n\t// Resolve source path\n\tconst resolvedSource = path.resolve(projectRoot, source);\n\n\tif (!fs.existsSync(resolvedSource)) {\n\t\tthrow new Error(`Source directory does not exist: ${resolvedSource}`);\n\t}\n\n\tif (!fs.statSync(resolvedSource).isDirectory()) {\n\t\tthrow new Error(`Source path is not a directory: ${resolvedSource}`);\n\t}\n\n\t// Resolve destination path (env var takes precedence)\n\tconst envDestination = process.env[envVariableName];\n\tconst finalDestination = envDestination || destination;\n\n\tif (!finalDestination) {\n\t\tthrow new Error(\n\t\t\t`Destination not specified. Provide either 'destination' option or set ${envVariableName} environment variable.`\n\t\t);\n\t}\n\n\tconst resolvedDestination = path.resolve(projectRoot, finalDestination);\n\n\t// Validate destination directory exists or can be created\n\tconst destinationDir = path.dirname(resolvedDestination);\n\tif (!fs.existsSync(destinationDir)) {\n\t\tif (createDestination) {\n\t\t\tfs.mkdirSync(destinationDir, { recursive: true });\n\t\t} else {\n\t\t\tthrow new Error(`Destination directory does not exist: ${destinationDir}`);\n\t\t}\n\t}\n\n\t// Check if destination is writable\n\ttry {\n\t\tfs.accessSync(destinationDir, fs.constants.W_OK);\n\t} catch {\n\t\tthrow new Error(`Destination directory is not writable: ${destinationDir}`);\n\t}\n\n\treturn {\n\t\tsource: resolvedSource,\n\t\tdestination: resolvedDestination\n\t};\n}\n\n/**\n * Cleans a directory by removing all its contents\n */\nexport function cleanDirectory(dirPath: string): void {\n\tif (fs.existsSync(dirPath)) {\n\t\tfs.rmSync(dirPath, { recursive: true, force: true });\n\t}\n\tfs.mkdirSync(dirPath, { recursive: true });\n}\n\n/**\n * Recursively counts files in a directory\n */\nexport function countFiles(dirPath: string): number {\n\tlet count = 0;\n\tconst items = fs.readdirSync(dirPath);\n\n\tfor (const item of items) {\n\t\tconst itemPath = path.join(dirPath, item);\n\t\tconst stats = fs.statSync(itemPath);\n\n\t\tif (stats.isDirectory()) {\n\t\t\tcount += countFiles(itemPath);\n\t\t} else {\n\t\t\tcount++;\n\t\t}\n\t}\n\n\treturn count;\n}\n\n/**\n * Logs message if verbose mode is enabled\n */\nexport function log(message: string, verbose: boolean = false): void {\n\tif (verbose) {\n\t\tconsole.log(`[vite-plugin-copy-files] ${message}`);\n\t}\n}\n"],"mappings":"0jBAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,eAAAE,EAAA,oBAAAC,EAAA,YAAAC,IAAA,eAAAC,EAAAL,GAAA,IAAAM,EAAe,iBCAf,IAAAC,EAAe,iBACfC,EAAiB,mBAMV,SAASC,EACfC,EACAC,EACiB,CACjB,GAAM,CACL,OAAAC,EAAS,OACT,YAAAC,EACA,gBAAAC,EAAkB,kBAClB,kBAAAC,EAAoB,EACrB,EAAIL,EAGEM,EAAiB,EAAAC,QAAK,QAAQN,EAAaC,CAAM,EAEvD,GAAI,CAAC,EAAAM,QAAG,WAAWF,CAAc,EAChC,MAAM,IAAI,MAAM,oCAAoCA,CAAc,EAAE,EAGrE,GAAI,CAAC,EAAAE,QAAG,SAASF,CAAc,EAAE,YAAY,EAC5C,MAAM,IAAI,MAAM,mCAAmCA,CAAc,EAAE,EAKpE,IAAMG,EADiB,QAAQ,IAAIL,CAAe,GACPD,EAE3C,GAAI,CAACM,EACJ,MAAM,IAAI,MACT,yEAAyEL,CAAe,wBACzF,EAGD,IAAMM,EAAsB,EAAAH,QAAK,QAAQN,EAAaQ,CAAgB,EAGhEE,EAAiB,EAAAJ,QAAK,QAAQG,CAAmB,EACvD,GAAI,CAAC,EAAAF,QAAG,WAAWG,CAAc,EAChC,GAAIN,EACH,EAAAG,QAAG,UAAUG,EAAgB,CAAE,UAAW,EAAK,CAAC,MAEhD,OAAM,IAAI,MAAM,yCAAyCA,CAAc,EAAE,EAK3E,GAAI,CACH,EAAAH,QAAG,WAAWG,EAAgB,EAAAH,QAAG,UAAU,IAAI,CAChD,MAAQ,CACP,MAAM,IAAI,MAAM,0CAA0CG,CAAc,EAAE,CAC3E,CAEA,MAAO,CACN,OAAQL,EACR,YAAaI,CACd,CACD,CAKO,SAASE,EAAeC,EAAuB,CACjD,EAAAL,QAAG,WAAWK,CAAO,GACxB,EAAAL,QAAG,OAAOK,EAAS,CAAE,UAAW,GAAM,MAAO,EAAK,CAAC,EAEpD,EAAAL,QAAG,UAAUK,EAAS,CAAE,UAAW,EAAK,CAAC,CAC1C,CAKO,SAASC,EAAWD,EAAyB,CACnD,IAAIE,EAAQ,EACNC,EAAQ,EAAAR,QAAG,YAAYK,CAAO,EAEpC,QAAWI,KAAQD,EAAO,CACzB,IAAME,EAAW,EAAAX,QAAK,KAAKM,EAASI,CAAI,EAC1B,EAAAT,QAAG,SAASU,CAAQ,EAExB,YAAY,EACrBH,GAASD,EAAWI,CAAQ,EAE5BH,GAEF,CAEA,OAAOA,CACR,CAKO,SAASI,EAAIC,EAAiBC,EAAmB,GAAa,CAChEA,GACH,QAAQ,IAAI,4BAA4BD,CAAO,EAAE,CAEnD,CD9FO,SAASE,EAAgBC,EAA4B,CAAC,EAAW,CACvE,GAAM,CAAE,YAAAC,EAAc,GAAM,QAAAC,EAAU,EAAM,EAAIF,EAE5CG,EAEJ,MAAO,CACN,KAAM,yBACN,eAAeC,EAAQ,CACtBD,EAAcC,EAAO,IACtB,EACA,YAAa,SAAY,CACxB,GAAI,CACH,IAAMC,EAAS,MAAMC,EAAUN,EAASG,CAAW,EAEnD,GAAIE,EAAO,QACVE,EACC,uBAAuBF,EAAO,WAAW,eAAeA,EAAO,MAAM,OAAOA,EAAO,WAAW,GAC9FH,CACD,MACM,IAAID,EACV,MAAMI,EAAO,MAEb,QAAQ,KACP,mDAAmDA,EAAO,OAAO,OAAO,EACzE,EAEF,OAASG,EAAO,CACf,IAAMC,EAAe,0BAA2BD,EAAgB,OAAO,GAEvE,GAAIP,EACH,MAAM,IAAI,MAAMQ,CAAY,EAE5B,QAAQ,KAAK,4BAA4BA,CAAY,EAAE,CAEzD,CACD,CACD,CACD,CAKA,eAAsBH,EACrBN,EACAG,EACsB,CACtB,GAAM,CAAE,iBAAAO,EAAmB,GAAM,QAAAR,EAAU,EAAM,EAAIF,EAErD,GAAI,CAEH,GAAM,CAAE,OAAAW,EAAQ,YAAAC,CAAY,EAAIC,EAAcb,EAASG,CAAW,EAElEI,EAAI,6BAA8BL,CAAO,EACzCK,EAAI,WAAWI,CAAM,GAAIT,CAAO,EAChCK,EAAI,gBAAgBK,CAAW,GAAIV,CAAO,EAGtCQ,IACHH,EAAI,oCAAqCL,CAAO,EAChDY,EAAeF,CAAW,GAI3BL,EAAI,mBAAoBL,CAAO,EAC/B,EAAAa,QAAG,OAAOJ,EAAQC,EAAa,CAAE,UAAW,EAAK,CAAC,EAGlD,IAAMI,EAAcC,EAAWL,CAAW,EAE1C,MAAO,CACN,QAAS,GACT,OAAAD,EACA,YAAAC,EACA,YAAAI,CACD,CACD,OAASR,EAAO,CACf,MAAO,CACN,QAAS,GACT,OAAQR,EAAQ,QAAU,OAC1B,YAAaA,EAAQ,aAAe,UACpC,MAAOQ,EACP,YAAa,CACd,CACD,CACD,CAMA,IAAOU,EAAQnB","names":["index_exports","__export","copyFiles","copyFilesPlugin","index_default","__toCommonJS","import_fs","import_fs","import_path","validatePaths","options","projectRoot","source","destination","envVariableName","createDestination","resolvedSource","path","fs","finalDestination","resolvedDestination","destinationDir","cleanDirectory","dirPath","countFiles","count","items","item","itemPath","log","message","verbose","copyFilesPlugin","options","failOnError","verbose","projectRoot","config","result","copyFiles","log","error","errorMessage","cleanDestination","source","destination","validatePaths","cleanDirectory","fs","filesCopied","countFiles","index_default"]}
package/package.json ADDED
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "@talixo-ds/vite-plugin-copy-files",
3
+ "version": "1.0.1",
4
+ "description": "Vite plugin for copying build artifacts to external directories",
5
+ "types": "./dist/index.d.ts",
6
+ "publishConfig": {
7
+ "access": "public"
8
+ },
9
+ "main": "./dist/index.js",
10
+ "module": "./dist/esm/index.js",
11
+ "sideEffects": false,
12
+ "files": [
13
+ "dist"
14
+ ],
15
+ "scripts": {
16
+ "build": "rm -rf dist && tsup src/index.ts --tsconfig tsconfig.build.json --config ../../tsup.config.ts",
17
+ "test": "vitest",
18
+ "test:ci": "vitest run",
19
+ "check-exports": "attw --pack ."
20
+ },
21
+ "keywords": [
22
+ "vite",
23
+ "plugin",
24
+ "copy",
25
+ "files",
26
+ "build",
27
+ "talixo"
28
+ ],
29
+ "peerDependencies": {
30
+ "vite": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0"
31
+ },
32
+ "devDependencies": {
33
+ "@types/node": "^22.12.0",
34
+ "vite": "^7.0.0"
35
+ },
36
+ "gitHead": "4673d0c577e51a8307883592f26c9937a0587a51"
37
+ }