@flairjs/webpack-loader 0.0.1-beta.5 → 0.0.1-beta.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/dist/cjs/index.js CHANGED
@@ -71,8 +71,33 @@ function tokensToCSSVars(tokens, prefix = []) {
71
71
  }
72
72
  return css$1;
73
73
  }
74
+ var Store = class {
75
+ fileNameToGeneratedCssNameMap = /* @__PURE__ */ new Map();
76
+ lastThemeUpdate = Date.now();
77
+ userTheme = /* @__PURE__ */ new Map();
78
+ getUserTheme() {
79
+ return this.userTheme.get(this.lastThemeUpdate) ?? null;
80
+ }
81
+ setUserTheme(theme) {
82
+ this.userTheme.set(this.lastThemeUpdate, theme);
83
+ }
84
+ getLastThemeUpdate() {
85
+ return this.lastThemeUpdate;
86
+ }
87
+ setLastThemeUpdate(timestamp) {
88
+ this.lastThemeUpdate = timestamp;
89
+ }
90
+ setFileNameToGeneratedCssNameMap(fileName, generatedCssName) {
91
+ this.fileNameToGeneratedCssNameMap.set(fileName, generatedCssName);
92
+ }
93
+ getGeneratedCssName(fileName) {
94
+ return this.fileNameToGeneratedCssNameMap.get(fileName);
95
+ }
96
+ };
97
+ const store = new Store();
74
98
  const __dirname$1 = (0, node_path.dirname)((0, node_url.fileURLToPath)(require("url").pathToFileURL(__filename).href));
75
99
  const getUserTheme = async () => {
100
+ if (store.getUserTheme()) return store.getUserTheme();
76
101
  try {
77
102
  let userThemeFilePath = path.default.resolve(process.cwd(), "flair.theme.ts");
78
103
  if (!(0, fs.existsSync)(userThemeFilePath)) userThemeFilePath = path.default.resolve(process.cwd(), "flair.theme.js");
@@ -88,10 +113,17 @@ const getUserTheme = async () => {
88
113
  });
89
114
  const cacheBuster = Date.now();
90
115
  const userTheme = await import(`${(0, url.pathToFileURL)(outFile).href}?update=${cacheBuster}`);
91
- if (userTheme.default) return {
92
- theme: userTheme.default,
93
- originalPath: userThemeFilePath
94
- };
116
+ if (userTheme.default) {
117
+ store.setUserTheme({
118
+ theme: userTheme.default,
119
+ originalPath: userThemeFilePath
120
+ });
121
+ return {
122
+ theme: userTheme.default,
123
+ originalPath: userThemeFilePath
124
+ };
125
+ }
126
+ store.setUserTheme(null);
95
127
  return null;
96
128
  } catch (error) {
97
129
  console.error("Error loading user theme:", error);
@@ -99,57 +131,72 @@ const getUserTheme = async () => {
99
131
  }
100
132
  };
101
133
  const require$1 = node_module.default.createRequire(require("url").pathToFileURL(__filename).href);
102
- /**
103
- * Initialize the shared plugin context
104
- */
105
- async function initializeSharedContext(options = {}) {
106
- const { buildThemeFile } = options;
107
- const fileNameToGeneratedCssNameMap = /* @__PURE__ */ new Map();
134
+ const getGeneratedCssDir = () => {
108
135
  const flairThemeFile = require$1.resolve("@flairjs/client/theme.css");
109
- const flairGeneratedCssDir = node_path.default.resolve(flairThemeFile, "../generated-css");
110
- if (!(0, node_fs.existsSync)(flairGeneratedCssDir)) await (0, node_fs_promises.mkdir)(flairGeneratedCssDir);
111
- else {
112
- await (0, node_fs_promises.rm)(flairGeneratedCssDir, {
113
- recursive: true,
114
- force: true
115
- });
116
- await (0, node_fs_promises.mkdir)(flairGeneratedCssDir);
136
+ return node_path.default.resolve(flairThemeFile, "../generated-css");
137
+ };
138
+ const setupGeneratedCssDir = async (options) => {
139
+ const flairGeneratedCssDir = getGeneratedCssDir();
140
+ const { clearExisting = true } = options ?? {};
141
+ try {
142
+ if (!(0, node_fs.existsSync)(flairGeneratedCssDir)) await (0, node_fs_promises.mkdir)(flairGeneratedCssDir);
143
+ else if (clearExisting) {
144
+ await (0, node_fs_promises.rm)(flairGeneratedCssDir, {
145
+ recursive: true,
146
+ force: true
147
+ });
148
+ await (0, node_fs_promises.mkdir)(flairGeneratedCssDir);
149
+ }
150
+ } catch (err) {
151
+ if (err?.code === "EEXIST") return flairGeneratedCssDir;
152
+ else if ((0, node_fs.existsSync)(flairGeneratedCssDir)) return flairGeneratedCssDir;
153
+ console.error(`[flairjs] Could not create generated CSS directory: ${flairGeneratedCssDir}`, err);
154
+ return null;
117
155
  }
156
+ return flairGeneratedCssDir;
157
+ };
158
+ const setupUserThemeFile = async ({ buildThemeFile }) => {
159
+ const flairThemeFile = require$1.resolve("@flairjs/client/theme.css");
118
160
  let userTheme = await getUserTheme();
119
161
  const buildThemeCSS = buildThemeFile ?? buildThemeTokens;
120
162
  if (userTheme) {
121
163
  const themeCSS = buildThemeCSS(userTheme.theme);
164
+ store.setLastThemeUpdate(Date.now());
122
165
  await (0, node_fs_promises.writeFile)(flairThemeFile, themeCSS, "utf-8");
123
166
  (0, node_fs.watch)(userTheme.originalPath, async () => {
124
167
  userTheme = await getUserTheme();
168
+ store.setLastThemeUpdate(Date.now());
125
169
  if (!userTheme) return;
126
170
  const themeCSS$1 = buildThemeCSS(userTheme.theme);
127
171
  await (0, node_fs_promises.writeFile)(flairThemeFile, themeCSS$1, "utf-8");
128
172
  });
129
173
  }
130
- const refreshCssFile = (filePath) => {
131
- if (fileNameToGeneratedCssNameMap.has(filePath)) {
132
- const previousGeneratedCssName = fileNameToGeneratedCssNameMap.get(filePath);
133
- setTimeout(() => {
134
- (0, node_fs_promises.rm)(node_path.default.join(flairGeneratedCssDir, previousGeneratedCssName));
135
- }, 2e3);
174
+ return userTheme;
175
+ };
176
+ const removeOutdatedCssFiles = async (sourceFilePath, cssFilePath, { flairGeneratedCssDir, clearInstantly = false }) => {
177
+ const previousGeneratedCssName = store.getGeneratedCssName(sourceFilePath);
178
+ if (previousGeneratedCssName && previousGeneratedCssName !== cssFilePath) {
179
+ if (clearInstantly) {
180
+ await (0, node_fs_promises.rm)(node_path.default.join(flairGeneratedCssDir, previousGeneratedCssName), { force: true });
181
+ store.setFileNameToGeneratedCssNameMap(sourceFilePath, cssFilePath);
182
+ return;
136
183
  }
137
- };
138
- return {
139
- flairThemeFile,
140
- flairGeneratedCssDir,
141
- userTheme,
142
- buildThemeCSS,
143
- refreshCssFile
144
- };
145
- }
184
+ setTimeout(() => {
185
+ (0, node_fs_promises.rm)(node_path.default.join(flairGeneratedCssDir, previousGeneratedCssName), { force: true });
186
+ }, 2e3);
187
+ }
188
+ store.setFileNameToGeneratedCssNameMap(sourceFilePath, cssFilePath);
189
+ };
146
190
  function shouldProcessFile(id, include, exclude) {
147
- const isIncluded = (0, picomatch.default)(include || ["**/*.{js,ts,jsx,tsx}"]);
148
- const isExcluded = (0, picomatch.default)(exclude || ["node_modules/**"]);
149
- if (!isIncluded(id)) return false;
150
- if (isExcluded(id)) return false;
191
+ const isIncluded = (0, picomatch.default)(include ?? ["**/*.{js,ts,jsx,tsx}"]);
192
+ const isExcluded = (0, picomatch.default)(exclude ?? ["**/node_modules/**"]);
193
+ if (!isIncluded(normalizeFilePath(id))) return false;
194
+ if (isExcluded(normalizeFilePath(id))) return false;
151
195
  return true;
152
196
  }
197
+ function normalizeFilePath(filePath) {
198
+ return filePath.replace(/\\/g, "/");
199
+ }
153
200
  const colors = {
154
201
  reset: "\x1B[0m",
155
202
  fg: {
@@ -191,28 +238,42 @@ const transformCode = (code, filePath, options) => {
191
238
 
192
239
  //#endregion
193
240
  //#region src/index.ts
241
+ let initialized = false;
194
242
  async function flairJsLoader(source, sourceMap) {
195
243
  const callback = this.async();
244
+ const options = this.getOptions() || {};
196
245
  if (!callback) {
197
246
  console.error("@flairjs/webpack-loader requires async support");
198
247
  return;
199
248
  }
200
- const options = this.getOptions() || {};
201
- const context = await initializeSharedContext(options);
202
249
  const fileName = this.resourcePath;
203
250
  if (!shouldProcessFile(fileName, options?.include, options?.exclude)) return callback(null, source, sourceMap);
251
+ let cssGeneratedDir = null;
252
+ let userTheme = null;
253
+ if (!initialized) {
254
+ cssGeneratedDir = await setupGeneratedCssDir();
255
+ userTheme = await setupUserThemeFile({ buildThemeFile: options.buildThemeFile });
256
+ initialized = true;
257
+ } else {
258
+ cssGeneratedDir = getGeneratedCssDir();
259
+ userTheme = await getUserTheme();
260
+ }
261
+ if (!cssGeneratedDir) {
262
+ console.error("[flairjs] Could not find generated CSS directory. Skipping processing.");
263
+ return callback(null, source, sourceMap);
264
+ }
204
265
  try {
205
266
  const result = transformCode(source, fileName, {
206
267
  appendTimestampToCssFile: true,
207
268
  classNameList: options?.classNameList,
208
269
  cssPreprocessor: options?.cssPreprocessor ? (css) => options.cssPreprocessor(css, fileName) : void 0,
209
- theme: context.userTheme?.theme,
210
- useTheme: !!context.userTheme,
211
- cssOutDir: context.flairGeneratedCssDir
270
+ theme: userTheme?.theme,
271
+ useTheme: !!userTheme,
272
+ cssOutDir: cssGeneratedDir
212
273
  });
213
274
  if (!result) return callback(null, source, sourceMap);
214
- if (result.generatedCssName) context.refreshCssFile(result.generatedCssName);
215
- callback(null, result.code, result.map ? JSON.parse(result.map ?? "{}") : sourceMap);
275
+ if (result.generatedCssName) removeOutdatedCssFiles(fileName, result.generatedCssName, { flairGeneratedCssDir: cssGeneratedDir });
276
+ callback(null, result.code, result.sourcemap ? JSON.parse(result.sourcemap ?? "{}") : sourceMap);
216
277
  } catch (error) {
217
278
  console.error("[@flairjs/webpack-loader]", error);
218
279
  callback(error, source, sourceMap);
package/dist/esm/index.js CHANGED
@@ -37,8 +37,33 @@ function tokensToCSSVars(tokens, prefix = []) {
37
37
  }
38
38
  return css$1;
39
39
  }
40
+ var Store = class {
41
+ fileNameToGeneratedCssNameMap = /* @__PURE__ */ new Map();
42
+ lastThemeUpdate = Date.now();
43
+ userTheme = /* @__PURE__ */ new Map();
44
+ getUserTheme() {
45
+ return this.userTheme.get(this.lastThemeUpdate) ?? null;
46
+ }
47
+ setUserTheme(theme) {
48
+ this.userTheme.set(this.lastThemeUpdate, theme);
49
+ }
50
+ getLastThemeUpdate() {
51
+ return this.lastThemeUpdate;
52
+ }
53
+ setLastThemeUpdate(timestamp) {
54
+ this.lastThemeUpdate = timestamp;
55
+ }
56
+ setFileNameToGeneratedCssNameMap(fileName, generatedCssName) {
57
+ this.fileNameToGeneratedCssNameMap.set(fileName, generatedCssName);
58
+ }
59
+ getGeneratedCssName(fileName) {
60
+ return this.fileNameToGeneratedCssNameMap.get(fileName);
61
+ }
62
+ };
63
+ const store = new Store();
40
64
  const __dirname = dirname(fileURLToPath(import.meta.url));
41
65
  const getUserTheme = async () => {
66
+ if (store.getUserTheme()) return store.getUserTheme();
42
67
  try {
43
68
  let userThemeFilePath = path$1.resolve(process.cwd(), "flair.theme.ts");
44
69
  if (!existsSync$1(userThemeFilePath)) userThemeFilePath = path$1.resolve(process.cwd(), "flair.theme.js");
@@ -54,10 +79,17 @@ const getUserTheme = async () => {
54
79
  });
55
80
  const cacheBuster = Date.now();
56
81
  const userTheme = await import(`${pathToFileURL(outFile).href}?update=${cacheBuster}`);
57
- if (userTheme.default) return {
58
- theme: userTheme.default,
59
- originalPath: userThemeFilePath
60
- };
82
+ if (userTheme.default) {
83
+ store.setUserTheme({
84
+ theme: userTheme.default,
85
+ originalPath: userThemeFilePath
86
+ });
87
+ return {
88
+ theme: userTheme.default,
89
+ originalPath: userThemeFilePath
90
+ };
91
+ }
92
+ store.setUserTheme(null);
61
93
  return null;
62
94
  } catch (error) {
63
95
  console.error("Error loading user theme:", error);
@@ -65,57 +97,72 @@ const getUserTheme = async () => {
65
97
  }
66
98
  };
67
99
  const require = module.createRequire(import.meta.url);
68
- /**
69
- * Initialize the shared plugin context
70
- */
71
- async function initializeSharedContext(options = {}) {
72
- const { buildThemeFile } = options;
73
- const fileNameToGeneratedCssNameMap = /* @__PURE__ */ new Map();
100
+ const getGeneratedCssDir = () => {
74
101
  const flairThemeFile = require.resolve("@flairjs/client/theme.css");
75
- const flairGeneratedCssDir = path.resolve(flairThemeFile, "../generated-css");
76
- if (!existsSync(flairGeneratedCssDir)) await mkdir(flairGeneratedCssDir);
77
- else {
78
- await rm(flairGeneratedCssDir, {
79
- recursive: true,
80
- force: true
81
- });
82
- await mkdir(flairGeneratedCssDir);
102
+ return path.resolve(flairThemeFile, "../generated-css");
103
+ };
104
+ const setupGeneratedCssDir = async (options) => {
105
+ const flairGeneratedCssDir = getGeneratedCssDir();
106
+ const { clearExisting = true } = options ?? {};
107
+ try {
108
+ if (!existsSync(flairGeneratedCssDir)) await mkdir(flairGeneratedCssDir);
109
+ else if (clearExisting) {
110
+ await rm(flairGeneratedCssDir, {
111
+ recursive: true,
112
+ force: true
113
+ });
114
+ await mkdir(flairGeneratedCssDir);
115
+ }
116
+ } catch (err) {
117
+ if (err?.code === "EEXIST") return flairGeneratedCssDir;
118
+ else if (existsSync(flairGeneratedCssDir)) return flairGeneratedCssDir;
119
+ console.error(`[flairjs] Could not create generated CSS directory: ${flairGeneratedCssDir}`, err);
120
+ return null;
83
121
  }
122
+ return flairGeneratedCssDir;
123
+ };
124
+ const setupUserThemeFile = async ({ buildThemeFile }) => {
125
+ const flairThemeFile = require.resolve("@flairjs/client/theme.css");
84
126
  let userTheme = await getUserTheme();
85
127
  const buildThemeCSS = buildThemeFile ?? buildThemeTokens;
86
128
  if (userTheme) {
87
129
  const themeCSS = buildThemeCSS(userTheme.theme);
130
+ store.setLastThemeUpdate(Date.now());
88
131
  await writeFile(flairThemeFile, themeCSS, "utf-8");
89
132
  watch(userTheme.originalPath, async () => {
90
133
  userTheme = await getUserTheme();
134
+ store.setLastThemeUpdate(Date.now());
91
135
  if (!userTheme) return;
92
136
  const themeCSS$1 = buildThemeCSS(userTheme.theme);
93
137
  await writeFile(flairThemeFile, themeCSS$1, "utf-8");
94
138
  });
95
139
  }
96
- const refreshCssFile = (filePath) => {
97
- if (fileNameToGeneratedCssNameMap.has(filePath)) {
98
- const previousGeneratedCssName = fileNameToGeneratedCssNameMap.get(filePath);
99
- setTimeout(() => {
100
- rm(path.join(flairGeneratedCssDir, previousGeneratedCssName));
101
- }, 2e3);
140
+ return userTheme;
141
+ };
142
+ const removeOutdatedCssFiles = async (sourceFilePath, cssFilePath, { flairGeneratedCssDir, clearInstantly = false }) => {
143
+ const previousGeneratedCssName = store.getGeneratedCssName(sourceFilePath);
144
+ if (previousGeneratedCssName && previousGeneratedCssName !== cssFilePath) {
145
+ if (clearInstantly) {
146
+ await rm(path.join(flairGeneratedCssDir, previousGeneratedCssName), { force: true });
147
+ store.setFileNameToGeneratedCssNameMap(sourceFilePath, cssFilePath);
148
+ return;
102
149
  }
103
- };
104
- return {
105
- flairThemeFile,
106
- flairGeneratedCssDir,
107
- userTheme,
108
- buildThemeCSS,
109
- refreshCssFile
110
- };
111
- }
150
+ setTimeout(() => {
151
+ rm(path.join(flairGeneratedCssDir, previousGeneratedCssName), { force: true });
152
+ }, 2e3);
153
+ }
154
+ store.setFileNameToGeneratedCssNameMap(sourceFilePath, cssFilePath);
155
+ };
112
156
  function shouldProcessFile(id, include, exclude) {
113
- const isIncluded = picomatch(include || ["**/*.{js,ts,jsx,tsx}"]);
114
- const isExcluded = picomatch(exclude || ["node_modules/**"]);
115
- if (!isIncluded(id)) return false;
116
- if (isExcluded(id)) return false;
157
+ const isIncluded = picomatch(include ?? ["**/*.{js,ts,jsx,tsx}"]);
158
+ const isExcluded = picomatch(exclude ?? ["**/node_modules/**"]);
159
+ if (!isIncluded(normalizeFilePath(id))) return false;
160
+ if (isExcluded(normalizeFilePath(id))) return false;
117
161
  return true;
118
162
  }
163
+ function normalizeFilePath(filePath) {
164
+ return filePath.replace(/\\/g, "/");
165
+ }
119
166
  const colors = {
120
167
  reset: "\x1B[0m",
121
168
  fg: {
@@ -157,28 +204,42 @@ const transformCode$1 = (code, filePath, options) => {
157
204
 
158
205
  //#endregion
159
206
  //#region src/index.ts
207
+ let initialized = false;
160
208
  async function flairJsLoader(source, sourceMap) {
161
209
  const callback = this.async();
210
+ const options = this.getOptions() || {};
162
211
  if (!callback) {
163
212
  console.error("@flairjs/webpack-loader requires async support");
164
213
  return;
165
214
  }
166
- const options = this.getOptions() || {};
167
- const context = await initializeSharedContext(options);
168
215
  const fileName = this.resourcePath;
169
216
  if (!shouldProcessFile(fileName, options?.include, options?.exclude)) return callback(null, source, sourceMap);
217
+ let cssGeneratedDir = null;
218
+ let userTheme = null;
219
+ if (!initialized) {
220
+ cssGeneratedDir = await setupGeneratedCssDir();
221
+ userTheme = await setupUserThemeFile({ buildThemeFile: options.buildThemeFile });
222
+ initialized = true;
223
+ } else {
224
+ cssGeneratedDir = getGeneratedCssDir();
225
+ userTheme = await getUserTheme();
226
+ }
227
+ if (!cssGeneratedDir) {
228
+ console.error("[flairjs] Could not find generated CSS directory. Skipping processing.");
229
+ return callback(null, source, sourceMap);
230
+ }
170
231
  try {
171
232
  const result = transformCode$1(source, fileName, {
172
233
  appendTimestampToCssFile: true,
173
234
  classNameList: options?.classNameList,
174
235
  cssPreprocessor: options?.cssPreprocessor ? (css) => options.cssPreprocessor(css, fileName) : void 0,
175
- theme: context.userTheme?.theme,
176
- useTheme: !!context.userTheme,
177
- cssOutDir: context.flairGeneratedCssDir
236
+ theme: userTheme?.theme,
237
+ useTheme: !!userTheme,
238
+ cssOutDir: cssGeneratedDir
178
239
  });
179
240
  if (!result) return callback(null, source, sourceMap);
180
- if (result.generatedCssName) context.refreshCssFile(result.generatedCssName);
181
- callback(null, result.code, result.map ? JSON.parse(result.map ?? "{}") : sourceMap);
241
+ if (result.generatedCssName) removeOutdatedCssFiles(fileName, result.generatedCssName, { flairGeneratedCssDir: cssGeneratedDir });
242
+ callback(null, result.code, result.sourcemap ? JSON.parse(result.sourcemap ?? "{}") : sourceMap);
182
243
  } catch (error) {
183
244
  console.error("[@flairjs/webpack-loader]", error);
184
245
  callback(error, source, sourceMap);
@@ -6,7 +6,6 @@ import { existsSync as existsSync$1 } from "fs";
6
6
  import path$1 from "path";
7
7
  import { fileURLToPath } from "node:url";
8
8
  import { pathToFileURL } from "url";
9
- import { transformCode } from "@flairjs/core";
10
9
 
11
10
  //#region rolldown:runtime
12
11
  var __create = Object.create;
@@ -28,6 +27,7 @@ var __copyProps$1 = (to, from, except, desc) => {
28
27
  }
29
28
  return to;
30
29
  };
30
+ var __reExport = (target, mod, secondTarget) => (__copyProps$1(target, mod, "default"), secondTarget && __copyProps$1(secondTarget, mod, "default"));
31
31
  var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps$1(isNodeMode || !mod || !mod.__esModule ? __defProp$1(target, "default", {
32
32
  value: mod,
33
33
  enumerable: true
@@ -3947,9 +3947,15 @@ var require_picomatch = /* @__PURE__ */ __commonJS({ "../../node_modules/.pnpm/p
3947
3947
  }) });
3948
3948
 
3949
3949
  //#endregion
3950
- //#region ../shared/dist/esm/index.js
3951
- var import_main = /* @__PURE__ */ __toESM(require_main(), 1);
3950
+ //#region ../core/browser.js
3952
3951
  var import_picomatch = /* @__PURE__ */ __toESM(require_picomatch(), 1);
3952
+ var import_main = /* @__PURE__ */ __toESM(require_main(), 1);
3953
+ var browser_exports = {};
3954
+ import * as import___flairjs_core_wasm32_wasi from "@flairjs/core-wasm32-wasi";
3955
+ __reExport(browser_exports, import___flairjs_core_wasm32_wasi);
3956
+
3957
+ //#endregion
3958
+ //#region ../shared/dist/esm/index.js
3953
3959
  String.raw;
3954
3960
  const buildThemeTokens = (theme, themeName) => {
3955
3961
  let css$1 = "";
@@ -3976,8 +3982,33 @@ function tokensToCSSVars(tokens, prefix = []) {
3976
3982
  }
3977
3983
  return css$1;
3978
3984
  }
3985
+ var Store = class {
3986
+ fileNameToGeneratedCssNameMap = /* @__PURE__ */ new Map();
3987
+ lastThemeUpdate = Date.now();
3988
+ userTheme = /* @__PURE__ */ new Map();
3989
+ getUserTheme() {
3990
+ return this.userTheme.get(this.lastThemeUpdate) ?? null;
3991
+ }
3992
+ setUserTheme(theme) {
3993
+ this.userTheme.set(this.lastThemeUpdate, theme);
3994
+ }
3995
+ getLastThemeUpdate() {
3996
+ return this.lastThemeUpdate;
3997
+ }
3998
+ setLastThemeUpdate(timestamp) {
3999
+ this.lastThemeUpdate = timestamp;
4000
+ }
4001
+ setFileNameToGeneratedCssNameMap(fileName, generatedCssName) {
4002
+ this.fileNameToGeneratedCssNameMap.set(fileName, generatedCssName);
4003
+ }
4004
+ getGeneratedCssName(fileName) {
4005
+ return this.fileNameToGeneratedCssNameMap.get(fileName);
4006
+ }
4007
+ };
4008
+ const store = new Store();
3979
4009
  const __dirname$1 = dirname(fileURLToPath(import.meta.url));
3980
4010
  const getUserTheme = async () => {
4011
+ if (store.getUserTheme()) return store.getUserTheme();
3981
4012
  try {
3982
4013
  let userThemeFilePath = path$1.resolve(process.cwd(), "flair.theme.ts");
3983
4014
  if (!existsSync$1(userThemeFilePath)) userThemeFilePath = path$1.resolve(process.cwd(), "flair.theme.js");
@@ -3993,10 +4024,17 @@ const getUserTheme = async () => {
3993
4024
  });
3994
4025
  const cacheBuster = Date.now();
3995
4026
  const userTheme = await import(`${pathToFileURL(outFile).href}?update=${cacheBuster}`);
3996
- if (userTheme.default) return {
3997
- theme: userTheme.default,
3998
- originalPath: userThemeFilePath
3999
- };
4027
+ if (userTheme.default) {
4028
+ store.setUserTheme({
4029
+ theme: userTheme.default,
4030
+ originalPath: userThemeFilePath
4031
+ });
4032
+ return {
4033
+ theme: userTheme.default,
4034
+ originalPath: userThemeFilePath
4035
+ };
4036
+ }
4037
+ store.setUserTheme(null);
4000
4038
  return null;
4001
4039
  } catch (error) {
4002
4040
  console.error("Error loading user theme:", error);
@@ -4004,57 +4042,72 @@ const getUserTheme = async () => {
4004
4042
  }
4005
4043
  };
4006
4044
  const require$1 = module$1.createRequire(import.meta.url);
4007
- /**
4008
- * Initialize the shared plugin context
4009
- */
4010
- async function initializeSharedContext(options = {}) {
4011
- const { buildThemeFile } = options;
4012
- const fileNameToGeneratedCssNameMap = /* @__PURE__ */ new Map();
4045
+ const getGeneratedCssDir = () => {
4013
4046
  const flairThemeFile = require$1.resolve("@flairjs/client/theme.css");
4014
- const flairGeneratedCssDir = path.resolve(flairThemeFile, "../generated-css");
4015
- if (!existsSync(flairGeneratedCssDir)) await mkdir(flairGeneratedCssDir);
4016
- else {
4017
- await rm(flairGeneratedCssDir, {
4018
- recursive: true,
4019
- force: true
4020
- });
4021
- await mkdir(flairGeneratedCssDir);
4047
+ return path.resolve(flairThemeFile, "../generated-css");
4048
+ };
4049
+ const setupGeneratedCssDir = async (options) => {
4050
+ const flairGeneratedCssDir = getGeneratedCssDir();
4051
+ const { clearExisting = true } = options ?? {};
4052
+ try {
4053
+ if (!existsSync(flairGeneratedCssDir)) await mkdir(flairGeneratedCssDir);
4054
+ else if (clearExisting) {
4055
+ await rm(flairGeneratedCssDir, {
4056
+ recursive: true,
4057
+ force: true
4058
+ });
4059
+ await mkdir(flairGeneratedCssDir);
4060
+ }
4061
+ } catch (err) {
4062
+ if (err?.code === "EEXIST") return flairGeneratedCssDir;
4063
+ else if (existsSync(flairGeneratedCssDir)) return flairGeneratedCssDir;
4064
+ console.error(`[flairjs] Could not create generated CSS directory: ${flairGeneratedCssDir}`, err);
4065
+ return null;
4022
4066
  }
4067
+ return flairGeneratedCssDir;
4068
+ };
4069
+ const setupUserThemeFile = async ({ buildThemeFile }) => {
4070
+ const flairThemeFile = require$1.resolve("@flairjs/client/theme.css");
4023
4071
  let userTheme = await getUserTheme();
4024
4072
  const buildThemeCSS = buildThemeFile ?? buildThemeTokens;
4025
4073
  if (userTheme) {
4026
4074
  const themeCSS = buildThemeCSS(userTheme.theme);
4075
+ store.setLastThemeUpdate(Date.now());
4027
4076
  await writeFile(flairThemeFile, themeCSS, "utf-8");
4028
4077
  watch(userTheme.originalPath, async () => {
4029
4078
  userTheme = await getUserTheme();
4079
+ store.setLastThemeUpdate(Date.now());
4030
4080
  if (!userTheme) return;
4031
4081
  const themeCSS$1 = buildThemeCSS(userTheme.theme);
4032
4082
  await writeFile(flairThemeFile, themeCSS$1, "utf-8");
4033
4083
  });
4034
4084
  }
4035
- const refreshCssFile = (filePath) => {
4036
- if (fileNameToGeneratedCssNameMap.has(filePath)) {
4037
- const previousGeneratedCssName = fileNameToGeneratedCssNameMap.get(filePath);
4038
- setTimeout(() => {
4039
- rm(path.join(flairGeneratedCssDir, previousGeneratedCssName));
4040
- }, 2e3);
4085
+ return userTheme;
4086
+ };
4087
+ const removeOutdatedCssFiles = async (sourceFilePath, cssFilePath, { flairGeneratedCssDir, clearInstantly = false }) => {
4088
+ const previousGeneratedCssName = store.getGeneratedCssName(sourceFilePath);
4089
+ if (previousGeneratedCssName && previousGeneratedCssName !== cssFilePath) {
4090
+ if (clearInstantly) {
4091
+ await rm(path.join(flairGeneratedCssDir, previousGeneratedCssName), { force: true });
4092
+ store.setFileNameToGeneratedCssNameMap(sourceFilePath, cssFilePath);
4093
+ return;
4041
4094
  }
4042
- };
4043
- return {
4044
- flairThemeFile,
4045
- flairGeneratedCssDir,
4046
- userTheme,
4047
- buildThemeCSS,
4048
- refreshCssFile
4049
- };
4050
- }
4095
+ setTimeout(() => {
4096
+ rm(path.join(flairGeneratedCssDir, previousGeneratedCssName), { force: true });
4097
+ }, 2e3);
4098
+ }
4099
+ store.setFileNameToGeneratedCssNameMap(sourceFilePath, cssFilePath);
4100
+ };
4051
4101
  function shouldProcessFile(id, include, exclude) {
4052
- const isIncluded = (0, import_picomatch.default)(include || ["**/*.{js,ts,jsx,tsx}"]);
4053
- const isExcluded = (0, import_picomatch.default)(exclude || ["node_modules/**"]);
4054
- if (!isIncluded(id)) return false;
4055
- if (isExcluded(id)) return false;
4102
+ const isIncluded = (0, import_picomatch.default)(include ?? ["**/*.{js,ts,jsx,tsx}"]);
4103
+ const isExcluded = (0, import_picomatch.default)(exclude ?? ["**/node_modules/**"]);
4104
+ if (!isIncluded(normalizeFilePath(id))) return false;
4105
+ if (isExcluded(normalizeFilePath(id))) return false;
4056
4106
  return true;
4057
4107
  }
4108
+ function normalizeFilePath(filePath) {
4109
+ return filePath.replace(/\\/g, "/");
4110
+ }
4058
4111
  const colors = {
4059
4112
  reset: "\x1B[0m",
4060
4113
  fg: {
@@ -4080,8 +4133,8 @@ const logger = {
4080
4133
  console.log(`${colors.bg.blue}${colors.fg.white}[flairjs/Info]${colors.reset} ${msg}${colors.reset}`);
4081
4134
  }
4082
4135
  };
4083
- const transformCode$1 = (code, filePath, options) => {
4084
- const result = transformCode(code, filePath, {
4136
+ const transformCode = (code, filePath, options) => {
4137
+ const result = (0, browser_exports.transformCode)(code, filePath, {
4085
4138
  cssOutDir: options.cssOutDir,
4086
4139
  classNameList: options.classNameList,
4087
4140
  useTheme: options.useTheme,
@@ -4096,38 +4149,58 @@ const transformCode$1 = (code, filePath, options) => {
4096
4149
 
4097
4150
  //#endregion
4098
4151
  //#region src/index.ts
4152
+ var initialized = false;
4099
4153
  function flairJsLoader(source, sourceMap) {
4100
4154
  return __awaiter(this, void 0, void 0, function() {
4101
- var callback, options, context$1, fileName, result;
4102
- var _a$1, _b;
4103
- return __generator(this, function(_c) {
4104
- switch (_c.label) {
4155
+ var callback, options, fileName, cssGeneratedDir, userTheme, result;
4156
+ var _a$1;
4157
+ return __generator(this, function(_b) {
4158
+ switch (_b.label) {
4105
4159
  case 0:
4106
4160
  callback = this.async();
4161
+ options = this.getOptions() || {};
4107
4162
  if (!callback) {
4108
4163
  console.error("@flairjs/webpack-loader requires async support");
4109
4164
  return [2];
4110
4165
  }
4111
- options = this.getOptions() || {};
4112
- return [4, initializeSharedContext(options)];
4113
- case 1:
4114
- context$1 = _c.sent();
4115
4166
  fileName = this.resourcePath;
4116
4167
  if (!shouldProcessFile(fileName, options === null || options === void 0 ? void 0 : options.include, options === null || options === void 0 ? void 0 : options.exclude)) return [2, callback(null, source, sourceMap)];
4168
+ cssGeneratedDir = null;
4169
+ userTheme = null;
4170
+ if (!!initialized) return [3, 3];
4171
+ return [4, setupGeneratedCssDir()];
4172
+ case 1:
4173
+ cssGeneratedDir = _b.sent();
4174
+ return [4, setupUserThemeFile({ buildThemeFile: options.buildThemeFile })];
4175
+ case 2:
4176
+ userTheme = _b.sent();
4177
+ initialized = true;
4178
+ return [3, 5];
4179
+ case 3:
4180
+ cssGeneratedDir = getGeneratedCssDir();
4181
+ return [4, getUserTheme()];
4182
+ case 4:
4183
+ userTheme = _b.sent();
4184
+ _b.label = 5;
4185
+ case 5:
4186
+ if (!cssGeneratedDir) {
4187
+ console.error("[flairjs] Could not find generated CSS directory. Skipping processing.");
4188
+ return [2, callback(null, source, sourceMap)];
4189
+ }
4117
4190
  try {
4118
- result = transformCode$1(source, fileName, {
4191
+ result = transformCode(source, fileName, {
4119
4192
  appendTimestampToCssFile: true,
4120
4193
  classNameList: options === null || options === void 0 ? void 0 : options.classNameList,
4121
4194
  cssPreprocessor: (options === null || options === void 0 ? void 0 : options.cssPreprocessor) ? function(css) {
4122
4195
  return options.cssPreprocessor(css, fileName);
4123
4196
  } : void 0,
4124
- theme: (_a$1 = context$1.userTheme) === null || _a$1 === void 0 ? void 0 : _a$1.theme,
4125
- useTheme: !!context$1.userTheme,
4126
- cssOutDir: context$1.flairGeneratedCssDir
4197
+ theme: userTheme === null || userTheme === void 0 ? void 0 : userTheme.theme,
4198
+ useTheme: !!userTheme,
4199
+ cssOutDir: cssGeneratedDir
4127
4200
  });
4128
4201
  if (!result) return [2, callback(null, source, sourceMap)];
4129
- if (result.generatedCssName) context$1.refreshCssFile(result.generatedCssName);
4130
- callback(null, result.code, result.map ? JSON.parse((_b = result.map) !== null && _b !== void 0 ? _b : "{}") : sourceMap);
4202
+ if (result.generatedCssName) removeOutdatedCssFiles(fileName, result.generatedCssName, { flairGeneratedCssDir: cssGeneratedDir });
4203
+ callback(null, result.code, result.sourcemap ? JSON.parse((_a$1 = result.sourcemap) !== null && _a$1 !== void 0 ? _a$1 : "{}") : sourceMap);
4131
4204
  } catch (error) {
4132
4205
  console.error("[@flairjs/webpack-loader]", error);
4133
4206
  callback(error, source, sourceMap);
package/package.json CHANGED
@@ -1,17 +1,6 @@
1
1
  {
2
2
  "name": "@flairjs/webpack-loader",
3
- "version": "0.0.1-beta.5",
4
- "type": "module",
5
- "exports": {
6
- ".": {
7
- "types": "./dist/types/index.d.ts",
8
- "import": "./dist/esm/index.js",
9
- "require": "./dist/cjs/index.js"
10
- },
11
- "./cached-css/*": {
12
- "import": "./dist/.cache/*"
13
- }
14
- },
3
+ "version": "0.0.1-beta.6",
15
4
  "main": "./dist/cjs/index.js",
16
5
  "module": "./dist/esm/index.js",
17
6
  "types": "./dist/types/index.d.ts",
@@ -24,7 +13,7 @@
24
13
  },
25
14
  "peerDependencies": {
26
15
  "webpack": ">=5.0.0",
27
- "@flairjs/core": "0.0.1-beta.4"
16
+ "@flairjs/core": "0.0.1-beta.5"
28
17
  },
29
18
  "devDependencies": {
30
19
  "@biomejs/biome": "^1.9.4",
@@ -33,11 +22,15 @@
33
22
  "rolldown": "1.0.0-beta.37",
34
23
  "typescript": "^5.8.2",
35
24
  "webpack": "^5.101.0",
36
- "@flairjs/bundler-shared": "0.0.1-beta.4",
37
- "@flairjs/core": "0.0.1-beta.4"
25
+ "@flairjs/bundler-shared": "0.0.1-beta.9",
26
+ "@flairjs/core": "0.0.1-beta.5"
27
+ },
28
+ "dependencies": {
29
+ "esbuild": "^0.25.10",
30
+ "picomatch": "^4.0.3"
38
31
  },
39
32
  "scripts": {
40
- "build": "rolldown -c",
33
+ "build": "tsc && rolldown -c",
41
34
  "check": "biome check --write",
42
35
  "dev": "rolldown -w -c",
43
36
  "format": "biome format --write"