emily-css 1.0.0 → 1.0.2

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
@@ -1,107 +1,159 @@
1
- # emily-ui
1
+ # EmilyUI
2
2
 
3
- A config-driven, utility-first CSS framework for developers in constrained environments. Define brand once (colours, fonts, spacing) → generate CSS → browse and copy production-ready components.
3
+ A config-driven utility CSS framework. Define your brand once, generate the CSS.
4
+
5
+ **EmilyUI** is the ecosystem name. `emily-css` is the utility layer published on npm — it's both the package you install and the CLI you use to generate and purge CSS. More packages coming.
4
6
 
5
7
  ## Features
6
8
 
7
- - **Config-driven** Entire framework configured via `emily.config.json`
8
- - **Utility-first** 11,844 composable utilities covering layout, spacing, typography, colours, responsive variants, state variants
9
- - **Responsive ready** All utilities work with responsive prefixes (sm:, md:, lg:, xl:, 2xl:)
10
- - **State variants** hover, focus-visible, active, disabled states built-in
11
- - **Accessibility first** WCAG 2.2 AA compliance in core utilities (focus rings, contrast, motion)
12
- - **Purge system** Remove unused CSS automatically (97% file size reduction)
13
- - **Framework-agnostic** Works with Drupal, static HTML, Power Pages, Vue, Next.js, anything that accepts CSS
14
- - **No build pipeline required** — Generate CSS, use it directly in your project
9
+ - **Works anywhere** - Generate static CSS and drop it into any project, no build pipeline required.
10
+ - **Config-driven** - Entire framework configured via `emily.config.json`
11
+ - **Utility-first** - Composable utilities for layout, spacing, typography and colour
12
+ - **Responsive ready** - All utilities work with responsive prefixes (`sm:`, `md:`, `lg:`, `xl:`, `2xl:`)
13
+ - **State variants** - `hover:`, `focus-visible:`, `active:`, `disabled:` built-in
14
+ - **Accessibility first** - WCAG 2.2 AA compliance in core utilities (focus rings, contrast, motion)
15
+ - **Purge system** - Remove unused CSS automatically for production
15
16
 
16
17
  ## Quick Start
17
18
 
18
19
  ### 1. Install
20
+
19
21
  ```bash
20
- npm install emily-ui
21
- emily-ui init
22
+ npm install emily-css
22
23
  ```
23
24
 
24
- The `init` command guides you through:
25
+ ### 2. Create your config
26
+
27
+ ```bash
28
+ npx emily-css init
29
+ ```
30
+
31
+ This walks you through:
32
+
25
33
  - Project name
26
34
  - Brand colours (primary, secondary, success, warning, error, neutral)
27
35
  - Font families
28
36
  - Base spacing unit
37
+ - Source directory (used by the purge command)
38
+
39
+ It then generates `emily.config.json` and runs your first build automatically.
40
+
41
+ ### 3. Link the CSS in your project
42
+
43
+ ```html
44
+ <link rel="stylesheet" href="./dist/emily.css">
45
+ ```
46
+
47
+ ### 4. Use the utility classes
48
+
49
+ ```html
50
+ <button class="px-4 py-2 rounded-md bg-primary-80 text-white hover:bg-primary-90 focus-visible:ring-2 focus-visible:ring-primary-50">
51
+ Button
52
+ </button>
53
+ ```
54
+
55
+ Colours, spacing and typography all come from your config.
56
+
57
+ ### 5. Purge unused CSS for production
29
58
 
30
- ### 2. Build CSS
31
59
  ```bash
32
- emily-ui build
60
+ npx emily-css purge
33
61
  ```
34
62
 
63
+ Scans your template files, keeps only the utilities you actually use.
64
+
35
65
  Output:
36
- - `dist/emily.css` Full CSS (1.1 MB)
37
- - `dist/emily.min.css` Minified (1.04 MB)
66
+ - `dist/emily.purged.css` - Purged CSS
67
+ - `dist/emily.purged.min.css` - Minified version
68
+
69
+ Use the purged file in production:
70
+
71
+ ```html
72
+ <link rel="stylesheet" href="./dist/emily.purged.min.css">
73
+ ```
74
+
75
+ ## Commands
38
76
 
39
- ### 2b. Run Tests (Optional)
40
77
  ```bash
41
- npm test
78
+ npx emily-css init # Create emily.config.json and run first build
79
+ npx emily-css build # Regenerate CSS after config changes
80
+ npx emily-css purge # Remove unused utilities for production
81
+ npm test # Run test suite (if working on EmilyUI itself)
42
82
  ```
43
- *(Run from inside the emily-ui project folder)*
44
83
 
45
- Automated validation of colour generation, utilities, variants, config integrity, and build output (66 tests, all passing). Tests confirm the generator works correctly; manual testing of real-world usage is still recommended before deploying to production.
84
+ ## How Purge Works
46
85
 
47
- ### 3. Use Components
48
- Open `showcase.html` in your browser to see 8 production components (button, input, textarea, select, checkbox, radio, card, alert). Copy the HTML, paste into your project.
86
+ EmilyUI scans your template files for class names and removes any utilities you are not using.
49
87
 
50
- ### 4. Reduce File Size (Recommended for Production)
51
- ```bash
52
- emily-ui build --purge ./src
88
+ For example:
89
+
90
+ ```html
91
+ <div class="p-4 bg-primary-80 rounded-lg">Content</div>
53
92
  ```
54
93
 
55
- Scans your HTML/templates for used classes, removes unused utilities. Typical reduction: 99%+ (1.1 MB → 10–50 KB).
94
+ EmilyUI keeps `.p-4`, `.bg-primary-80`, `.rounded-lg` and removes everything else.
56
95
 
57
- Output:
58
- - `dist/emily.purged.css` — Only utilities you use
59
- - `dist/emily.purged.min.css` Minified version
96
+ Supported file types: `.html`, `.twig`, `.njk`, `.liquid`, `.hbs`, `.jsx`, `.tsx`, `.vue`, `.php`, `.astro`, `.svelte`, `.blade.php` (configurable via `extensions` in `emily.config.json`)
97
+
98
+ **Note:** Class names must exist as plain text in your files. Dynamically constructed class names will not be detected:
99
+
100
+ ```js
101
+ // This will be missed by purge:
102
+ const colour = 'primary-80'
103
+ const cls = `bg-${colour}`
104
+
105
+ // This will be detected:
106
+ const cls = 'bg-primary-80'
107
+ ```
60
108
 
61
- ## File Size Comparison
109
+ If you use dynamic classes, either keep them as plain strings or manually safelist them in your config.
62
110
 
63
- Emily uses a purge-based approach (generate all utilities, then remove unused). Unpurged file size: ~1.1 MB.
111
+ ## File Size
64
112
 
65
- For context:
66
- - **Tailwind v2** (purge-based): 2.4–8MB unpurged → <10KB purged
67
- - **Emily v1** (purge-based): 1.1MB unpurged → 10–50KB purged
68
- - **Tailwind v3/v4** (JIT): Generates only what you use, no purge step needed
113
+ EmilyUI uses a purge-based approach (generate all utilities, then remove unused).
69
114
 
70
- Emily's unpurged file is roughly half the size of Tailwind v2. For production, both frameworks achieve similar post-purge sizes. JIT-style on-demand generation is planned for Emily v2.
115
+ | | Unpurged | Purged |
116
+ |---|---|---|
117
+ | Tailwind v2 | 2.4-8MB | under 10KB |
118
+ | EmilyUI v1 | 1.1MB | 10-50KB |
119
+ | Tailwind v3/v4 (JIT) | generates on demand | - |
120
+
121
+ EmilyUI's unpurged file is roughly half the size of Tailwind v2. Post-purge sizes are comparable. JIT-style generation is planned for v2.
71
122
 
72
123
  ## File Structure
73
124
 
74
125
  ```
75
- emily-ui/
126
+ emily-css/
76
127
  ├── src/
77
- │ ├── index.js Main build script
78
- │ ├── generators.js Utility generation functions
79
- │ ├── purge.js CSS purge system
80
- └── init.js Interactive config generator
128
+ │ ├── index.js - Main build script
129
+ │ ├── generators.js - Utility generation functions
130
+ │ ├── purge.js - Purge system
131
+ ├── purge-cmd.js - Purge CLI command
132
+ │ └── init.js - Interactive setup
81
133
  ├── dist/
82
- │ ├── emily.css Generated CSS
83
- │ ├── emily.min.css Minified CSS
84
- │ ├── emily.purged.css Purged CSS (with --purge flag)
134
+ │ ├── emily.css - Generated CSS
135
+ │ ├── emily.min.css - Minified CSS
136
+ │ ├── emily.purged.css - Purged CSS
85
137
  │ └── emily.purged.min.css
86
- ├── showcase.html Component browser
87
- ├── emily.config.json Framework configuration
138
+ ├── showcase.html - Example components
139
+ ├── emily.config.json - Your config
88
140
  ├── package.json
89
141
  └── README.md
90
142
  ```
91
143
 
92
144
  ## Configuration
93
145
 
94
- Edit `emily.config.json` to customize:
146
+ Edit `emily.config.json` to customise:
95
147
 
96
148
  ```json
97
149
  {
98
150
  "name": "My Brand",
99
151
  "description": "Design system",
100
-
152
+
101
153
  "baseUnit": "8px",
102
154
  "baseFontSize": "16px",
103
155
  "fontFamily": "system-ui",
104
-
156
+
105
157
  "colours": {
106
158
  "primary": "#0077b6",
107
159
  "secondary": "#006d9e",
@@ -110,7 +162,7 @@ Edit `emily.config.json` to customize:
110
162
  "error": "#b20000",
111
163
  "neutral": "#6b7280"
112
164
  },
113
-
165
+
114
166
  "breakpoints": {
115
167
  "sm": "640px",
116
168
  "md": "768px",
@@ -118,55 +170,43 @@ Edit `emily.config.json` to customize:
118
170
  "xl": "1280px",
119
171
  "2xl": "1536px"
120
172
  },
121
-
122
- "spacing": {
123
- "scale": { "0": "0px", "1": "0.25rem", ... },
124
- "borderRadius": { "sm": "4px", "base": "8px", "lg": "16px", ... }
125
- },
126
-
127
- "typography": {
128
- "fontWeights": { "light": 300, "normal": 400, ... },
129
- "fontSizes": [ { "name": "sm", "value": "14px" }, ... ]
130
- },
131
-
132
- "shadows": { ... },
133
- "transitions": { ... },
134
- "zIndex": { ... },
135
- "opacity": [ ... ],
136
-
173
+
137
174
  "purge": {
138
- "extensions": [".html", ".jsx", ".tsx", ".vue", ...]
175
+ "sourceDir": "./src",
176
+ "extensions": [".html", ".jsx", ".tsx", ".vue"]
139
177
  }
140
178
  }
141
179
  ```
142
180
 
143
181
  After editing, rebuild:
182
+
144
183
  ```bash
145
- emily-ui build
184
+ npx emily-css build
146
185
  ```
147
186
 
148
187
  ## Utilities
149
188
 
150
- Emily generates utilities across these categories:
151
-
152
- - **Display** block, inline, flex, grid, hidden
153
- - **Spacing** margin (m-), padding (p-), gap (gap-)
154
- - **Sizing** width (w-), height (h-), max-width, min-height
155
- - **Positioning** absolute, relative, fixed, sticky, top, right, bottom, left
156
- - **Flexbox** flex, flex-direction, justify-content, align-items, flex-wrap
157
- - **Grid** grid, grid-cols, grid-rows, grid-gap
158
- - **Colours** background (bg-), text, borders, accent for form controls
159
- - **Typography** font-size, font-weight, line-height, text-align
160
- - **Borders** border-width, border-style, border-colour, border-radius
161
- - **Shadows** box-shadow, text-shadow
162
- - **Opacity** opacity levels
163
- - **Accessibility** sr-only, focus-visible, motion-safe, forced-colors
164
- - **State variants** hover:, focus-visible:, active:, disabled:
165
- - **Responsive variants** sm:, md:, lg:, xl:, 2xl:
189
+ EmilyUI generates utilities across these categories:
190
+
191
+ - **Display** - block, inline, flex, grid, hidden
192
+ - **Spacing** - margin (`m-`), padding (`p-`), gap (`gap-`)
193
+ - **Sizing** - width (`w-`), height (`h-`), max-width, min-height
194
+ - **Positioning** - absolute, relative, fixed, sticky, top, right, bottom, left
195
+ - **Flexbox** - flex, flex-direction, justify-content, align-items, flex-wrap
196
+ - **Grid** - grid, grid-cols, grid-rows, grid-gap
197
+ - **Colours** - background (`bg-`), text, borders, accent for form controls
198
+ - **Typography** - font-size, font-weight, line-height, text-align
199
+ - **Borders** - border-width, border-style, border-colour, border-radius
200
+ - **Shadows** - box-shadow, text-shadow
201
+ - **Opacity** - opacity levels
202
+ - **Accessibility** - sr-only, focus-visible, motion-safe, forced-colors
203
+ - **State variants** - `hover:`, `focus-visible:`, `active:`, `disabled:`
204
+ - **Responsive variants** - `sm:`, `md:`, `lg:`, `xl:`, `2xl:`
166
205
 
167
206
  ## Examples
168
207
 
169
208
  ### Button
209
+
170
210
  ```html
171
211
  <button class="px-4 py-2 rounded-md bg-primary-80 text-white hover:bg-primary-90 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-50">
172
212
  Click me
@@ -174,6 +214,7 @@ Emily generates utilities across these categories:
174
214
  ```
175
215
 
176
216
  ### Responsive Card
217
+
177
218
  ```html
178
219
  <div class="w-full md:w-96 p-4 md:p-6 rounded-lg bg-neutral-10 border-1 border-neutral-30 shadow-md">
179
220
  <h2 class="text-lg font-semibold text-neutral-90">Title</h2>
@@ -182,11 +223,12 @@ Emily generates utilities across these categories:
182
223
  ```
183
224
 
184
225
  ### Accessible Form Input
226
+
185
227
  ```html
186
228
  <label for="email" class="block text-sm font-medium text-neutral-80">
187
229
  Email
188
230
  </label>
189
- <input
231
+ <input
190
232
  id="email"
191
233
  type="email"
192
234
  class="mt-1 w-full px-3 py-2 border-1 border-neutral-40 rounded-md focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-50"
@@ -197,52 +239,50 @@ Emily generates utilities across these categories:
197
239
 
198
240
  All utilities are built with WCAG 2.2 AA in mind:
199
241
 
200
- - **Focus rings** Focus-visible states include proper colour contrast
201
- - **Colour contrast** All colour scales meet AA contrast ratios
202
- - **Motion** `motion-safe` and `motion-reduce` utilities for users with vestibular disorders
203
- - **Semantic HTML** Components use proper heading hierarchy and form labels
204
- - **Screen reader support** — `.sr-only` utility for screen-reader-only content
205
- - **Forced colours** — Utilities respect Windows High Contrast mode
242
+ - **Focus rings** - Focus-visible states include proper colour contrast
243
+ - **Colour contrast** - All colour scales meet AA contrast ratios
244
+ - **Motion** - `motion-safe` and `motion-reduce` utilities for users with vestibular disorders
245
+ - **Screen reader support** - `.sr-only` utility for screen-reader-only content
246
+ - **Forced colours** - Utilities respect Windows High Contrast mode
206
247
 
207
- ## Known Limitations
248
+ ## Testing
208
249
 
209
- These are post-v1 priorities:
210
- - Arbitrary values (`w-[123px]`) — deferred to v2
211
- - Extend system for custom utilities — deferred to v2
212
- - Pattern utilities (Wrapper, Flow, Stack) — deferred to v2
213
- - Watch mode / HMR deferred to v2
214
- - Pre-built component tier — deferred to v2
250
+ ```bash
251
+ npm test
252
+ ```
253
+
254
+ 66 automated tests covering colour generation, utilities, variants, config integrity, and build output. All passing.
215
255
 
216
256
  ## Troubleshooting
217
257
 
218
258
  ### Styles not applying?
219
- 1. Check that responsive prefix is correct: `.md\:flex` not `.md:flex`
220
- 2. Verify class name spelling in HTML
221
- 3. Clear browser cache and rebuild CSS
259
+
260
+ 1. Check the responsive prefix: `.md\:flex` not `.md:flex`
261
+ 2. Verify class name spelling
262
+ 3. Clear browser cache and rebuild: `npx emily-css build`
222
263
 
223
264
  ### File size too large?
224
- Use the purge system:
265
+
225
266
  ```bash
226
- emily-ui build --purge ./src
267
+ npx emily-css purge
227
268
  ```
228
269
 
229
270
  ### Config not applying?
271
+
230
272
  1. Edit `emily.config.json`
231
- 2. Run `npm run build` to regenerate CSS
232
- 3. No cache invalidation needed (CSS is regenerated from scratch)
273
+ 2. Run `npx emily-css build`
274
+ 3. No cache invalidation needed
233
275
 
234
276
  ## CDN
235
277
 
236
- Use emily-ui directly without npm via jsDelivr:
237
-
238
278
  ```html
239
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/emily-ui/dist/emily.css">
279
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/emily-css/dist/emily.css">
240
280
  ```
241
281
 
242
282
  ## Support
243
283
 
244
- Open an issue or start a discussion on GitHub:
245
- https://github.com/andyjterry/emily-ui
284
+ - Website: https://www.emilyui.com
285
+ - GitHub: https://github.com/andyjterry/emily-ui
246
286
 
247
287
  ## License
248
288
 
package/bin/emilyui.js CHANGED
@@ -6,12 +6,15 @@ if (command === "init") {
6
6
  require("../src/init.js");
7
7
  } else if (command === "build") {
8
8
  require("../src/index.js");
9
+ } else if (command === "purge") {
10
+ require("../src/purge-cmd.js");
9
11
  } else {
10
12
  console.log(`
11
- emily-ui Config-driven CSS framework generator
13
+ emily-css - Config-driven CSS framework generator
12
14
 
13
15
  Usage:
14
- emily-ui init Set up a new project
15
- emily-ui build Generate emily.css from your existing config
16
+ emily-css init Set up a new project
17
+ emily-css build Generate emily.css from your config
18
+ emily-css purge Remove unused utilities for production
16
19
  `);
17
- }
20
+ }
package/package.json CHANGED
@@ -1,15 +1,18 @@
1
1
  {
2
2
  "name": "emily-css",
3
- "version": "1.0.0",
4
- "description": "Config-driven, utility-first CSS framework. Define brand colours once, generate 11,000+ utilities, browse and copy production-ready components.",
3
+ "version": "1.0.2",
4
+ "description": "A config-driven utility CSS framework. Define your brand once, generate the CSS.",
5
5
  "main": "src/index.js",
6
6
  "bin": {
7
- "emily-ui": "./bin/emilyui.js"
7
+ "emily-css": "./bin/emilyui.js"
8
8
  },
9
9
  "files": [
10
10
  "bin/",
11
11
  "src/",
12
- "dist/",
12
+ "dist/emily.css",
13
+ "dist/emily.min.css",
14
+ "dist/emily.demo.css",
15
+ "dist/emily.demo.min.css",
13
16
  "fonts/",
14
17
  "README.md",
15
18
  "LICENSE"
package/src/index.js CHANGED
@@ -777,7 +777,7 @@ function addStateVariants(css) {
777
777
  function build(options = {}) {
778
778
  const configPath = path.join(process.cwd(), 'emily.config.json');
779
779
  if (!fs.existsSync(configPath)) {
780
- console.error(`\n emily-ui: No config found.\n Expected: ${configPath}\n Run "emily-ui init" to create one.\n`);
780
+ console.error(`\n emily-css: No config found.\n Expected: ${configPath}\n Run "emily-css init" to create one.\n`);
781
781
  process.exit(1);
782
782
  }
783
783
  const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
@@ -786,7 +786,7 @@ function build(options = {}) {
786
786
  const { purgeCSS } = require('./purge.js');
787
787
  const cssPath = path.join(process.cwd(), 'dist/emily.css');
788
788
  if (!fs.existsSync(cssPath)) {
789
- console.error(' emily-ui: Run emily-ui build first before purging.');
789
+ console.error(' emily-css: Run "emily-css build" first.');
790
790
  process.exit(1);
791
791
  }
792
792
  console.log(`Purging unused utilities from ${options.purge}...`);
package/src/init.js CHANGED
@@ -23,16 +23,16 @@ function isValidHex(hex) {
23
23
 
24
24
  // Default colours
25
25
  const defaultColours = {
26
- primary: '#0077b6',
27
- secondary: '#006d9e',
26
+ primary: '#DB2777',
27
+ secondary: '#2563EB',
28
28
  success: '#017F65',
29
29
  warning: '#ffc107',
30
30
  error: '#b20000',
31
- neutral: '#6b7280'
31
+ neutral: '#57534E'
32
32
  };
33
33
 
34
34
  // Default config template - matches emily.config.json structure
35
- function createDefaultConfig(name, colours, fonts, baseUnit) {
35
+ function createDefaultConfig(name, colours, fonts, baseUnit, sourceDir) {
36
36
  return {
37
37
  name,
38
38
  description: `${name} design system`,
@@ -206,10 +206,15 @@ async function init() {
206
206
  }
207
207
  }
208
208
 
209
- // 5. Create config
210
- const config = createDefaultConfig(name, colours, fonts, baseUnit);
209
+ // 5. Source directory for purge
210
+ console.log('\nSource directory for purge (where your templates/HTML live):');
211
+ let sourceDir = await prompt(' Source directory [./src]: ');
212
+ sourceDir = sourceDir.trim() || './src';
211
213
 
212
- // 6. Write config file to the user's project directory
214
+ // 6. Create config
215
+ const config = createDefaultConfig(name, colours, fonts, baseUnit, sourceDir);
216
+
217
+ // 7. Write config file to the user's project directory
213
218
  const configPath = path.join(process.cwd(), 'emily.config.json');
214
219
  fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
215
220
 
@@ -219,13 +224,13 @@ async function init() {
219
224
  console.log(` Base unit: ${baseUnit}px`);
220
225
  console.log(`\n📝 Config saved: ${configPath}`);
221
226
 
222
- // 7. Run build
227
+ // 8. Run build
223
228
  console.log('\n🔨 Building CSS...\n');
224
229
  rl.close();
225
230
 
226
231
  // Spawn build process
227
232
  const { spawn } = require('child_process');
228
- const build = spawn('npx', ['emily-ui', 'build'], {
233
+ const build = spawn('npx', ['emily-css', 'build'], {
229
234
  cwd: process.cwd(),
230
235
  stdio: 'inherit'
231
236
  });
@@ -237,7 +242,7 @@ async function init() {
237
242
  console.log(' 1. Open showcase.html in your browser to see components');
238
243
  console.log(' 2. Copy component code into your project');
239
244
  console.log(' 3. Update emily.config.json to customize colours/fonts');
240
- console.log(' 4. Run: npm run build -- --purge ./src (to reduce CSS size)');
245
+ console.log(' 4. Run: emily-css purge (to remove unused CSS for production)');
241
246
  } else {
242
247
  console.log('\n❌ Build failed');
243
248
  }
@@ -0,0 +1,55 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+
4
+ function runPurge() {
5
+ const configPath = path.join(process.cwd(), 'emily.config.json');
6
+
7
+ if (!fs.existsSync(configPath)) {
8
+ console.error('\n emily-css: No config found. Run "emily-css init" first.\n');
9
+ process.exit(1);
10
+ }
11
+
12
+ const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
13
+ const sourceDir = config.purge && config.purge.sourceDir;
14
+
15
+ if (!sourceDir) {
16
+ console.error('\n emily-css: No purge sourceDir in emily.config.json.');
17
+ console.error(' Add: "purge": { "sourceDir": "./src" }\n');
18
+ process.exit(1);
19
+ }
20
+
21
+ const cssPath = path.join(process.cwd(), 'dist/emily.css');
22
+
23
+ if (!fs.existsSync(cssPath)) {
24
+ console.error('\n emily-css: No CSS found. Run "emily-css build" first.\n');
25
+ process.exit(1);
26
+ }
27
+
28
+ const { purgeCSS } = require('./purge.js');
29
+
30
+ console.log('\nPurging unused utilities from ' + sourceDir + '...');
31
+
32
+ const css = fs.readFileSync(cssPath, 'utf8');
33
+ const purged = purgeCSS(css, sourceDir);
34
+ const minified = purged
35
+ .replace(/\/\*[\s\S]*?\*\//g, '')
36
+ .replace(/\s+/g, ' ')
37
+ .replace(/\s?\{/g, '{')
38
+ .replace(/\s?\}/g, '}')
39
+ .replace(/;\s/g, ';')
40
+ .trim();
41
+
42
+ fs.writeFileSync(path.join(process.cwd(), 'dist/emily.purged.css'), purged);
43
+ fs.writeFileSync(path.join(process.cwd(), 'dist/emily.purged.min.css'), minified);
44
+
45
+ const original = Buffer.byteLength(css, 'utf8');
46
+ const purgedSize = Buffer.byteLength(purged, 'utf8');
47
+ const reduction = Math.round((1 - purgedSize / original) * 100);
48
+
49
+ console.log('\n\u2713 Purged CSS written:');
50
+ console.log(' dist/emily.purged.css');
51
+ console.log(' dist/emily.purged.min.css');
52
+ console.log('\n ' + Math.round(original / 1024) + 'KB -> ' + Math.round(purgedSize / 1024) + 'KB (' + reduction + '% reduction)\n');
53
+ }
54
+
55
+ runPurge();