
Security News
Attackers Are Hunting High-Impact Node.js Maintainers in a Coordinated Social Engineering Campaign
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.
file-variants
Advanced tools
Create multiple file variants, build with one (and replace within if needed), and deploy. Solves the problem of using multiple somewhat similar files in a sort of multitenant system. Highly configurable and flexible pseudo multitenant file builder.
Sometimes you need to have multiple slightly different variants of the same file, say a different logo for each of your clients, but you want to keep your codebase to one single instance with smaller parts being switched out depending on client, platform, behaviour etc. (a sort of pseudo multitenancy). file-variants is an attempt to solve one part of this problem: using multiple file variants, but only building with one of them at a time.
npm install --save-dev file-variants
Add the following to your package.json file:
{
"scripts": {
"fv-build": "file-variants build"
}
}
Now run npm run fv-build (or npx file-variants build)
build
build [variant]
common options:
path=path # specify path to search in (relative from cwd)
config=path # specify path to global config (relative from cwd)
include=[,input] # inputs to include
exclude=[,input] # inputs to exclude
override=input,variant # override the variant for a specific input (repeatable)
replace=input,keyword,replacement # replacements for a specific input (repeatable)
global-replace=keyword,replacement # replacements for all inputs (repeatable)
verbose # debug info
Because naming is difficult, please study the file structure below meant to represent the build of an imaginary logo image in order to understand what we've named the different parts of file-variants.
.
+-- _src
| +-- _Logo # input (directory)
| +-- fvi.config.json # config
| +-- foo.png # file variant --\
| +-- bar.png # file variant ---|--> file variant*s*
| +-- foobar.png # file variant --/
| +-- Logo.png # output
| ...
Here each part mentioned in Naming convention will be explained.
NOTE: Configs must always be named "fvi.config.json".
type Variant = string;
type Encoding = 'utf8' | 'utf-8' | 'ascii' | 'base64' | 'binary' | 'hex' | 'latin1' | 'ucs-2' | 'ucs2' | 'utf16le';
interface Config {
default: Variant;
name?: string;
outputName?: string;
encoding?: Encoding;
outPath?: string;
fallbacks?: {
[variant: Variant]: Variant;
};
useGlobalReplacements?: boolean | string[];
marking?: boolean | string;
exclude?: string;
}
default (required): the default variant to use as fallback if all else fails.name: name of input. If left empty the input directory's name will be used instead.outputName: name of output (excluding extension). If left empty, name will be used instead.encoding: common encoding of all file variants. If left empty, utf8 will be used. However, encoding only matters if replacements are being used on the output. If replacements are provided and are to be used, encoding must be any of the following values: ascii, utf8, utf-8, or latin1.outPath: relative (from input's path) path to place output at.
fallbacks: a map of variant to variant fallbacks. If a variant isn't detected inside input, but is detected inside fallbacks as a key, the corresponding key's value will be used as the variant instead. This will be done recursively until a valid file variant is found, or until no fallbacks remain, in which case default will be used as a variant instead.useGlobalReplacements: control what keywords should be replaced by global-replace(s) (option).
marking: mark the output to ignore changes more easily.
exclude: which file variants to exclude (regex). Matches entire filename (including variant).If you need many cli arguments when building, using a global config may be easier. You can specify which global config to use with the config=[path] argument passed to build.
Global configs must always be .json-files.
interface GlobalConfig {
values?: {
variant?: string;
};
options?: string[];
overrides?: {
marking?: boolean | string;
};
}
The files for each example can be found under examples/.
You have 3 clients who use your product. You want to keep a shared codebase, where the only difference between these 3 clients is their logo.
.
+-- _src
| +-- _Logo
| +-- fvi.config.json
| +-- foo.png
| +-- bar.png
| +-- foobar.png
| ...
npm run fv-build foobar
Logo.png is now a direct copy of foobar.png. You can now always import Logo.png instead of checking for the current client or doing lazy imports (which require you to build with all logos included).
.
+-- _src
| +-- _Logo
| +-- fvi.config.json
| +-- foo.png
| +-- bar.png
| +-- foobar.png
| +-- Logo.png # copy of src/Logo/foobar.png
| ...
.
+-- _src
| +-- _colors
| +-- fvi.config.json
| +-- colors_a.ini
| +-- colors_b.ini
| +-- colors_c.ini
| ...
fvi.config.json
{
"default": "colors_a",
"fallbacks": {
"foo": "colors_b"
},
"marking": true
}
colors_b.ini
[main]
primary=rgba(255, 0, 255, ALPHA_VALUE)
secondary=rgba(0, 255, 0, ALPHA_VALUE)
npm run fv-build foo replace=colors,ALPHA_VALUE,0.5
.
+-- _src
| +-- _colors
| +-- fvi.config.json
| +-- colors_a.ini
| +-- colors_b.ini
| +-- colors_c.ini
| +-- colors.fvo.ini # copy of src/colors/colors_b.ini
| ...
colors.fvo.ini
[main]
primary=rgba(255, 0, 255, 0.5)
secondary=rgba(0, 255, 0, 0.5)
.gitignore
# file-variants outputs
*.fvo*
.
+-- _src
| +-- _splash
| +-- fvi.config.json
| +-- red.x64.png
| +-- red.x128.png
| +-- red.x256.png
| +-- green.x64.png
| +-- green.x128.png
| +-- green.x256.png
| +-- blue.x64.png
| +-- blue.x128.png
| +-- blue.x256.png
| ...
fvi.config.json
{
"default": "red",
"//": "{part0} (pattern {part}\\d*} with only one (1) backslash) means the first part of the",
"//": "filename after variant (ie. red/green/blue in this case).",
"outputName": "{name}_{part0}"
}
npm run fv-build
.
+-- _src
| +-- _splash
| +-- fvi.config.json
| +-- red.x64.png
| +-- red.x128.png
| +-- red.x256.png
| +-- green.x64.png
| +-- green.x128.png
| +-- green.x256.png
| +-- blue.x64.png
| +-- blue.x128.png
| +-- blue.x256.png
| +-- splash_x64.png
| +-- splash_x128.png
| +-- splash_x256.png
| ...
.gitignore
# file-variants outputs
splash*.png
.
+-- _src
| +-- _config
| +-- fvi.config.json
| +-- A.ini
| +-- A.README.md
| +-- B.ini
| +-- B.README.md
| +-- C.ini
| +-- C.README.md
| ...
fvi.config.json
{
"default": "A",
"exclude": "README"
}
npm run fv-build
.
+-- _src
| +-- _config
| +-- fvi.config.json
| +-- A.ini
| +-- A.README.md
| +-- B.ini
| +-- B.README.md
| +-- C.ini
| +-- C.README.md
| +-- config.ini # No README as output!
| ...
.gitignore
# file-variants outputs
config.ini
MIT. Copyright (c) 2021 Emil Engelin.
FAQs
Create multiple file variants, build with one (and replace within if needed), and deploy. Solves the problem of using multiple somewhat similar files in a sort of multitenant system. Highly configurable and flexible pseudo multitenant file builder.
We found that file-variants demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.