@flairjs/webpack-loader 0.0.1-beta.1

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 ADDED
File without changes
@@ -0,0 +1,223 @@
1
+ //#region rolldown:runtime
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __copyProps = (to, from, except, desc) => {
9
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
10
+ key = keys[i];
11
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
12
+ get: ((k) => from[k]).bind(null, key),
13
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
14
+ });
15
+ }
16
+ return to;
17
+ };
18
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
19
+ value: mod,
20
+ enumerable: true
21
+ }) : target, mod));
22
+
23
+ //#endregion
24
+ let node_module = require("node:module");
25
+ node_module = __toESM(node_module);
26
+ let node_fs = require("node:fs");
27
+ node_fs = __toESM(node_fs);
28
+ let node_fs_promises = require("node:fs/promises");
29
+ node_fs_promises = __toESM(node_fs_promises);
30
+ let node_path = require("node:path");
31
+ node_path = __toESM(node_path);
32
+ let esbuild = require("esbuild");
33
+ esbuild = __toESM(esbuild);
34
+ let fs = require("fs");
35
+ fs = __toESM(fs);
36
+ let node_url = require("node:url");
37
+ node_url = __toESM(node_url);
38
+ let path = require("path");
39
+ path = __toESM(path);
40
+ let url = require("url");
41
+ url = __toESM(url);
42
+ let picomatch = require("picomatch");
43
+ picomatch = __toESM(picomatch);
44
+ let __flairjs_core = require("@flairjs/core");
45
+ __flairjs_core = __toESM(__flairjs_core);
46
+
47
+ //#region ../shared/dist/esm/index.js
48
+ String.raw;
49
+ const buildThemeTokens = (theme, themeName) => {
50
+ let css$1 = "";
51
+ const { tokens, selector } = theme;
52
+ if (typeof selector === "string") css$1 += `${selector} {\n`;
53
+ css$1 += tokensToCSSVars(tokens, theme.prefix ? [theme.prefix] : []);
54
+ if (typeof selector === "string") css$1 += `}\n`;
55
+ else css$1 = selector(css$1, themeName);
56
+ Object.entries(theme.themes ?? {}).forEach(([name, themeConfig]) => {
57
+ css$1 += buildThemeTokens({
58
+ prefix: theme.prefix,
59
+ selector: theme.selector,
60
+ ...themeConfig
61
+ }, name);
62
+ });
63
+ return css$1;
64
+ };
65
+ function tokensToCSSVars(tokens, prefix = []) {
66
+ let css$1 = "";
67
+ for (const [key, value] of Object.entries(tokens)) {
68
+ const newPrefix = [...prefix, key];
69
+ if (typeof value === "string" || typeof value === "number") css$1 += `--${newPrefix.join("-")}: ${value};\n`;
70
+ else if (typeof value === "object" && value !== null) css$1 += tokensToCSSVars(value, newPrefix);
71
+ }
72
+ return css$1;
73
+ }
74
+ const __dirname$1 = (0, node_path.dirname)((0, node_url.fileURLToPath)(require("url").pathToFileURL(__filename).href));
75
+ const getUserTheme = async () => {
76
+ try {
77
+ let userThemeFilePath = path.default.resolve(process.cwd(), "flair.theme.ts");
78
+ if (!(0, fs.existsSync)(userThemeFilePath)) userThemeFilePath = path.default.resolve(process.cwd(), "flair.theme.js");
79
+ if (!(0, fs.existsSync)(userThemeFilePath)) return null;
80
+ const outFile = path.default.resolve(__dirname$1, `flair.theme.js`);
81
+ await esbuild.build({
82
+ entryPoints: [userThemeFilePath],
83
+ outfile: outFile,
84
+ platform: "node",
85
+ bundle: true,
86
+ format: "esm",
87
+ external: ["*"]
88
+ });
89
+ const cacheBuster = Date.now();
90
+ const userTheme = await import(`${(0, url.pathToFileURL)(outFile).href}?update=${cacheBuster}`);
91
+ if (userTheme.default) return {
92
+ theme: userTheme.default,
93
+ originalPath: userThemeFilePath
94
+ };
95
+ return null;
96
+ } catch (error) {
97
+ console.error("Error loading user theme:", error);
98
+ return null;
99
+ }
100
+ };
101
+ 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();
108
+ 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);
117
+ }
118
+ let userTheme = await getUserTheme();
119
+ const buildThemeCSS = buildThemeFile ?? buildThemeTokens;
120
+ if (userTheme) {
121
+ const themeCSS = buildThemeCSS(userTheme.theme);
122
+ await (0, node_fs_promises.writeFile)(flairThemeFile, themeCSS, "utf-8");
123
+ (0, node_fs.watch)(userTheme.originalPath, async () => {
124
+ userTheme = await getUserTheme();
125
+ if (!userTheme) return;
126
+ const themeCSS$1 = buildThemeCSS(userTheme.theme);
127
+ await (0, node_fs_promises.writeFile)(flairThemeFile, themeCSS$1, "utf-8");
128
+ });
129
+ }
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);
136
+ }
137
+ };
138
+ return {
139
+ flairThemeFile,
140
+ flairGeneratedCssDir,
141
+ userTheme,
142
+ buildThemeCSS,
143
+ refreshCssFile
144
+ };
145
+ }
146
+ 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;
151
+ return true;
152
+ }
153
+ const colors = {
154
+ reset: "\x1B[0m",
155
+ fg: {
156
+ red: "\x1B[31m",
157
+ yellow: "\x1B[33m",
158
+ blue: "\x1B[34m",
159
+ white: "\x1B[37m"
160
+ },
161
+ bg: {
162
+ red: "\x1B[41m",
163
+ yellow: "\x1B[43m",
164
+ blue: "\x1B[44m"
165
+ }
166
+ };
167
+ const logger = {
168
+ error: (msg) => {
169
+ console.log(`${colors.bg.red}${colors.fg.white}[flairjs/Error]${colors.reset} ${colors.fg.red}${msg}${colors.reset}`);
170
+ },
171
+ warn: (msg) => {
172
+ console.log(`${colors.bg.yellow}${colors.fg.white}[flairjs/Warning]${colors.reset} ${msg}${colors.reset}`);
173
+ },
174
+ info: (msg) => {
175
+ console.log(`${colors.bg.blue}${colors.fg.white}[flairjs/Info]${colors.reset} ${msg}${colors.reset}`);
176
+ }
177
+ };
178
+ const transformCode = (code, filePath, options) => {
179
+ const result = (0, __flairjs_core.transformCode)(code, filePath, {
180
+ cssOutDir: options.cssOutDir,
181
+ classNameList: options.classNameList,
182
+ useTheme: options.useTheme,
183
+ theme: options.theme,
184
+ appendTimestampToCssFile: options.appendTimestampToCssFile
185
+ }, options.cssPreprocessor);
186
+ (result?.logs ?? []).forEach((log) => {
187
+ if (logger[log.level]) logger[log.level](log.message);
188
+ });
189
+ return result;
190
+ };
191
+
192
+ //#endregion
193
+ //#region src/index.ts
194
+ async function flairJsLoader(source, sourceMap) {
195
+ const callback = this.async();
196
+ if (!callback) {
197
+ console.error("@flairjs/webpack-loader requires async support");
198
+ return;
199
+ }
200
+ const options = this.getOptions() || {};
201
+ const context = await initializeSharedContext(options);
202
+ const fileName = this.resourcePath;
203
+ if (!shouldProcessFile(fileName, options?.include, options?.exclude)) return callback(null, source, sourceMap);
204
+ try {
205
+ const result = transformCode(source, fileName, {
206
+ appendTimestampToCssFile: true,
207
+ classNameList: options?.classNameList,
208
+ cssPreprocessor: options?.cssPreprocessor ? (css) => options.cssPreprocessor(css, fileName) : void 0,
209
+ theme: context.userTheme?.theme,
210
+ useTheme: !!context.userTheme,
211
+ cssOutDir: context.flairGeneratedCssDir
212
+ });
213
+ if (!result) return callback(null, source, sourceMap);
214
+ if (result.generatedCssName) context.refreshCssFile(result.generatedCssName);
215
+ callback(null, result.code, result.sourcemap ? JSON.parse(result.sourcemap ?? "{}") : sourceMap);
216
+ } catch (error) {
217
+ console.error("[@flairjs/webpack-loader]", error);
218
+ callback(error, source, sourceMap);
219
+ }
220
+ }
221
+
222
+ //#endregion
223
+ module.exports = flairJsLoader;
@@ -0,0 +1,189 @@
1
+ import module from "node:module";
2
+ import { existsSync, watch } from "node:fs";
3
+ import { mkdir, rm, writeFile } from "node:fs/promises";
4
+ import path, { dirname } from "node:path";
5
+ import * as esbuild from "esbuild";
6
+ import { existsSync as existsSync$1 } from "fs";
7
+ import { fileURLToPath } from "node:url";
8
+ import path$1 from "path";
9
+ import { pathToFileURL } from "url";
10
+ import picomatch from "picomatch";
11
+ import { transformCode } from "@flairjs/core";
12
+
13
+ //#region ../shared/dist/esm/index.js
14
+ String.raw;
15
+ const buildThemeTokens = (theme, themeName) => {
16
+ let css$1 = "";
17
+ const { tokens, selector } = theme;
18
+ if (typeof selector === "string") css$1 += `${selector} {\n`;
19
+ css$1 += tokensToCSSVars(tokens, theme.prefix ? [theme.prefix] : []);
20
+ if (typeof selector === "string") css$1 += `}\n`;
21
+ else css$1 = selector(css$1, themeName);
22
+ Object.entries(theme.themes ?? {}).forEach(([name, themeConfig]) => {
23
+ css$1 += buildThemeTokens({
24
+ prefix: theme.prefix,
25
+ selector: theme.selector,
26
+ ...themeConfig
27
+ }, name);
28
+ });
29
+ return css$1;
30
+ };
31
+ function tokensToCSSVars(tokens, prefix = []) {
32
+ let css$1 = "";
33
+ for (const [key, value] of Object.entries(tokens)) {
34
+ const newPrefix = [...prefix, key];
35
+ if (typeof value === "string" || typeof value === "number") css$1 += `--${newPrefix.join("-")}: ${value};\n`;
36
+ else if (typeof value === "object" && value !== null) css$1 += tokensToCSSVars(value, newPrefix);
37
+ }
38
+ return css$1;
39
+ }
40
+ const __dirname = dirname(fileURLToPath(import.meta.url));
41
+ const getUserTheme = async () => {
42
+ try {
43
+ let userThemeFilePath = path$1.resolve(process.cwd(), "flair.theme.ts");
44
+ if (!existsSync$1(userThemeFilePath)) userThemeFilePath = path$1.resolve(process.cwd(), "flair.theme.js");
45
+ if (!existsSync$1(userThemeFilePath)) return null;
46
+ const outFile = path$1.resolve(__dirname, `flair.theme.js`);
47
+ await esbuild.build({
48
+ entryPoints: [userThemeFilePath],
49
+ outfile: outFile,
50
+ platform: "node",
51
+ bundle: true,
52
+ format: "esm",
53
+ external: ["*"]
54
+ });
55
+ const cacheBuster = Date.now();
56
+ const userTheme = await import(`${pathToFileURL(outFile).href}?update=${cacheBuster}`);
57
+ if (userTheme.default) return {
58
+ theme: userTheme.default,
59
+ originalPath: userThemeFilePath
60
+ };
61
+ return null;
62
+ } catch (error) {
63
+ console.error("Error loading user theme:", error);
64
+ return null;
65
+ }
66
+ };
67
+ 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();
74
+ 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);
83
+ }
84
+ let userTheme = await getUserTheme();
85
+ const buildThemeCSS = buildThemeFile ?? buildThemeTokens;
86
+ if (userTheme) {
87
+ const themeCSS = buildThemeCSS(userTheme.theme);
88
+ await writeFile(flairThemeFile, themeCSS, "utf-8");
89
+ watch(userTheme.originalPath, async () => {
90
+ userTheme = await getUserTheme();
91
+ if (!userTheme) return;
92
+ const themeCSS$1 = buildThemeCSS(userTheme.theme);
93
+ await writeFile(flairThemeFile, themeCSS$1, "utf-8");
94
+ });
95
+ }
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);
102
+ }
103
+ };
104
+ return {
105
+ flairThemeFile,
106
+ flairGeneratedCssDir,
107
+ userTheme,
108
+ buildThemeCSS,
109
+ refreshCssFile
110
+ };
111
+ }
112
+ 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;
117
+ return true;
118
+ }
119
+ const colors = {
120
+ reset: "\x1B[0m",
121
+ fg: {
122
+ red: "\x1B[31m",
123
+ yellow: "\x1B[33m",
124
+ blue: "\x1B[34m",
125
+ white: "\x1B[37m"
126
+ },
127
+ bg: {
128
+ red: "\x1B[41m",
129
+ yellow: "\x1B[43m",
130
+ blue: "\x1B[44m"
131
+ }
132
+ };
133
+ const logger = {
134
+ error: (msg) => {
135
+ console.log(`${colors.bg.red}${colors.fg.white}[flairjs/Error]${colors.reset} ${colors.fg.red}${msg}${colors.reset}`);
136
+ },
137
+ warn: (msg) => {
138
+ console.log(`${colors.bg.yellow}${colors.fg.white}[flairjs/Warning]${colors.reset} ${msg}${colors.reset}`);
139
+ },
140
+ info: (msg) => {
141
+ console.log(`${colors.bg.blue}${colors.fg.white}[flairjs/Info]${colors.reset} ${msg}${colors.reset}`);
142
+ }
143
+ };
144
+ const transformCode$1 = (code, filePath, options) => {
145
+ const result = transformCode(code, filePath, {
146
+ cssOutDir: options.cssOutDir,
147
+ classNameList: options.classNameList,
148
+ useTheme: options.useTheme,
149
+ theme: options.theme,
150
+ appendTimestampToCssFile: options.appendTimestampToCssFile
151
+ }, options.cssPreprocessor);
152
+ (result?.logs ?? []).forEach((log) => {
153
+ if (logger[log.level]) logger[log.level](log.message);
154
+ });
155
+ return result;
156
+ };
157
+
158
+ //#endregion
159
+ //#region src/index.ts
160
+ async function flairJsLoader(source, sourceMap) {
161
+ const callback = this.async();
162
+ if (!callback) {
163
+ console.error("@flairjs/webpack-loader requires async support");
164
+ return;
165
+ }
166
+ const options = this.getOptions() || {};
167
+ const context = await initializeSharedContext(options);
168
+ const fileName = this.resourcePath;
169
+ if (!shouldProcessFile(fileName, options?.include, options?.exclude)) return callback(null, source, sourceMap);
170
+ try {
171
+ const result = transformCode$1(source, fileName, {
172
+ appendTimestampToCssFile: true,
173
+ classNameList: options?.classNameList,
174
+ cssPreprocessor: options?.cssPreprocessor ? (css) => options.cssPreprocessor(css, fileName) : void 0,
175
+ theme: context.userTheme?.theme,
176
+ useTheme: !!context.userTheme,
177
+ cssOutDir: context.flairGeneratedCssDir
178
+ });
179
+ if (!result) return callback(null, source, sourceMap);
180
+ if (result.generatedCssName) context.refreshCssFile(result.generatedCssName);
181
+ callback(null, result.code, result.sourcemap ? JSON.parse(result.sourcemap ?? "{}") : sourceMap);
182
+ } catch (error) {
183
+ console.error("[@flairjs/webpack-loader]", error);
184
+ callback(error, source, sourceMap);
185
+ }
186
+ }
187
+
188
+ //#endregion
189
+ export { flairJsLoader as default };
@@ -0,0 +1,6 @@
1
+ import { SharedPluginOptions } from "@flairjs/bundler-shared";
2
+ import { LoaderContext } from "webpack";
3
+ interface FlairJsWebpackLoaderOptions extends SharedPluginOptions {
4
+ }
5
+ export default function flairJsLoader(this: LoaderContext<FlairJsWebpackLoaderOptions>, source: string, sourceMap: string): Promise<void>;
6
+ export {};