├── examples ├── .gitignore ├── simple │ ├── static │ │ ├── test2.txt │ │ ├── test1.txt │ │ └── dir │ │ │ └── test2.txt │ ├── src │ │ └── index.html │ └── package.json ├── multiple-nested-config │ ├── assets │ │ ├── bbb.txt │ │ ├── aaa.txt │ │ └── ccc.txt │ ├── src │ │ └── index.html │ └── package.json ├── simple-custom-out-dir │ ├── assets │ │ └── bbb.txt │ ├── src │ │ └── client │ │ │ └── index.html │ └── package.json ├── single-files │ ├── static │ │ ├── test1.txt │ │ └── dir │ │ │ └── test2.txt │ ├── src │ │ └── index.html │ └── package.json ├── multiple-staticpath │ ├── public │ │ └── public.txt │ ├── static │ │ ├── test1.txt │ │ └── dir │ │ │ └── test2.txt │ ├── src │ │ └── index.html │ └── package.json ├── multiple-entry-points │ ├── static │ │ ├── test1.txt │ │ └── dir │ │ │ └── test2.txt │ ├── src │ │ ├── a │ │ │ └── index.html │ │ └── b │ │ │ └── index.html │ └── package.json ├── multiple-environments │ ├── static-dev │ │ └── dev.txt │ ├── static-prod │ │ └── prod.txt │ ├── static-dev2 │ │ └── additional-from-dev2.txt │ ├── src │ │ └── index.html │ └── package.json └── multiple-entry-points-with-common-static │ ├── static │ ├── test1.txt │ └── dir │ │ └── test2.txt │ ├── src │ ├── a │ │ └── index.html │ └── b │ │ └── index.html │ └── package.json ├── .github └── FUNDING.yml ├── .gitignore ├── .npmrc ├── .npmignore ├── .eslintrc.js ├── package.json ├── LICENSE ├── README.md └── index.js /examples/.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | .cache -------------------------------------------------------------------------------- /examples/simple/static/test2.txt: -------------------------------------------------------------------------------- 1 | test2 -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: [elwin013] 2 | -------------------------------------------------------------------------------- /examples/simple/static/test1.txt: -------------------------------------------------------------------------------- 1 | test1 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .vscode 3 | .idea -------------------------------------------------------------------------------- /examples/multiple-nested-config/assets/bbb.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/simple-custom-out-dir/assets/bbb.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/simple/static/dir/test2.txt: -------------------------------------------------------------------------------- 1 | dir/test2 -------------------------------------------------------------------------------- /examples/single-files/static/test1.txt: -------------------------------------------------------------------------------- 1 | test1 2 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | sign-git-tag=true 2 | sign-git-commit=true 3 | -------------------------------------------------------------------------------- /examples/multiple-nested-config/assets/aaa.txt: -------------------------------------------------------------------------------- 1 | asdf -------------------------------------------------------------------------------- /examples/multiple-nested-config/assets/ccc.txt: -------------------------------------------------------------------------------- 1 | ccc -------------------------------------------------------------------------------- /examples/multiple-staticpath/public/public.txt: -------------------------------------------------------------------------------- 1 | public -------------------------------------------------------------------------------- /examples/single-files/static/dir/test2.txt: -------------------------------------------------------------------------------- 1 | test2 2 | -------------------------------------------------------------------------------- /examples/multiple-entry-points/static/test1.txt: -------------------------------------------------------------------------------- 1 | test1 2 | -------------------------------------------------------------------------------- /examples/multiple-staticpath/static/test1.txt: -------------------------------------------------------------------------------- 1 | test1 2 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | examples 2 | node_modules 3 | .vscode 4 | .idea 5 | -------------------------------------------------------------------------------- /examples/multiple-entry-points/static/dir/test2.txt: -------------------------------------------------------------------------------- 1 | test2 2 | -------------------------------------------------------------------------------- /examples/multiple-environments/static-dev/dev.txt: -------------------------------------------------------------------------------- 1 | test1 2 | -------------------------------------------------------------------------------- /examples/multiple-environments/static-prod/prod.txt: -------------------------------------------------------------------------------- 1 | test1 2 | -------------------------------------------------------------------------------- /examples/multiple-staticpath/static/dir/test2.txt: -------------------------------------------------------------------------------- 1 | test2 2 | -------------------------------------------------------------------------------- /examples/multiple-environments/static-dev2/additional-from-dev2.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/multiple-entry-points-with-common-static/static/test1.txt: -------------------------------------------------------------------------------- 1 | test1 2 | -------------------------------------------------------------------------------- /examples/multiple-entry-points-with-common-static/static/dir/test2.txt: -------------------------------------------------------------------------------- 1 | test2 2 | -------------------------------------------------------------------------------- /examples/simple/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /examples/single-files/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /examples/multiple-staticpath/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /examples/multiple-entry-points/src/a/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /examples/multiple-entry-points/src/b/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /examples/multiple-environments/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /examples/multiple-nested-config/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /examples/simple-custom-out-dir/src/client/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /examples/multiple-entry-points-with-common-static/src/a/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /examples/multiple-entry-points-with-common-static/src/b/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /examples/multiple-staticpath/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "multiple-staticpath", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "build": "parcel build src/index.html" 8 | }, 9 | "staticFiles": { 10 | "staticPath": [ 11 | "static", 12 | "public" 13 | ], 14 | "watcherGlob": "**" 15 | }, 16 | "devDependencies": { 17 | "parcel-bundler": "1.12.4", 18 | "parcel-plugin-static-files-copy": "file:../.." 19 | }, 20 | "dependencies": {} 21 | } 22 | -------------------------------------------------------------------------------- /examples/simple/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "simple", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "build": "parcel build src/index.html", 8 | "watch": "parcel src/index.html" 9 | }, 10 | "staticFiles": { 11 | "staticPath": [ 12 | "static", 13 | "static" 14 | ], 15 | "watcherGlob": "**" 16 | }, 17 | "devDependencies": { 18 | "parcel-bundler": "1.12.4", 19 | "parcel-plugin-static-files-copy": "file:../.." 20 | }, 21 | "dependencies": {} 22 | } 23 | -------------------------------------------------------------------------------- /examples/multiple-entry-points/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "multiple-entry-points", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "build": "parcel build src/*/index.html" 8 | }, 9 | "staticFiles": { 10 | "staticPath": [ 11 | { 12 | "staticPath": "static", 13 | "staticOutDir": "assets" 14 | } 15 | ] 16 | }, 17 | "devDependencies": { 18 | "parcel-bundler": "1.12.4", 19 | "parcel-plugin-static-files-copy": "file:../.." 20 | }, 21 | "dependencies": {} 22 | } 23 | -------------------------------------------------------------------------------- /examples/multiple-entry-points-with-common-static/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "multiple-entry-points-with-common-static", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "build": "parcel build src/*/index.html" 8 | }, 9 | "staticFiles": { 10 | "staticPath": [ 11 | { 12 | "staticPath": "static", 13 | "staticOutDir": "/assets" 14 | } 15 | ] 16 | }, 17 | "devDependencies": { 18 | "parcel-bundler": "1.12.4", 19 | "parcel-plugin-static-files-copy": "file:../.." 20 | }, 21 | "dependencies": {} 22 | } 23 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "env": { 3 | "es6": true, 4 | "node": true 5 | }, 6 | "extends": "eslint:recommended", 7 | "parserOptions": { 8 | "ecmaVersion": 2017 9 | }, 10 | "rules": { 11 | "indent": [ 12 | "error", 13 | 4 14 | ], 15 | "linebreak-style": [ 16 | "error", 17 | "unix" 18 | ], 19 | "quotes": [ 20 | "error", 21 | "single" 22 | ], 23 | "semi": [ 24 | "error", 25 | "always" 26 | ], 27 | "no-console": "off", 28 | } 29 | }; -------------------------------------------------------------------------------- /examples/simple-custom-out-dir/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "simple-custom-out-dir", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "build": "parcel build src/client/index.html -d dist/client", 8 | "watch": "parcel src/client/index.html -d dist/client" 9 | }, 10 | "staticFiles": { 11 | "staticPath": [ 12 | { 13 | "staticPath": "assets", 14 | "staticOutDir": "assets" 15 | } 16 | ], 17 | "watcherGlob": "**" 18 | }, 19 | "devDependencies": { 20 | "parcel-bundler": "1.12.4", 21 | "parcel-plugin-static-files-copy": "file:../.." 22 | }, 23 | "dependencies": {} 24 | } 25 | -------------------------------------------------------------------------------- /examples/single-files/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "simple", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "build": "parcel build src/index.html", 8 | "serve": "parcel src/index.html" 9 | }, 10 | "staticFiles": { 11 | "staticPath": [ 12 | { 13 | "staticPath": "static/test1.txt", 14 | "staticOutDir": "test1" 15 | }, 16 | { 17 | "staticPath": "static/dir/test2.txt" 18 | } 19 | ], 20 | "watcherGlob": "**" 21 | }, 22 | "devDependencies": { 23 | "parcel-bundler": "1.12.4", 24 | "parcel-plugin-static-files-copy": "file:../.." 25 | }, 26 | "dependencies": {} 27 | } 28 | -------------------------------------------------------------------------------- /examples/multiple-environments/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "multiple-environments", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "build:dev": "NODE_ENV=dev parcel build src/index.html", 8 | "build:prod": "NODE_ENV=prod parcel build src/index.html" 9 | }, 10 | "staticFiles": { 11 | "staticPath": [ 12 | { 13 | "staticPath": "static-dev", 14 | "env": "dev" 15 | }, 16 | { 17 | "staticPath": "static-dev2", 18 | "env": "dev" 19 | }, 20 | { 21 | "staticPath": "static-prod", 22 | "env": "prod" 23 | } 24 | ], 25 | "watcherGlob": "**" 26 | }, 27 | "devDependencies": { 28 | "parcel-bundler": "1.12.4", 29 | "parcel-plugin-static-files-copy": "file:../.." 30 | }, 31 | "dependencies": {} 32 | } 33 | -------------------------------------------------------------------------------- /examples/multiple-nested-config/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "multiple-nested-config", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "build": "NODE_ENV=dev parcel build src/index.html", 8 | "build-prod": "NODE_ENV=prod parcel build src/index.html" 9 | }, 10 | "staticFiles": { 11 | "staticPath": [ 12 | { 13 | "staticPath": [ 14 | "assets/aaa.txt", 15 | "assets/bbb.txt" 16 | ], 17 | "env": "dev", 18 | "staticOutDir": "vendor1" 19 | }, 20 | { 21 | "staticPath": [ 22 | "assets/bbb.txt", 23 | "assets/ccc.txt" 24 | ], 25 | "env": "prod", 26 | "staticOutDir": "vendor2" 27 | } 28 | ] 29 | }, 30 | "devDependencies": { 31 | "parcel-bundler": "1.12.4", 32 | "parcel-plugin-static-files-copy": "file:../.." 33 | }, 34 | "dependencies": {} 35 | } 36 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "author": { 3 | "name": "Kamil Banach", 4 | "email": "kontakt@elwin013.com" 5 | }, 6 | "bugs": { 7 | "url": "https://github.com/elwin013/parcel-plugin-static-files-copy/issues" 8 | }, 9 | "dependencies": { 10 | "minimatch": "3.0.4", 11 | "path": "0.12.7" 12 | }, 13 | "deprecated": false, 14 | "description": "ParcelJS plugin to copy static files from static dir to bundle directory.", 15 | "devDependencies": { 16 | "eslint": "5.12.0" 17 | }, 18 | "homepage": "https://github.com/elwin013/parcel-plugin-static-files-copy#readme", 19 | "keywords": [ 20 | "parcel" 21 | ], 22 | "license": "MIT", 23 | "main": "index.js", 24 | "name": "parcel-plugin-static-files-copy", 25 | "repository": { 26 | "type": "git", 27 | "url": "git+ssh://git@github.com/elwin013/parcel-plugin-static-files-copy.git" 28 | }, 29 | "scripts": { 30 | "test": "eslint index.js" 31 | }, 32 | "version": "2.6.0" 33 | } 34 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018-2020 Kamil Banach 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. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # parcel-plugin-static-files-copy 2 | 3 | ParcelJS plugin to copy static files from some directory to directory with bundle. 4 | 5 | ### Looking for the ParcelV2 plugin? Check out [parcel-reporter-static-files-copy](https://github.com/elwin013/parcel-reporter-static-files-copy) 6 | 7 | ## Install 8 | 9 | ``` 10 | yarn add parcel-plugin-static-files-copy --dev 11 | ``` 12 | 13 | ``` 14 | npm install -D parcel-plugin-static-files-copy 15 | ``` 16 | 17 | ## Usage 18 | 19 | 1. Create `static` directory in you project root. 20 | 2. Fill it with your static files 21 | 3. Run build - and that's all! 22 | 23 | ## Customization 24 | 25 | Beyond the default settings, you can: 26 | 27 | 1. Name of the directory to be copied. 28 | 2. Copy single files. 29 | 3. Copy multiple directories. 30 | 4. Copy from a different directory based on different output directory. 31 | 5. Watch for changes during development (rebuilding when necessary). 32 | 6. Exclude paths from copying. 33 | 34 | ### Example 35 | 36 | The following configures the plugin to copy all files in `public` to the build directory and watch for changes 37 | in all source files (`**` is a deep wildcard). 38 | 39 | ```json 40 | // package.json 41 | { 42 | ... 43 | "staticFiles": { 44 | "staticPath": "public", 45 | "watcherGlob": "**" 46 | } 47 | } 48 | ``` 49 | 50 | ### Multiple Static Directories 51 | 52 | To copy more than one directory to the build directory, specify `staticPath` as an array. The following copies 53 | `public` and `vendor/public`: 54 | 55 | ```json 56 | // package.json 57 | { 58 | ... 59 | "staticFiles": { 60 | "staticPath": ["public", "vendor/public"] 61 | } 62 | } 63 | ``` 64 | 65 | ### Copying single files 66 | 67 | To copy single file (instead of content of directory) just pass path to a file instead of directory. 68 | 69 | ```json 70 | // package.json 71 | { 72 | ... 73 | "staticFiles": { 74 | "staticPath": ["path/to/a/file.txt"] 75 | } 76 | } 77 | ``` 78 | 79 | ### Different source of static files based on output directory 80 | 81 | To copy different files (from different directories) based on output directory (e.g. `--out-dir dist1` and `--out-dir dist2`) 82 | make `staticPath` a object: 83 | 84 | ```json 85 | // package.json 86 | { 87 | ... 88 | "staticFiles": { 89 | "staticPath": [ 90 | { 91 | "outDirPattern": "**/dist1", 92 | "staticPath": "static1" 93 | }, 94 | { 95 | "outDirPattern": "**/dist2", 96 | "staticPath": "static2" 97 | } 98 | ] 99 | }, 100 | } 101 | ``` 102 | 103 | ### Specify directory to copy static files into 104 | 105 | If you want your files from `staticPath` to get copied into a subdirectory inside the parcel `--out-dir`, make 106 | `staticPath` an object with `staticOutDir` key: 107 | 108 | ```json 109 | // package.json 110 | { 111 | ... 112 | "staticFiles": { 113 | "staticPath": [ 114 | { 115 | "staticPath": "static1", 116 | "staticOutDir": "vendor" 117 | } 118 | ] 119 | }, 120 | } 121 | ``` 122 | 123 | Copies files from `static1` into the `vendor` directory inside the `--out-dir`. 124 | 125 | ### Watching for Changes 126 | 127 | Parcel can rebuild your bundle(s) whenever changes occur in the static directory. This is disabled by default, but it 128 | can be enabled by specifying a glob pattern for files that should be watched. 129 | 130 | Note the relative file path is used in matching (not just the file name). To match filenames in deep directories, 131 | start with a "globstar" (double star). The plugin uses Node's built-in [Minimatch Library](https://github.com/isaacs/minimatch) 132 | for glob matching. 133 | 134 | The following watches all XML files in the static directory: 135 | 136 | ```json 137 | // package.json 138 | { 139 | ... 140 | "staticFiles": { 141 | "staticPath": "public", 142 | "watcherGlob": "**/*.xml" 143 | } 144 | } 145 | ``` 146 | 147 | To disable watching, either remove the `"watcherGlob"` key (disabled is the default) or set it to false/null/undefined: 148 | 149 | ```json 150 | // package.json 151 | { 152 | ... 153 | "staticFiles": { 154 | "staticPath": "public", 155 | "watcherGlob": false 156 | } 157 | } 158 | ``` 159 | 160 | ### Excluding paths 161 | 162 | You can exclude files and directories in your `staticPath` from getting copied to the `outDir` by specifying `excludeGlob`: 163 | 164 | ```json 165 | // package.json 166 | { 167 | ... 168 | "staticFiles": { 169 | "staticPath": "public", 170 | "excludeGlob": "**/*.md" 171 | } 172 | } 173 | ``` 174 | 175 | Excludes all `.md` files in the `public` path from getting copied. 176 | 177 | 178 | Multiple `excludeGlob`s are possible by specifying it as array: 179 | 180 | ```json 181 | // package.json 182 | { 183 | ... 184 | "staticFiles": { 185 | "staticPath": "public", 186 | "excludeGlob": ["docs", "docs/**"] 187 | } 188 | } 189 | ``` 190 | 191 | Excludes the `docs` directory and all files inside the `docs` directory from getting copied. 192 | 193 | 194 | ### Including paths 195 | 196 | You can use the `excludeGlob` and negate it to achieve including behavior: 197 | 198 | 199 | ```json 200 | // package.json 201 | { 202 | ... 203 | "staticFiles": { 204 | "staticPath": "src", 205 | "excludeGlob": "**/!(locales)/*.+(!(txt)|!(json))" 206 | } 207 | } 208 | ``` 209 | 210 | Includes only files from `locales` directory with `.txt` or `.json` extension. 211 | 212 | 213 | ### Minimatch glob options 214 | 215 | Passing [options into minimatch](https://github.com/isaacs/minimatch#options) to change `watcherGlob` and `excludeGlob` 216 | behavior is possible by specifying a `globOptions` object: 217 | 218 | ```json 219 | // package.json 220 | { 221 | ... 222 | "staticFiles": { 223 | "staticPath": "public", 224 | "excludeGlob": ["test", "test/**"], 225 | "globOptions": { 226 | "dot": true 227 | } 228 | } 229 | } 230 | ``` 231 | 232 | Excludes the `test` directory and all files inside the `test` directory, including files starting with a dot, from 233 | getting copied. 234 | 235 | ### Dev and production config using NODE_ENV 236 | 237 | You can use `env` parameter in `staticPath` object to select static path used in environment chosen by passing `NODE_ENV`: 238 | 239 | ```json 240 | // package.json 241 | { 242 | ... 243 | "scripts": { 244 | "build:dev": "NODE_ENV=dev parcel build src/index.html", 245 | "build:prod": "NODE_ENV=prod parcel build src/index.html" 246 | }, 247 | ... 248 | "staticFiles": { 249 | "staticPath": [ 250 | { 251 | "staticPath": "static-dev", 252 | "env": "dev" 253 | }, 254 | { 255 | "staticPath": "static-prod", 256 | "env": "prod" 257 | } 258 | ] 259 | } 260 | } 261 | ``` 262 | 263 | Then running: 264 | * `build:dev` will copy files from `static-dev` only, 265 | * `build:prod` will copy files from `static-prod` only. 266 | 267 | You can specify from zero to many static paths per environment. 268 | 269 | ### Additional examples 270 | 271 | Check [examples](https://github.com/elwin013/parcel-plugin-static-files-copy/tree/master/examples) directory for 272 | additional examples. 273 | 274 | ## Contribute 275 | 276 | Are you interested in contributing? Awesome! Fork, make change, commit and create pull request. I'll do my best to merge 277 | changes! 278 | 279 | ## License 280 | 281 | [MIT](/LICENSE) 282 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const fs = require('fs'); 3 | const minimatch = require('minimatch'); 4 | const path = require('path'); 5 | 6 | const DEFAULT_CONFIG = { 7 | 'staticPath': ['static'], 8 | 'watcherGlob': null, 9 | 'excludeGlob': null, 10 | 'globOptions': {} 11 | }; 12 | 13 | module.exports = bundler => { 14 | bundler.on('bundled', async (bundle) => { 15 | 16 | // main asset and package dir, depending on version of parcel-bundler 17 | let mainAsset = 18 | bundler.mainAsset || // parcel < 1.8 19 | bundler.mainBundle.entryAsset || // parcel >= 1.8 single entry point 20 | bundler.mainBundle.childBundles.values().next().value.entryAsset; // parcel >= 1.8 multiple entry points 21 | let pkg; 22 | if (typeof mainAsset.getPackage === 'function') { // parcel > 1.8 23 | pkg = (await mainAsset.getPackage()); 24 | } else { // parcel <= 1.8 25 | pkg = mainAsset.package; 26 | } 27 | 28 | // config 29 | let config = Object.assign({}, DEFAULT_CONFIG, pkg.staticFiles); 30 | if (pkg.staticPath) { // parcel-plugin-static-files-copy<1.2.5 31 | config.staticPath = pkg.staticPath; 32 | } 33 | if (!Array.isArray(config.staticPath)) { // ensure array 34 | config.staticPath = [config.staticPath]; 35 | } 36 | if (config.excludeGlob && !Array.isArray(config.excludeGlob)) { 37 | config.excludeGlob = [config.excludeGlob]; 38 | } 39 | 40 | // poor-man's logger 41 | const logLevel = parseInt(bundler.options.logLevel); 42 | const pmLog = (level, ...msgs) => { 43 | if (logLevel >= level) { 44 | console.log(...msgs); 45 | } 46 | }; 47 | 48 | // static paths are usually just a string can be specified as 49 | // an object to make them conditional on the output directory 50 | // by specifying them in the form 51 | // {"outDirPattern":"dist1", "staticPath":"static1"}, 52 | // {"outDirPattern":"dist2", "staticPath":"static2"} 53 | config.staticPath = config.staticPath.map(path => { 54 | if (typeof path === 'object') { 55 | if (!path.staticPath) { 56 | console.error(`Error: parcel-plugin-static-files-copy: When staticPath is an object, expecting it to have at least the 'staticPath' key, but found: ${path}`); 57 | return null; 58 | } 59 | 60 | if (path.outDirPattern) { 61 | if (minimatch(bundler.options.outDir, path.outDirPattern, config.globOptions)) { 62 | pmLog(4, `outDir matches '${path.outDirPattern}' so copying static files from '${path.staticPath}'`); 63 | } else { 64 | pmLog(4, `outDir does not match '${path.outDirPattern}' so not copying static files from '${path.staticPath}'`); 65 | return null; 66 | } 67 | } 68 | 69 | return path; 70 | } else { 71 | return {staticPath: path}; 72 | } 73 | }).filter(path => path != null); 74 | 75 | // recursive copy function 76 | let numWatches = 0; 77 | 78 | /** 79 | * Recurse into directory and execute callback function for each file and folder. 80 | * 81 | * Based on https://github.com/douzi8/file-system/blob/master/file-system.js#L254 82 | * 83 | * @param dirpath directory to start from 84 | * @param callback function to be run on every file/directory 85 | */ 86 | const recurseSync = (dirpath, callback) => { 87 | const rootpath = dirpath; 88 | 89 | function recurse(dirpath) { 90 | fs.readdirSync(dirpath).forEach(function (filename) { 91 | const filepath = path.join(dirpath, filename); 92 | const stats = fs.statSync(filepath); 93 | const relative = path.relative(rootpath, filepath); 94 | 95 | if (stats.isDirectory()) { 96 | callback(filepath, relative); 97 | recurse(filepath); 98 | } else { 99 | callback(filepath, relative, filename); 100 | } 101 | 102 | }); 103 | } 104 | 105 | recurse(dirpath); 106 | }; 107 | 108 | function copySingleFile(bundleDir, dest, filepath) { 109 | if (fs.existsSync(dest)) { 110 | const destStat = fs.statSync(dest); 111 | const srcStat = fs.statSync(filepath); 112 | if (destStat.mtime < srcStat.mtime) { // File was modified - let's copy it and inform about overwriting. 113 | pmLog(3, `Static file '${filepath}' already exists in '${bundleDir}'. Overwriting.`); 114 | fs.copyFileSync(filepath, dest); 115 | } 116 | } else { 117 | fs.copyFileSync(filepath, dest); 118 | } 119 | // watch for changes? 120 | if (config.watcherGlob && bundler.watcher && minimatch(filepath, config.watcherGlob, config.globOptions)) { 121 | numWatches++; 122 | bundler.watch(filepath, mainAsset); 123 | } 124 | } 125 | 126 | const shouldBeExcluded = (file, staticPath, excludeGlob) => { 127 | return !!excludeGlob.find(excludeGlob => 128 | minimatch(file, path.join(staticPath, excludeGlob), config.globOptions) 129 | ); 130 | }; 131 | 132 | const copyFile = (filepath, bundleDir, excludeGlob) => { 133 | if (shouldBeExcluded(filepath, path.dirname(filepath), excludeGlob)) { 134 | return; 135 | } 136 | const dest = path.join(bundleDir, path.basename(filepath)); 137 | copySingleFile(bundleDir, dest, filepath); 138 | }; 139 | 140 | const copyDir = (staticDir, bundleDir, excludeGlob) => { 141 | const copy = (filepath, relative, filename) => { 142 | if (shouldBeExcluded(filepath, staticDir, excludeGlob)) { 143 | return; 144 | } 145 | 146 | const dest = filepath.replace(staticDir, bundleDir); 147 | if (!filename) { 148 | if (!fs.existsSync(dest)) { 149 | fs.mkdirSync(dest, {recursive: true}); 150 | } 151 | } else { 152 | copySingleFile(bundleDir, dest, filepath); 153 | } 154 | }; 155 | recurseSync(staticDir, copy); 156 | }; 157 | 158 | const outDir = bundler.options.outDir; 159 | const currentEnv = process.env.NODE_ENV; 160 | 161 | function processStaticFiles(singleBundle) { 162 | for (let dir of config.staticPath) { 163 | if (dir.env && dir.env !== currentEnv) { 164 | continue; 165 | } 166 | 167 | const copyTo = dir.staticOutDir && dir.staticOutDir.startsWith('/') 168 | ? path.join(outDir, dir.staticOutDir) 169 | : path.join(path.dirname(singleBundle.name), dir.staticOutDir ? dir.staticOutDir : ''); 170 | // merge global exclude glob with static path exclude glob 171 | const excludeGlob = (config.excludeGlob || []).concat((dir.excludeGlob || [])); 172 | 173 | if (!fs.existsSync(copyTo)) { 174 | fs.mkdirSync(copyTo, {recursive: true}); 175 | } 176 | 177 | var paths = dir.staticPath; 178 | if (!Array.isArray(paths)) { 179 | paths = [paths]; 180 | } 181 | for (let singlePath of paths) { 182 | let staticPath = path.join(pkg.pkgdir, singlePath); 183 | if (!fs.existsSync(staticPath)) { 184 | pmLog(2, `Static path (file or directory) '${staticPath}' does not exist. Skipping.`); 185 | continue; 186 | } 187 | if (fs.statSync(staticPath).isDirectory()) { 188 | copyDir(staticPath, copyTo, excludeGlob); 189 | } else { 190 | copyFile(staticPath, copyTo, excludeGlob); 191 | } 192 | } 193 | } 194 | } 195 | 196 | if (!bundle.name) { // multiple entry points 197 | for (let singleBundle of bundler.mainBundle.childBundles.values()) { 198 | processStaticFiles(singleBundle); 199 | } 200 | } else { 201 | processStaticFiles(bundle); 202 | } 203 | 204 | if (config.watcherGlob && bundler.watcher) { 205 | pmLog(3, `Watching for changes in ${numWatches} static files.`); 206 | } 207 | 208 | }); 209 | }; 210 | --------------------------------------------------------------------------------