Repository: elwin013/parcel-plugin-static-files-copy Branch: master Commit: 7452db085082 Files: 47 Total size: 21.5 KB Directory structure: gitextract_j8ar7_22/ ├── .eslintrc.js ├── .github/ │ └── FUNDING.yml ├── .gitignore ├── .npmignore ├── .npmrc ├── LICENSE ├── README.md ├── examples/ │ ├── .gitignore │ ├── multiple-entry-points/ │ │ ├── package.json │ │ ├── src/ │ │ │ ├── a/ │ │ │ │ └── index.html │ │ │ └── b/ │ │ │ └── index.html │ │ └── static/ │ │ ├── dir/ │ │ │ └── test2.txt │ │ └── test1.txt │ ├── multiple-entry-points-with-common-static/ │ │ ├── package.json │ │ ├── src/ │ │ │ ├── a/ │ │ │ │ └── index.html │ │ │ └── b/ │ │ │ └── index.html │ │ └── static/ │ │ ├── dir/ │ │ │ └── test2.txt │ │ └── test1.txt │ ├── multiple-environments/ │ │ ├── package.json │ │ ├── src/ │ │ │ └── index.html │ │ ├── static-dev/ │ │ │ └── dev.txt │ │ ├── static-dev2/ │ │ │ └── additional-from-dev2.txt │ │ └── static-prod/ │ │ └── prod.txt │ ├── multiple-nested-config/ │ │ ├── assets/ │ │ │ ├── aaa.txt │ │ │ ├── bbb.txt │ │ │ └── ccc.txt │ │ ├── package.json │ │ └── src/ │ │ └── index.html │ ├── multiple-staticpath/ │ │ ├── package.json │ │ ├── public/ │ │ │ └── public.txt │ │ ├── src/ │ │ │ └── index.html │ │ └── static/ │ │ ├── dir/ │ │ │ └── test2.txt │ │ └── test1.txt │ ├── simple/ │ │ ├── package.json │ │ ├── src/ │ │ │ └── index.html │ │ └── static/ │ │ ├── dir/ │ │ │ └── test2.txt │ │ ├── test1.txt │ │ └── test2.txt │ ├── simple-custom-out-dir/ │ │ ├── assets/ │ │ │ └── bbb.txt │ │ ├── package.json │ │ └── src/ │ │ └── client/ │ │ └── index.html │ └── single-files/ │ ├── package.json │ ├── src/ │ │ └── index.html │ └── static/ │ ├── dir/ │ │ └── test2.txt │ └── test1.txt ├── index.js └── package.json ================================================ FILE CONTENTS ================================================ ================================================ FILE: .eslintrc.js ================================================ module.exports = { "env": { "es6": true, "node": true }, "extends": "eslint:recommended", "parserOptions": { "ecmaVersion": 2017 }, "rules": { "indent": [ "error", 4 ], "linebreak-style": [ "error", "unix" ], "quotes": [ "error", "single" ], "semi": [ "error", "always" ], "no-console": "off", } }; ================================================ FILE: .github/FUNDING.yml ================================================ github: [elwin013] ================================================ FILE: .gitignore ================================================ node_modules .vscode .idea ================================================ FILE: .npmignore ================================================ examples node_modules .vscode .idea ================================================ FILE: .npmrc ================================================ sign-git-tag=true sign-git-commit=true ================================================ FILE: LICENSE ================================================ MIT License Copyright (c) 2018-2020 Kamil Banach Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================ # parcel-plugin-static-files-copy ParcelJS plugin to copy static files from some directory to directory with bundle. ### Looking for the ParcelV2 plugin? Check out [parcel-reporter-static-files-copy](https://github.com/elwin013/parcel-reporter-static-files-copy) ## Install ``` yarn add parcel-plugin-static-files-copy --dev ``` ``` npm install -D parcel-plugin-static-files-copy ``` ## Usage 1. Create `static` directory in you project root. 2. Fill it with your static files 3. Run build - and that's all! ## Customization Beyond the default settings, you can: 1. Name of the directory to be copied. 2. Copy single files. 3. Copy multiple directories. 4. Copy from a different directory based on different output directory. 5. Watch for changes during development (rebuilding when necessary). 6. Exclude paths from copying. ### Example The following configures the plugin to copy all files in `public` to the build directory and watch for changes in all source files (`**` is a deep wildcard). ```json // package.json { ... "staticFiles": { "staticPath": "public", "watcherGlob": "**" } } ``` ### Multiple Static Directories To copy more than one directory to the build directory, specify `staticPath` as an array. The following copies `public` and `vendor/public`: ```json // package.json { ... "staticFiles": { "staticPath": ["public", "vendor/public"] } } ``` ### Copying single files To copy single file (instead of content of directory) just pass path to a file instead of directory. ```json // package.json { ... "staticFiles": { "staticPath": ["path/to/a/file.txt"] } } ``` ### Different source of static files based on output directory To copy different files (from different directories) based on output directory (e.g. `--out-dir dist1` and `--out-dir dist2`) make `staticPath` a object: ```json // package.json { ... "staticFiles": { "staticPath": [ { "outDirPattern": "**/dist1", "staticPath": "static1" }, { "outDirPattern": "**/dist2", "staticPath": "static2" } ] }, } ``` ### Specify directory to copy static files into If you want your files from `staticPath` to get copied into a subdirectory inside the parcel `--out-dir`, make `staticPath` an object with `staticOutDir` key: ```json // package.json { ... "staticFiles": { "staticPath": [ { "staticPath": "static1", "staticOutDir": "vendor" } ] }, } ``` Copies files from `static1` into the `vendor` directory inside the `--out-dir`. ### Watching for Changes Parcel can rebuild your bundle(s) whenever changes occur in the static directory. This is disabled by default, but it can be enabled by specifying a glob pattern for files that should be watched. Note the relative file path is used in matching (not just the file name). To match filenames in deep directories, start with a "globstar" (double star). The plugin uses Node's built-in [Minimatch Library](https://github.com/isaacs/minimatch) for glob matching. The following watches all XML files in the static directory: ```json // package.json { ... "staticFiles": { "staticPath": "public", "watcherGlob": "**/*.xml" } } ``` To disable watching, either remove the `"watcherGlob"` key (disabled is the default) or set it to false/null/undefined: ```json // package.json { ... "staticFiles": { "staticPath": "public", "watcherGlob": false } } ``` ### Excluding paths You can exclude files and directories in your `staticPath` from getting copied to the `outDir` by specifying `excludeGlob`: ```json // package.json { ... "staticFiles": { "staticPath": "public", "excludeGlob": "**/*.md" } } ``` Excludes all `.md` files in the `public` path from getting copied. Multiple `excludeGlob`s are possible by specifying it as array: ```json // package.json { ... "staticFiles": { "staticPath": "public", "excludeGlob": ["docs", "docs/**"] } } ``` Excludes the `docs` directory and all files inside the `docs` directory from getting copied. ### Including paths You can use the `excludeGlob` and negate it to achieve including behavior: ```json // package.json { ... "staticFiles": { "staticPath": "src", "excludeGlob": "**/!(locales)/*.+(!(txt)|!(json))" } } ``` Includes only files from `locales` directory with `.txt` or `.json` extension. ### Minimatch glob options Passing [options into minimatch](https://github.com/isaacs/minimatch#options) to change `watcherGlob` and `excludeGlob` behavior is possible by specifying a `globOptions` object: ```json // package.json { ... "staticFiles": { "staticPath": "public", "excludeGlob": ["test", "test/**"], "globOptions": { "dot": true } } } ``` Excludes the `test` directory and all files inside the `test` directory, including files starting with a dot, from getting copied. ### Dev and production config using NODE_ENV You can use `env` parameter in `staticPath` object to select static path used in environment chosen by passing `NODE_ENV`: ```json // package.json { ... "scripts": { "build:dev": "NODE_ENV=dev parcel build src/index.html", "build:prod": "NODE_ENV=prod parcel build src/index.html" }, ... "staticFiles": { "staticPath": [ { "staticPath": "static-dev", "env": "dev" }, { "staticPath": "static-prod", "env": "prod" } ] } } ``` Then running: * `build:dev` will copy files from `static-dev` only, * `build:prod` will copy files from `static-prod` only. You can specify from zero to many static paths per environment. ### Additional examples Check [examples](https://github.com/elwin013/parcel-plugin-static-files-copy/tree/master/examples) directory for additional examples. ## Contribute Are you interested in contributing? Awesome! Fork, make change, commit and create pull request. I'll do my best to merge changes! ## License [MIT](/LICENSE) ================================================ FILE: examples/.gitignore ================================================ dist .cache ================================================ FILE: examples/multiple-entry-points/package.json ================================================ { "name": "multiple-entry-points", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "build": "parcel build src/*/index.html" }, "staticFiles": { "staticPath": [ { "staticPath": "static", "staticOutDir": "assets" } ] }, "devDependencies": { "parcel-bundler": "1.12.4", "parcel-plugin-static-files-copy": "file:../.." }, "dependencies": {} } ================================================ FILE: examples/multiple-entry-points/src/a/index.html ================================================ ================================================ FILE: examples/multiple-entry-points/src/b/index.html ================================================ ================================================ FILE: examples/multiple-entry-points/static/dir/test2.txt ================================================ test2 ================================================ FILE: examples/multiple-entry-points/static/test1.txt ================================================ test1 ================================================ FILE: examples/multiple-entry-points-with-common-static/package.json ================================================ { "name": "multiple-entry-points-with-common-static", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "build": "parcel build src/*/index.html" }, "staticFiles": { "staticPath": [ { "staticPath": "static", "staticOutDir": "/assets" } ] }, "devDependencies": { "parcel-bundler": "1.12.4", "parcel-plugin-static-files-copy": "file:../.." }, "dependencies": {} } ================================================ FILE: examples/multiple-entry-points-with-common-static/src/a/index.html ================================================ ================================================ FILE: examples/multiple-entry-points-with-common-static/src/b/index.html ================================================ ================================================ FILE: examples/multiple-entry-points-with-common-static/static/dir/test2.txt ================================================ test2 ================================================ FILE: examples/multiple-entry-points-with-common-static/static/test1.txt ================================================ test1 ================================================ FILE: examples/multiple-environments/package.json ================================================ { "name": "multiple-environments", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "build:dev": "NODE_ENV=dev parcel build src/index.html", "build:prod": "NODE_ENV=prod parcel build src/index.html" }, "staticFiles": { "staticPath": [ { "staticPath": "static-dev", "env": "dev" }, { "staticPath": "static-dev2", "env": "dev" }, { "staticPath": "static-prod", "env": "prod" } ], "watcherGlob": "**" }, "devDependencies": { "parcel-bundler": "1.12.4", "parcel-plugin-static-files-copy": "file:../.." }, "dependencies": {} } ================================================ FILE: examples/multiple-environments/src/index.html ================================================ ================================================ FILE: examples/multiple-environments/static-dev/dev.txt ================================================ test1 ================================================ FILE: examples/multiple-environments/static-dev2/additional-from-dev2.txt ================================================ ================================================ FILE: examples/multiple-environments/static-prod/prod.txt ================================================ test1 ================================================ FILE: examples/multiple-nested-config/assets/aaa.txt ================================================ asdf ================================================ FILE: examples/multiple-nested-config/assets/bbb.txt ================================================ ================================================ FILE: examples/multiple-nested-config/assets/ccc.txt ================================================ ccc ================================================ FILE: examples/multiple-nested-config/package.json ================================================ { "name": "multiple-nested-config", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "build": "NODE_ENV=dev parcel build src/index.html", "build-prod": "NODE_ENV=prod parcel build src/index.html" }, "staticFiles": { "staticPath": [ { "staticPath": [ "assets/aaa.txt", "assets/bbb.txt" ], "env": "dev", "staticOutDir": "vendor1" }, { "staticPath": [ "assets/bbb.txt", "assets/ccc.txt" ], "env": "prod", "staticOutDir": "vendor2" } ] }, "devDependencies": { "parcel-bundler": "1.12.4", "parcel-plugin-static-files-copy": "file:../.." }, "dependencies": {} } ================================================ FILE: examples/multiple-nested-config/src/index.html ================================================ ================================================ FILE: examples/multiple-staticpath/package.json ================================================ { "name": "multiple-staticpath", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "build": "parcel build src/index.html" }, "staticFiles": { "staticPath": [ "static", "public" ], "watcherGlob": "**" }, "devDependencies": { "parcel-bundler": "1.12.4", "parcel-plugin-static-files-copy": "file:../.." }, "dependencies": {} } ================================================ FILE: examples/multiple-staticpath/public/public.txt ================================================ public ================================================ FILE: examples/multiple-staticpath/src/index.html ================================================ ================================================ FILE: examples/multiple-staticpath/static/dir/test2.txt ================================================ test2 ================================================ FILE: examples/multiple-staticpath/static/test1.txt ================================================ test1 ================================================ FILE: examples/simple/package.json ================================================ { "name": "simple", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "build": "parcel build src/index.html", "watch": "parcel src/index.html" }, "staticFiles": { "staticPath": [ "static", "static" ], "watcherGlob": "**" }, "devDependencies": { "parcel-bundler": "1.12.4", "parcel-plugin-static-files-copy": "file:../.." }, "dependencies": {} } ================================================ FILE: examples/simple/src/index.html ================================================ ================================================ FILE: examples/simple/static/dir/test2.txt ================================================ dir/test2 ================================================ FILE: examples/simple/static/test1.txt ================================================ test1 ================================================ FILE: examples/simple/static/test2.txt ================================================ test2 ================================================ FILE: examples/simple-custom-out-dir/assets/bbb.txt ================================================ ================================================ FILE: examples/simple-custom-out-dir/package.json ================================================ { "name": "simple-custom-out-dir", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "build": "parcel build src/client/index.html -d dist/client", "watch": "parcel src/client/index.html -d dist/client" }, "staticFiles": { "staticPath": [ { "staticPath": "assets", "staticOutDir": "assets" } ], "watcherGlob": "**" }, "devDependencies": { "parcel-bundler": "1.12.4", "parcel-plugin-static-files-copy": "file:../.." }, "dependencies": {} } ================================================ FILE: examples/simple-custom-out-dir/src/client/index.html ================================================ ================================================ FILE: examples/single-files/package.json ================================================ { "name": "simple", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "build": "parcel build src/index.html", "serve": "parcel src/index.html" }, "staticFiles": { "staticPath": [ { "staticPath": "static/test1.txt", "staticOutDir": "test1" }, { "staticPath": "static/dir/test2.txt" } ], "watcherGlob": "**" }, "devDependencies": { "parcel-bundler": "1.12.4", "parcel-plugin-static-files-copy": "file:../.." }, "dependencies": {} } ================================================ FILE: examples/single-files/src/index.html ================================================ ================================================ FILE: examples/single-files/static/dir/test2.txt ================================================ test2 ================================================ FILE: examples/single-files/static/test1.txt ================================================ test1 ================================================ FILE: index.js ================================================ 'use strict'; const fs = require('fs'); const minimatch = require('minimatch'); const path = require('path'); const DEFAULT_CONFIG = { 'staticPath': ['static'], 'watcherGlob': null, 'excludeGlob': null, 'globOptions': {} }; module.exports = bundler => { bundler.on('bundled', async (bundle) => { // main asset and package dir, depending on version of parcel-bundler let mainAsset = bundler.mainAsset || // parcel < 1.8 bundler.mainBundle.entryAsset || // parcel >= 1.8 single entry point bundler.mainBundle.childBundles.values().next().value.entryAsset; // parcel >= 1.8 multiple entry points let pkg; if (typeof mainAsset.getPackage === 'function') { // parcel > 1.8 pkg = (await mainAsset.getPackage()); } else { // parcel <= 1.8 pkg = mainAsset.package; } // config let config = Object.assign({}, DEFAULT_CONFIG, pkg.staticFiles); if (pkg.staticPath) { // parcel-plugin-static-files-copy<1.2.5 config.staticPath = pkg.staticPath; } if (!Array.isArray(config.staticPath)) { // ensure array config.staticPath = [config.staticPath]; } if (config.excludeGlob && !Array.isArray(config.excludeGlob)) { config.excludeGlob = [config.excludeGlob]; } // poor-man's logger const logLevel = parseInt(bundler.options.logLevel); const pmLog = (level, ...msgs) => { if (logLevel >= level) { console.log(...msgs); } }; // static paths are usually just a string can be specified as // an object to make them conditional on the output directory // by specifying them in the form // {"outDirPattern":"dist1", "staticPath":"static1"}, // {"outDirPattern":"dist2", "staticPath":"static2"} config.staticPath = config.staticPath.map(path => { if (typeof path === 'object') { if (!path.staticPath) { 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}`); return null; } if (path.outDirPattern) { if (minimatch(bundler.options.outDir, path.outDirPattern, config.globOptions)) { pmLog(4, `outDir matches '${path.outDirPattern}' so copying static files from '${path.staticPath}'`); } else { pmLog(4, `outDir does not match '${path.outDirPattern}' so not copying static files from '${path.staticPath}'`); return null; } } return path; } else { return {staticPath: path}; } }).filter(path => path != null); // recursive copy function let numWatches = 0; /** * Recurse into directory and execute callback function for each file and folder. * * Based on https://github.com/douzi8/file-system/blob/master/file-system.js#L254 * * @param dirpath directory to start from * @param callback function to be run on every file/directory */ const recurseSync = (dirpath, callback) => { const rootpath = dirpath; function recurse(dirpath) { fs.readdirSync(dirpath).forEach(function (filename) { const filepath = path.join(dirpath, filename); const stats = fs.statSync(filepath); const relative = path.relative(rootpath, filepath); if (stats.isDirectory()) { callback(filepath, relative); recurse(filepath); } else { callback(filepath, relative, filename); } }); } recurse(dirpath); }; function copySingleFile(bundleDir, dest, filepath) { if (fs.existsSync(dest)) { const destStat = fs.statSync(dest); const srcStat = fs.statSync(filepath); if (destStat.mtime < srcStat.mtime) { // File was modified - let's copy it and inform about overwriting. pmLog(3, `Static file '${filepath}' already exists in '${bundleDir}'. Overwriting.`); fs.copyFileSync(filepath, dest); } } else { fs.copyFileSync(filepath, dest); } // watch for changes? if (config.watcherGlob && bundler.watcher && minimatch(filepath, config.watcherGlob, config.globOptions)) { numWatches++; bundler.watch(filepath, mainAsset); } } const shouldBeExcluded = (file, staticPath, excludeGlob) => { return !!excludeGlob.find(excludeGlob => minimatch(file, path.join(staticPath, excludeGlob), config.globOptions) ); }; const copyFile = (filepath, bundleDir, excludeGlob) => { if (shouldBeExcluded(filepath, path.dirname(filepath), excludeGlob)) { return; } const dest = path.join(bundleDir, path.basename(filepath)); copySingleFile(bundleDir, dest, filepath); }; const copyDir = (staticDir, bundleDir, excludeGlob) => { const copy = (filepath, relative, filename) => { if (shouldBeExcluded(filepath, staticDir, excludeGlob)) { return; } const dest = filepath.replace(staticDir, bundleDir); if (!filename) { if (!fs.existsSync(dest)) { fs.mkdirSync(dest, {recursive: true}); } } else { copySingleFile(bundleDir, dest, filepath); } }; recurseSync(staticDir, copy); }; const outDir = bundler.options.outDir; const currentEnv = process.env.NODE_ENV; function processStaticFiles(singleBundle) { for (let dir of config.staticPath) { if (dir.env && dir.env !== currentEnv) { continue; } const copyTo = dir.staticOutDir && dir.staticOutDir.startsWith('/') ? path.join(outDir, dir.staticOutDir) : path.join(path.dirname(singleBundle.name), dir.staticOutDir ? dir.staticOutDir : ''); // merge global exclude glob with static path exclude glob const excludeGlob = (config.excludeGlob || []).concat((dir.excludeGlob || [])); if (!fs.existsSync(copyTo)) { fs.mkdirSync(copyTo, {recursive: true}); } var paths = dir.staticPath; if (!Array.isArray(paths)) { paths = [paths]; } for (let singlePath of paths) { let staticPath = path.join(pkg.pkgdir, singlePath); if (!fs.existsSync(staticPath)) { pmLog(2, `Static path (file or directory) '${staticPath}' does not exist. Skipping.`); continue; } if (fs.statSync(staticPath).isDirectory()) { copyDir(staticPath, copyTo, excludeGlob); } else { copyFile(staticPath, copyTo, excludeGlob); } } } } if (!bundle.name) { // multiple entry points for (let singleBundle of bundler.mainBundle.childBundles.values()) { processStaticFiles(singleBundle); } } else { processStaticFiles(bundle); } if (config.watcherGlob && bundler.watcher) { pmLog(3, `Watching for changes in ${numWatches} static files.`); } }); }; ================================================ FILE: package.json ================================================ { "author": { "name": "Kamil Banach", "email": "kontakt@elwin013.com" }, "bugs": { "url": "https://github.com/elwin013/parcel-plugin-static-files-copy/issues" }, "dependencies": { "minimatch": "3.0.4", "path": "0.12.7" }, "deprecated": false, "description": "ParcelJS plugin to copy static files from static dir to bundle directory.", "devDependencies": { "eslint": "5.12.0" }, "homepage": "https://github.com/elwin013/parcel-plugin-static-files-copy#readme", "keywords": [ "parcel" ], "license": "MIT", "main": "index.js", "name": "parcel-plugin-static-files-copy", "repository": { "type": "git", "url": "git+ssh://git@github.com/elwin013/parcel-plugin-static-files-copy.git" }, "scripts": { "test": "eslint index.js" }, "version": "2.6.0" }