├── .changeset ├── README.md └── config.json ├── .editorconfig ├── .gitignore ├── .vscode ├── extensions.json ├── launch.json └── settings.json ├── COMPARE.md ├── LICENSE.txt ├── NOTES.md ├── README.md ├── biome.json ├── bun.lockb ├── commitlint.config.cjs ├── demo ├── .gitignore ├── README.md ├── astro.config.mjs ├── package.json ├── public │ ├── astro.svg │ ├── favicon.svg │ ├── main.js │ └── reset.css ├── src │ ├── env.d.ts │ └── pages │ │ └── index.astro └── tsconfig.json ├── package.json ├── packages └── min │ ├── README.md │ ├── package.json │ └── src │ ├── index.ts │ ├── integration.ts │ └── utils │ ├── logger.ts │ └── options.ts ├── pnpm-lock.yaml ├── pnpm-workspace.yaml ├── slogan-light-transparent.svg ├── tsconfig.json └── tsup.config.ts /.changeset/README.md: -------------------------------------------------------------------------------- 1 | # Changesets 2 | 3 | Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works 4 | with multi-package repos, or single-package repos to help you version and publish your code. You can 5 | find the full documentation for it [in our repository](https://github.com/changesets/changesets) 6 | 7 | We have a quick list of common questions to get you started engaging with this project in 8 | [our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md) 9 | -------------------------------------------------------------------------------- /.changeset/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://unpkg.com/@changesets/config@3.0.0/schema.json", 3 | "changelog": "@changesets/cli/changelog", 4 | "commit": false, 5 | "fixed": [], 6 | "linked": [], 7 | "access": "restricted", 8 | "baseBranch": "main", 9 | "updateInternalDependencies": "patch", 10 | "ignore": [] 11 | } -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | indent_size = 2 7 | indent_style = space 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false 13 | 14 | [*.{json,md,ts}] 15 | indent_style = space 16 | 17 | [*.{cjs,json,mjs,svg,yaml,yml}] 18 | insert_final_newline = false 19 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .npmignore 2 | _* 3 | dist/ 4 | node_modules/ 5 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "astro-build.astro-vscode", 4 | "biomejs.biome" 5 | ] 6 | } -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "command": "./node_modules/.bin/astro dev", 6 | "name": "Development server", 7 | "request": "launch", 8 | "type": "node-terminal" 9 | } 10 | ] 11 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "cSpell.words": [ 3 | "astro", 4 | "Astro", 5 | "astrojs", 6 | "biomejs", 7 | "Codeium", 8 | "Codespaces", 9 | "commitlint", 10 | "FOSS", 11 | "lightningcss", 12 | "mastro", 13 | "minifier", 14 | "multipass", 15 | "npmignore", 16 | "Redwerkz", 17 | "tsconfigs", 18 | "tsup", 19 | "volta", 20 | "withastro" 21 | ], 22 | "json.schemas": [ 23 | { 24 | "url": "https://cdn.jsdelivr.net/npm/tsup/schema.json", 25 | "fileMatch": ["package.json", "tsup.config.json"] 26 | } 27 | ] 28 | } -------------------------------------------------------------------------------- /COMPARE.md: -------------------------------------------------------------------------------- 1 | # Comparison 2 | 3 | - `astro-min` 4 | [![install size][pkgphobia-badge-min]][pkgphobia-result-min] 5 | - `astro-compress` 6 | [![install size][pkgphobia-badge-compress]][pkgphobia-result-compress] 7 | 8 | [pkgphobia-badge-min]: https://packagephobia.com/badge?p=astro-min 9 | [pkgphobia-result-min]: https://packagephobia.com/result?p=astro-min 10 | [pkgphobia-badge-compress]: https://packagephobia.com/badge?p=astro-compress 11 | [pkgphobia-result-compress]: https://packagephobia.com/result?p=astro-compress 12 | 13 | # Benchmark 14 | 15 | Added to build of 16 | 17 | ```sh 18 | 00:11:20 ✓ Completed in 679.58s. 19 | 20 | 00:11:23 [build] Waiting for integration "astro-min", hook "astro:build:done"... 21 | 00:11:23 [astro-min] 3638 files minified in 2.9s saving 7MB! 22 | 00:11:23 [build] 3637 page(s) built in 684.91s 23 | 00:11:23 [build] Complete! 24 | ``` 25 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright 2024 Marc Redwerkz 2 | 3 | Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. 4 | 5 | THE SOFTWARE IS PROVIDED “AS IS” AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 6 | -------------------------------------------------------------------------------- /NOTES.md: -------------------------------------------------------------------------------- 1 | # 2 | https://github.com/release-it/conventional-changelog 3 | https://github.com/release-it/release-it 4 | https://github.com/7-docs/7-docs 5 | https://github.com/favoloso/conventional-changelog-emoji 6 | https://coveralls.io/ 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ./packages/min/README.md 2 | -------------------------------------------------------------------------------- /biome.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://biomejs.dev/schemas/1.5.3/schema.json", 3 | "formatter": { 4 | "enabled": true, 5 | "formatWithErrors": true, 6 | "indentStyle": "tab", 7 | "lineEnding": "lf", 8 | "lineWidth": 80 9 | }, 10 | "javascript": { 11 | "formatter": { 12 | "arrowParentheses": "always", 13 | "quoteStyle": "single", 14 | "semicolons": "asNeeded" 15 | } 16 | }, 17 | "json": { 18 | "formatter": { 19 | "indentStyle": "space", 20 | "indentWidth": 2 21 | } 22 | }, 23 | "linter": { 24 | "ignore": [".astro"], 25 | "rules": { 26 | "a11y": { 27 | "all": true 28 | }, 29 | "recommended": true 30 | } 31 | }, 32 | "organizeImports": { 33 | "enabled": true 34 | } 35 | } -------------------------------------------------------------------------------- /bun.lockb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/advanced-astro/min/3c4ae09938e76992fa1d731e841cdf7fe4a282ba/bun.lockb -------------------------------------------------------------------------------- /commitlint.config.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ['@commitlint/config-conventional'] 3 | } -------------------------------------------------------------------------------- /demo/.gitignore: -------------------------------------------------------------------------------- 1 | # build output 2 | dist/ 3 | # generated types 4 | .astro/ 5 | 6 | # dependencies 7 | node_modules/ 8 | 9 | # logs 10 | npm-debug.log* 11 | yarn-debug.log* 12 | yarn-error.log* 13 | pnpm-debug.log* 14 | 15 | 16 | # environment variables 17 | .env 18 | .env.production 19 | 20 | # macOS-specific files 21 | .DS_Store 22 | -------------------------------------------------------------------------------- /demo/README.md: -------------------------------------------------------------------------------- 1 | # Astro Starter Kit: Minimal 2 | 3 | ```sh 4 | npm create astro@latest -- --template minimal 5 | ``` 6 | 7 | [![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/withastro/astro/tree/latest/examples/minimal) 8 | [![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/withastro/astro/tree/latest/examples/minimal) 9 | [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/withastro/astro?devcontainer_path=.devcontainer/minimal/devcontainer.json) 10 | 11 | > 🧑‍🚀 **Seasoned astronaut?** Delete this file. Have fun! 12 | 13 | ## 🚀 Project Structure 14 | 15 | Inside of your Astro project, you'll see the following folders and files: 16 | 17 | ```text 18 | / 19 | ├── public/ 20 | ├── src/ 21 | │ └── pages/ 22 | │ └── index.astro 23 | └── package.json 24 | ``` 25 | 26 | Astro looks for `.astro` or `.md` files in the `src/pages/` directory. Each page is exposed as a route based on its file name. 27 | 28 | There's nothing special about `src/components/`, but that's where we like to put any Astro/React/Vue/Svelte/Preact components. 29 | 30 | Any static assets, like images, can be placed in the `public/` directory. 31 | 32 | ## 🧞 Commands 33 | 34 | All commands are run from the root of the project, from a terminal: 35 | 36 | | Command | Action | 37 | | :------------------------ | :----------------------------------------------- | 38 | | `npm install` | Installs dependencies | 39 | | `npm run dev` | Starts local dev server at `localhost:4321` | 40 | | `npm run build` | Build your production site to `./dist/` | 41 | | `npm run preview` | Preview your build locally, before deploying | 42 | | `npm run astro ...` | Run CLI commands like `astro add`, `astro check` | 43 | | `npm run astro -- --help` | Get help using the Astro CLI | 44 | 45 | ## 👀 Want to learn more? 46 | 47 | Feel free to check [our documentation](https://docs.astro.build) or jump into our [Discord server](https://astro.build/chat). 48 | -------------------------------------------------------------------------------- /demo/astro.config.mjs: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'astro/config' 2 | import min from 'astro-min' 3 | 4 | export default defineConfig({ 5 | integrations: [ 6 | min( 7 | { 8 | do_not_minify_doctype: false, 9 | ensure_spec_compliant_unquoted_attribute_values: false, 10 | keep_closing_tags: false, 11 | keep_comments: false, 12 | keep_html_and_head_opening_tags: false, 13 | keep_input_type_text_attr: false, 14 | keep_spaces_between_attributes: false, 15 | keep_ssi_comments: false, 16 | minify_css: false, 17 | minify_js: false, 18 | preserve_brace_template_syntax: false, 19 | preserve_chevron_percent_template_syntax: false, 20 | remove_bangs: false, 21 | remove_processing_instructions: false, 22 | } 23 | ) 24 | ] 25 | }) 26 | -------------------------------------------------------------------------------- /demo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "demo", 3 | "version": "0.0.1", 4 | "private": true, 5 | "type": "module", 6 | "scripts": { 7 | "astro": "astro", 8 | "build": "astro check && astro build", 9 | "dev": "astro dev", 10 | "preview": "astro preview", 11 | "start": "astro dev" 12 | }, 13 | "dependencies": { 14 | "astro-min": "workspace:^" 15 | }, 16 | "devDependencies": { 17 | "@astrojs/check": "^0.5.5", 18 | "astro": "^4.4.1" 19 | } 20 | } -------------------------------------------------------------------------------- /demo/public/astro.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 10 | -------------------------------------------------------------------------------- /demo/public/favicon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 8 | 10 | -------------------------------------------------------------------------------- /demo/public/main.js: -------------------------------------------------------------------------------- 1 | /* Exoscriptum */ 2 | function inlineScript() { 3 | console.log('Hello 🌐!'); 4 | } 5 | 6 | inlineScript(); 7 | -------------------------------------------------------------------------------- /demo/public/reset.css: -------------------------------------------------------------------------------- 1 | /* Box sizing rules */ 2 | *, 3 | *::before, 4 | *::after { 5 | box-sizing: border-box; 6 | } 7 | 8 | /* Prevent font size inflation */ 9 | html { 10 | -moz-text-size-adjust: none; 11 | -webkit-text-size-adjust: none; 12 | text-size-adjust: none; 13 | } 14 | 15 | /* Remove default margin in favour of better control in authored CSS */ 16 | body, h1, h2, h3, h4, p, 17 | figure, blockquote, dl, dd { 18 | margin-block-end: 0; 19 | } 20 | 21 | /* Remove list styles on ul, ol elements with a list role, which suggests default styling will be removed */ 22 | ul[role='list'], 23 | ol[role='list'] { 24 | list-style: none; 25 | } 26 | 27 | /* Set core body defaults */ 28 | body { 29 | min-height: 100vh; 30 | line-height: 1.5; 31 | } 32 | 33 | /* Set shorter line heights on headings and interactive elements */ 34 | h1, h2, h3, h4, 35 | button, input, label { 36 | line-height: 1.1; 37 | } 38 | 39 | /* Balance text wrapping on headings */ 40 | h1, h2, 41 | h3, h4 { 42 | text-wrap: balance; 43 | } 44 | 45 | /* A elements that don't have a class get default styles */ 46 | a:not([class]) { 47 | text-decoration-skip-ink: auto; 48 | color: currentColor; 49 | } 50 | 51 | /* Make images easier to work with */ 52 | img, 53 | picture { 54 | max-width: 100%; 55 | display: block; 56 | } 57 | 58 | /* Inherit fonts for inputs and buttons */ 59 | input, button, 60 | textarea, select { 61 | font: inherit; 62 | } 63 | 64 | /* Make sure textareas without a rows attribute are not tiny */ 65 | textarea:not([rows]) { 66 | min-height: 10em; 67 | } 68 | 69 | /* Anything that has been anchored to should have extra scroll margin */ 70 | :target { 71 | scroll-margin-block: 5ex; 72 | } 73 | -------------------------------------------------------------------------------- /demo/src/env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /demo/src/pages/index.astro: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | --- 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Advanced Astro 12 | 86 | 93 | 94 | 95 |

Advanced Astro

96 | 97 | 98 | -------------------------------------------------------------------------------- /demo/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "astro/tsconfigs/strictest" 3 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "root", 3 | "version": "0.0.0", 4 | "private": true, 5 | "type": "module", 6 | "scripts": { 7 | "build": "pnpm --filter astro-min --filter demo run build", 8 | "format": "biome check --apply ./packages", 9 | "prepack": "npmignore --auto", 10 | "publish": "pnpm publish --filter astro-min --no-git-checks", 11 | "publish:dry": "pnpm publish --dry-run --filter astro-min --no-git-checks", 12 | "version": "changeset version && pnpm install --no-frozen-lockfile --lockfile-only" 13 | }, 14 | "devDependencies": { 15 | "@biomejs/biome": "^1.5.3", 16 | "@changesets/changelog-github": "^0.5.0", 17 | "@changesets/cli": "^2.27.1", 18 | "@types/node": "^20.11.17", 19 | "npmignore": "^0.3.1" 20 | }, 21 | "packageManager": "bun@1.0.26" 22 | } -------------------------------------------------------------------------------- /packages/min/README.md: -------------------------------------------------------------------------------- 1 | # ✳ AstroMin 2 | 3 | > Extremely fast and smart🔹 Minification of 🟠 HTML 🟡 JS 🔵 CSS 🟣 SVG 4 | > Meticulously optimized for Speed 🥇 and Effectiveness 🏅 based on Rust 🦀 5 | 6 | [![Built with Astro][astro-badge]][astro-build] 7 | [![GitHub Repo Stars][gh-stars]][gh-repo] 8 | [![NPM Package Version][npm-version]][npm-package] 9 | [![License: MIT][license-img]][license-url] 10 | [![Types][types]][gh-repo] 11 | [![Socket Badge](https://socket.dev/api/badge/npm/package/astro-min)](https://socket.dev/npm/package/astro-min) 12 | 13 | ## Feature Highlights ✨ 14 | 15 | - ⚡ Performant parallel processing (+1k files/s) 16 | - 🪶 Lighter build output (~25% smaller) 17 | - 📦 small packaged size (~30KB) 18 | 19 | ## Feature Roadmap 🌱 20 | 21 | - [x] HTML, CSS, JS, SVG 22 | - [x] Files and inline Code 23 | - [x] Static Site Minification 24 | 25 | > **Note** 26 | > 27 | > `astro-min` focuses on compressing statically generated content and pre-rendered routes 28 | 29 | - [ ] Support SSR / Hybrid Rendering 30 | - [ ] Remove Comments from external CSS/JS 31 | 32 | ## Getting started 🎯 33 | 34 | Use your package manager of your choice 35 | 36 | ```sh 37 | # NPM 38 | npm run astro add astro-min 39 | 40 | # Bun (known bug 🐛) 41 | #bun astro add astro-min 42 | 43 | # PNPM 44 | pnpm astro add astro-min 45 | 46 | # Yarn 47 | yarn astro add astro-min 48 | ``` 49 | 50 | ### Manual Installation 🧑‍💻 51 | 52 | 1. Install package `astro-min` 53 | 54 | 2. Import and add to integrations list 55 | 56 | ```js 57 | //astro.config.mjs 58 | import { defineConfig } from 'astro/config' 59 | import min from 'astro-min' 60 | 61 | export default defineConfig({ 62 | integrations: [min()] 63 | }) 64 | ``` 65 | 66 | ## Options 🔧 67 | 68 | ```js 69 | //astro.config.mjs 70 | import { defineConfig } from 'astro/config' 71 | import minify from 'astro-min' 72 | 73 | export default defineConfig({ 74 | integrations: [ 75 | minify({ 76 | do_not_minify_doctype: false, 77 | ensure_spec_compliant_unquoted_attribute_values: false, 78 | keep_closing_tags: false, 79 | keep_comments: false, 80 | keep_html_and_head_opening_tags: false, 81 | keep_input_type_text_attr: false, 82 | keep_spaces_between_attributes: false, 83 | keep_ssi_comments: false, 84 | minify_css: false, 85 | minify_js: false, 86 | preserve_brace_template_syntax: false, 87 | preserve_chevron_percent_template_syntax: false, 88 | remove_bangs: false, 89 | remove_processing_instructions: false, 90 | }) 91 | ] 92 | }) 93 | ``` 94 | 95 | > [!IMPORTANT] 96 | > 97 | > Use `astro-min` last in your integration list for the best optimization 98 | > Optional: but before `astro-compressor` and `astro-compress` for images only 99 | 100 | ```js 101 | //astro.config.mjs 102 | import { defineConfig } from 'astro/config' 103 | import compressor from 'astro-compressor' 104 | import minify from 'astro-min' 105 | 106 | export default defineConfig({ 107 | integrations: [ 108 | minify({ 109 | // do_not_minify_doctype: false, 110 | // ensure_spec_compliant_unquoted_attribute_values: false, 111 | // keep_closing_tags: false, 112 | // keep_comments: false, 113 | // keep_html_and_head_opening_tags: false, 114 | // keep_input_type_text_attr: false, 115 | // keep_spaces_between_attributes: false, 116 | // keep_ssi_comments: false, 117 | // minify_css: false, 118 | // minify_js: false, 119 | // preserve_brace_template_syntax: false, 120 | // preserve_chevron_percent_template_syntax: false, 121 | // remove_bangs: false, 122 | // remove_processing_instructions: false, 123 | }), 124 | compress({ 125 | CSS: false, 126 | HTML: false, 127 | Image: true, 128 | JavaScript: false, 129 | SVG: false 130 | }), 131 | compressor() 132 | ] 133 | }) 134 | ``` 135 | 136 | ## Development 💻 137 | 138 | [![Open in StackBlitz][open-in-sb]](https://stackblitz.com/github/advanced-astro/astro-min) 139 | [![Open with CodeSandbox][open-in-csb]](https://codesandbox.io/p/sandbox/github/advanced-astro/astro-min) 140 | [![Open in GitHub Codespaces][open-in-ghc]](https://codespaces.new/advanced-astro/astro-min?devcontainer_path=.devcontainer/minimal/devcontainer.json) 141 | [![Open in Gitpod][open-in-gp]](https://gitpod.io/#https://github.com/advanced-astro/astro-min) 142 | 143 | ## Learn more 🔖 144 | 145 | - 146 | - 147 | 148 | ## Versus 🏅 149 | 150 | - [astro-compress](https://github.com/astro-community/AstroCompress) 151 | - 🐌 uses terser based on javascript 152 | - 💤 lightningcss not yet implemented 153 | 154 | - [astro-html-minify](https://github.com/frontendista/astro-html-minify) 155 | - 🐌 uses terser based on javascript 156 | 157 | ## Colophon 📃 158 | 159 | Build with modern FOSS 💚 and AI assistance 🤖 160 | 161 | - [VSCodium](https://vscodium.com) 162 | - [Codeium](https://codeium.com/?referral_id=eXJlZEB0dXRhLmlv) 163 | - [tsup](https://tsup.egoist.dev) 164 | 165 | Next generation ✨ web development based on Rust 🦀 166 | 167 | - [Minify-HTML](https://github.com/wilsonzlin/minify-html) 168 | - [Minify-JS](https://github.com/wilsonzlin/minify-js) 169 | - [LightningCSS](https://lightningcss.dev) 170 | 171 | ## Changelog 📖 172 | 173 | 1.2.0 - 🛠 Feat: Parallel processing 174 | - ✨ Feat: Skip `*.min.*` 175 | 1.1.0 - 🐛 Fix: Auto install bug 176 | 177 | [astro-badge]: https://astro.badg.es/v2/built-with-astro/tiny.svg 178 | [astro-build]: https://astro.build/integrations/?categories%5B%5D=recent 179 | [codestyle-img]: https://flat.badgen.net/badge/code%20style/ts-standard/blue?icon=typescript 180 | [codestyle-url]: https://github.com/standard/ts-standard 181 | [gh-stars]: https://img.shields.io/github/stars/advanced-astro/astro-min 182 | [gh-repo]: https://github.com/advanced-astro/astro-min 183 | [license-img]: https://flat.badgen.net/github/license/amio/badgen 184 | [license-url]: https://opensource.org/license/isc-license-txt/ 185 | [open-in-csb]: https://assets.codesandbox.io/github/button-edit-lime.svg 186 | [open-in-ghc]: https://github.com/codespaces/badge.svg 187 | [open-in-gp]: https://gitpod.io/button/open-in-gitpod.svg 188 | [open-in-sb]: https://developer.stackblitz.com/img/open_in_stackblitz.svg 189 | [npm-package]: https://www.npmjs.com/package/astro-min 190 | [npm-version]: https://img.shields.io/npm/v/astro-min?style=flat-square 191 | [pkgphobia-img]: https://packagephobia.com/badge?p=astro-min&style=flat-square 192 | [pkgphobia-url]: https://packagephobia.com/result?p=astro-min 193 | [types]: https://img.shields.io/npm/types/astro-min?style=flat-square 194 | 195 | [Advanced Astro](https://advanced-astro.dev) 196 | -------------------------------------------------------------------------------- /packages/min/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "astro-min", 3 | "version": "1.2.8", 4 | "description": "Extremely ⚡ fast and smart 🟠 HTML 🟡 JS 🔵 CSS 🟣 SVG minification for Astro 🚀 based on Rust 🦀", 5 | "keywords": [ 6 | "astro", 7 | "astro-component", 8 | "astro-integration", 9 | "minify", 10 | "html-minify", 11 | "lightningcss", 12 | "minify-html", 13 | "minify-js", 14 | "optimization", 15 | "perf", 16 | "performance", 17 | "rust", 18 | "svgo", 19 | "withastro" 20 | ], 21 | "homepage": "https://github.com/advanced-astro/astro-min#readme", 22 | "repository": { 23 | "type": "git", 24 | "url": "git+https://github.com/advanced-astro/astro-min.git" 25 | }, 26 | "license": "ISC", 27 | "author": "Marc Redwerkz", 28 | "type": "module", 29 | "exports": { 30 | ".": "./dist/index.js" 31 | }, 32 | "source": "src/index.ts", 33 | "types": "dist/index.d.ts", 34 | "files": [ 35 | "dist", 36 | "package.json", 37 | "LICENSE.txt", 38 | "README.md" 39 | ], 40 | "scripts": { 41 | "build": "tsup", 42 | "dev": "tsup --watch" 43 | }, 44 | "dependencies": { 45 | "@minify-html/node": "0.15.0", 46 | "svgo": "^3.2.0" 47 | }, 48 | "devDependencies": { 49 | "astro": "^4.6.3", 50 | "glob": "^10.3.12", 51 | "tsup": "^8.0.2", 52 | "typescript": "5.3.3" 53 | }, 54 | "peerDependencies": { 55 | "astro": "^4.0.0 || ^3.0.0 || ^2.0.0 || ^1.0.0" 56 | }, 57 | "packageManager": "pnpm@9.0.5" 58 | } 59 | -------------------------------------------------------------------------------- /packages/min/src/index.ts: -------------------------------------------------------------------------------- 1 | import { createIntegration } from './integration.ts' 2 | // import { createSvgIntegration } from './integrations/vector' 3 | 4 | export default createIntegration 5 | -------------------------------------------------------------------------------- /packages/min/src/integration.ts: -------------------------------------------------------------------------------- 1 | import fs from 'fs' 2 | import { join } from 'path' 3 | import { fileURLToPath } from 'url' 4 | 5 | import minifyHtml from '@minify-html/node' 6 | import type { AstroIntegration } from 'astro' 7 | import { glob } from 'glob' 8 | import { performance } from 'perf_hooks' 9 | 10 | import { optimize } from 'svgo' 11 | import { logServerMessage } from './utils/logger.ts' 12 | import { Options } from './utils/options.ts' 13 | 14 | /** 15 | * Creates a new integration with the given options. 16 | * 17 | * @param {Options} [options] - The options for the integration. 18 | * @return {AstroIntegration} - The created integration. 19 | */ 20 | export function createIntegration(options?: Options): AstroIntegration { 21 | return { 22 | name: 'astro-min', 23 | hooks: { 24 | 'astro:config:setup': async ({ config }) => { 25 | config.compressHTML = false 26 | }, 27 | 'astro:build:done': async ({ dir }) => { 28 | const start = performance.now() 29 | const cwd = fileURLToPath(dir) 30 | 31 | const [cssFiles, htmlFiles, jsFiles, svgFiles] = await Promise.all([ 32 | glob('**/*.css', { cwd, ignore: ['**/*-min.css', '**/*.min.css'] }), 33 | glob('**/*.html', { cwd }), 34 | glob('**/*.js', { cwd, ignore: ['**/*.min.js', '**/*.min.js'] }), 35 | glob('**/*.svg', { cwd }), 36 | ]) 37 | 38 | if (htmlFiles.length === 0 && svgFiles.length === 0) return 39 | 40 | /** 41 | * A function that minifies and writes a file. 42 | * 43 | * @param {string} filename - the name of the file to minify and write 44 | * @param {string} type - the type of file 45 | * @return {Promise} a Promise that resolves when the file is minified and written 46 | */ 47 | const minifyAndWriteFile = async ( 48 | filename: string, 49 | type: string, 50 | ): Promise => { 51 | const filePath = join(cwd, filename) 52 | const fileOrg = await fs.promises.readFile(filePath, 'utf8') 53 | // biome-ignore lint/suspicious/noImplicitAnyLet: 54 | let fileMin 55 | if (type === 'svg') { 56 | fileMin = optimize(fileOrg, { 57 | multipass: true, 58 | plugins: [ 59 | { 60 | name: 'preset-default', 61 | params: { 62 | overrides: { 63 | removeViewBox: false, 64 | }, 65 | }, 66 | }, 67 | ], 68 | }) 69 | await fs.promises.writeFile(filePath, fileMin.data, 'utf-8') 70 | } else { 71 | fileMin = minifyHtml.minify( 72 | Buffer.from(fileOrg), 73 | options != null ? options : {}, 74 | ) 75 | await fs.promises.writeFile(filePath, fileMin, 'utf-8') 76 | } 77 | } 78 | 79 | const minifyAndWritePromises = [] 80 | 81 | for (const filename of cssFiles) { 82 | minifyAndWritePromises.push(minifyAndWriteFile(filename, 'css')) 83 | } 84 | for (const filename of htmlFiles) { 85 | minifyAndWritePromises.push(minifyAndWriteFile(filename, 'html')) 86 | } 87 | for (const filename of jsFiles) { 88 | minifyAndWritePromises.push(minifyAndWriteFile(filename, 'js')) 89 | } 90 | for (const filename of svgFiles) { 91 | minifyAndWritePromises.push(minifyAndWriteFile(filename, 'svg')) 92 | } 93 | 94 | await Promise.all(minifyAndWritePromises) 95 | 96 | const end = performance.now() 97 | const deltaT = end - start 98 | const humanTime = 99 | deltaT < 1000 100 | ? `${deltaT.toFixed(0)}ms` 101 | : `${(deltaT / 1000).toFixed(1)}s` 102 | 103 | logServerMessage(`✴️ Completed in ${humanTime}`) 104 | }, 105 | }, 106 | } 107 | } 108 | 109 | export default createIntegration 110 | -------------------------------------------------------------------------------- /packages/min/src/utils/logger.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Logs a server message with a timestamp and a tag. 3 | * 4 | * @param {string} message - The message to be logged. 5 | * @return {void} This function does not return anything. 6 | */ 7 | export const logServerMessage = (message: string): void => { 8 | const date = new Date().toLocaleTimeString() 9 | console.log(`${date} \x1b[32mastro-min:\x1b[0m ${message}`) 10 | } 11 | -------------------------------------------------------------------------------- /packages/min/src/utils/options.ts: -------------------------------------------------------------------------------- 1 | export interface Options { 2 | do_not_minify_doctype?: boolean 3 | ensure_spec_compliant_unquoted_attribute_values?: boolean 4 | keep_closing_tags?: boolean 5 | keep_comments?: boolean 6 | keep_html_and_head_opening_tags?: boolean 7 | keep_input_type_text_attr?: boolean 8 | keep_spaces_between_attributes?: boolean 9 | keep_ssi_comments?: boolean 10 | minify_css?: boolean 11 | minify_js?: boolean 12 | preserve_brace_template_syntax?: boolean 13 | preserve_chevron_percent_template_syntax?: boolean 14 | remove_bangs?: boolean 15 | remove_processing_instructions?: boolean 16 | } 17 | -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - "packages/*" 3 | - "demo" -------------------------------------------------------------------------------- /slogan-light-transparent.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 11 | 15 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": "./", 4 | "paths": { 5 | "@/*": ["packages/min/src/*"] 6 | }, 7 | "allowImportingTsExtensions": true, 8 | "esModuleInterop": true, 9 | "experimentalDecorators": true, 10 | "isolatedModules": true, 11 | "module": "NodeNext", 12 | "moduleResolution": "NodeNext", 13 | "noUncheckedIndexedAccess": true, 14 | "skipLibCheck": true, 15 | "strict": true, 16 | "target": "ES2020" 17 | }, 18 | "include": [ 19 | "packages/min/src/**/*" 20 | ] 21 | } -------------------------------------------------------------------------------- /tsup.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'tsup' 2 | 3 | export default defineConfig({ 4 | bundle: true, 5 | clean: true, 6 | dts: true, 7 | entry: ["src/index.ts"], 8 | format: ["esm"], 9 | minify: true, 10 | }) 11 | --------------------------------------------------------------------------------