astro-purgecss 4.1.0 → 4.2.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
@@ -79,6 +79,14 @@ export default defineConfig({
79
79
  blocklist: ['usedClass', /^nav-/],
80
80
  content: [
81
81
  process.cwd() + '/src/**/*.{astro,vue}' // Watching astro and vue sources (for SSR, read the note below)
82
+ ],
83
+ extractors: [
84
+ {
85
+ // Example using a taiwindcss compatible class extractor
86
+ extractor: (content) =>
87
+ content.match(/[^<>"'`\s]*[^<>"'`\s:]/g) || [],
88
+ extensions: ['astro', 'html']
89
+ }
82
90
  ]
83
91
  })
84
92
  ]
@@ -103,6 +111,11 @@ export type PurgeCSSOptions = {
103
111
  safelist?: UserDefinedSafelist; // indicates which selectors are safe to leave in the final CSS
104
112
  blocklist?: StringRegExpArray; // blocks the CSS selectors from appearing in the final output CSS
105
113
  content?: Array<string | RawContent>;
114
+ extractors?: // provides custom functions to extract CSS classes in specific ways (eg. when using tailwind.css)
115
+ Array<{
116
+ extractor: (content: string) => string[]; // matched css classes
117
+ extensions: string[]; // file extensions for which this extractor is to be used
118
+ }>;
106
119
  };
107
120
  ```
108
121
 
@@ -116,7 +129,38 @@ We have also setup an example repository available here: [example-purgecss](../.
116
129
 
117
130
  - If you are using [inline styles](https://docs.astro.build/en/guides/styling/#scoped-styles), this plugin won't be able to purge those css rules, due to astro's way of handling scoped css rules.
118
131
 
119
- - If you are using `tailwind.css`, please read about purge limitations in this guide [writing-purgeable-html](https://v2.tailwindcss.com/docs/optimizing-for-production#writing-purgeable-html)
132
+ - If you are using Astro view transitions, use the following options so that purgecss keeps the corresponding animations:
133
+
134
+ ```diff
135
+ export default defineConfig({
136
+ integrations: [
137
+ purgecss({
138
+ + keyframes: false
139
+ + , safelist: {
140
+ + greedy: [/*astro*/]
141
+ + }
142
+ }),
143
+ ],
144
+ });
145
+ ```
146
+
147
+ - If you are using `tailwind.css`, please read about purge limitations in this guide [writing-purgeable-html](https://v2.tailwindcss.com/docs/optimizing-for-production#writing-purgeable-html). You may also need a custom class extractor compatible with arbitrary and container based `tailwind.css` classes. For example:
148
+
149
+ ```js
150
+ export default defineConfig({
151
+ integrations: [
152
+ purgecss({
153
+ extractors: [
154
+ {
155
+ extractor: (content) =>
156
+ content.match(/[^<>"'`\s]*[^<>"'`\s:]/g) || [],
157
+ extensions: ['astro', 'html']
158
+ }
159
+ ]
160
+ })
161
+ ]
162
+ });
163
+ ```
120
164
 
121
165
  ## Changelog
122
166
 
package/dist/index.mjs CHANGED
@@ -1,15 +1,9 @@
1
- import { PurgeCSS } from "purgecss";
2
- import { writeFile } from "node:fs/promises";
1
+ import { createHash } from "crypto";
2
+ import { rename, writeFile } from "node:fs/promises";
3
+ import path from "node:path";
3
4
  import { fileURLToPath } from "node:url";
4
- function handleWindowsPath(outputPath) {
5
- if (process.platform !== "win32")
6
- return outputPath;
7
- if (outputPath.endsWith("\\")) {
8
- outputPath = outputPath.substring(0, outputPath.length - 1);
9
- }
10
- outputPath = outputPath.replaceAll("\\", "/");
11
- return outputPath;
12
- }
5
+ import { PurgeCSS } from "purgecss";
6
+ import { handleWindowsPath, replaceStringInDirectory } from "./utils";
13
7
  function src_default(options = {}) {
14
8
  return {
15
9
  name: "astro-purgecss",
@@ -27,7 +21,18 @@ function src_default(options = {}) {
27
21
  ]
28
22
  });
29
23
  await Promise.all(
30
- purged.filter(({ file }) => file == null ? void 0 : file.endsWith(".css")).map(async ({ css, file }) => await writeFile(file, css))
24
+ purged.filter(({ file }) => file == null ? void 0 : file.endsWith(".css")).map(async ({ css, file }) => {
25
+ if (!file) return;
26
+ await writeFile(file, css);
27
+ const hash = await createHash("sha256").update(css).digest("hex").substring(0, 7);
28
+ const newPath = file.slice(0, -12) + hash + ".css";
29
+ await rename(file, newPath);
30
+ await replaceStringInDirectory(
31
+ outDir + "../",
32
+ path.basename(file),
33
+ path.basename(newPath)
34
+ );
35
+ })
31
36
  );
32
37
  }
33
38
  }
@@ -0,0 +1,3 @@
1
+ export declare function handleWindowsPath(outputPath: string): string;
2
+ export declare function replaceStringInFile(filePath: string, searchValue: string, replaceValue: string): Promise<void>;
3
+ export declare function replaceStringInDirectory(directory: string, searchValue: string, replaceValue: string): Promise<void>;
package/dist/utils.mjs ADDED
@@ -0,0 +1,42 @@
1
+ import { readdir, readFile, writeFile } from "node:fs/promises";
2
+ import path from "node:path";
3
+ function handleWindowsPath(outputPath) {
4
+ if (process.platform !== "win32") return outputPath;
5
+ if (outputPath.endsWith("\\")) {
6
+ outputPath = outputPath.substring(0, outputPath.length - 1);
7
+ }
8
+ outputPath = outputPath.replaceAll("\\", "/");
9
+ return outputPath;
10
+ }
11
+ async function replaceStringInFile(filePath, searchValue, replaceValue) {
12
+ try {
13
+ const fileContent = await readFile(filePath, "utf8");
14
+ if (fileContent.includes(searchValue)) {
15
+ const re = new RegExp(searchValue, "g");
16
+ const newContent = fileContent.replace(re, replaceValue);
17
+ await writeFile(filePath, newContent, "utf8");
18
+ }
19
+ } catch (err) {
20
+ console.error(`Error processing file ${filePath}: ${err}`);
21
+ }
22
+ }
23
+ async function replaceStringInDirectory(directory, searchValue, replaceValue) {
24
+ try {
25
+ const files = await readdir(directory, { withFileTypes: true });
26
+ for (const file of files) {
27
+ const fullPath = path.join(directory, file.name);
28
+ if (file.isDirectory()) {
29
+ await replaceStringInDirectory(fullPath, searchValue, replaceValue);
30
+ } else if (file.isFile()) {
31
+ await replaceStringInFile(fullPath, searchValue, replaceValue);
32
+ }
33
+ }
34
+ } catch (err) {
35
+ console.error(`Error processing directory ${directory}: ${err}`);
36
+ }
37
+ }
38
+ export {
39
+ handleWindowsPath,
40
+ replaceStringInDirectory,
41
+ replaceStringInFile
42
+ };
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.1.0",
4
+ "version": "4.2.0",
5
5
  "type": "module",
6
6
  "types": "dist/index.d.ts",
7
7
  "author": "codiume",
@@ -37,10 +37,10 @@
37
37
  },
38
38
  "peerDependencies": {
39
39
  "astro": "^4.0.0",
40
- "purgecss": "^5.0.0"
40
+ "purgecss": "^6.0.0"
41
41
  },
42
42
  "scripts": {
43
- "build": "astro-build --src src/index.ts",
43
+ "build": "astro-build --src src/index.ts src/utils.ts",
44
44
  "typecheck": "tsc --declaration --emitDeclarationOnly"
45
45
  }
46
46
  }