tailwind-to-style 2.8.4 → 2.8.6

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
@@ -7,10 +7,11 @@
7
7
 
8
8
  `tailwind-to-style` is a JavaScript library designed to convert Tailwind CSS utility classes into inline styles or JavaScript objects. This is especially useful when you need to dynamically apply styles to elements in frameworks like React, where inline styles or style objects are frequently used.
9
9
 
10
- The library exposes two main functions:
10
+ The library exposes two main functions and a CLI tool:
11
11
 
12
12
  1. **`tws`**: Converts Tailwind CSS classes into inline CSS styles or JavaScript objects (JSON).
13
13
  2. **`twsx`**: A more advanced function that allows you to define nested and complex styles similar to SCSS, including support for responsive, state variants, and grouping.
14
+ 3. **`twsx-cli`**: A command-line tool for generating CSS files from `twsx.*.js` files with watch mode support.
14
15
 
15
16
  ## Installation
16
17
 
@@ -505,18 +506,29 @@ export default {
505
506
  plugins: [
506
507
  twsxPlugin({
507
508
  inputDir: 'src',
508
- outputDir: 'src/styles'
509
+ outputDir: 'src/styles',
510
+ preserveStructure: false // Set to true to generate CSS next to JS files
509
511
  })
510
512
  ]
511
513
  };
512
514
  ```
513
515
 
514
- After build, individual CSS files will be created in `src/styles/` (e.g., `twsx.card.css`, `twsx.button.css`).
516
+ **Configuration Options:**
517
+ - `inputDir`: Directory to scan for `twsx.*.js` files (default: `'src'`)
518
+ - `outputDir`: Directory where CSS files will be generated (default: `'src/styles'`)
519
+ - `preserveStructure`: Whether to generate CSS files next to their JS counterparts (default: `false`)
520
+
521
+ **Default mode:** CSS files created in `src/styles/` (e.g., `twsx.card.css`, `twsx.button.css`).
522
+ **Preserve structure mode:** CSS files created next to JS files (e.g., `src/components/Card/twsx.card.css`).
523
+
515
524
  Import in your components:
516
525
  ```js
517
- // Import specific CSS files
526
+ // Default mode
518
527
  import './styles/twsx.card.css';
519
528
  import './styles/twsx.button.css';
529
+
530
+ // Preserve structure mode
531
+ import './twsx.card.css'; // If in same directory
520
532
  ```
521
533
 
522
534
  #### Webpack Plugin Usage Example
@@ -529,56 +541,152 @@ module.exports = {
529
541
  plugins: [
530
542
  new TwsxPlugin({
531
543
  inputDir: 'src',
532
- outputDir: 'src/styles'
544
+ outputDir: 'src/styles',
545
+ preserveStructure: false // Set to true to generate CSS next to JS files
533
546
  })
534
547
  ]
535
548
  };
536
549
  ```
537
550
 
538
- After build, individual CSS files will be created in `src/styles/` (e.g., `twsx.card.css`, `twsx.button.css`).
551
+ **Configuration Options:**
552
+ - `inputDir`: Directory to scan for `twsx.*.js` files (default: `'src'`)
553
+ - `outputDir`: Directory where CSS files will be generated (default: `'src/styles'`)
554
+ - `preserveStructure`: Whether to generate CSS files next to their JS counterparts (default: `false`)
555
+
556
+ **Default mode:** CSS files created in `src/styles/` (e.g., `twsx.card.css`, `twsx.button.css`).
557
+ **Preserve structure mode:** CSS files created next to JS files (e.g., `src/components/Card/twsx.card.css`).
558
+
539
559
  Import in your components:
540
560
  ```js
541
- // Import specific CSS files
561
+ // Default mode
542
562
  import './styles/twsx.card.css';
543
563
  import './styles/twsx.button.css';
564
+
565
+ // Preserve structure mode
566
+ import './twsx.card.css'; // If in same directory
544
567
  ```
545
568
 
546
569
  ## Build-Time CSS Generation via Script
547
570
 
548
571
  In addition to using the Vite/Webpack plugin, you can also use a Node.js script to generate CSS files from `twsx.*.js` files manually or as part of your build workflow.
549
572
 
550
- ### Script: tailwind-to-style/lib/build-twsx.js
573
+ ### Script: tailwind-to-style/lib/twsx-cli.js (Legacy)
574
+
575
+ > **💡 Recommended:** Use `npx twsx-cli` instead of calling the script directly.
551
576
 
552
577
  This script will recursively scan for all `twsx.*.js` files in your project, generate CSS using the `twsx` function, and write individual CSS files to the specified output directory.
553
578
 
554
579
  #### How to Use
555
580
 
556
581
  1. Create JS files with `twsx.` prefix containing style objects anywhere in your `src/` folder (e.g., `src/components/twsx.card.js`).
557
- 2. Run the script with the following command:
558
582
 
583
+ 2. **One-time Build:**
559
584
  ```bash
560
- node tailwind-to-style/lib/build-twsx.js
585
+ node tailwind-to-style/lib/twsx-cli.js
586
+ ```
587
+
588
+ 3. **Watch Mode (Auto-rebuild on file changes):**
589
+ ```bash
590
+ node tailwind-to-style/lib/twsx-cli.js --watch
591
+ ```
592
+
593
+ 4. **Preserve Structure Mode (Generate CSS next to JS files):**
594
+ ```bash
595
+ # One-time build with preserve structure
596
+ node tailwind-to-style/lib/twsx-cli.js --preserve-structure
597
+
598
+ # Watch mode with preserve structure
599
+ node tailwind-to-style/lib/twsx-cli.js --watch --preserve-structure
561
600
  ```
562
601
 
563
602
  You can configure input and output directories using environment variables:
564
603
  ```bash
565
- TWSX_INPUT_DIR=src TWSX_OUTPUT_DIR=dist/styles node tailwind-to-style/lib/build-twsx.js
604
+ TWSX_INPUT_DIR=src TWSX_OUTPUT_DIR=dist/styles node tailwind-to-style/lib/twsx-cli.js --watch
605
+ ```
606
+
607
+ Or use environment variables for preserve structure:
608
+ ```bash
609
+ TWSX_PRESERVE_STRUCTURE=true node tailwind-to-style/lib/twsx-cli.js --watch
566
610
  ```
567
611
 
568
- 3. After running, individual CSS files will be available in the output directory (default: `src/styles/`):
612
+ 5. **Output locations:**
569
613
 
614
+ **Default mode:** CSS files will be in the output directory (default: `src/styles/`):
570
615
  ```
571
616
  src/styles/twsx.card.css
572
617
  src/styles/twsx.button.css
573
618
  ```
574
619
 
575
- 4. Import the generated CSS files in your components:
620
+ **Preserve structure mode:** CSS files will be generated next to their JS counterparts:
621
+ ```
622
+ src/components/Button/twsx.button.js → src/components/Button/twsx.button.css
623
+ src/components/Card/twsx.card.js → src/components/Card/twsx.card.css
624
+ ```
625
+
626
+ 5. Import the generated CSS files in your components:
576
627
 
628
+ **Default mode:**
577
629
  ```js
578
630
  import './styles/twsx.card.css';
579
631
  import './styles/twsx.button.css';
580
632
  ```
581
633
 
634
+ **Preserve structure mode:**
635
+ ```js
636
+ // In src/components/Button/Button.jsx
637
+ import './twsx.button.css';
638
+
639
+ // In src/components/Card/Card.jsx
640
+ import './twsx.card.css';
641
+ ```
642
+
643
+ #### Usage in Different Projects
644
+
645
+ **React/Next.js/Vue/Any Project:**
646
+
647
+ 1. Install the package:
648
+ ```bash
649
+ npm install tailwind-to-style
650
+ ```
651
+
652
+ 2. Add to your `package.json`:
653
+ ```json
654
+ {
655
+ "scripts": {
656
+ "twsx:build": "node node_modules/tailwind-to-style/lib/twsx-cli.js",
657
+ "twsx:watch": "node node_modules/tailwind-to-style/lib/twsx-cli.js --watch",
658
+ "twsx:preserve": "node node_modules/tailwind-to-style/lib/twsx-cli.js --preserve-structure",
659
+ "twsx:dev": "node node_modules/tailwind-to-style/lib/twsx-cli.js --watch --preserve-structure",
660
+ "dev": "npm run twsx:watch & next dev"
661
+ }
662
+ }
663
+ ```
664
+
665
+ 3. For development with auto-rebuild:
666
+ ```bash
667
+ npm run twsx:watch
668
+ ```
669
+
670
+ 4. For production build:
671
+ ```bash
672
+ npm run twsx:build
673
+ ```
674
+
675
+ **VS Code Integration:**
676
+ Add to your workspace settings (`.vscode/settings.json`):
677
+ ```json
678
+ {
679
+ "emeraldwalk.runonsave": {
680
+ "commands": [
681
+ {
682
+ "match": "twsx\\..*\\.js$",
683
+ "cmd": "npm run twsx:build"
684
+ }
685
+ ]
686
+ }
687
+ }
688
+ ```
689
+
582
690
  #### Automatic Integration
583
691
 
584
692
  You can add this script to the build section in your `package.json`:
@@ -586,7 +694,7 @@ You can add this script to the build section in your `package.json`:
586
694
  ```json
587
695
  {
588
696
  "scripts": {
589
- "build-css": "node tailwind-to-style/lib/build-twsx.js"
697
+ "build-css": "node tailwind-to-style/lib/twsx-cli.js"
590
698
  }
591
699
  }
592
700
  ```
@@ -1,5 +1,5 @@
1
1
  /**
2
- * tailwind-to-style v2.8.4
2
+ * tailwind-to-style v2.8.6
3
3
  * Convert tailwind classes to inline style
4
4
  *
5
5
  * @author Bigetion
package/dist/index.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * tailwind-to-style v2.8.4
2
+ * tailwind-to-style v2.8.6
3
3
  * Convert tailwind classes to inline style
4
4
  *
5
5
  * @author Bigetion
package/dist/index.esm.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * tailwind-to-style v2.8.4
2
+ * tailwind-to-style v2.8.6
3
3
  * Convert tailwind classes to inline style
4
4
  *
5
5
  * @author Bigetion
@@ -0,0 +1,149 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+ import { pathToFileURL } from "url";
4
+ import { twsx } from "tailwind-to-style";
5
+ import chokidar from "chokidar";
6
+
7
+ function findTwsxFiles(dir, files = []) {
8
+ const items = fs.readdirSync(dir);
9
+ for (const item of items) {
10
+ const fullPath = path.join(dir, item);
11
+ const stat = fs.statSync(fullPath);
12
+ if (stat.isDirectory()) {
13
+ findTwsxFiles(fullPath, files);
14
+ } else if (item.startsWith("twsx.") && item.endsWith(".js")) {
15
+ files.push(fullPath);
16
+ }
17
+ }
18
+ return files;
19
+ }
20
+
21
+ async function buildTwsx(inputDir, outputDir, preserveStructure = false) {
22
+ try {
23
+ const twsxFiles = findTwsxFiles(inputDir);
24
+ const generatedCssFiles = [];
25
+
26
+ // Generate CSS from JS files
27
+ for (const filePath of twsxFiles) {
28
+ try {
29
+ const styleModule = await import(
30
+ pathToFileURL(filePath).href + `?update=${Date.now()}`
31
+ );
32
+ const styleObj = styleModule.default || styleModule;
33
+ const css = twsx(styleObj, { inject: false });
34
+ const fileName = path.basename(filePath).replace(/\.js$/, ".css");
35
+
36
+ let cssFilePath;
37
+ if (preserveStructure) {
38
+ // Generate CSS in the same directory as the JS file
39
+ cssFilePath = filePath.replace(/\.js$/, ".css");
40
+ } else {
41
+ // Generate CSS in the output directory
42
+ cssFilePath = path.join(outputDir, fileName);
43
+ }
44
+
45
+ fs.writeFileSync(cssFilePath, css);
46
+ generatedCssFiles.push(preserveStructure ? cssFilePath : fileName);
47
+ console.log(`[twsx-cli] CSS written to ${cssFilePath}`);
48
+ } catch (err) {
49
+ console.error(
50
+ `[twsx-cli] Error importing or processing ${filePath}:`,
51
+ err
52
+ );
53
+ }
54
+ }
55
+
56
+ // Clean up orphaned CSS files
57
+ if (!preserveStructure && fs.existsSync(outputDir)) {
58
+ const existingCssFiles = fs
59
+ .readdirSync(outputDir)
60
+ .filter((file) => file.startsWith("twsx.") && file.endsWith(".css"));
61
+
62
+ for (const cssFile of existingCssFiles) {
63
+ if (!generatedCssFiles.includes(cssFile)) {
64
+ const cssFilePath = path.join(outputDir, cssFile);
65
+ fs.unlinkSync(cssFilePath);
66
+ console.log(`[twsx-cli] Removed orphaned CSS: ${cssFilePath}`);
67
+ }
68
+ }
69
+ } else if (preserveStructure) {
70
+ // Clean up orphaned CSS files in preserve structure mode
71
+ const twsxFiles = findTwsxFiles(inputDir);
72
+ const expectedCssFiles = twsxFiles.map(file => file.replace(/\.js$/, ".css"));
73
+
74
+ // Find and remove orphaned CSS files
75
+ function cleanupOrphanedCss(dir) {
76
+ if (!fs.existsSync(dir)) return;
77
+
78
+ const items = fs.readdirSync(dir);
79
+ for (const item of items) {
80
+ const fullPath = path.join(dir, item);
81
+ const stat = fs.statSync(fullPath);
82
+ if (stat.isDirectory()) {
83
+ cleanupOrphanedCss(fullPath);
84
+ } else if (item.startsWith("twsx.") && item.endsWith(".css")) {
85
+ if (!expectedCssFiles.includes(fullPath)) {
86
+ fs.unlinkSync(fullPath);
87
+ console.log(`[twsx-cli] Removed orphaned CSS: ${fullPath}`);
88
+ }
89
+ }
90
+ }
91
+ }
92
+
93
+ cleanupOrphanedCss(inputDir);
94
+ }
95
+ } catch (err) {
96
+ console.error("[twsx-cli] Error scanning for twsx files:", err);
97
+ }
98
+ }
99
+
100
+ const inputDir =
101
+ process.env.TWSX_INPUT_DIR || path.resolve(process.cwd(), "src");
102
+ const outputDir =
103
+ process.env.TWSX_OUTPUT_DIR || path.resolve(process.cwd(), "src/styles");
104
+ const watchMode = process.argv.includes("--watch") || process.env.TWSX_WATCH === "true";
105
+ const preserveStructure = process.argv.includes("--preserve-structure") || process.env.TWSX_PRESERVE_STRUCTURE === "true";
106
+
107
+ if (!preserveStructure && !fs.existsSync(outputDir)) {
108
+ fs.mkdirSync(outputDir, { recursive: true });
109
+ }
110
+
111
+ // Initial build
112
+ (async () => {
113
+ try {
114
+ await buildTwsx(inputDir, outputDir, preserveStructure);
115
+ console.log(`[twsx-cli] Initial build completed`);
116
+
117
+ if (watchMode) {
118
+ console.log(`[twsx-cli] Watching for changes in ${inputDir}...`);
119
+
120
+ const watcher = chokidar.watch(`${inputDir}/**/twsx.*.js`, {
121
+ ignored: /node_modules/,
122
+ persistent: true,
123
+ });
124
+
125
+ watcher
126
+ .on("change", async (filePath) => {
127
+ console.log(`[twsx-cli] File changed: ${filePath}`);
128
+ await buildTwsx(inputDir, outputDir, preserveStructure);
129
+ })
130
+ .on("add", async (filePath) => {
131
+ console.log(`[twsx-cli] File added: ${filePath}`);
132
+ await buildTwsx(inputDir, outputDir, preserveStructure);
133
+ })
134
+ .on("unlink", async (filePath) => {
135
+ console.log(`[twsx-cli] File removed: ${filePath}`);
136
+ await buildTwsx(inputDir, outputDir, preserveStructure);
137
+ });
138
+
139
+ // Keep the process alive
140
+ process.on("SIGINT", () => {
141
+ console.log("\n[twsx-cli] Stopping watcher...");
142
+ watcher.close();
143
+ process.exit(0);
144
+ });
145
+ }
146
+ } catch (err) {
147
+ console.error("[twsx-cli] Error writing CSS:", err);
148
+ }
149
+ })();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tailwind-to-style",
3
- "version": "2.8.4",
3
+ "version": "2.8.6",
4
4
  "description": "Convert tailwind classes to inline style",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
@@ -12,9 +12,11 @@
12
12
  "README.md",
13
13
  "LICENSE",
14
14
  "plugins",
15
- "lib",
16
- "twsx.css"
15
+ "lib"
17
16
  ],
17
+ "bin": {
18
+ "twsx-cli": "./lib/twsx-cli.js"
19
+ },
18
20
  "scripts": {
19
21
  "test": "node --experimental-vm-modules node_modules/jest/bin/jest.js --passWithNoTests",
20
22
  "build": "rollup -c rollup.config.js",
@@ -54,6 +56,7 @@
54
56
  "@rollup/plugin-terser": "^0.4.4",
55
57
  "babel-jest": "^28.1.0",
56
58
  "babel-loader": "^10.0.0",
59
+ "chokidar": "^4.0.1",
57
60
  "eslint": "^8.16.0",
58
61
  "jest": "^28.1.0",
59
62
  "prettier": "^3.5.3",
@@ -17,7 +17,7 @@ function findTwsxFiles(dir, files = []) {
17
17
  return files;
18
18
  }
19
19
 
20
- async function buildTwsx(inputDir, outputDir) {
20
+ async function buildTwsx(inputDir, outputDir, preserveStructure = false) {
21
21
  try {
22
22
  const twsxFiles = findTwsxFiles(inputDir);
23
23
  const generatedCssFiles = [];
@@ -31,9 +31,24 @@ async function buildTwsx(inputDir, outputDir) {
31
31
  const styleObj = styleModule.default || styleModule;
32
32
  const css = twsx(styleObj, { inject: false });
33
33
  const fileName = path.basename(filePath).replace(/\.js$/, ".css");
34
- const cssFilePath = path.join(outputDir, fileName);
34
+
35
+ let cssFilePath;
36
+ if (preserveStructure) {
37
+ // Generate CSS file next to the JS file
38
+ cssFilePath = filePath.replace(/\.js$/, ".css");
39
+ } else {
40
+ // Generate CSS file in the output directory
41
+ cssFilePath = path.join(outputDir, fileName);
42
+ }
43
+
44
+ // Ensure the directory exists
45
+ const cssDir = path.dirname(cssFilePath);
46
+ if (!fs.existsSync(cssDir)) {
47
+ fs.mkdirSync(cssDir, { recursive: true });
48
+ }
49
+
35
50
  fs.writeFileSync(cssFilePath, css);
36
- generatedCssFiles.push(fileName);
51
+ generatedCssFiles.push(preserveStructure ? cssFilePath : fileName);
37
52
  } catch (err) {
38
53
  console.error(
39
54
  `[vite-twsx] Error importing or processing ${filePath}:`,
@@ -43,15 +58,27 @@ async function buildTwsx(inputDir, outputDir) {
43
58
  }
44
59
 
45
60
  // Clean up orphaned CSS files
46
- if (fs.existsSync(outputDir)) {
47
- const existingCssFiles = fs
48
- .readdirSync(outputDir)
49
- .filter((file) => file.startsWith("twsx.") && file.endsWith(".css"));
61
+ if (preserveStructure) {
62
+ // For preserve structure mode, clean up next to JS files
63
+ const allJsFiles = findTwsxFiles(inputDir);
64
+ for (const jsFile of allJsFiles) {
65
+ const cssFile = jsFile.replace(/\.js$/, ".css");
66
+ if (fs.existsSync(cssFile) && !generatedCssFiles.includes(cssFile)) {
67
+ fs.unlinkSync(cssFile);
68
+ }
69
+ }
70
+ } else {
71
+ // For normal mode, clean up in output directory
72
+ if (fs.existsSync(outputDir)) {
73
+ const existingCssFiles = fs
74
+ .readdirSync(outputDir)
75
+ .filter((file) => file.startsWith("twsx.") && file.endsWith(".css"));
50
76
 
51
- for (const cssFile of existingCssFiles) {
52
- if (!generatedCssFiles.includes(cssFile)) {
53
- const cssFilePath = path.join(outputDir, cssFile);
54
- fs.unlinkSync(cssFilePath);
77
+ for (const cssFile of existingCssFiles) {
78
+ if (!generatedCssFiles.includes(cssFile)) {
79
+ const cssFilePath = path.join(outputDir, cssFile);
80
+ fs.unlinkSync(cssFilePath);
81
+ }
55
82
  }
56
83
  }
57
84
  }
@@ -65,8 +92,9 @@ export default function twsxPlugin(options = {}) {
65
92
  const inputDir = options.inputDir || path.resolve(process.cwd(), "src");
66
93
  const outputDir =
67
94
  options.outputDir || path.resolve(process.cwd(), "src/styles");
95
+ const preserveStructure = options.preserveStructure || false;
68
96
 
69
- if (!fs.existsSync(outputDir)) {
97
+ if (!preserveStructure && !fs.existsSync(outputDir)) {
70
98
  fs.mkdirSync(outputDir, { recursive: true });
71
99
  }
72
100
 
@@ -74,14 +102,14 @@ export default function twsxPlugin(options = {}) {
74
102
  name: "vite-twsx",
75
103
  async buildStart() {
76
104
  try {
77
- await buildTwsx(inputDir, outputDir);
105
+ await buildTwsx(inputDir, outputDir, preserveStructure);
78
106
  } catch (err) {
79
107
  console.error("[vite-twsx] Error writing CSS:", err);
80
108
  }
81
109
  },
82
110
  async handleHotUpdate() {
83
111
  try {
84
- await buildTwsx(inputDir, outputDir);
112
+ await buildTwsx(inputDir, outputDir, preserveStructure);
85
113
  } catch (err) {
86
114
  console.error("[vite-twsx] Error updating CSS:", err);
87
115
  }
@@ -17,7 +17,7 @@ function findTwsxFiles(dir, files = []) {
17
17
  return files;
18
18
  }
19
19
 
20
- async function buildTwsx(inputDir, outputDir) {
20
+ async function buildTwsx(inputDir, outputDir, preserveStructure = false) {
21
21
  try {
22
22
  const twsxFiles = findTwsxFiles(inputDir);
23
23
  const generatedCssFiles = [];
@@ -31,9 +31,24 @@ async function buildTwsx(inputDir, outputDir) {
31
31
  const styleObj = styleModule.default || styleModule;
32
32
  const css = twsx(styleObj, { inject: false });
33
33
  const fileName = path.basename(filePath).replace(/\.js$/, ".css");
34
- const cssFilePath = path.join(outputDir, fileName);
34
+
35
+ let cssFilePath;
36
+ if (preserveStructure) {
37
+ // Generate CSS file next to the JS file
38
+ cssFilePath = filePath.replace(/\.js$/, ".css");
39
+ } else {
40
+ // Generate CSS file in the output directory
41
+ cssFilePath = path.join(outputDir, fileName);
42
+ }
43
+
44
+ // Ensure the directory exists
45
+ const cssDir = path.dirname(cssFilePath);
46
+ if (!fs.existsSync(cssDir)) {
47
+ fs.mkdirSync(cssDir, { recursive: true });
48
+ }
49
+
35
50
  fs.writeFileSync(cssFilePath, css);
36
- generatedCssFiles.push(fileName);
51
+ generatedCssFiles.push(preserveStructure ? cssFilePath : fileName);
37
52
  } catch (err) {
38
53
  console.error(
39
54
  `[webpack-twsx] Error importing or processing ${filePath}:`,
@@ -43,16 +58,28 @@ async function buildTwsx(inputDir, outputDir) {
43
58
  }
44
59
 
45
60
  // Clean up orphaned CSS files
46
- if (fs.existsSync(outputDir)) {
47
- const existingCssFiles = fs.readdirSync(outputDir).filter((file) => {
48
- return file.startsWith("twsx.") && file.endsWith(".css");
49
- });
61
+ if (preserveStructure) {
62
+ // For preserve structure mode, clean up next to JS files
63
+ const allJsFiles = findTwsxFiles(inputDir);
64
+ for (const jsFile of allJsFiles) {
65
+ const cssFile = jsFile.replace(/\.js$/, ".css");
66
+ if (fs.existsSync(cssFile) && !generatedCssFiles.includes(cssFile)) {
67
+ fs.unlinkSync(cssFile);
68
+ }
69
+ }
70
+ } else {
71
+ // For normal mode, clean up in output directory
72
+ if (fs.existsSync(outputDir)) {
73
+ const existingCssFiles = fs.readdirSync(outputDir).filter((file) => {
74
+ return file.startsWith("twsx.") && file.endsWith(".css");
75
+ });
50
76
 
51
- if (Array.isArray(existingCssFiles) && Array.isArray(generatedCssFiles)) {
52
- for (const cssFile of existingCssFiles) {
53
- if (!generatedCssFiles.includes(cssFile)) {
54
- const cssFilePath = path.join(outputDir, cssFile);
55
- fs.unlinkSync(cssFilePath);
77
+ if (Array.isArray(existingCssFiles) && Array.isArray(generatedCssFiles)) {
78
+ for (const cssFile of existingCssFiles) {
79
+ if (!generatedCssFiles.includes(cssFile)) {
80
+ const cssFilePath = path.join(outputDir, cssFile);
81
+ fs.unlinkSync(cssFilePath);
82
+ }
56
83
  }
57
84
  }
58
85
  }
@@ -67,7 +94,9 @@ class TwsxPlugin {
67
94
  this.inputDir = options.inputDir || path.resolve(process.cwd(), "src");
68
95
  this.outputDir =
69
96
  options.outputDir || path.resolve(process.cwd(), "src/styles");
70
- if (!fs.existsSync(this.outputDir)) {
97
+ this.preserveStructure = options.preserveStructure || false;
98
+
99
+ if (!this.preserveStructure && !fs.existsSync(this.outputDir)) {
71
100
  fs.mkdirSync(this.outputDir, { recursive: true });
72
101
  }
73
102
  }
@@ -75,14 +104,14 @@ class TwsxPlugin {
75
104
  apply(compiler) {
76
105
  compiler.hooks.beforeCompile.tapPromise("TwsxPlugin", async () => {
77
106
  try {
78
- await buildTwsx(this.inputDir, this.outputDir);
107
+ await buildTwsx(this.inputDir, this.outputDir, this.preserveStructure);
79
108
  } catch (err) {
80
109
  console.error("[webpack-twsx] Error writing CSS:", err);
81
110
  }
82
111
  });
83
112
  compiler.hooks.watchRun.tapPromise("TwsxPlugin", async () => {
84
113
  try {
85
- await buildTwsx(this.inputDir, this.outputDir);
114
+ await buildTwsx(this.inputDir, this.outputDir, this.preserveStructure);
86
115
  } catch (err) {
87
116
  console.error("[webpack-twsx] Error updating CSS:", err);
88
117
  }
package/lib/build-twsx.js DELETED
@@ -1,59 +0,0 @@
1
- import fs from "fs";
2
- import path from "path";
3
- import { pathToFileURL } from "url";
4
- import { twsx } from "tailwind-to-style";
5
-
6
- function findTwsxFiles(dir, files = []) {
7
- const items = fs.readdirSync(dir);
8
- for (const item of items) {
9
- const fullPath = path.join(dir, item);
10
- const stat = fs.statSync(fullPath);
11
- if (stat.isDirectory()) {
12
- findTwsxFiles(fullPath, files);
13
- } else if (item.startsWith("twsx.") && item.endsWith(".js")) {
14
- files.push(fullPath);
15
- }
16
- }
17
- return files;
18
- }
19
-
20
- async function buildTwsx(inputDir, outputDir) {
21
- try {
22
- const twsxFiles = findTwsxFiles(inputDir);
23
- for (const filePath of twsxFiles) {
24
- try {
25
- const styleModule = await import(
26
- pathToFileURL(filePath).href + `?update=${Date.now()}`
27
- );
28
- const styleObj = styleModule.default || styleModule;
29
- const css = twsx(styleObj, { inject: false });
30
- const fileName = path.basename(filePath).replace(/\.js$/, ".css");
31
- const cssFilePath = path.join(outputDir, fileName);
32
- fs.writeFileSync(cssFilePath, css);
33
- } catch (err) {
34
- console.error(
35
- `[build-twsx] Error importing or processing ${filePath}:`,
36
- err
37
- );
38
- }
39
- }
40
- } catch (err) {
41
- console.error("[build-twsx] Error scanning for twsx files:", err);
42
- }
43
- }
44
-
45
- const inputDir =
46
- process.env.TWSX_INPUT_DIR || path.resolve(process.cwd(), "src");
47
- const outputDir =
48
- process.env.TWSX_OUTPUT_DIR || path.resolve(process.cwd(), "src/styles");
49
- if (!fs.existsSync(outputDir)) {
50
- fs.mkdirSync(outputDir, { recursive: true });
51
- }
52
-
53
- (async () => {
54
- try {
55
- await buildTwsx(inputDir, outputDir);
56
- } catch (err) {
57
- console.error("[build-twsx] Error writing CSS:", err);
58
- }
59
- })();
package/twsx.css DELETED
File without changes