Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
141 changes: 133 additions & 8 deletions javascript/packages/minifier/README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# Herb Minifier <Badge type="info" text="coming soon" />
# Herb Minifier

**Package:** [`@herb-tools/minifier`](https://www.npmjs.com/package/@herb-tools/minifier)

---

HTML+ERB template minification.
HTML+ERB template minification. Removes non-significant whitespace while preserving whitespace in `<pre>` and `<code>` tags.

## Installation

Expand All @@ -26,14 +26,139 @@ bun add @herb-tools/minifier
```
:::

<!-- ### Usage -->
## Usage

<!-- TODO -->
### Basic Usage

<!-- #### Configuration Options -->
```typescript
import { Herb } from '@herb-tools/node-wasm'
import { Minifier } from '@herb-tools/minifier'

<!-- TODO -->
// Create and initialize minifier
const minifier = new Minifier(Herb)
await minifier.initialize()

<!-- #### CLI Usage -->
const template = `
<div class="container">
<h1>Hello World</h1>
<p>This is a test</p>
</div>
`

<!-- TODO -->
const minified = minifier.minifyString(template)
// Result: '<div class="container"><h1>Hello World</h1><p>This is a test</p></div>'
```

### Minifying AST Nodes

You can also minify AST nodes directly:

```typescript
import { Herb } from '@herb-tools/node-wasm'
import { Minifier } from '@herb-tools/minifier'

const minifier = new Minifier(Herb)
await minifier.initialize()

const parseResult = Herb.parse(template, { track_whitespace: true })
const minifiedNode = minifier.minify(parseResult.value)
```

### Whitespace Preservation

The minifier preserves whitespace in `<pre>` and `<code>` tags:

```typescript
const template = `
<div>
<pre>
Line 1
Line 2
Line 3
</pre>
</div>
`

const minified = minifier.minifyString(template)
// Result: '<div><pre>\n Line 1\n Line 2\n Line 3\n </pre></div>'
```

### ERB Support

The minifier works seamlessly with ERB templates:

```typescript
const template = `
<div>
<% if admin? %>
<span>Admin</span>
<% else %>
<span>User</span>
<% end %>
</div>
`

const minified = minifier.minifyString(template)
// Result: '<div><%if admin?%><span>Admin</span><%else%><span>User</span><%end%></div>'
```

## API Reference

### `Minifier`

The main minifier class.

#### Constructor

```typescript
new Minifier(herb: HerbBackend)
```

**Parameters:**
- `herb`: The Herb backend instance

#### Methods

##### `initialize()`

```typescript
async initialize(): Promise<void>
```

Initializes the minifier by loading the Herb backend. Must be called before using minification methods.

##### `minifyString()`

```typescript
minifyString(template: string): string
```

Minifies an HTML+ERB template string.

**Parameters:**
- `template`: The template string to minify

**Returns:** The minified template string

##### `minify()`

```typescript
minify<T extends Node>(node: T): T
```

Minifies an HTML+ERB AST node.

**Parameters:**
- `node`: The AST node to minify

**Returns:** The minified AST node

## Features

- ✅ Removes non-significant whitespace
- ✅ Preserves whitespace in `<pre>` and `<code>` tags
- ✅ Supports nested preserve-whitespace tags
- ✅ Works with ERB templates
- ✅ Preserves HTML attributes
- ✅ Handles self-closing tags
- ✅ Gracefully handles parse errors (returns original template)
45 changes: 45 additions & 0 deletions javascript/packages/minifier/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
{
"name": "@herb-tools/minifier",
"version": "0.7.5",
"description": "HTML+ERB template minification",
"license": "MIT",
"homepage": "https://herb-tools.dev",
"bugs": "https://github.com/marcoroth/herb/issues/new?title=Package%20%60@herb-tools/minifier%60:%20",
"repository": {
"type": "git",
"url": "https://github.com/marcoroth/herb.git",
"directory": "javascript/packages/minifier"
},
"main": "./dist/index.cjs",
"module": "./dist/index.esm.js",
"require": "./dist/index.cjs",
"types": "./dist/types/index.d.ts",
"scripts": {
"build": "yarn clean && rollup -c rollup.config.mjs",
"dev": "rollup -c rollup.config.mjs -w",
"clean": "rimraf dist",
"test": "vitest run",
"test:watch": "vitest --watch",
"prepublishOnly": "yarn clean && yarn build && yarn test"
},
"exports": {
"./package.json": "./package.json",
".": {
"types": "./dist/types/index.d.ts",
"import": "./dist/index.esm.js",
"require": "./dist/index.cjs",
"default": "./dist/index.esm.js"
}
},
"dependencies": {
"@herb-tools/core": "0.7.5",
"@herb-tools/printer": "0.7.5",
"@herb-tools/rewriter": "0.7.5"
},
"files": [
"package.json",
"README.md",
"dist/",
"src/"
]
}
32 changes: 32 additions & 0 deletions javascript/packages/minifier/project.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{
"name": "@herb-tools/minifier",
"$schema": "../../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "javascript/packages/minifier/src",
"projectType": "library",
"targets": {
"build": {
"executor": "nx:run-script",
"options": {
"script": "build"
},
"dependsOn": [
"@herb-tools/core:build",
"@herb-tools/printer:build",
"@herb-tools/rewriter:build"
]
},
"test": {
"executor": "nx:run-script",
"options": {
"script": "test"
}
},
"clean": {
"executor": "nx:run-script",
"options": {
"script": "clean"
}
}
},
"tags": []
}
61 changes: 61 additions & 0 deletions javascript/packages/minifier/rollup.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import typescript from "@rollup/plugin-typescript"
import { nodeResolve } from "@rollup/plugin-node-resolve"
import commonjs from "@rollup/plugin-commonjs"
import json from "@rollup/plugin-json"

const external = [
"path",
"url",
"fs",
"module",
"@herb-tools/tailwind-class-sorter"
]

function isExternal(id) {
return (
external.includes(id) ||
external.some((pkg) => id === pkg || id.startsWith(pkg + "/"))
)
}

export default [
// Browser-compatible entry point (core APIs only)
{
input: "src/index.ts",
output: {
file: "dist/index.esm.js",
format: "esm",
sourcemap: true,
},
external: [],
plugins: [
nodeResolve({ preferBuiltins: true }),
commonjs(),
json(),
typescript({
tsconfig: "./tsconfig.json",
declaration: true,
declarationDir: "./dist/types",
rootDir: "src/",
}),
],
},
{
input: "src/index.ts",
output: {
file: "dist/index.cjs",
format: "cjs",
sourcemap: true,
},
external: [],
plugins: [
nodeResolve({ preferBuiltins: true }),
commonjs(),
json(),
typescript({
tsconfig: "./tsconfig.json",
rootDir: "src/",
}),
],
}
]
1 change: 1 addition & 0 deletions javascript/packages/minifier/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { Minifier, minify } from "./minifier.js"
23 changes: 23 additions & 0 deletions javascript/packages/minifier/src/minifier-rewriter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { ASTRewriter } from "@herb-tools/rewriter"
import { MinifierVisitor } from "./minifier-visitor.js"

import type { RewriteContext } from "@herb-tools/rewriter"
import type { Node } from "@herb-tools/core"

export class MinifyRewriter extends ASTRewriter {
get name() {
return "Minifier"
}

get description() {
return "Minifies HTML+ERB documents by removing non-significant whitespace."
}

rewrite<T extends Node>(node: T, _context?: RewriteContext): T {
const visitor = new MinifierVisitor()

node.accept(visitor)

return node
}
}
Loading
Loading