astro-purgecss 4.6.2 → 4.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -10,7 +10,7 @@
10
10
 
11
11
  ## 📦 Installation
12
12
 
13
- ### Quick Install
13
+ ### Quick Install
14
14
 
15
15
  the `astro add` command-line tool automates the installation for you. Run one of the following commands in a new terminal window. (If you aren’t sure which package manager you’re using, run the first command.) Then, follow the prompts, and type “y” in the terminal (meaning “yes”) for each one.
16
16
 
@@ -23,7 +23,7 @@ npx astro add astro-purgecss
23
23
  yarn astro add astro-purgecss
24
24
  ```
25
25
 
26
- ### Manual Install
26
+ ### 🔧 Manual Install
27
27
 
28
28
  First, install the `purgecss` & `astro-purgecss` packages using your package manager. (If you aren’t sure which package manager you’re using, run the first command.)
29
29
 
@@ -75,7 +75,7 @@ export default defineConfig({
75
75
  });
76
76
  ```
77
77
 
78
- ## 📖 Configuration
78
+ ## ⚙️ Configuration
79
79
 
80
80
  [PurgeCSS][purgecss] has a list of options that allow you to customize its behavior. And this Astro integration allow you to pass those options easily in your `astro.config.mjs` file:
81
81
 
@@ -88,7 +88,7 @@ export default defineConfig({
88
88
  safelist: ['random', 'yep', 'button', /^nav-/],
89
89
  blocklist: ['usedClass', /^nav-/],
90
90
  content: [
91
- process.cwd() + '/src/**/*.{astro,vue}' // Watching astro and vue sources (for SSR, read the note below)
91
+ process.cwd() + '/src/**/*.{astro,vue}' // Watching astro and vue sources (read SSR docs below)
92
92
  ],
93
93
  extractors: [
94
94
  {
@@ -103,15 +103,11 @@ export default defineConfig({
103
103
  });
104
104
  ```
105
105
 
106
- > **Note**
107
- >
108
- > If you are using **Astro SSR** in your project, you must add your astro and framework sources files into the `content` option (see in the example). Otherwise, as the package only look at the final build sent to the client, with SSR, some pages may not be included and may break your CSS.
109
-
110
- ### Available Options
106
+ ### 📖 Available Options
111
107
 
112
108
  Here is a list of options, that are allowed to be passed in the config:
113
109
 
114
- ```ts
110
+ ```typescript
115
111
  export type PurgeCSSOptions = {
116
112
  fontFace?: boolean; // removes any unused @font-face if set to true
117
113
  keyframes?: boolean; // removes unused keyframes by setting if set to true
@@ -121,11 +117,11 @@ export type PurgeCSSOptions = {
121
117
  safelist?: UserDefinedSafelist; // indicates which selectors are safe to leave in the final CSS
122
118
  blocklist?: StringRegExpArray; // blocks the CSS selectors from appearing in the final output CSS
123
119
  content?: Array<string | RawContent>;
124
- extractors?: // provides custom functions to extract CSS classes in specific ways (eg. when using tailwind.css)
125
- Array<{
120
+ // provides custom functions to extract CSS classes in specific ways (eg. when using tailwind.css)
121
+ extractors?: {
126
122
  extractor: (content: string) => string[]; // matched css classes
127
123
  extensions: string[]; // file extensions for which this extractor is to be used
128
- }>;
124
+ }[];
129
125
  };
130
126
  ```
131
127
 
@@ -133,22 +129,51 @@ To learn more about the available options, please refer to [PurgeCSS][purgecss-o
133
129
 
134
130
  We have also setup an example repository available here: [example-purgecss](../../apps/example-purgecss)
135
131
 
136
- ### Caveats
132
+ ## 🌐 SSR Mode
133
+
134
+ If you are using **Astro SSR** in your project, you must add your Astro and framework source files into the `content` option (see example below). Since the integration analyzes the final client-side build, some SSR-rendered pages might not be included in the initial scan, which could result in necessary CSS being incorrectly purged.
135
+
136
+ Example configuration for SSR:
137
+
138
+ ```js
139
+ export default defineConfig({
140
+ integrations: [
141
+ purgecss({
142
+ content: [
143
+ './src/**/*.{astro,js,jsx,ts,tsx,vue,svelte}'
144
+ // Add any other template files that contain styles
145
+ ]
146
+ })
147
+ ]
148
+ });
149
+ ```
150
+
151
+ ### Important Notes
152
+
153
+ 1. **CSS Retention**: Due to the integration's file scanning approach, some unused CSS might be retained. This is a deliberate trade-off to prevent accidentally removing dynamically used styles.
154
+
155
+ 2. **Inline Styles vs External Stylesheets**: The integration can more accurately analyze and purge external stylesheets compared to inline styles embedded within components:
156
+ - ✅ **Recommended**: Use external stylesheet files (`.css`)
157
+ - ⚠️ **Less Effective**: Inline styles in component files
158
+
159
+ ## ⚠️ Caveats
137
160
 
138
161
  - Some options are not allowed to be passed in your `astro.config.mjs` config file, to not interfere with the internals of this integration.
139
162
 
140
163
  - If you are using Astro view transitions, use the following options so that purgecss keeps the corresponding animations:
141
164
 
142
- ```diff
165
+ ```js
143
166
  export default defineConfig({
144
167
  integrations: [
145
168
  purgecss({
146
- + keyframes: false,
147
- + safelist: {
148
- + greedy: [/*astro*/]
149
- + }
150
- }),
151
- ],
169
+ keyframes: false,
170
+ safelist: {
171
+ greedy: [
172
+ /*astro*/
173
+ ]
174
+ }
175
+ })
176
+ ]
152
177
  });
153
178
  ```
154
179
 
@@ -170,11 +195,11 @@ export default defineConfig({
170
195
  });
171
196
  ```
172
197
 
173
- ## Changelog
198
+ ## 📝 Changelog
174
199
 
175
200
  Please see the [Changelog](CHANGELOG.md) for more information on what has changed recently.
176
201
 
177
- ## Acknowledgements
202
+ ## 💝 Acknowledgements
178
203
 
179
204
  - [Purgecss][purgecss]
180
205
 
package/dist/index.cjs CHANGED
@@ -1,2 +1,2 @@
1
- 'use strict';var path=require('path'),purgecss=require('purgecss'),crypto=require('crypto'),promises=require('fs/promises'),url=require('url');var g,h,b,y,F=!0;typeof process<"u"&&({FORCE_COLOR:g,NODE_DISABLE_COLORS:h,NO_COLOR:b,TERM:y}=process.env||{},F=process.stdout&&process.stdout.isTTY);var T={enabled:!h&&b==null&&y!=="dumb"&&(g!=null&&g!=="0"||F)};function t(r,e){let s=new RegExp(`\\x1b\\[${e}m`,"g"),n=`\x1B[${r}m`,i=`\x1B[${e}m`;return function(a){return !T.enabled||a==null?a:n+(~(""+a).indexOf(i)?a.replace(s,i+n):a)+i}}var p=t(2,22),$=t(31,39),C=t(32,39),O=t(34,39);async function E(r){try{return await promises.readFile(r,"utf8")}catch(e){return x(`Error reading file ${r}: ${e}`),""}}async function u(r,e){try{await promises.writeFile(r,e,"utf8");}catch(s){return x(`Error writing file ${r}: ${s}`),""}}function P(r,e,s,n){try{return e.includes(s)?e.replace(new RegExp(s,"g"),n):e}catch(i){return x(`Error processing file ${r}: ${i}`),""}}function R(r){let e=url.fileURLToPath(r);return e=e.replace(/\/+$/,""),process.platform!=="win32"?e:e.replace(/^\/+/,"")}async function D({css:r,file:e}){if(!e.includes("_astro"))return await u(e,r),[e,e];let s=crypto.createHash("sha256").update(r).digest("hex").substring(0,8),n=`${e.slice(0,-13)}.${s}.css`;return await u(n,r),await promises.unlink(e),[e,n]}var m=new Intl.DateTimeFormat("en-us",{hour:"2-digit",minute:"2-digit",second:"2-digit",hour12:!1});function d(r){let e=m.format(new Date);console.log(p(e),C("\u25B6"),r);}function x(r){let e=m.format(new Date);console.error(p(e),$("\u25A0"),r);}function f(r){let e=m.format(new Date);console.log(p(e),O("[purgecss]"),r);}function H(r={}){return {name:"astro-purgecss",hooks:{"astro:build:done":async({dir:e,pages:s})=>{f("Generating purged css files...");let n=R(e),i=await new purgecss.PurgeCSS().purge({css:[`${n}/**/*.css`],defaultExtractor:o=>o.match(/[\w-/:]+(?<!:)/g)||[],...r,content:[`${n}/**/*.html`,`${n}/**/*.js`,...r.content||[]]}),a=await Promise.all(i.filter(({file:o})=>o?.endsWith(".css")).map(async({css:o,file:c})=>{let l=await D({css:o,file:c});return d(l[1].replace(n,"")),l}));f("Generating purged html pages...");let L=s.filter(o=>typeof o.pathname=="string").map(o=>path.extname(o.pathname).toLowerCase()===".html"?path.join(n,o.pathname):path.join(n,o.pathname,"index.html"));await Promise.all(L.map(async o=>{let c=await E(o);for(let[l,w]of a)l!==w&&(c=P(o,c,l.replace(n,""),w.replace(n,"")));await u(o,c),d(o.replace(n,""));}));}}}}var we=H;module.exports=we;//# sourceMappingURL=index.cjs.map
1
+ 'use strict';var fs=require('fs'),path=require('path'),url=require('url'),purgecss=require('purgecss'),crypto=require('crypto'),promises=require('fs/promises');var b,S,$,O,R=!0;typeof process<"u"&&({FORCE_COLOR:b,NODE_DISABLE_COLORS:S,NO_COLOR:$,TERM:O}=process.env||{},R=process.stdout&&process.stdout.isTTY);var L={enabled:!S&&$==null&&O!=="dumb"&&(b!=null&&b!=="0"||R)};function e(n,t){let s=new RegExp(`\\x1b\\[${t}m`,"g"),g=`\x1B[${n}m`,i=`\x1B[${t}m`;return function(l){return !L.enabled||l==null?l:g+(~(""+l).indexOf(i)?l.replace(s,i+g):l)+i}}var y=e(2,22),E=e(31,39),A=e(32,39);async function P(n){try{return await promises.readFile(n,"utf8")}catch(t){return N(`Error reading file ${n}: ${t}`),""}}async function F(n,t){try{await promises.writeFile(n,t,"utf8");}catch(s){return N(`Error writing file ${n}: ${s}`),""}}async function x(n,t,s){await F(n,t),fs.existsSync(s)&&s!==n&&await promises.unlink(s);}function T(n,t){let s=crypto.createHash("sha256").update(t).digest("hex").slice(0,8);return `${n.slice(0,-13)}.${s}.css`}var D=new Intl.DateTimeFormat("en-us",{hour:"2-digit",minute:"2-digit",second:"2-digit",hour12:!1});function d(n){let t=D.format(new Date);console.log(y(t),A("\u25B6"),n);}function N(n){let t=D.format(new Date);console.error(y(t),E("\u25A0"),n);}var v="astro-purgecss",G=n=>n.match(/[\w-/:]+(?<!:)/g)||[];function W(n={}){let t;return {name:v,hooks:{"astro:config:done":({config:s})=>{t=s;},"astro:build:done":async({dir:s,pages:g,logger:i})=>{let l=t.output;i.info(`\u{1F4E6} Running in '${l}' mode`);let o=url.fileURLToPath(s),I=l!=="static";if(!o||!t.build.format||!t.build.assets){i.warn(`${v} requires the following astro.config options: 'outDir', 'build.format', 'build.assets'`);return}let f=(await new purgecss.PurgeCSS().purge({css:[path.join(o,"/**/*.css")],defaultExtractor:G,...n,content:[path.join(o,"/**/*.html"),path.join(o,"/**/*.js"),...n.content||[]]})).filter(({file:c})=>c?.endsWith(".css"));if(f.length===0){i.info("\u2139\uFE0F No CSS files found to process");return}if(i.info(`Found ${f.length} CSS ${f.length===1?"file":"files"} to process`),I){await Promise.all(f.map(async({css:c,file:r})=>{await x(r,c,r),d(r.replace(o,""));})),i.info("\u{1F389} Purging completed successfully!");return}let m=(await Promise.all(f.map(async({css:c,file:r})=>{if(!r.includes(t.build.assets)){await x(r,c,r);let w=r.replace(o,"");return d(w),{oldFilename:w,newFilename:w}}let p=T(r,c);await x(p,c,r);let h=r.replace(o,""),C=p.replace(o,"");return d(C),{oldFilename:h,newFilename:C}}))).filter(({oldFilename:c,newFilename:r})=>c!==r);if(m.length>0){i.info(`Updating ${m.length} CSS ${m.length===1?"reference":"references"} in HTML files...`);let c=g.filter(r=>typeof r.pathname=="string").map(r=>{let a=r.pathname;if(a==="")return path.join(o,"index.html");switch(t.build.format){case"file":return path.join(o,`${a}.html`);case"directory":return path.join(o,a,"index.html");case"preserve":let p=path.join(o,`${a}.html`);return fs.existsSync(p)?p:path.join(o,a,"index.html")}});await Promise.all(c.map(async r=>{let a=await P(r);for(let{oldFilename:p,newFilename:h}of m)a.includes(p)&&(a=a.replace(new RegExp(p,"g"),h));await F(r,a),d(r.replace(o,""));}));}i.info("\u{1F389} Purging completed successfully!");}}}}var Ae=W;module.exports=Ae;//# sourceMappingURL=index.cjs.map
2
2
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../node_modules/.pnpm/kleur@4.1.5/node_modules/kleur/colors.mjs","../src/utils.ts","../src/index.ts"],"names":["FORCE_COLOR","NODE_DISABLE_COLORS","NO_COLOR","TERM","isTTY","$","init","x","y","rgx","open","close","txt","dim","italic","red","green","yellow","blue","readFileContent","filePath","readFile","err","error","writeFileContent","content","writeFile","replaceValueInFile","searchValue","replaceValue","cleanPath","file","path","fileURLToPath","writeCssFile","css","hash","createHash","newFile","unlink","dt","success","message","date","headline","Plugin","options","dir","pages","outDir","purged","PurgeCSS","processed","htmlPages","e","page","extname","join","oldFilename","newFilename","src_default"],"mappings":"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","file":"index.cjs","sourcesContent":["let FORCE_COLOR, NODE_DISABLE_COLORS, NO_COLOR, TERM, isTTY=true;\nif (typeof process !== 'undefined') {\n\t({ FORCE_COLOR, NODE_DISABLE_COLORS, NO_COLOR, TERM } = process.env || {});\n\tisTTY = process.stdout && process.stdout.isTTY;\n}\n\nexport const $ = {\n\tenabled: !NODE_DISABLE_COLORS && NO_COLOR == null && TERM !== 'dumb' && (\n\t\tFORCE_COLOR != null && FORCE_COLOR !== '0' || isTTY\n\t)\n}\n\nfunction init(x, y) {\n\tlet rgx = new RegExp(`\\\\x1b\\\\[${y}m`, 'g');\n\tlet open = `\\x1b[${x}m`, close = `\\x1b[${y}m`;\n\n\treturn function (txt) {\n\t\tif (!$.enabled || txt == null) return txt;\n\t\treturn open + (!!~(''+txt).indexOf(close) ? txt.replace(rgx, close + open) : txt) + close;\n\t};\n}\n\n// modifiers\nexport const reset = init(0, 0);\nexport const bold = init(1, 22);\nexport const dim = init(2, 22);\nexport const italic = init(3, 23);\nexport const underline = init(4, 24);\nexport const inverse = init(7, 27);\nexport const hidden = init(8, 28);\nexport const strikethrough = init(9, 29);\n\n// colors\nexport const black = init(30, 39);\nexport const red = init(31, 39);\nexport const green = init(32, 39);\nexport const yellow = init(33, 39);\nexport const blue = init(34, 39);\nexport const magenta = init(35, 39);\nexport const cyan = init(36, 39);\nexport const white = init(37, 39);\nexport const gray = init(90, 39);\nexport const grey = init(90, 39);\n\n// background colors\nexport const bgBlack = init(40, 49);\nexport const bgRed = init(41, 49);\nexport const bgGreen = init(42, 49);\nexport const bgYellow = init(43, 49);\nexport const bgBlue = init(44, 49);\nexport const bgMagenta = init(45, 49);\nexport const bgCyan = init(46, 49);\nexport const bgWhite = init(47, 49);\n","import { blue, dim, green, red } from 'kleur/colors';\nimport { createHash } from 'node:crypto';\nimport { readFile, unlink, writeFile } from 'node:fs/promises';\nimport { fileURLToPath } from 'node:url';\n\nexport async function readFileContent(filePath: string): Promise<string> {\n try {\n const content = await readFile(filePath, 'utf8');\n return content;\n } catch (err) {\n error(`Error reading file ${filePath}: ${err}`);\n return '';\n }\n}\n\nexport async function writeFileContent(filePath: string, content: string) {\n try {\n await writeFile(filePath, content, 'utf8');\n } catch (err) {\n error(`Error writing file ${filePath}: ${err}`);\n return '';\n }\n}\n\nexport function replaceValueInFile(\n filePath: string,\n content: string,\n searchValue: string,\n replaceValue: string\n): string {\n try {\n if (content.includes(searchValue)) {\n return content.replace(new RegExp(searchValue, 'g'), replaceValue);\n }\n\n return content;\n } catch (err) {\n error(`Error processing file ${filePath}: ${err}`);\n return '';\n }\n}\n\n// Clean from extra slash on windows and trailing forward slash on non-windows\nexport function cleanPath(file: URL): string {\n let path = fileURLToPath(file);\n\n // Remove trailing forward slash if present\n path = path.replace(/\\/+$/, '');\n\n if (process.platform !== 'win32') return path;\n\n // Remove leading forward slash if present\n return path.replace(/^\\/+/, '');\n}\n\nexport async function writeCssFile({\n css,\n file\n}: {\n css: string;\n file: string;\n}) {\n // Skip re-hashing a file if it's not generated by Astro ex: assets/styles/light.css\n if (!file.includes('_astro')) {\n await writeFileContent(file, css);\n return [file, file];\n }\n\n // Get content hash before writing to file\n const hash = createHash('sha256').update(css).digest('hex').substring(0, 8);\n\n // Generate new file name with hash\n // Astro orignal hash is 8 characters long\n const newFile = `${file.slice(0, -13)}.${hash}.css`;\n\n // Write purged CSS to new file\n await writeFileContent(newFile, css);\n\n // Remove old file\n await unlink(file);\n\n return [file, newFile];\n}\n\nexport const dt = new Intl.DateTimeFormat('en-us', {\n hour: '2-digit',\n minute: '2-digit',\n second: '2-digit',\n hour12: false\n});\n\nexport function success(message: string) {\n const date = dt.format(new Date());\n console.log(dim(date), green('▶'), message);\n}\n\nexport function error(message: string) {\n const date = dt.format(new Date());\n console.error(dim(date), red('■'), message);\n}\n\nexport function headline(message: string) {\n const date = dt.format(new Date());\n console.log(dim(date), blue('[purgecss]'), message);\n}\n","import type { AstroIntegration } from 'astro';\nimport { extname, join } from 'node:path';\nimport { PurgeCSS, type UserDefinedOptions } from 'purgecss';\n\nimport {\n cleanPath,\n headline,\n readFileContent,\n replaceValueInFile,\n success,\n writeCssFile,\n writeFileContent\n} from './utils';\n\nexport interface PurgeCSSOptions extends Partial<UserDefinedOptions> {}\n\nfunction Plugin(options: PurgeCSSOptions = {}): AstroIntegration {\n return {\n name: 'astro-purgecss',\n hooks: {\n 'astro:build:done': async ({ dir, pages }) => {\n headline('Generating purged css files...');\n\n const outDir = cleanPath(dir);\n const purged = await new PurgeCSS().purge({\n css: [`${outDir}/**/*.css`],\n defaultExtractor: (content) => content.match(/[\\w-/:]+(?<!:)/g) || [],\n ...options,\n content: [\n `${outDir}/**/*.html`,\n `${outDir}/**/*.js`,\n ...(options.content || [])\n ]\n });\n\n const processed = await Promise.all(\n purged\n .filter(({ file }) => file?.endsWith('.css'))\n .map(async ({ css, file }) => {\n const processed = await writeCssFile({ css, file } as {\n css: string;\n file: string;\n });\n success(processed[1].replace(outDir, ''));\n\n return processed;\n })\n );\n\n headline('Generating purged html pages...');\n const htmlPages = pages\n .filter((e: any) => typeof e.pathname == 'string')\n .map((page) => {\n // see: https://docs.astro.build/en/reference/configuration-reference/#buildformat\n const isHtmlFile = extname(page.pathname).toLowerCase() === '.html';\n return isHtmlFile\n ? join(outDir, page.pathname)\n : join(outDir, page.pathname, 'index.html');\n });\n\n await Promise.all(\n htmlPages.map(async (page) => {\n let content = await readFileContent(page);\n\n for (const [oldFilename, newFilename] of processed) {\n // Replace only if name of the old file\n // is different from name of the new file (hash changes)\n if (oldFilename !== newFilename) {\n content = replaceValueInFile(\n page,\n content,\n oldFilename.replace(outDir, ''),\n newFilename.replace(outDir, '')\n );\n }\n }\n await writeFileContent(page, content);\n success(page.replace(outDir, ''));\n })\n );\n }\n }\n };\n}\n\nexport default Plugin;\n"]}
1
+ {"version":3,"sources":["../../../node_modules/.pnpm/kleur@4.1.5/node_modules/kleur/colors.mjs","../src/utils.ts","../src/index.ts"],"names":["FORCE_COLOR","NODE_DISABLE_COLORS","NO_COLOR","TERM","isTTY","$","init","x","y","rgx","open","close","txt","dim","red","green","readFileContent","filePath","readFile","err","error","writeFileContent","content","writeFile","writeCssFile","newFilePath","css","oldFilePath","existsSync","unlink","generateFileHash","hash","createHash","dt","success","message","date","INTEGRATION_NAME","defaultExtractor","Plugin","options","config","cfg","dir","pages","logger","buildMode","outDir","fileURLToPath","isSSR","purgedCssFiles","PurgeCSS","join","file","changedFiles","relativePath","hashedFilename","relativeOldPath","relativeNewPath","oldFilename","newFilename","htmlFiles","page","pathname","directFile","htmlFile","src_default"],"mappings":"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","file":"index.cjs","sourcesContent":["let FORCE_COLOR, NODE_DISABLE_COLORS, NO_COLOR, TERM, isTTY=true;\nif (typeof process !== 'undefined') {\n\t({ FORCE_COLOR, NODE_DISABLE_COLORS, NO_COLOR, TERM } = process.env || {});\n\tisTTY = process.stdout && process.stdout.isTTY;\n}\n\nexport const $ = {\n\tenabled: !NODE_DISABLE_COLORS && NO_COLOR == null && TERM !== 'dumb' && (\n\t\tFORCE_COLOR != null && FORCE_COLOR !== '0' || isTTY\n\t)\n}\n\nfunction init(x, y) {\n\tlet rgx = new RegExp(`\\\\x1b\\\\[${y}m`, 'g');\n\tlet open = `\\x1b[${x}m`, close = `\\x1b[${y}m`;\n\n\treturn function (txt) {\n\t\tif (!$.enabled || txt == null) return txt;\n\t\treturn open + (!!~(''+txt).indexOf(close) ? txt.replace(rgx, close + open) : txt) + close;\n\t};\n}\n\n// modifiers\nexport const reset = init(0, 0);\nexport const bold = init(1, 22);\nexport const dim = init(2, 22);\nexport const italic = init(3, 23);\nexport const underline = init(4, 24);\nexport const inverse = init(7, 27);\nexport const hidden = init(8, 28);\nexport const strikethrough = init(9, 29);\n\n// colors\nexport const black = init(30, 39);\nexport const red = init(31, 39);\nexport const green = init(32, 39);\nexport const yellow = init(33, 39);\nexport const blue = init(34, 39);\nexport const magenta = init(35, 39);\nexport const cyan = init(36, 39);\nexport const white = init(37, 39);\nexport const gray = init(90, 39);\nexport const grey = init(90, 39);\n\n// background colors\nexport const bgBlack = init(40, 49);\nexport const bgRed = init(41, 49);\nexport const bgGreen = init(42, 49);\nexport const bgYellow = init(43, 49);\nexport const bgBlue = init(44, 49);\nexport const bgMagenta = init(45, 49);\nexport const bgCyan = init(46, 49);\nexport const bgWhite = init(47, 49);\n","import { dim, green, red } from 'kleur/colors';\nimport { createHash } from 'node:crypto';\nimport { existsSync } from 'node:fs';\nimport { readFile, unlink, writeFile } from 'node:fs/promises';\n\nexport async function readFileContent(filePath: string): Promise<string> {\n try {\n const content = await readFile(filePath, 'utf8');\n return content;\n } catch (err) {\n error(`Error reading file ${filePath}: ${err}`);\n return '';\n }\n}\n\nexport async function writeFileContent(filePath: string, content: string) {\n try {\n await writeFile(filePath, content, 'utf8');\n } catch (err) {\n error(`Error writing file ${filePath}: ${err}`);\n return '';\n }\n}\n\nexport async function writeCssFile(\n newFilePath: string,\n css: string,\n oldFilePath: string\n) {\n await writeFileContent(newFilePath, css);\n\n // Remove old file if it exists and is different from new file\n if (existsSync(oldFilePath) && oldFilePath !== newFilePath) {\n await unlink(oldFilePath);\n }\n}\n\nexport function generateFileHash(filePath: string, content: string) {\n // Get content hash before writing to file\n const hash = createHash('sha256').update(content).digest('hex').slice(0, 8);\n\n // Generate new file name with hash\n // Astro orignal hash is 8 characters long\n return `${filePath.slice(0, -13)}.${hash}.css`;\n}\n\nexport const dt = new Intl.DateTimeFormat('en-us', {\n hour: '2-digit',\n minute: '2-digit',\n second: '2-digit',\n hour12: false\n});\n\nexport function success(message: string) {\n const date = dt.format(new Date());\n console.log(dim(date), green('▶'), message);\n}\n\nexport function error(message: string) {\n const date = dt.format(new Date());\n console.error(dim(date), red('■'), message);\n}\n","import type { AstroConfig, AstroIntegration } from 'astro';\nimport { existsSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { PurgeCSS, type UserDefinedOptions } from 'purgecss';\n\nimport {\n generateFileHash,\n readFileContent,\n success,\n writeCssFile,\n writeFileContent\n} from './utils';\n\n/**\n * Extended PurgeCSS options interface that allows partial configuration\n * of the standard PurgeCSS options\n */\nexport interface PurgeCSSOptions extends Partial<UserDefinedOptions> {}\n\nconst INTEGRATION_NAME = 'astro-purgecss' as const;\n\n/**\n * default extractor to handle various CSS selector patterns\n * @param content string\n */\nconst defaultExtractor = (content: string) =>\n content.match(/[\\w-/:]+(?<!:)/g) || [];\n\n/**\n * Astro integration for PurgeCSS that removes unused CSS from the final build\n * @param options - PurgeCSS configuration options\n * @returns AstroIntegration - The configured Astro integration\n */\nfunction Plugin(options: PurgeCSSOptions = {}): AstroIntegration {\n let config: AstroConfig;\n\n return {\n name: INTEGRATION_NAME,\n hooks: {\n 'astro:config:done': ({ config: cfg }) => {\n config = cfg;\n },\n 'astro:build:done': async ({ dir, pages, logger }) => {\n const buildMode = config.output;\n logger.info(`📦 Running in '${buildMode}' mode`);\n\n // Convert the URL to a filesystem path\n const outDir = fileURLToPath(dir);\n\n // Used to skip file rehashing for SSR/Hybrid modes\n const isSSR = buildMode !== 'static';\n\n // Validate required Astro configuration\n if (!outDir || !config.build.format || !config.build.assets) {\n logger.warn(\n `${INTEGRATION_NAME} requires the following astro.config options: 'outDir', 'build.format', 'build.assets'`\n );\n return;\n }\n\n // Run PurgeCSS on all CSS files\n const purgeResults = await new PurgeCSS().purge({\n css: [join(outDir, '/**/*.css')],\n defaultExtractor,\n ...options,\n content: [\n join(outDir, '/**/*.html'),\n join(outDir, '/**/*.js'),\n ...(options.content || [])\n ]\n });\n\n // Filter out non-CSS files from purge results\n const purgedCssFiles = purgeResults.filter(({ file }) =>\n file?.endsWith('.css')\n ) as Array<{\n css: string;\n file: string;\n }>;\n\n if (purgedCssFiles.length === 0) {\n logger.info('ℹ️ No CSS files found to process');\n return;\n }\n\n logger.info(\n `Found ${purgedCssFiles.length} CSS ${purgedCssFiles.length === 1 ? 'file' : 'files'} to process`\n );\n\n // Handle SSR/Hybrid mode\n if (isSSR) {\n await Promise.all(\n purgedCssFiles.map(async ({ css, file }) => {\n await writeCssFile(file, css, file);\n success(file.replace(outDir, ''));\n })\n );\n logger.info('🎉 Purging completed successfully!');\n return;\n }\n\n // Process files for static mode with content hashing\n let processedFiles = await Promise.all(\n purgedCssFiles.map(async ({ css, file }) => {\n const isAssetFile = file.includes(config.build.assets);\n\n // Skip rehashing for non-asset files (not generated by astro)\n // ex: assets/styles/light.css\n if (!isAssetFile) {\n await writeCssFile(file, css, file);\n const relativePath = file.replace(outDir, '');\n success(relativePath);\n return {\n oldFilename: relativePath,\n newFilename: relativePath\n };\n }\n\n // Generate new filename with content hash\n const hashedFilename = generateFileHash(file, css);\n await writeCssFile(hashedFilename, css, file);\n\n const relativeOldPath = file.replace(outDir, '');\n const relativeNewPath = hashedFilename.replace(outDir, '');\n success(relativeNewPath);\n\n return {\n oldFilename: relativeOldPath,\n newFilename: relativeNewPath\n };\n })\n );\n\n // Filter to only get files that actually changed\n const changedFiles = processedFiles.filter(\n ({ oldFilename, newFilename }) => oldFilename !== newFilename\n );\n\n if (changedFiles.length > 0) {\n logger.info(\n `Updating ${changedFiles.length} CSS ${changedFiles.length === 1 ? 'reference' : 'references'} in HTML files...`\n );\n // Get all HTML pages based on build format\n const htmlFiles = pages\n .filter((page) => typeof page.pathname === 'string')\n .map((page) => {\n const pathname = page.pathname as string;\n\n // Handle root/index page\n if (pathname === '') {\n return join(outDir, 'index.html');\n }\n\n switch (config.build.format) {\n case 'file':\n // Format: /blog -> /blog.html\n return join(outDir, `${pathname}.html`);\n\n case 'directory':\n // Format: /blog -> /blog/index.html\n return join(outDir, pathname, 'index.html');\n\n case 'preserve':\n // Check if direct HTML file exists, otherwise use directory format\n const directFile = join(outDir, `${pathname}.html`);\n return existsSync(directFile)\n ? directFile\n : join(outDir, pathname, 'index.html');\n }\n });\n\n // Update CSS references in HTML files\n await Promise.all(\n htmlFiles.map(async (htmlFile) => {\n let content = await readFileContent(htmlFile);\n\n for (const { oldFilename, newFilename } of changedFiles) {\n if (content.includes(oldFilename)) {\n content = content.replace(\n new RegExp(oldFilename, 'g'),\n newFilename\n );\n }\n }\n\n await writeFileContent(htmlFile, content);\n success(htmlFile.replace(outDir, ''));\n })\n );\n }\n\n logger.info('🎉 Purging completed successfully!');\n }\n }\n };\n}\n\nexport default Plugin;\n"]}
package/dist/index.d.cts CHANGED
@@ -1,8 +1,17 @@
1
1
  import { AstroIntegration } from 'astro';
2
2
  import { UserDefinedOptions } from 'purgecss';
3
3
 
4
+ /**
5
+ * Extended PurgeCSS options interface that allows partial configuration
6
+ * of the standard PurgeCSS options
7
+ */
4
8
  interface PurgeCSSOptions extends Partial<UserDefinedOptions> {
5
9
  }
10
+ /**
11
+ * Astro integration for PurgeCSS that removes unused CSS from the final build
12
+ * @param options - PurgeCSS configuration options
13
+ * @returns AstroIntegration - The configured Astro integration
14
+ */
6
15
  declare function Plugin(options?: PurgeCSSOptions): AstroIntegration;
7
16
 
8
17
  export { type PurgeCSSOptions, Plugin as default };
package/dist/index.d.ts CHANGED
@@ -1,8 +1,17 @@
1
1
  import { AstroIntegration } from 'astro';
2
2
  import { UserDefinedOptions } from 'purgecss';
3
3
 
4
+ /**
5
+ * Extended PurgeCSS options interface that allows partial configuration
6
+ * of the standard PurgeCSS options
7
+ */
4
8
  interface PurgeCSSOptions extends Partial<UserDefinedOptions> {
5
9
  }
10
+ /**
11
+ * Astro integration for PurgeCSS that removes unused CSS from the final build
12
+ * @param options - PurgeCSS configuration options
13
+ * @returns AstroIntegration - The configured Astro integration
14
+ */
6
15
  declare function Plugin(options?: PurgeCSSOptions): AstroIntegration;
7
16
 
8
17
  export { type PurgeCSSOptions, Plugin as default };
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- import {extname,join}from'node:path';import {PurgeCSS}from'purgecss';import {createHash}from'node:crypto';import {readFile,writeFile,unlink}from'node:fs/promises';import {fileURLToPath}from'node:url';var g,h,b,y,F=!0;typeof process<"u"&&({FORCE_COLOR:g,NODE_DISABLE_COLORS:h,NO_COLOR:b,TERM:y}=process.env||{},F=process.stdout&&process.stdout.isTTY);var T={enabled:!h&&b==null&&y!=="dumb"&&(g!=null&&g!=="0"||F)};function t(r,e){let s=new RegExp(`\\x1b\\[${e}m`,"g"),n=`\x1B[${r}m`,i=`\x1B[${e}m`;return function(a){return !T.enabled||a==null?a:n+(~(""+a).indexOf(i)?a.replace(s,i+n):a)+i}}var p=t(2,22),$=t(31,39),C=t(32,39),O=t(34,39);async function E(r){try{return await readFile(r,"utf8")}catch(e){return x(`Error reading file ${r}: ${e}`),""}}async function u(r,e){try{await writeFile(r,e,"utf8");}catch(s){return x(`Error writing file ${r}: ${s}`),""}}function P(r,e,s,n){try{return e.includes(s)?e.replace(new RegExp(s,"g"),n):e}catch(i){return x(`Error processing file ${r}: ${i}`),""}}function R(r){let e=fileURLToPath(r);return e=e.replace(/\/+$/,""),process.platform!=="win32"?e:e.replace(/^\/+/,"")}async function D({css:r,file:e}){if(!e.includes("_astro"))return await u(e,r),[e,e];let s=createHash("sha256").update(r).digest("hex").substring(0,8),n=`${e.slice(0,-13)}.${s}.css`;return await u(n,r),await unlink(e),[e,n]}var m=new Intl.DateTimeFormat("en-us",{hour:"2-digit",minute:"2-digit",second:"2-digit",hour12:!1});function d(r){let e=m.format(new Date);console.log(p(e),C("\u25B6"),r);}function x(r){let e=m.format(new Date);console.error(p(e),$("\u25A0"),r);}function f(r){let e=m.format(new Date);console.log(p(e),O("[purgecss]"),r);}function H(r={}){return {name:"astro-purgecss",hooks:{"astro:build:done":async({dir:e,pages:s})=>{f("Generating purged css files...");let n=R(e),i=await new PurgeCSS().purge({css:[`${n}/**/*.css`],defaultExtractor:o=>o.match(/[\w-/:]+(?<!:)/g)||[],...r,content:[`${n}/**/*.html`,`${n}/**/*.js`,...r.content||[]]}),a=await Promise.all(i.filter(({file:o})=>o?.endsWith(".css")).map(async({css:o,file:c})=>{let l=await D({css:o,file:c});return d(l[1].replace(n,"")),l}));f("Generating purged html pages...");let L=s.filter(o=>typeof o.pathname=="string").map(o=>extname(o.pathname).toLowerCase()===".html"?join(n,o.pathname):join(n,o.pathname,"index.html"));await Promise.all(L.map(async o=>{let c=await E(o);for(let[l,w]of a)l!==w&&(c=P(o,c,l.replace(n,""),w.replace(n,"")));await u(o,c),d(o.replace(n,""));}));}}}}var we=H;export{we as default};//# sourceMappingURL=index.js.map
1
+ import {existsSync}from'node:fs';import {join}from'node:path';import {fileURLToPath}from'node:url';import {PurgeCSS}from'purgecss';import {createHash}from'node:crypto';import {writeFile,unlink,readFile}from'node:fs/promises';var b,S,$,O,R=!0;typeof process<"u"&&({FORCE_COLOR:b,NODE_DISABLE_COLORS:S,NO_COLOR:$,TERM:O}=process.env||{},R=process.stdout&&process.stdout.isTTY);var L={enabled:!S&&$==null&&O!=="dumb"&&(b!=null&&b!=="0"||R)};function e(n,t){let s=new RegExp(`\\x1b\\[${t}m`,"g"),g=`\x1B[${n}m`,i=`\x1B[${t}m`;return function(l){return !L.enabled||l==null?l:g+(~(""+l).indexOf(i)?l.replace(s,i+g):l)+i}}var y=e(2,22),E=e(31,39),A=e(32,39);async function P(n){try{return await readFile(n,"utf8")}catch(t){return N(`Error reading file ${n}: ${t}`),""}}async function F(n,t){try{await writeFile(n,t,"utf8");}catch(s){return N(`Error writing file ${n}: ${s}`),""}}async function x(n,t,s){await F(n,t),existsSync(s)&&s!==n&&await unlink(s);}function T(n,t){let s=createHash("sha256").update(t).digest("hex").slice(0,8);return `${n.slice(0,-13)}.${s}.css`}var D=new Intl.DateTimeFormat("en-us",{hour:"2-digit",minute:"2-digit",second:"2-digit",hour12:!1});function d(n){let t=D.format(new Date);console.log(y(t),A("\u25B6"),n);}function N(n){let t=D.format(new Date);console.error(y(t),E("\u25A0"),n);}var v="astro-purgecss",G=n=>n.match(/[\w-/:]+(?<!:)/g)||[];function W(n={}){let t;return {name:v,hooks:{"astro:config:done":({config:s})=>{t=s;},"astro:build:done":async({dir:s,pages:g,logger:i})=>{let l=t.output;i.info(`\u{1F4E6} Running in '${l}' mode`);let o=fileURLToPath(s),I=l!=="static";if(!o||!t.build.format||!t.build.assets){i.warn(`${v} requires the following astro.config options: 'outDir', 'build.format', 'build.assets'`);return}let f=(await new PurgeCSS().purge({css:[join(o,"/**/*.css")],defaultExtractor:G,...n,content:[join(o,"/**/*.html"),join(o,"/**/*.js"),...n.content||[]]})).filter(({file:c})=>c?.endsWith(".css"));if(f.length===0){i.info("\u2139\uFE0F No CSS files found to process");return}if(i.info(`Found ${f.length} CSS ${f.length===1?"file":"files"} to process`),I){await Promise.all(f.map(async({css:c,file:r})=>{await x(r,c,r),d(r.replace(o,""));})),i.info("\u{1F389} Purging completed successfully!");return}let m=(await Promise.all(f.map(async({css:c,file:r})=>{if(!r.includes(t.build.assets)){await x(r,c,r);let w=r.replace(o,"");return d(w),{oldFilename:w,newFilename:w}}let p=T(r,c);await x(p,c,r);let h=r.replace(o,""),C=p.replace(o,"");return d(C),{oldFilename:h,newFilename:C}}))).filter(({oldFilename:c,newFilename:r})=>c!==r);if(m.length>0){i.info(`Updating ${m.length} CSS ${m.length===1?"reference":"references"} in HTML files...`);let c=g.filter(r=>typeof r.pathname=="string").map(r=>{let a=r.pathname;if(a==="")return join(o,"index.html");switch(t.build.format){case"file":return join(o,`${a}.html`);case"directory":return join(o,a,"index.html");case"preserve":let p=join(o,`${a}.html`);return existsSync(p)?p:join(o,a,"index.html")}});await Promise.all(c.map(async r=>{let a=await P(r);for(let{oldFilename:p,newFilename:h}of m)a.includes(p)&&(a=a.replace(new RegExp(p,"g"),h));await F(r,a),d(r.replace(o,""));}));}i.info("\u{1F389} Purging completed successfully!");}}}}var Ae=W;export{Ae as default};//# sourceMappingURL=index.js.map
2
2
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../node_modules/.pnpm/kleur@4.1.5/node_modules/kleur/colors.mjs","../src/utils.ts","../src/index.ts"],"names":["FORCE_COLOR","NODE_DISABLE_COLORS","NO_COLOR","TERM","isTTY","$","init","x","y","rgx","open","close","txt","dim","italic","red","green","yellow","blue","readFileContent","filePath","readFile","err","error","writeFileContent","content","writeFile","replaceValueInFile","searchValue","replaceValue","cleanPath","file","path","fileURLToPath","writeCssFile","css","hash","createHash","newFile","unlink","dt","success","message","date","headline","Plugin","options","dir","pages","outDir","purged","PurgeCSS","processed","htmlPages","e","page","extname","join","oldFilename","newFilename","src_default"],"mappings":"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","file":"index.js","sourcesContent":["let FORCE_COLOR, NODE_DISABLE_COLORS, NO_COLOR, TERM, isTTY=true;\nif (typeof process !== 'undefined') {\n\t({ FORCE_COLOR, NODE_DISABLE_COLORS, NO_COLOR, TERM } = process.env || {});\n\tisTTY = process.stdout && process.stdout.isTTY;\n}\n\nexport const $ = {\n\tenabled: !NODE_DISABLE_COLORS && NO_COLOR == null && TERM !== 'dumb' && (\n\t\tFORCE_COLOR != null && FORCE_COLOR !== '0' || isTTY\n\t)\n}\n\nfunction init(x, y) {\n\tlet rgx = new RegExp(`\\\\x1b\\\\[${y}m`, 'g');\n\tlet open = `\\x1b[${x}m`, close = `\\x1b[${y}m`;\n\n\treturn function (txt) {\n\t\tif (!$.enabled || txt == null) return txt;\n\t\treturn open + (!!~(''+txt).indexOf(close) ? txt.replace(rgx, close + open) : txt) + close;\n\t};\n}\n\n// modifiers\nexport const reset = init(0, 0);\nexport const bold = init(1, 22);\nexport const dim = init(2, 22);\nexport const italic = init(3, 23);\nexport const underline = init(4, 24);\nexport const inverse = init(7, 27);\nexport const hidden = init(8, 28);\nexport const strikethrough = init(9, 29);\n\n// colors\nexport const black = init(30, 39);\nexport const red = init(31, 39);\nexport const green = init(32, 39);\nexport const yellow = init(33, 39);\nexport const blue = init(34, 39);\nexport const magenta = init(35, 39);\nexport const cyan = init(36, 39);\nexport const white = init(37, 39);\nexport const gray = init(90, 39);\nexport const grey = init(90, 39);\n\n// background colors\nexport const bgBlack = init(40, 49);\nexport const bgRed = init(41, 49);\nexport const bgGreen = init(42, 49);\nexport const bgYellow = init(43, 49);\nexport const bgBlue = init(44, 49);\nexport const bgMagenta = init(45, 49);\nexport const bgCyan = init(46, 49);\nexport const bgWhite = init(47, 49);\n","import { blue, dim, green, red } from 'kleur/colors';\nimport { createHash } from 'node:crypto';\nimport { readFile, unlink, writeFile } from 'node:fs/promises';\nimport { fileURLToPath } from 'node:url';\n\nexport async function readFileContent(filePath: string): Promise<string> {\n try {\n const content = await readFile(filePath, 'utf8');\n return content;\n } catch (err) {\n error(`Error reading file ${filePath}: ${err}`);\n return '';\n }\n}\n\nexport async function writeFileContent(filePath: string, content: string) {\n try {\n await writeFile(filePath, content, 'utf8');\n } catch (err) {\n error(`Error writing file ${filePath}: ${err}`);\n return '';\n }\n}\n\nexport function replaceValueInFile(\n filePath: string,\n content: string,\n searchValue: string,\n replaceValue: string\n): string {\n try {\n if (content.includes(searchValue)) {\n return content.replace(new RegExp(searchValue, 'g'), replaceValue);\n }\n\n return content;\n } catch (err) {\n error(`Error processing file ${filePath}: ${err}`);\n return '';\n }\n}\n\n// Clean from extra slash on windows and trailing forward slash on non-windows\nexport function cleanPath(file: URL): string {\n let path = fileURLToPath(file);\n\n // Remove trailing forward slash if present\n path = path.replace(/\\/+$/, '');\n\n if (process.platform !== 'win32') return path;\n\n // Remove leading forward slash if present\n return path.replace(/^\\/+/, '');\n}\n\nexport async function writeCssFile({\n css,\n file\n}: {\n css: string;\n file: string;\n}) {\n // Skip re-hashing a file if it's not generated by Astro ex: assets/styles/light.css\n if (!file.includes('_astro')) {\n await writeFileContent(file, css);\n return [file, file];\n }\n\n // Get content hash before writing to file\n const hash = createHash('sha256').update(css).digest('hex').substring(0, 8);\n\n // Generate new file name with hash\n // Astro orignal hash is 8 characters long\n const newFile = `${file.slice(0, -13)}.${hash}.css`;\n\n // Write purged CSS to new file\n await writeFileContent(newFile, css);\n\n // Remove old file\n await unlink(file);\n\n return [file, newFile];\n}\n\nexport const dt = new Intl.DateTimeFormat('en-us', {\n hour: '2-digit',\n minute: '2-digit',\n second: '2-digit',\n hour12: false\n});\n\nexport function success(message: string) {\n const date = dt.format(new Date());\n console.log(dim(date), green('▶'), message);\n}\n\nexport function error(message: string) {\n const date = dt.format(new Date());\n console.error(dim(date), red('■'), message);\n}\n\nexport function headline(message: string) {\n const date = dt.format(new Date());\n console.log(dim(date), blue('[purgecss]'), message);\n}\n","import type { AstroIntegration } from 'astro';\nimport { extname, join } from 'node:path';\nimport { PurgeCSS, type UserDefinedOptions } from 'purgecss';\n\nimport {\n cleanPath,\n headline,\n readFileContent,\n replaceValueInFile,\n success,\n writeCssFile,\n writeFileContent\n} from './utils';\n\nexport interface PurgeCSSOptions extends Partial<UserDefinedOptions> {}\n\nfunction Plugin(options: PurgeCSSOptions = {}): AstroIntegration {\n return {\n name: 'astro-purgecss',\n hooks: {\n 'astro:build:done': async ({ dir, pages }) => {\n headline('Generating purged css files...');\n\n const outDir = cleanPath(dir);\n const purged = await new PurgeCSS().purge({\n css: [`${outDir}/**/*.css`],\n defaultExtractor: (content) => content.match(/[\\w-/:]+(?<!:)/g) || [],\n ...options,\n content: [\n `${outDir}/**/*.html`,\n `${outDir}/**/*.js`,\n ...(options.content || [])\n ]\n });\n\n const processed = await Promise.all(\n purged\n .filter(({ file }) => file?.endsWith('.css'))\n .map(async ({ css, file }) => {\n const processed = await writeCssFile({ css, file } as {\n css: string;\n file: string;\n });\n success(processed[1].replace(outDir, ''));\n\n return processed;\n })\n );\n\n headline('Generating purged html pages...');\n const htmlPages = pages\n .filter((e: any) => typeof e.pathname == 'string')\n .map((page) => {\n // see: https://docs.astro.build/en/reference/configuration-reference/#buildformat\n const isHtmlFile = extname(page.pathname).toLowerCase() === '.html';\n return isHtmlFile\n ? join(outDir, page.pathname)\n : join(outDir, page.pathname, 'index.html');\n });\n\n await Promise.all(\n htmlPages.map(async (page) => {\n let content = await readFileContent(page);\n\n for (const [oldFilename, newFilename] of processed) {\n // Replace only if name of the old file\n // is different from name of the new file (hash changes)\n if (oldFilename !== newFilename) {\n content = replaceValueInFile(\n page,\n content,\n oldFilename.replace(outDir, ''),\n newFilename.replace(outDir, '')\n );\n }\n }\n await writeFileContent(page, content);\n success(page.replace(outDir, ''));\n })\n );\n }\n }\n };\n}\n\nexport default Plugin;\n"]}
1
+ {"version":3,"sources":["../../../node_modules/.pnpm/kleur@4.1.5/node_modules/kleur/colors.mjs","../src/utils.ts","../src/index.ts"],"names":["FORCE_COLOR","NODE_DISABLE_COLORS","NO_COLOR","TERM","isTTY","$","init","x","y","rgx","open","close","txt","dim","red","green","readFileContent","filePath","readFile","err","error","writeFileContent","content","writeFile","writeCssFile","newFilePath","css","oldFilePath","existsSync","unlink","generateFileHash","hash","createHash","dt","success","message","date","INTEGRATION_NAME","defaultExtractor","Plugin","options","config","cfg","dir","pages","logger","buildMode","outDir","fileURLToPath","isSSR","purgedCssFiles","PurgeCSS","join","file","changedFiles","relativePath","hashedFilename","relativeOldPath","relativeNewPath","oldFilename","newFilename","htmlFiles","page","pathname","directFile","htmlFile","src_default"],"mappings":"iOAAA,IAAIA,CAAaC,CAAAA,CAAAA,CAAqBC,EAAUC,CAAMC,CAAAA,CAAAA,CAAM,CACxD,CAAA,CAAA,OAAO,OAAY,CAAA,GAAA,GACrB,CAAE,WAAAJ,CAAAA,CAAAA,CAAa,oBAAAC,CAAqB,CAAA,QAAA,CAAAC,EAAU,IAAAC,CAAAA,CAAK,CAAI,CAAA,OAAA,CAAQ,GAAO,EAAA,GACvEC,CAAQ,CAAA,OAAA,CAAQ,MAAU,EAAA,OAAA,CAAQ,MAAO,CAAA,KAAA,CAAA,CAGnC,IAAMC,CAAI,CAAA,CAChB,OAAS,CAAA,CAACJ,CAAuBC,EAAAA,CAAAA,EAAY,MAAQC,CAAS,GAAA,MAAA,GAC7DH,GAAe,IAAQA,EAAAA,CAAAA,GAAgB,KAAOI,CAEhD,CAAA,CAAA,CAEA,SAASE,CAAAA,CAAKC,CAAGC,CAAAA,CAAAA,CAAG,CACnB,IAAIC,CAAAA,CAAM,IAAI,MAAA,CAAO,CAAWD,QAAAA,EAAAA,CAAC,IAAK,GAAG,CAAA,CACrCE,CAAO,CAAA,CAAA,KAAA,EAAQH,CAAC,CAAA,CAAA,CAAA,CAAKI,EAAQ,CAAQH,KAAAA,EAAAA,CAAC,IAE1C,OAAO,SAAUI,EAAK,CACrB,OAAI,CAACP,CAAAA,CAAE,OAAWO,EAAAA,CAAAA,EAAO,KAAaA,CAC/BF,CAAAA,CAAAA,EAAU,CAAE,CAAA,EAAA,CAAGE,CAAK,EAAA,OAAA,CAAQD,CAAK,CAAIC,CAAAA,CAAAA,CAAI,OAAQH,CAAAA,CAAAA,CAAKE,CAAQD,CAAAA,CAAI,EAAIE,CAAOD,CAAAA,CAAAA,CACrF,CACD,CAGO,IAEME,CAAMP,CAAAA,CAAAA,CAAK,CAAG,CAAA,EAAE,EAShBQ,CAAAA,CAAMR,CAAK,CAAA,EAAA,CAAI,EAAE,CACjBS,CAAAA,CAAAA,CAAQT,EAAK,EAAI,CAAA,EAAE,EC9BhC,eAAsBU,CAAAA,CAAgBC,CAAmC,CAAA,CACvE,GAAI,CAEF,OADgB,MAAMC,QAAAA,CAASD,CAAU,CAAA,MAAM,CAEjD,CAASE,MAAAA,CAAAA,CAAK,CACZ,OAAAC,CAAAA,CAAM,sBAAsBH,CAAQ,CAAA,EAAA,EAAKE,CAAG,CAAA,CAAE,CACvC,CAAA,EACT,CACF,CAEA,eAAsBE,CAAiBJ,CAAAA,CAAAA,CAAkBK,CAAiB,CAAA,CACxE,GAAI,CACF,MAAMC,SAAUN,CAAAA,CAAAA,CAAUK,CAAS,CAAA,MAAM,EAC3C,CAASH,MAAAA,CAAAA,CAAK,CACZ,OAAAC,CAAAA,CAAM,sBAAsBH,CAAQ,CAAA,EAAA,EAAKE,CAAG,CAAA,CAAE,CACvC,CAAA,EACT,CACF,CAEA,eAAsBK,CACpBC,CAAAA,CAAAA,CACAC,CACAC,CAAAA,CAAAA,CACA,CACA,MAAMN,CAAAA,CAAiBI,CAAaC,CAAAA,CAAG,CAGnCE,CAAAA,UAAAA,CAAWD,CAAW,CAAKA,EAAAA,CAAAA,GAAgBF,GAC7C,MAAMI,MAAAA,CAAOF,CAAW,EAE5B,CAEO,SAASG,CAAAA,CAAiBb,CAAkBK,CAAAA,CAAAA,CAAiB,CAElE,IAAMS,CAAAA,CAAOC,UAAW,CAAA,QAAQ,CAAE,CAAA,MAAA,CAAOV,CAAO,CAAE,CAAA,MAAA,CAAO,KAAK,CAAA,CAAE,KAAM,CAAA,CAAA,CAAG,CAAC,CAI1E,CAAA,OAAO,GAAGL,CAAS,CAAA,KAAA,CAAM,EAAG,CAAG,EAAA,CAAC,CAAIc,CAAAA,EAAAA,CAAI,CAC1C,IAAA,CAAA,CAEO,IAAME,CAAK,CAAA,IAAI,IAAK,CAAA,cAAA,CAAe,OAAS,CAAA,CACjD,KAAM,SACN,CAAA,MAAA,CAAQ,SACR,CAAA,MAAA,CAAQ,SACR,CAAA,MAAA,CAAQ,EACV,CAAC,CAAA,CAEM,SAASC,CAAQC,CAAAA,CAAAA,CAAiB,CACvC,IAAMC,CAAAA,CAAOH,CAAG,CAAA,MAAA,CAAO,IAAI,IAAM,EACjC,OAAQ,CAAA,GAAA,CAAIpB,CAAIuB,CAAAA,CAAI,CAAGrB,CAAAA,CAAAA,CAAM,QAAG,CAAGoB,CAAAA,CAAO,EAC5C,CAEO,SAASf,CAAAA,CAAMe,EAAiB,CACrC,IAAMC,CAAOH,CAAAA,CAAAA,CAAG,MAAO,CAAA,IAAI,IAAM,CACjC,CAAA,OAAA,CAAQ,KAAMpB,CAAAA,CAAAA,CAAIuB,CAAI,CAAA,CAAGtB,EAAI,QAAG,CAAA,CAAGqB,CAAO,EAC5C,CCzCA,IAAME,EAAmB,gBAMnBC,CAAAA,CAAAA,CAAoBhB,CACxBA,EAAAA,CAAAA,CAAQ,KAAM,CAAA,iBAAiB,GAAK,EAAC,CAOvC,SAASiB,CAAOC,CAAAA,CAAAA,CAA2B,EAAsB,CAAA,CAC/D,IAAIC,CAAAA,CAEJ,OAAO,CACL,KAAMJ,CACN,CAAA,KAAA,CAAO,CACL,mBAAA,CAAqB,CAAC,CAAE,OAAQK,CAAI,CAAA,GAAM,CACxCD,CAAAA,CAASC,EACX,CAAA,CACA,mBAAoB,MAAO,CAAE,IAAAC,CAAK,CAAA,KAAA,CAAAC,EAAO,MAAAC,CAAAA,CAAO,CAAM,GAAA,CACpD,IAAMC,CAAAA,CAAYL,EAAO,MACzBI,CAAAA,CAAAA,CAAO,IAAK,CAAA,CAAA,sBAAA,EAAkBC,CAAS,CAAA,MAAA,CAAQ,EAG/C,IAAMC,CAAAA,CAASC,aAAcL,CAAAA,CAAG,CAG1BM,CAAAA,CAAAA,CAAQH,IAAc,QAG5B,CAAA,GAAI,CAACC,CAAU,EAAA,CAACN,EAAO,KAAM,CAAA,MAAA,EAAU,CAACA,CAAAA,CAAO,KAAM,CAAA,MAAA,CAAQ,CAC3DI,CAAO,CAAA,IAAA,CACL,CAAGR,EAAAA,CAAgB,CACrB,sFAAA,CAAA,CAAA,CACA,MACF,CAeA,IAAMa,CAZe,CAAA,CAAA,MAAM,IAAIC,QAAAA,GAAW,KAAM,CAAA,CAC9C,IAAK,CAACC,IAAAA,CAAKL,EAAQ,WAAW,CAAC,CAC/B,CAAA,gBAAA,CAAAT,CACA,CAAA,GAAGE,EACH,OAAS,CAAA,CACPY,IAAKL,CAAAA,CAAAA,CAAQ,YAAY,CAAA,CACzBK,KAAKL,CAAQ,CAAA,UAAU,CACvB,CAAA,GAAIP,CAAQ,CAAA,OAAA,EAAW,EACzB,CACF,CAAC,CAGmC,EAAA,MAAA,CAAO,CAAC,CAAE,IAAA,CAAAa,CAAK,CAAA,GACjDA,CAAM,EAAA,QAAA,CAAS,MAAM,CACvB,CAAA,CAKA,GAAIH,CAAAA,CAAe,MAAW,GAAA,CAAA,CAAG,CAC/BL,CAAO,CAAA,IAAA,CAAK,6CAAmC,CAAA,CAC/C,MACF,CAOA,GALAA,CAAO,CAAA,IAAA,CACL,SAASK,CAAe,CAAA,MAAM,QAAQA,CAAe,CAAA,MAAA,GAAW,CAAI,CAAA,MAAA,CAAS,OAAO,CAAA,WAAA,CACtF,EAGID,CAAO,CAAA,CACT,MAAM,OAAA,CAAQ,GACZC,CAAAA,CAAAA,CAAe,IAAI,MAAO,CAAE,GAAAxB,CAAAA,CAAAA,CAAK,IAAA2B,CAAAA,CAAK,IAAM,CAC1C,MAAM7B,EAAa6B,CAAM3B,CAAAA,CAAAA,CAAK2B,CAAI,CAClCnB,CAAAA,CAAAA,CAAQmB,CAAK,CAAA,OAAA,CAAQN,CAAQ,CAAA,EAAE,CAAC,EAClC,CAAC,CACH,CAAA,CACAF,CAAO,CAAA,IAAA,CAAK,2CAAoC,CAChD,CAAA,MACF,CAmCA,IAAMS,CAhCe,CAAA,CAAA,MAAM,QAAQ,GACjCJ,CAAAA,CAAAA,CAAe,GAAI,CAAA,MAAO,CAAE,GAAA,CAAAxB,EAAK,IAAA2B,CAAAA,CAAK,CAAM,GAAA,CAK1C,GAAI,CAJgBA,EAAK,QAASZ,CAAAA,CAAAA,CAAO,KAAM,CAAA,MAAM,CAInC,CAAA,CAChB,MAAMjB,CAAa6B,CAAAA,CAAAA,CAAM3B,CAAK2B,CAAAA,CAAI,CAClC,CAAA,IAAME,EAAeF,CAAK,CAAA,OAAA,CAAQN,EAAQ,EAAE,CAAA,CAC5C,OAAAb,CAAQqB,CAAAA,CAAY,CACb,CAAA,CACL,WAAaA,CAAAA,CAAAA,CACb,YAAaA,CACf,CACF,CAGA,IAAMC,CAAiB1B,CAAAA,CAAAA,CAAiBuB,EAAM3B,CAAG,CAAA,CACjD,MAAMF,CAAAA,CAAagC,CAAgB9B,CAAAA,CAAAA,CAAK2B,CAAI,CAE5C,CAAA,IAAMI,EAAkBJ,CAAK,CAAA,OAAA,CAAQN,EAAQ,EAAE,CAAA,CACzCW,CAAkBF,CAAAA,CAAAA,CAAe,OAAQT,CAAAA,CAAAA,CAAQ,EAAE,CACzD,CAAA,OAAAb,CAAQwB,CAAAA,CAAe,CAEhB,CAAA,CACL,YAAaD,CACb,CAAA,WAAA,CAAaC,CACf,CACF,CAAC,CACH,GAGoC,MAClC,CAAA,CAAC,CAAE,WAAAC,CAAAA,CAAAA,CAAa,YAAAC,CAAY,CAAA,GAAMD,CAAgBC,GAAAA,CACpD,CAEA,CAAA,GAAIN,EAAa,MAAS,CAAA,CAAA,CAAG,CAC3BT,CAAAA,CAAO,IACL,CAAA,CAAA,SAAA,EAAYS,EAAa,MAAM,CAAA,KAAA,EAAQA,CAAa,CAAA,MAAA,GAAW,CAAI,CAAA,WAAA,CAAc,YAAY,CAC/F,iBAAA,CAAA,CAAA,CAEA,IAAMO,CAAYjB,CAAAA,CAAAA,CACf,OAAQkB,CAAS,EAAA,OAAOA,CAAK,CAAA,QAAA,EAAa,QAAQ,CAAA,CAClD,IAAKA,CAAS,EAAA,CACb,IAAMC,CAAAA,CAAWD,CAAK,CAAA,QAAA,CAGtB,GAAIC,CAAa,GAAA,EAAA,CACf,OAAOX,IAAAA,CAAKL,CAAQ,CAAA,YAAY,EAGlC,OAAQN,CAAAA,CAAO,MAAM,MAAQ,EAC3B,IAAK,MAEH,CAAA,OAAOW,IAAKL,CAAAA,CAAAA,CAAQ,CAAGgB,EAAAA,CAAQ,OAAO,CAExC,CAAA,IAAK,WAEH,CAAA,OAAOX,IAAKL,CAAAA,CAAAA,CAAQgB,EAAU,YAAY,CAAA,CAE5C,IAAK,UAAA,CAEH,IAAMC,CAAAA,CAAaZ,KAAKL,CAAQ,CAAA,CAAA,EAAGgB,CAAQ,CAAO,KAAA,CAAA,CAAA,CAClD,OAAOnC,UAAWoC,CAAAA,CAAU,CACxBA,CAAAA,CAAAA,CACAZ,IAAKL,CAAAA,CAAAA,CAAQgB,EAAU,YAAY,CAC3C,CACF,CAAC,CAGH,CAAA,MAAM,QAAQ,GACZF,CAAAA,CAAAA,CAAU,GAAI,CAAA,MAAOI,CAAa,EAAA,CAChC,IAAI3C,CAAU,CAAA,MAAMN,EAAgBiD,CAAQ,CAAA,CAE5C,OAAW,CAAE,WAAA,CAAAN,CAAa,CAAA,WAAA,CAAAC,CAAY,CAAA,GAAKN,EACrChC,CAAQ,CAAA,QAAA,CAASqC,CAAW,CAAA,GAC9BrC,CAAUA,CAAAA,CAAAA,CAAQ,QAChB,IAAI,MAAA,CAAOqC,CAAa,CAAA,GAAG,CAC3BC,CAAAA,CACF,GAIJ,MAAMvC,CAAAA,CAAiB4C,CAAU3C,CAAAA,CAAO,CACxCY,CAAAA,CAAAA,CAAQ+B,EAAS,OAAQlB,CAAAA,CAAAA,CAAQ,EAAE,CAAC,EACtC,CAAC,CACH,EACF,CAEAF,CAAO,CAAA,IAAA,CAAK,2CAAoC,EAClD,CACF,CACF,CACF,CAEA,IAAOqB,EAAQ3B,CAAAA","file":"index.js","sourcesContent":["let FORCE_COLOR, NODE_DISABLE_COLORS, NO_COLOR, TERM, isTTY=true;\nif (typeof process !== 'undefined') {\n\t({ FORCE_COLOR, NODE_DISABLE_COLORS, NO_COLOR, TERM } = process.env || {});\n\tisTTY = process.stdout && process.stdout.isTTY;\n}\n\nexport const $ = {\n\tenabled: !NODE_DISABLE_COLORS && NO_COLOR == null && TERM !== 'dumb' && (\n\t\tFORCE_COLOR != null && FORCE_COLOR !== '0' || isTTY\n\t)\n}\n\nfunction init(x, y) {\n\tlet rgx = new RegExp(`\\\\x1b\\\\[${y}m`, 'g');\n\tlet open = `\\x1b[${x}m`, close = `\\x1b[${y}m`;\n\n\treturn function (txt) {\n\t\tif (!$.enabled || txt == null) return txt;\n\t\treturn open + (!!~(''+txt).indexOf(close) ? txt.replace(rgx, close + open) : txt) + close;\n\t};\n}\n\n// modifiers\nexport const reset = init(0, 0);\nexport const bold = init(1, 22);\nexport const dim = init(2, 22);\nexport const italic = init(3, 23);\nexport const underline = init(4, 24);\nexport const inverse = init(7, 27);\nexport const hidden = init(8, 28);\nexport const strikethrough = init(9, 29);\n\n// colors\nexport const black = init(30, 39);\nexport const red = init(31, 39);\nexport const green = init(32, 39);\nexport const yellow = init(33, 39);\nexport const blue = init(34, 39);\nexport const magenta = init(35, 39);\nexport const cyan = init(36, 39);\nexport const white = init(37, 39);\nexport const gray = init(90, 39);\nexport const grey = init(90, 39);\n\n// background colors\nexport const bgBlack = init(40, 49);\nexport const bgRed = init(41, 49);\nexport const bgGreen = init(42, 49);\nexport const bgYellow = init(43, 49);\nexport const bgBlue = init(44, 49);\nexport const bgMagenta = init(45, 49);\nexport const bgCyan = init(46, 49);\nexport const bgWhite = init(47, 49);\n","import { dim, green, red } from 'kleur/colors';\nimport { createHash } from 'node:crypto';\nimport { existsSync } from 'node:fs';\nimport { readFile, unlink, writeFile } from 'node:fs/promises';\n\nexport async function readFileContent(filePath: string): Promise<string> {\n try {\n const content = await readFile(filePath, 'utf8');\n return content;\n } catch (err) {\n error(`Error reading file ${filePath}: ${err}`);\n return '';\n }\n}\n\nexport async function writeFileContent(filePath: string, content: string) {\n try {\n await writeFile(filePath, content, 'utf8');\n } catch (err) {\n error(`Error writing file ${filePath}: ${err}`);\n return '';\n }\n}\n\nexport async function writeCssFile(\n newFilePath: string,\n css: string,\n oldFilePath: string\n) {\n await writeFileContent(newFilePath, css);\n\n // Remove old file if it exists and is different from new file\n if (existsSync(oldFilePath) && oldFilePath !== newFilePath) {\n await unlink(oldFilePath);\n }\n}\n\nexport function generateFileHash(filePath: string, content: string) {\n // Get content hash before writing to file\n const hash = createHash('sha256').update(content).digest('hex').slice(0, 8);\n\n // Generate new file name with hash\n // Astro orignal hash is 8 characters long\n return `${filePath.slice(0, -13)}.${hash}.css`;\n}\n\nexport const dt = new Intl.DateTimeFormat('en-us', {\n hour: '2-digit',\n minute: '2-digit',\n second: '2-digit',\n hour12: false\n});\n\nexport function success(message: string) {\n const date = dt.format(new Date());\n console.log(dim(date), green('▶'), message);\n}\n\nexport function error(message: string) {\n const date = dt.format(new Date());\n console.error(dim(date), red('■'), message);\n}\n","import type { AstroConfig, AstroIntegration } from 'astro';\nimport { existsSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { PurgeCSS, type UserDefinedOptions } from 'purgecss';\n\nimport {\n generateFileHash,\n readFileContent,\n success,\n writeCssFile,\n writeFileContent\n} from './utils';\n\n/**\n * Extended PurgeCSS options interface that allows partial configuration\n * of the standard PurgeCSS options\n */\nexport interface PurgeCSSOptions extends Partial<UserDefinedOptions> {}\n\nconst INTEGRATION_NAME = 'astro-purgecss' as const;\n\n/**\n * default extractor to handle various CSS selector patterns\n * @param content string\n */\nconst defaultExtractor = (content: string) =>\n content.match(/[\\w-/:]+(?<!:)/g) || [];\n\n/**\n * Astro integration for PurgeCSS that removes unused CSS from the final build\n * @param options - PurgeCSS configuration options\n * @returns AstroIntegration - The configured Astro integration\n */\nfunction Plugin(options: PurgeCSSOptions = {}): AstroIntegration {\n let config: AstroConfig;\n\n return {\n name: INTEGRATION_NAME,\n hooks: {\n 'astro:config:done': ({ config: cfg }) => {\n config = cfg;\n },\n 'astro:build:done': async ({ dir, pages, logger }) => {\n const buildMode = config.output;\n logger.info(`📦 Running in '${buildMode}' mode`);\n\n // Convert the URL to a filesystem path\n const outDir = fileURLToPath(dir);\n\n // Used to skip file rehashing for SSR/Hybrid modes\n const isSSR = buildMode !== 'static';\n\n // Validate required Astro configuration\n if (!outDir || !config.build.format || !config.build.assets) {\n logger.warn(\n `${INTEGRATION_NAME} requires the following astro.config options: 'outDir', 'build.format', 'build.assets'`\n );\n return;\n }\n\n // Run PurgeCSS on all CSS files\n const purgeResults = await new PurgeCSS().purge({\n css: [join(outDir, '/**/*.css')],\n defaultExtractor,\n ...options,\n content: [\n join(outDir, '/**/*.html'),\n join(outDir, '/**/*.js'),\n ...(options.content || [])\n ]\n });\n\n // Filter out non-CSS files from purge results\n const purgedCssFiles = purgeResults.filter(({ file }) =>\n file?.endsWith('.css')\n ) as Array<{\n css: string;\n file: string;\n }>;\n\n if (purgedCssFiles.length === 0) {\n logger.info('ℹ️ No CSS files found to process');\n return;\n }\n\n logger.info(\n `Found ${purgedCssFiles.length} CSS ${purgedCssFiles.length === 1 ? 'file' : 'files'} to process`\n );\n\n // Handle SSR/Hybrid mode\n if (isSSR) {\n await Promise.all(\n purgedCssFiles.map(async ({ css, file }) => {\n await writeCssFile(file, css, file);\n success(file.replace(outDir, ''));\n })\n );\n logger.info('🎉 Purging completed successfully!');\n return;\n }\n\n // Process files for static mode with content hashing\n let processedFiles = await Promise.all(\n purgedCssFiles.map(async ({ css, file }) => {\n const isAssetFile = file.includes(config.build.assets);\n\n // Skip rehashing for non-asset files (not generated by astro)\n // ex: assets/styles/light.css\n if (!isAssetFile) {\n await writeCssFile(file, css, file);\n const relativePath = file.replace(outDir, '');\n success(relativePath);\n return {\n oldFilename: relativePath,\n newFilename: relativePath\n };\n }\n\n // Generate new filename with content hash\n const hashedFilename = generateFileHash(file, css);\n await writeCssFile(hashedFilename, css, file);\n\n const relativeOldPath = file.replace(outDir, '');\n const relativeNewPath = hashedFilename.replace(outDir, '');\n success(relativeNewPath);\n\n return {\n oldFilename: relativeOldPath,\n newFilename: relativeNewPath\n };\n })\n );\n\n // Filter to only get files that actually changed\n const changedFiles = processedFiles.filter(\n ({ oldFilename, newFilename }) => oldFilename !== newFilename\n );\n\n if (changedFiles.length > 0) {\n logger.info(\n `Updating ${changedFiles.length} CSS ${changedFiles.length === 1 ? 'reference' : 'references'} in HTML files...`\n );\n // Get all HTML pages based on build format\n const htmlFiles = pages\n .filter((page) => typeof page.pathname === 'string')\n .map((page) => {\n const pathname = page.pathname as string;\n\n // Handle root/index page\n if (pathname === '') {\n return join(outDir, 'index.html');\n }\n\n switch (config.build.format) {\n case 'file':\n // Format: /blog -> /blog.html\n return join(outDir, `${pathname}.html`);\n\n case 'directory':\n // Format: /blog -> /blog/index.html\n return join(outDir, pathname, 'index.html');\n\n case 'preserve':\n // Check if direct HTML file exists, otherwise use directory format\n const directFile = join(outDir, `${pathname}.html`);\n return existsSync(directFile)\n ? directFile\n : join(outDir, pathname, 'index.html');\n }\n });\n\n // Update CSS references in HTML files\n await Promise.all(\n htmlFiles.map(async (htmlFile) => {\n let content = await readFileContent(htmlFile);\n\n for (const { oldFilename, newFilename } of changedFiles) {\n if (content.includes(oldFilename)) {\n content = content.replace(\n new RegExp(oldFilename, 'g'),\n newFilename\n );\n }\n }\n\n await writeFileContent(htmlFile, content);\n success(htmlFile.replace(outDir, ''));\n })\n );\n }\n\n logger.info('🎉 Purging completed successfully!');\n }\n }\n };\n}\n\nexport default Plugin;\n"]}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "astro-purgecss",
3
3
  "description": "Remove unused CSS rules from your final Astro bundle",
4
- "version": "4.6.2",
4
+ "version": "4.8.0",
5
5
  "homepage": "https://github.com/codiume/orbit",
6
6
  "bugs": "https://github.com/codiume/orbit/issues",
7
7
  "author": "codiume",