🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

minify-html-css

Package Overview
Dependencies
Maintainers
1
Versions
6
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

minify-html-css - npm Package Compare versions

Comparing version
1.1.0
to
1.2.0
+251
dist/cli.js
#!/usr/bin/env node
// src/cli.ts
import { readFileSync, writeFileSync } from "fs";
import { resolve } from "path";
// src/minify-css.ts
import {
transform
} from "lightningcss";
// src/utils/merge-options.ts
function mergeOptions(targetOptions, sourceOptions, disabledOptions3, callback) {
const mergedOptions = structuredClone(targetOptions);
for (const key in sourceOptions) {
if (disabledOptions3?.includes(key)) {
continue;
}
const targetValue = targetOptions[key];
const sourceValue = sourceOptions[key];
let mergedValue = sourceValue;
if (callback) {
const callbackResult = callback(
key,
targetValue,
sourceValue,
targetOptions,
sourceOptions
);
if (callbackResult !== void 0) {
mergedValue = callbackResult;
mergedOptions[key] = mergedValue;
continue;
}
}
if (isPlainObject(sourceValue) && Object.hasOwn(targetOptions, key) && isPlainObject(targetValue)) {
mergedValue = mergeOptions(targetValue, sourceValue);
}
mergedOptions[key] = mergedValue;
}
return mergedOptions;
}
function isPlainObject(value) {
return typeof value === "object" && !Array.isArray(value) && value !== null;
}
// src/minify-css.ts
var disabledOptions = [
"filename",
"code",
"sourceMap",
"inputSourceMap",
"projectRoot",
"include",
"exclude",
"visitor",
"customAtRules"
];
function minifyCSS(input, options) {
const baseOptions = {
filename: "",
code: Buffer.from(input),
minify: true,
sourceMap: false
};
let mergedOptions = baseOptions;
if (options) {
mergedOptions = mergeOptions(baseOptions, options, disabledOptions);
}
const transformResult = transform(mergedOptions);
return { ...transformResult, code: transformResult.code.toString() };
}
// src/minify-html.ts
import { minifyFragmentSync } from "@swc/html";
var disabledOptions2 = [
"context_element",
"filename",
"forceSetHtml5Doctype",
"form_element",
"iframeSrcdoc",
"mode",
"scriptingEnabled",
"selfClosingVoidElements"
];
function minifyHTML(input, options) {
const baseOptions = {
collapseWhitespaces: "all",
sortSpaceSeparatedAttributeValues: false,
minifyCss: { lib: "lightningcss" }
};
let mergedOptions = baseOptions;
if (options) {
mergedOptions = mergeOptions(
baseOptions,
options,
disabledOptions2,
(key, targetValue, sourceValue) => {
if (key === "minifyCss") {
if (sourceValue === true) {
return targetValue;
} else {
return false;
}
}
}
);
}
const transformOutput = minifyFragmentSync(input, mergedOptions);
return transformOutput;
}
// src/utils/cli-utils.ts
function parseOptions(args) {
const options = {};
for (let i = 0; i < args.length; i++) {
const arg = args[i];
switch (arg) {
case "-i":
case "--input":
options.input = args[++i];
break;
case "-o":
case "--output":
options.output = args[++i];
break;
case "-t":
case "--type":
options.type = args[++i];
break;
case "-h":
case "--help":
options.help = true;
break;
case "-v":
case "--version":
options.version = true;
break;
default:
if (arg.startsWith("-")) {
console.error(`Unknown option: ${arg}.`);
process.exit(1);
}
if (options.input) {
console.error(`Unknown positional argument: ${arg}.`);
process.exit(1);
}
options.input = arg;
}
}
return options;
}
function detectFileType(filePath) {
const ext = filePath.split(".").pop()?.toLowerCase();
if (ext === "html" || ext === "htm") return "html";
if (ext === "css") return "css";
return null;
}
// src/cli.ts
var helpText = `
Usage: minify-html-css <input> [options]
Positional arguments:
<input> Input file path (can be provided as a positional argument or with -i/--input)
Options:
-i, --input <file> Input file path (required unless provided as a positional argument)
-o, --output <file> Output file path (optional, defaults to stdout)
-t, --type <type> File type: html or css (auto-detected if not specified)
-h, --help Display this help message
-v, --version Display version number
Examples:
minify-html-css input.html -o output.html
minify-html-css -i input.html -o output.html
minify-html-css -i styles.css -o styles.min.css
minify-html-css -i index.html -t html
minify-html-css input.html > output.html
minify-html-css -i input.html > output.html
minify-html-css ./path/to/file.css -o ./path/to/file.min.css
`;
function main() {
const args = process.argv.slice(2);
const options = parseOptions(args);
if (options.help) {
console.log(helpText);
process.exit(0);
}
if (options.version) {
console.log("1.1.0");
process.exit(0);
}
if (!options.input) {
console.error("Error: Input file is required.");
console.log(helpText);
process.exit(1);
}
try {
const inputPath = resolve(process.cwd(), options.input);
const content = readFileSync(inputPath, "utf-8");
let fileType;
if (options.type) {
const normalizedType = options.type.toLowerCase();
if (normalizedType !== "html" && normalizedType !== "css") {
console.error(
'Error: Invalid file type. The file type must be "html" or "css".'
);
process.exit(1);
}
fileType = normalizedType;
} else {
const detectedFileType = detectFileType(options.input);
if (!detectedFileType) {
console.error(
"Error: Could not detect file type. Please specify using -t option."
);
process.exit(1);
}
fileType = detectedFileType;
}
let result;
switch (fileType) {
case "html":
result = minifyHTML(content);
break;
case "css":
result = minifyCSS(content);
break;
default:
throw new Error("Unexpected file type");
}
if (options.output) {
const outputPath = resolve(process.cwd(), options.output);
writeFileSync(outputPath, result.code, "utf-8");
console.log(`Minified ${options.input} written to: ${outputPath}.`);
process.exit(0);
} else {
console.log(result.code);
process.exit(0);
}
} catch (error) {
if (error instanceof Error) {
console.error(`Error: ${error.message}.`);
} else {
console.error("An unknown error occurred.");
}
process.exit(1);
}
}
main();
+4
-4

@@ -24,3 +24,3 @@ import * as lightningcss from 'lightningcss';

drafts?: {
/** Whether to enable @custom-media rules. */
/** Whether to enable `@custom-media` rules. */
customMedia?: boolean;

@@ -30,3 +30,3 @@ };

nonStandard?: {
/** Whether to enable the non-standard >>> and /deep/ selector combinators used by Angular and Vue. */
/** Whether to enable the non-standard `>>>` and `/deep/` selector combinators used by Angular and Vue. */
deepSelectorCombinator?: boolean;

@@ -73,5 +73,5 @@ };

/**
* A list of class names, ids, and custom identifiers (e.g. @keyframes) that are known
* A list of class names, ids, and custom identifiers (e.g. `@keyframes`) that are known
* to be unused. These will be removed during minification. Note that these are not
* selectors but individual names (without any . or # prefixes).
* selectors but individual names (without any `.` or `#` prefixes).
*/

@@ -78,0 +78,0 @@ unusedSymbols?: string[];

@@ -24,3 +24,3 @@ import * as lightningcss from 'lightningcss';

drafts?: {
/** Whether to enable @custom-media rules. */
/** Whether to enable `@custom-media` rules. */
customMedia?: boolean;

@@ -30,3 +30,3 @@ };

nonStandard?: {
/** Whether to enable the non-standard >>> and /deep/ selector combinators used by Angular and Vue. */
/** Whether to enable the non-standard `>>>` and `/deep/` selector combinators used by Angular and Vue. */
deepSelectorCombinator?: boolean;

@@ -73,5 +73,5 @@ };

/**
* A list of class names, ids, and custom identifiers (e.g. @keyframes) that are known
* A list of class names, ids, and custom identifiers (e.g. `@keyframes`) that are known
* to be unused. These will be removed during minification. Note that these are not
* selectors but individual names (without any . or # prefixes).
* selectors but individual names (without any `.` or `#` prefixes).
*/

@@ -78,0 +78,0 @@ unusedSymbols?: string[];

{
"name": "minify-html-css",
"version": "1.1.0",
"version": "1.2.0",
"description": "🔽 A library to minify HTML and CSS.",

@@ -38,2 +38,5 @@ "keywords": [

"types": "dist/index.d.ts",
"bin": {
"minify-html-css": "./dist/cli.js"
},
"files": [

@@ -45,24 +48,27 @@ "dist/",

"scripts": {
"dev": "tsup --watch",
"build": "tsup",
"test": "bun test",
"test:watch": "bun test --watch",
"dev": "bun run --bun tsup --watch",
"build": "bun run --bun tsup",
"test": "bun test --concurrent",
"test:watch": "bun run test --watch",
"pretest:all": "bun run build",
"test:all": "CLI_TESTS=1 bun run test",
"format": "biome format --write",
"lint": "biome lint . --write"
"lint": "biome lint . --write",
"release": "semantic-release"
},
"dependencies": {
"@swc/html": "^1.13.5",
"lightningcss": "^1.30.1"
"@swc/html": "^1.15.7",
"lightningcss": "^1.30.2"
},
"devDependencies": {
"@biomejs/biome": "2.2.2",
"@commitlint/cli": "^19.8.1",
"@commitlint/config-conventional": "^19.8.1",
"@biomejs/biome": "^2.3.10",
"@commitlint/cli": "^20.2.0",
"@commitlint/config-conventional": "^20.2.0",
"@semantic-release/changelog": "^6.0.3",
"@semantic-release/git": "^10.0.1",
"@types/bun": "^1.2.21",
"lefthook": "^1.12.3",
"semantic-release": "^24.2.7",
"tsup": "^8.5.0",
"typescript": "^5.9.2"
"@types/bun": "^1.3.5",
"lefthook": "^2.0.13",
"semantic-release": "^25.0.2",
"tsup": "^8.5.1",
"typescript": "^5.9.3"
},

@@ -69,0 +75,0 @@ "engines": {

+137
-39

@@ -18,2 +18,3 @@ # minify-html-css

- [API Documentation](#api-documentation)
- [CLI](#cli)
- [TODO](#todo)

@@ -66,6 +67,24 @@ - [Contributing](#contributing)

const minifiedHtml = minifyHTML(html).code;
console.log(minifiedHtml); // "<div><h1>Hello World!</h1><style>body{color:red}</style></div>"
const result = minifyHTML(html).code;
console.log(result); // "<div><h1>Hello World!</h1><style>body{color:red}</style></div>"
```
```typescript
import { minifyCSS } from 'minify-html-css';
const css = `
/* page styles */
:root { --main-color: red; }
body {
color: var(--main-color);
margin: 0;
line-height: 1.4;
}
`;
const result = minifyCSS(css).code;
console.log(result); // ":root{--main-color:red}body{color:var(--main-color);margin:0;line-height:1.4}"
```
---

@@ -77,59 +96,138 @@

**Description:**
Minifies an HTML string by removing unnecessary whitespace, comments, and compressing inline JS and CSS (where supported). Returns an object containing `code` property for transformed code and `errors` array for possible errors.
#### minifyHTML: What it does
Minifies an HTML string (whitespace, comments, attributes, inline assets depending on options).
#### minifyHTML: Return value
Returns the underlying `@swc/html` minifier result. In practice you’ll primarily use:
- `code`: the minified HTML
- `errors`: an array of parse/minification errors (if any)
> **Implementation note:**
> This function is a wrapper around the [`@swc/html`](https://github.com/swc-project/swc/tree/main/packages/html) package and uses its minification logic under the hood.
> This is a small wrapper around [`@swc/html`](https://github.com/swc-project/swc/tree/main/packages/html) (SWC’s HTML minifier).
**Parameters:**
#### minifyHTML: Parameters
- `input` (`string`): The HTML code to minify.
- `options?` (`MinifyHTMLOptions`): Configuration object for fine-grained control.
- `input` (`string`): HTML to minify.
- `options?` (`MinifyHTMLOptions`): Optional configuration.
The available options are:
#### minifyHTML: Options
| Option | Type | Default | Description |
| ----------------------------------- | -------------------------------------------------------------------------------------------- | --------- | -------------------------------------------------------------------------------------------------------- |
| `collapseWhitespaces` | `'none' \| 'all' \| 'smart' \| 'conservative' \| 'advanced-conservative' \| 'only-metadata'` | `'all'` | Controls how whitespace is collapsed and removed throughout the document. |
| `removeEmptyMetadataElements` | `boolean` | `true` | Removes empty metadata elements such as `<script>`, `<style>`, `<meta>`, and `<link>`. |
| `removeComments` | `boolean` | `true` | Removes all HTML comments unless matched by `preserveComments`. |
| `preserveComments` | `string[]` | | Array of regex strings; comments matching any are preserved. You can override the default patterns. |
| `minifyConditionalComments` | `boolean` | `true` | Minifies IE conditional comments. |
| `removeEmptyAttributes` | `boolean` | `true` | Removes empty attributes from HTML tags (when safe). |
| `removeRedundantAttributes` | `'none' \| 'all' \| 'smart'` | `'smart'` | Controls removal of redundant or default attributes. |
| `collapseBooleanAttributes` | `boolean` | `true` | Collapses boolean attributes to their short form (e.g. `checked`). |
| `normalizeAttributes` | `boolean` | `true` | Cleans up attribute values by removing unnecessary spaces, and strips `javascript:` from event handlers. |
| `minifyJson` | `boolean \| { pretty?: boolean }` | `true` | Minifies embedded JSON within `<script type="application/json">`. |
| `minifyJs` | `boolean` | `true` | Minifies inline JavaScript. |
| `minifyCss` | `boolean` | `true` | Minifies inline CSS. |
| `minifyAdditionalScriptsContent` | `[string, MinifierType][]` | | Minifies additional `<script>` types, specifying type pattern and minifier. |
| `minifyAdditionalAttributes` | `[string, MinifierType][]` | | Minifies additional attribute values, specifying attribute name pattern and minifier. |
| `sortSpaceSeparatedAttributeValues` | `boolean` | `false` | Sorts space-separated attribute values like `class` or `rel`. |
| `sortAttributes` | `boolean` | `false` | Sorts all attributes of each element in reverse alphabetical order. |
| `tagOmission` | `boolean` | `true` | Omits optional end tags when valid per HTML spec. |
| `quotes` | `boolean` | `false` | Always wrap attribute values in quotes. |
This package keeps the inline docs for options in the type files (with full JSDoc and defaults). Start here:
For detailed type definitions and documentation, see [`src/minify-html-types.ts`](https://github.com/femincan/minify-html-css/blob/main/src/minify-html-types.ts).
- [`src/minify-html-types.ts`](src/minify-html-types.ts) (HTML options + `MinifierType`)
#### minifyHTML: Examples
```ts
import { minifyHTML } from 'minify-html-css';
const input = `
<div>
<!-- hi -->
Again
</div>
`;
// Keep HTML comments
const result = minifyHTML(input, { removeComments: false }).code;
console.log(result); // <div><!-- hi -->Again</div>
```
### `minifyCSS(input: string, options?: MinifyCSSOptions): TransformResult`
**Description:**
Minifies CSS code by removing unnecessary whitespace, optimizing values, and applying various transformations.
#### minifyCSS: What it does
Minifies CSS using Lightning CSS.
#### minifyCSS: Return value
Returns the underlying `lightningcss` transform result, with one convenience tweak: `code` is returned as a `string` (not a `Buffer`).
> **Implementation note:**
> This function is a wrapper around the [`lightningcss`](https://github.com/parcel-bundler/lightningcss) package and uses its minification logic under the hood.
> This is a wrapper around [`lightningcss`](https://github.com/parcel-bundler/lightningcss).
**Parameters:**
#### minifyCSS: Parameters
- `input` (`string`): The CSS code to minify.
- `options?` (`MinifyCSSOptions`): Configuration object for fine-grained control.
- `input` (`string`): CSS to minify.
- `options?` (`MinifyCSSOptions`): Optional configuration.
For detailed type definitions and documentation for options, see [`src/minify-css-types.ts`](https://github.com/femincan/minify-html-css/blob/main/src/minify-css-types.ts).
#### minifyCSS: Options
See the full option surface (typed + documented) here:
- [`src/minify-css-types.ts`](src/minify-css-types.ts)
#### minifyCSS: Example
```ts
import { minifyCSS, minifyHTML } from 'minify-html-css';
const input = `
body {
color: red;
}
@keyframes slidein {
from {
transform: translateX(0%);
}
to {
transform: translateX(100%);
}
}
`;
// Remove unused @keyframes 'slidein'
const result = minifyCSS(input, { unusedSymbols: ['slidein'] }).code;
console.log(result); // body{color:red}
```
---
### CLI
This package also ships a CLI binary named `minify-html-css`.
**Run via `npx` (no global install):**
```bash
npx minify-html-css -i input.html -o output.html
npx minify-html-css -i styles.css -o styles.min.css
```
**Or install globally:**
```bash
npm install -g minify-html-css
minify-html-css -i input.html -o output.html
```
**Options:**
- `-i, --input <file>`: input file path (alternatively you can pass the input file as the first positional argument)
- `-o, --output <file>`: output file path (if omitted, prints to stdout)
- `-t, --type <html|css>`: file type (auto-detected from extension if omitted)
- `-h, --help`: show help
- `-v, --version`: show version
**Examples:**
```bash
# Auto-detect file type from extension
minify-html-css index.html > index.min.html
# Force type when extension can't be detected
minify-html-css -i input -t html > output.html
```
---
## TODO
- [x] Implement CSS minification function (`minifyCSS`) built on top of Lightning CSS
- [ ] Implement CLI usage (command-line tool)
- [x] Implement HTML minification function (`minifyHTML`) built on top of `@swc/html`
- [x] Implement CSS minification function (`minifyCSS`) built on top of `lightningcss`
- [x] Implement CLI usage (command-line tool)

@@ -136,0 +234,0 @@ ---