Minifier of js, css, html and img files with CLI and programmatic interfaces
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Flexible configuration management supporting .minify.json files with directory traversal for CLI usage and direct options passing for programmatic usage.
The CLI automatically reads .minify.json configuration files from the current directory or parent directories. For programmatic usage, pass options directly to minify functions.
interface MinifyConfiguration {
js?: JSConfiguration;
css?: CSSConfiguration;
html?: HTMLConfiguration;
img?: ImageConfiguration;
}
interface JSConfiguration {
type?: 'putout' | 'terser' | 'esbuild' | 'swc';
putout?: PutoutOptions;
terser?: TerserOptions;
esbuild?: ESBuildOptions;
swc?: SWCOptions;
}
interface CSSConfiguration {
type?: 'lightningcss' | 'clean-css';
'clean-css'?: CleanCSSOptions;
}
interface HTMLConfiguration extends HTMLMinifierOptions {}
interface ImageConfiguration {
maxSize?: number;
}Usage Examples:
import { minify } from "minify";
// Programmatic usage - pass options directly
const options = {
js: { type: 'terser', terser: { mangle: true } },
css: { type: 'clean-css' },
html: { removeComments: true }
};
const minified = await minify.js(source, options);
// CLI usage automatically loads .minify.json files
// No programmatic import needed for configuration filesThe configuration file uses JSON format with sections for each minifier type:
{
"js": {
"type": "putout",
"putout": {
"quote": "'",
"mangle": true,
"mangleClassNames": true,
"removeUnusedVariables": true,
"removeConsole": false,
"removeUselessSpread": true
},
"terser": {
"mangle": true,
"compress": {
"drop_console": true
}
},
"esbuild": {
"minifyWhitespace": true,
"minifyIdentifiers": true,
"minifySyntax": true
},
"swc": {
"mangle": true,
"module": true
}
},
"css": {
"type": "clean-css",
"clean-css": {
"level": 2,
"compatibility": "*"
}
},
"html": {
"removeComments": true,
"removeCommentsFromCDATA": true,
"removeCDATASectionsFromCDATA": true,
"collapseWhitespace": true,
"collapseBooleanAttributes": true,
"removeAttributeQuotes": true,
"removeRedundantAttributes": true,
"useShortDoctype": true,
"removeEmptyAttributes": true,
"removeEmptyElements": false,
"removeOptionalTags": true,
"removeScriptTypeAttributes": true,
"removeStyleLinkTypeAttributes": true,
"minifyJS": true,
"minifyCSS": true
},
"img": {
"maxSize": 4096
}
}The system walks up parent directories to find .minify.json files:
interface DirectoryTraversal {
startDirectory: string; // Current working directory
searchPattern: string; // ".minify.json" filename
traversalOrder: string[]; // Directories checked in order
stopCondition: string; // Root directory or first file found
}
// Example traversal path:
// /project/src/components/ → /project/src/components/.minify.json
// /project/src/ → /project/src/.minify.json
// /project/ → /project/.minify.json
// / → /.minify.jsonDirectory Traversal Examples:
// Project structure:
// /project/
// ├── .minify.json ← Root configuration
// ├── src/
// │ ├── .minify.json ← Source-specific overrides
// │ └── components/
// │ └── Button.js ← Uses src/.minify.json
// CLI working from /project/src/components/
minify Button.js
// Uses: /project/src/.minify.json
// CLI working from /project/
minify src/components/Button.js
// Uses: /project/.minify.json
// No configuration file found - uses defaults
// CLI working from /tmp/
minify /some/file.js
// Uses: built-in defaultsConfigure JavaScript minifiers with type selection and options:
{
"js": {
"type": "putout",
"putout": {
"quote": "'",
"mangle": true,
"mangleClassNames": true,
"removeUnusedVariables": true,
"removeConsole": false,
"removeUselessSpread": true
}
}
}JavaScript Configuration Examples:
// Putout configuration (default)
{
"js": {
"type": "putout",
"putout": {
"mangle": true,
"removeUnusedVariables": false,
"quote": "'"
}
}
}
// Terser configuration
{
"js": {
"type": "terser",
"terser": {
"mangle": {
"toplevel": true
},
"compress": {
"drop_console": true,
"drop_debugger": true,
"pure_funcs": ["console.log"]
}
}
}
}
// ESBuild configuration
{
"js": {
"type": "esbuild",
"esbuild": {
"minifyWhitespace": true,
"minifyIdentifiers": true,
"minifySyntax": true,
"target": ["es2020"]
}
}
}
// SWC configuration
{
"js": {
"type": "swc",
"swc": {
"mangle": true,
"module": true,
"compress": {
"unused": true
}
}
}
}Configure CSS minifiers with backend selection and optimization levels:
{
"css": {
"type": "clean-css",
"clean-css": {
"level": {
"1": {
"specialComments": 0,
"removeWhitespace": true
},
"2": {
"mergeAdjacentRules": true,
"removeEmpty": true,
"removeDuplicateRules": true
}
},
"compatibility": {
"properties": {
"colors": false,
"ieFilters": true
}
}
}
}
}CSS Configuration Examples:
// LightningCSS (default - minimal configuration)
{
"css": {
"type": "lightningcss"
}
}
// Clean-CSS with optimization levels
{
"css": {
"type": "clean-css",
"clean-css": {
"level": 2,
"compatibility": "*",
"format": "beautify",
"sourceMap": true
}
}
}
// Clean-CSS with detailed options
{
"css": {
"type": "clean-css",
"clean-css": {
"level": {
"1": {
"cleanupCharsets": true,
"normalizeUrls": true,
"optimizeBackground": true,
"optimizeBorderRadius": true,
"optimizeFilter": true,
"optimizeFont": true,
"removeEmpty": true,
"removeWhitespace": true,
"specialComments": "all"
},
"2": {
"mergeAdjacentRules": true,
"mergeIntoShorthands": true,
"mergeMedia": true,
"removeDuplicateRules": true,
"removeUnusedAtRules": false
}
}
}
}
}Configure HTML minification with comprehensive optimization settings:
{
"html": {
"removeComments": true,
"removeCommentsFromCDATA": true,
"removeCDATASectionsFromCDATA": true,
"collapseWhitespace": true,
"collapseBooleanAttributes": true,
"removeAttributeQuotes": true,
"removeRedundantAttributes": true,
"useShortDoctype": true,
"removeEmptyAttributes": true,
"removeEmptyElements": false,
"removeOptionalTags": true,
"removeScriptTypeAttributes": true,
"removeStyleLinkTypeAttributes": true,
"minifyJS": true,
"minifyCSS": true
}
}HTML Configuration Examples:
// Conservative HTML minification
{
"html": {
"removeComments": false,
"collapseWhitespace": true,
"removeEmptyElements": false,
"removeOptionalTags": false,
"minifyJS": false,
"minifyCSS": false
}
}
// Aggressive HTML minification
{
"html": {
"removeComments": true,
"collapseWhitespace": true,
"removeAttributeQuotes": true,
"removeRedundantAttributes": true,
"removeEmptyAttributes": true,
"removeOptionalTags": true,
"minifyJS": true,
"minifyCSS": true,
"useShortDoctype": true
}
}
// Template-friendly configuration
{
"html": {
"collapseWhitespace": true,
"removeComments": false,
"removeEmptyElements": false,
"ignoreCustomFragments": [
"<%[\\s\\S]*?%>",
"<\\?[\\s\\S]*?\\?>"
]
}
}Configure image processing and base64 inlining thresholds:
{
"img": {
"maxSize": 102400
}
}Image Configuration Examples:
// Conservative image inlining (small files only)
{
"img": {
"maxSize": 10000
}
}
// Aggressive image inlining
{
"img": {
"maxSize": 500000
}
}
// Disable image inlining
{
"img": {
"maxSize": 0
}
}
// Default behavior (100KB threshold)
{
"img": {
"maxSize": 102400
}
}Configuration sources are applied in order of precedence:
interface ConfigurationPrecedence {
1: 'runtime-options'; // Highest: Options passed to minify functions
2: 'nearest-config-file'; // .minify.json in current/nearest parent directory
3: 'default-settings'; // Lowest: Built-in default configurations
}
// Example precedence resolution for programmatic usage:
const runtimeOptions = { js: { type: 'terser' } }; // Passed to function
const finalConfig = {
...builtInDefaults,
...runtimeOptions // Takes precedence
};Hierarchy Examples:
// Project with nested configuration
// /project/.minify.json:
{
"js": { "type": "putout" },
"css": { "type": "clean-css" }
}
// /project/src/.minify.json:
{
"js": { "type": "terser" } // Overrides parent
}
// CLI working from /project/src/ uses nearest config:
minify app.js
// Uses: { js: { type: "terser" }, css: { type: "clean-css" } }
// Programmatic usage ignores config files:
const result = await minify.js(source, {
js: { type: 'esbuild' } // Only uses passed options
});Robust error handling for configuration file issues:
interface ConfigurationErrors {
fileNotFound: 'cli-uses-defaults'; // CLI continues with defaults
invalidJSON: 'cli-throws-parse-error'; // JSON syntax errors in CLI
filePermissions: 'cli-throws-access-error'; // File access denied in CLI
malformedOptions: 'validates-at-usage'; // Validation during minification
}Error Handling Examples:
# Missing configuration file (CLI uses defaults)
minify app.js
# Uses built-in defaults, no error
# Invalid JSON syntax in .minify.json
# { "js": { type: "invalid" } // Missing closing brace
minify app.js
# CLI Error: JSON parse error in .minify.json
# File permission error
# .minify.json exists but is not readable
minify app.js
# CLI Error: EACCES - cannot read .minify.json// Invalid configuration options (caught during programmatic usage)
const invalidConfig = { js: { type: 'nonexistent-minifier' } };
try {
const result = await minify.js(source, invalidConfig);
} catch (error) {
console.log(error.message); // Invalid minifier type error
}Different approaches for various use cases:
interface UsagePatterns {
programmatic: 'pass-options-directly';
cli: 'use-minify-json-files';
testing: 'pass-options-directly';
environment: 'conditional-configuration';
}
// Production vs Development example
const getConfig = (environment) => ({
js: {
type: environment === 'production' ? 'terser' : 'putout',
[environment === 'production' ? 'terser' : 'putout']: {
mangle: environment === 'production',
removeConsole: environment === 'production'
}
}
});Testing Integration Examples:
// Test configuration by passing options directly
import { minify } from 'minify';
describe('Configuration System', () => {
test('should use custom JS configuration', async () => {
const options = { js: { type: 'esbuild' } };
const result = await minify.js('function test() {}', options);
expect(result).toBeTruthy();
});
test('should use custom CSS configuration', async () => {
const options = { css: { type: 'clean-css' } };
const result = await minify.css('body { color: red; }', options);
expect(result).toBeTruthy();
});
});
// Development environment - different configs for dev vs prod
const isDev = process.env.NODE_ENV === 'development';
const devConfig = {
js: {
type: 'putout',
putout: { removeConsole: false } // Keep console in dev
}
};
const prodConfig = {
js: {
type: 'terser',
terser: { compress: { drop_console: true } }
}
};
const config = isDev ? devConfig : prodConfig;
const result = await minify.js(source, config);