Minify4U
A VS Code extension that minifies source files whenever they change and writes the output to a path that is freely configurable per file type. Unlike minifiers that only write next to the source, Minify4U routes each file type into
its own output folder — e.g. sources in Why Minify4U?It combines what usually takes two tools — a minifier and a CSS compiler — and adds the one thing both tend to miss: a freely configurable output path per file type.
Supported languages
When it buildsMinify4U watches the file system, so a build is triggered by any change to a source file —
an editor save, a
The two are mutually exclusive, so a save never builds twice. Switch to Minify4U never reacts to its own output: every file it writes is announced beforehand and
ignored for a moment. Without that, a compiled
How it worksOn every change, Minify4U picks the rule to apply:
The file is then minified with the matching minifier and written to the target folder (relative to the folder root) with the configured extension. Already-minified files are skipped. Saving Asking on demandBuilding is quiet unless there is something to report — otherwise the output channel would fill up in every project. But that makes a build that does nothing ambiguous: not configured, switched off, or broken? The command
Errors always surface as a notification, on an automatic build as well. Readable CSS next to the minified fileSome setups load plain, non-minified CSS — a theme's
Like every Both settings are independent, take the same values (folder ·
There is no
Vendor prefixes
Off by default. When on, every CSS file Minify4U produces — from SCSS, Sass, LESS and plain CSS, minified and readable alike — is run through Autoprefixer. Prefixes go in before minifying, and source maps keep pointing at the original source. The targets come from your project, not from a setting: browserslist searches upwards
from the source file for a For projects that carry no browserslist config,
Every write names what it prefixed against, so the targets are never a silent guess:
Off by default because prefixes change the files you ship — that should never arrive as a side effect of an update. Source maps
One switch, off by default. When on, every CSS file compiled from SCSS, Sass or LESS —
minified and readable alike, including Sources are referenced relative to the map, so the mapping works on a server that mirrors your local tree — and the source text is also embedded into the map, so it even works where the source tree is not deployed. Off by default because the maps land next to your output files: an upload-on-save watcher
would deploy them, and nobody should get surprise files from an update. Turning the switch
off again removes the comment on the next build, but already written Sass partialsA partial ( The dependencies are not guessed from
ConfigurationWhere to change the settingsTwo ways, same result: In the settings editor — In
User vs. Workspace — and what "inherited" meansThe settings editor has tabs: User applies to every project, Workspace only to the one that is open (with several project folders a Folder tab appears too). The more specific level wins. The trap: an empty field on the Workspace tab does not mean "off here", it means "nothing set here" — the value from the User level still applies. VS Code writes "(Also modified in: User)" next to the setting name in that case, and that note is how you spot an inherited value. This is the single most common source of surprise: set Simple: output folder per languageFor the common case, one setting per language is enough. The minifier and extension are chosen automatically:
Each of these settings takes a folder path relative to the folder root:
When
|
| Answer | writes into the project's settings |
|---|---|
| Keep it here | "*" — unchanged behaviour, just no longer inherited |
| Choose folder… | the picked folder, relative to the project root |
| Don't minify here | "" — this language is off in this project |
Every answer makes the value explicit, so the question never returns — not in this session and
not in any later one. Entries from minify4u.rules never raise it: those are written by hand,
which is a decision rather than an inheritance.
Turning building off leaves whatever the previous build wrote where it is; the output channel names the file, and you delete it yourself. Minify4U never removes files on its own.
Excluding files
minify4u.exclude takes globs (relative to the folder root) that Minify4U ignores
completely, for every language:
{
"minify4u.exclude": ["**/node_modules/**", "**/.vscode/**", "**/vendor/**"]
}
Skipped files are named in the "Minify4U" output channel, so a file that is deliberately ignored never looks like a broken extension.
The default is ["**/node_modules/**", "**/.vscode/**"] — build folders are deliberately not in
it, because silently refusing to build for anyone whose sources live in build/ would be worse
than the problem. See When * is inherited for how that case is handled
instead. Keeping .vscode out matters more
than it looks: VS Code treats its own settings.json as JSONC, so without that entry every
edit to your project configuration would write a minified copy of it into your JSONC output
folder.
Advanced: rules for globs & special cases
minify4u.rules supports glob matching, custom extensions and an explicit minifier.
Rules take precedence over minify4u.output.<language>:
{
"minify4u.rules": [
{
"glob": "src/js/vendor/**/*.js",
"savePath": "assets/js/vendor",
"suffix": ".min.js",
"minifier": "terser"
}
]
}
| Field | Required | Description |
|---|---|---|
glob |
– | Glob relative to the folder root. Alternative to type. |
type |
– | VS Code language ID (javascript, css, scss, …). Alternative to glob. |
savePath |
✓ | Target folder relative to the folder root. * writes next to the source file. |
suffix |
✓ | Output extension (replaces the original extension). |
minifier |
✓ | One of the values from the minifier table below. |
Either
globortypemust be set.
minify4u.rulesis an array of objects, which the VS Code settings editor cannot render as a form — use "Edit in settings.json" (it offers autocompletion forminifier).
Minifier values
| Value | Result |
|---|---|
terser |
minify JavaScript |
clean-css |
minify CSS |
sass |
compile + minify SCSS/SASS → CSS |
sass-expanded |
compile SCSS/SASS → readable CSS — not minified |
less |
compile + minify LESS → CSS |
less-expanded |
compile LESS → readable CSS — not minified |
html |
minify HTML |
json |
minify JSON/JSONC (compact) |
json-pretty |
convert JSON/JSONC to readable JSON (comments/trailing commas removed, indented) — not minified |
Example — readable CSS from one specific file. minify4u.expanded.<language> applies to
every file of that language in the folder; a rule is how you single one out:
{
"minify4u.rules": [
{
"glob": "files4u/scss/main.scss",
"savePath": "assets/css",
"suffix": ".css",
"minifier": "sass-expanded"
}
]
}
Remember that a rule replaces the per-language settings for the files it matches, and produces exactly one output —
output.scssandexpanded.scssno longer apply tomain.scsshere.
Example — convert JSONC to readable JSON (instead of minifying):
{
"minify4u.rules": [
{
"glob": "config/**/*.jsonc",
"savePath": "config",
"suffix": ".json",
"minifier": "json-pretty"
}
]
}
Multi-root workspaces
Every Minify4U setting except minify4u.trigger is resource-scoped: the configuration is
read for the changed file, so each root folder in a multi-root workspace can use its own
values. One project writes to
assets/js, the next to dist/scripts, a third disables CSS entirely — same setting, three
answers.
Put per-project values in <project>/.vscode/settings.json. More specific wins:
| Level | Where | Priority |
|---|---|---|
| Folder | <project>/.vscode/settings.json |
highest |
| Workspace | *.code-workspace → "settings" |
|
| User | global settings.json |
|
| Default | the extension's own default | lowest |
In the settings editor this per-project level is the "Folder" tab. It appears once your workspace has more than one root folder.
Watch out for a global "minify4u.enable": false — it silently disables Minify4U in every
project that does not set enable: true itself.
Development
npm install
npm run compile # esbuild → dist/extension.js
npm run watch # watch mode
npm run typecheck # tsc --noEmit
- Debug:
F5launches the Extension Host (uses.vscode/launch.json). - Package:
npm run package(vsce package) creates a.vsixfor local installation.
Limitations
- Output is written flat into
savePath(source basename +suffix); the subfolder structure under the glob is not mirrored yet.
License
MIT © Frank Hackenberg (4UWeb)
Built by ForYourWeb — Frank Hackenberg, full stack web developer.