esm-styles 0.3.11 → 0.4.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
@@ -181,6 +181,11 @@ export default {
181
181
  hover: '(hover: hover)',
182
182
  // ...whatever you want
183
183
  },
184
+
185
+ // Import aliases (optional) - replace long relative paths with short prefixes
186
+ aliases: {
187
+ '@': '.', // resolves relative to sourcePath
188
+ },
184
189
  }
185
190
  ```
186
191
 
@@ -451,6 +456,50 @@ The build process wraps floors in their respective layers and generates a main C
451
456
 
452
457
  Missing variables in one theme automatically inherit from the previous theme in the configuration.
453
458
 
459
+ ### Import Aliases
460
+
461
+ Simplify imports in your style files by configuring path aliases:
462
+
463
+ ```js
464
+ // esm-styles.config.js
465
+ export default {
466
+ // ...
467
+ aliases: {
468
+ '@': '.', // @ resolves to sourcePath
469
+ '@components': './components',
470
+ },
471
+ }
472
+ ```
473
+
474
+ Then use in your style files:
475
+
476
+ ```js
477
+ // Before (relative paths)
478
+ import $theme from '../../$theme.mjs'
479
+ import { button } from '../components/button.styles.mjs'
480
+
481
+ // After (with aliases)
482
+ import $theme from '@/$theme.mjs'
483
+ import { button } from '@components/button.styles.mjs'
484
+ ```
485
+
486
+ Alias paths are resolved relative to the `sourcePath` directory. This feature uses esbuild internally for fast module resolution.
487
+
488
+ #### IDE Support for Aliases
489
+
490
+ To enable Cmd+click navigation and IntelliSense for aliased imports, create a `jsconfig.json` in your styles source directory with matching path mappings:
491
+
492
+ ```json
493
+ {
494
+ "compilerOptions": {
495
+ "baseUrl": ".",
496
+ "paths": {
497
+ "@/*": ["./*"]
498
+ }
499
+ }
500
+ }
501
+ ```
502
+
454
503
  ## Additional documentation
455
504
 
456
505
  For humans: [doc/usage-guide.md](doc/usage-guide.md)
package/dist/lib/build.js CHANGED
@@ -6,7 +6,38 @@ import path from 'node:path';
6
6
  import fs from 'node:fs/promises';
7
7
  // import { inspect } from 'node:util'
8
8
  import _ from 'lodash';
9
- import CleanCSS from 'clean-css';
9
+ import * as esbuild from 'esbuild';
10
+ /**
11
+ * Import a module with alias resolution using esbuild.
12
+ * Falls back to direct import when no aliases are configured.
13
+ */
14
+ async function importWithAliases(filePath, aliases, sourcePath) {
15
+ // If no aliases configured, use direct import with cache-busting
16
+ if (!aliases || Object.keys(aliases).length === 0) {
17
+ const fileUrl = pathToFileUrl(filePath).href + `?update=${Date.now()}`;
18
+ return import(fileUrl);
19
+ }
20
+ // Resolve aliases relative to sourcePath
21
+ const resolvedAliases = {};
22
+ for (const [key, value] of Object.entries(aliases)) {
23
+ resolvedAliases[key] = path.resolve(sourcePath, value);
24
+ }
25
+ // Use esbuild to bundle with alias resolution
26
+ const result = await esbuild.build({
27
+ entryPoints: [filePath],
28
+ bundle: true,
29
+ write: false,
30
+ format: 'esm',
31
+ platform: 'node',
32
+ alias: resolvedAliases,
33
+ // Prevent esbuild from trying to resolve node_modules
34
+ packages: 'external',
35
+ });
36
+ // Import from data URL to avoid filesystem caching
37
+ const code = result.outputFiles[0].text;
38
+ const dataUrl = `data:text/javascript;base64,${Buffer.from(code).toString('base64')}`;
39
+ return import(dataUrl);
40
+ }
10
41
  export async function build(configPath = 'esm-styles.config.js') {
11
42
  // --- Supporting module generation ---
12
43
  // Debug: log mergedSets and sets
@@ -23,6 +54,7 @@ export async function build(configPath = 'esm-styles.config.js') {
23
54
  const suffix = config.sourceFilesSuffix || '.styles.mjs';
24
55
  const floors = config.floors || [];
25
56
  const mainCssFile = config.mainCssFile || 'styles.css';
57
+ const aliases = config.aliases;
26
58
  // Helper function to generate CSS comment header
27
59
  const generateCssComment = (sourceName) => {
28
60
  const normalizedBasePath = (config.basePath || '.').replace(/^\.*\//, '');
@@ -38,8 +70,8 @@ export async function build(configPath = 'esm-styles.config.js') {
38
70
  if (config.globalVariables) {
39
71
  const inputFile = path.join(sourcePath, `${config.globalVariables}${suffix}`);
40
72
  const outputFile = path.join(outputPath, `global.css`);
41
- const fileUrl = pathToFileUrl(inputFile).href + `?update=${Date.now()}`;
42
- const varsObj = (await import(fileUrl)).default;
73
+ const varsObj = (await importWithAliases(inputFile, aliases, sourcePath))
74
+ .default;
43
75
  const cssVars = getCssVariables(varsObj);
44
76
  const rootSelector = config.globalRootSelector || ':root';
45
77
  const comment = generateCssComment(config.globalVariables);
@@ -57,8 +89,7 @@ export async function build(configPath = 'esm-styles.config.js') {
57
89
  for (const setName of sets) {
58
90
  // Inheritance: merge with previous
59
91
  const inputFile = path.join(sourcePath, `${setName}${suffix}`);
60
- const fileUrl = pathToFileUrl(inputFile).href + `?update=${Date.now()}`;
61
- const varsObj = _.merge({}, prevVarsObj, (await import(fileUrl)).default);
92
+ const varsObj = _.merge({}, prevVarsObj, (await importWithAliases(inputFile, aliases, sourcePath)).default);
62
93
  prevVarsObj = varsObj;
63
94
  mergedSets[setName] = _.cloneDeep(varsObj);
64
95
  // For each selector config for this set
@@ -187,8 +218,8 @@ export async function build(configPath = 'esm-styles.config.js') {
187
218
  // Ensure the output directory exists
188
219
  await fs.mkdir(floorOutputDir, { recursive: true });
189
220
  const outputFile = path.join(floorOutputDir, `${source}.css`);
190
- const fileUrl = pathToFileUrl(inputFile).href + `?update=${Date.now()}`;
191
- const stylesObj = (await import(fileUrl)).default;
221
+ const stylesObj = (await importWithAliases(inputFile, aliases, sourcePath))
222
+ .default;
192
223
  const css = getCss(stylesObj, {
193
224
  ...mediaShorthands,
194
225
  globalRootSelector: config.globalRootSelector,
@@ -204,7 +235,13 @@ export async function build(configPath = 'esm-styles.config.js') {
204
235
  }
205
236
  // if floor should be minified, minify wrappedCss string
206
237
  if (minify) {
207
- wrappedCss = new CleanCSS().minify(wrappedCss).styles;
238
+ const result = await esbuild.transform(wrappedCss, {
239
+ loader: 'css',
240
+ minifyWhitespace: true,
241
+ minifyIdentifiers: true,
242
+ minifySyntax: false,
243
+ });
244
+ wrappedCss = result.code;
208
245
  }
209
246
  await fs.writeFile(outputFile, wrappedCss, 'utf8');
210
247
  // Calculate relative path from default output directory for imports
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "esm-styles",
3
- "version": "0.3.11",
3
+ "version": "0.4.0",
4
4
  "description": "A library for working with ESM styles",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -35,7 +35,6 @@
35
35
  "watch": "dist/watch.js"
36
36
  },
37
37
  "devDependencies": {
38
- "@types/clean-css": "^4.2.11",
39
38
  "@types/jest": "^29.5.14",
40
39
  "@types/js-beautify": "^1.14.3",
41
40
  "@types/lodash": "^4.17.16",
@@ -50,7 +49,7 @@
50
49
  "typescript": "^5.8.3"
51
50
  },
52
51
  "dependencies": {
53
- "clean-css": "^5.3.3",
52
+ "esbuild": "^0.27.2",
54
53
  "js-beautify": "^1.15.4"
55
54
  },
56
55
  "repository": {