@aippy/vite-plugins 0.2.1 → 0.2.4

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.
@@ -0,0 +1,26 @@
1
+ /**
2
+ * HTML processing utilities for aippy preload plugin
3
+ */
4
+ /**
5
+ * Generate meta tags for asset preloading
6
+ * @param assets - Array of asset URLs
7
+ * @returns HTML meta tags string
8
+ */
9
+ export declare function generateMetaTags(assets: string[]): string;
10
+ /**
11
+ * Inject meta tags into HTML content
12
+ * @param htmlContent - Original HTML content
13
+ * @param metaTags - Meta tags to inject
14
+ * @returns Modified HTML content
15
+ */
16
+ export declare function injectMetaTags(htmlContent: string, metaTags: string): string;
17
+ /**
18
+ * Log scan results to console
19
+ * @param assets - Array of found assets
20
+ */
21
+ export declare function logScanResults(assets: string[]): void;
22
+ /**
23
+ * Log injection result to console
24
+ * @param count - Number of meta tags injected
25
+ */
26
+ export declare function logInjectionResult(count: number): void;
@@ -1,12 +1,12 @@
1
1
  import { Plugin } from 'vite';
2
- interface AssetPreloadOptions {
3
- extensions?: string[];
4
- includeFiles?: string[];
5
- exclude?: string[];
6
- outDir?: string;
7
- includeSubdirs?: boolean;
8
- deepScan?: boolean;
9
- srcDir?: string;
10
- }
2
+ import { AssetPreloadOptions } from './types';
3
+ /**
4
+ * Aippy preload plugin - scans source files for assets and injects preload meta tags
5
+ *
6
+ * This plugin scans source files (not build output) to avoid including third-party libraries
7
+ *
8
+ * @param options - Plugin options
9
+ * @returns Vite plugin
10
+ */
11
11
  export declare function aippyPreloadPlugin(options?: AssetPreloadOptions): Plugin;
12
12
  export default aippyPreloadPlugin;
@@ -1,147 +1,123 @@
1
- var f = Object.defineProperty;
2
- var g = (e, s, t) => s in e ? f(e, s, { enumerable: !0, configurable: !0, writable: !0, value: t }) : e[s] = t;
3
- var p = (e, s, t) => g(e, typeof s != "symbol" ? s + "" : s, t);
4
- import r from "fs/promises";
5
- import a from "path";
6
- import { glob as l } from "glob";
7
- import { extractAssetsFromContent as c } from "../utils/index.js";
8
- class F {
9
- constructor(s = {}) {
10
- p(this, "options");
11
- this.options = {
12
- extensions: [".js", ".css", ".png", ".jpg", ".jpeg", ".gif", ".svg", ".woff", ".woff2", ".ttf", ".eot"],
13
- includeFiles: [],
14
- exclude: ["*.map"],
15
- outDir: "dist",
16
- includeSubdirs: !0,
17
- deepScan: !0,
18
- srcDir: "src",
19
- ...s
20
- };
21
- }
22
- /**
23
- * Scan external file resources
24
- */
25
- async scanExternalFiles() {
26
- const s = [], t = this.options.extensions.map(
27
- (i) => this.options.includeSubdirs ? a.join(this.options.outDir, "**", `*${i}`) : a.join(this.options.outDir, `*${i}`)
28
- ), n = await l(t, {
29
- ignore: this.options.exclude,
30
- absolute: !0
31
- });
32
- if (s.push(...n), this.options.includeFiles.length > 0) {
33
- const i = this.options.includeFiles.map((h) => this.options.includeSubdirs ? a.join(this.options.outDir, "**", h) : a.join(this.options.outDir, h)), u = await l(i, {
34
- ignore: this.options.exclude,
35
- absolute: !0
36
- });
37
- s.push(...u);
1
+ import { promises as i } from "fs";
2
+ import u from "path";
3
+ import { extractAssetsFromContent as r } from "../utils/index.js";
4
+ import { g as l } from "../file-scanner-DHkDSQm8.js";
5
+ async function d(s) {
6
+ const t = [], n = [u.join(process.cwd(), "index.html")];
7
+ for (const c of n)
8
+ try {
9
+ const e = await i.readFile(c, "utf-8"), o = r(e, "html", s);
10
+ t.push(...o);
11
+ } catch {
12
+ console.warn("⚠️ No index.html found in project root");
38
13
  }
39
- return [...new Set(s)].map((i) => `/${a.relative(this.options.outDir, i).replace(/\\/g, "/")}`);
40
- }
41
- /**
42
- * Scan HTML files
43
- */
44
- async scanHtmlFiles() {
45
- const s = [], t = await l("**/*.html", { cwd: this.options.outDir, absolute: !0 });
46
- for (const n of t)
47
- try {
48
- const o = await r.readFile(n, "utf-8"), i = c(o, "html", this.options.extensions);
49
- s.push(...i);
50
- } catch (o) {
51
- console.warn(`⚠️ Failed to read HTML file: ${n}`, o);
52
- }
53
- return s;
54
- }
55
- /**
56
- * Scan JS files
57
- */
58
- async scanJsFiles() {
59
- const s = [], t = await l("**/*.js", { cwd: this.options.outDir, absolute: !0 });
60
- for (const n of t)
61
- try {
62
- const o = await r.readFile(n, "utf-8"), i = c(o, "js", this.options.extensions);
63
- s.push(...i);
64
- } catch (o) {
65
- console.warn(`⚠️ Failed to read JS file: ${n}`, o);
66
- }
67
- return s;
68
- }
69
- /**
70
- * Scan CSS files
71
- */
72
- async scanCssFiles() {
73
- const s = [], t = await l("**/*.css", { cwd: this.options.outDir, absolute: !0 });
74
- for (const n of t)
75
- try {
76
- const o = await r.readFile(n, "utf-8"), i = c(o, "css", this.options.extensions);
77
- s.push(...i);
78
- } catch (o) {
79
- console.warn(`⚠️ Failed to read CSS file: ${n}`, o);
80
- }
81
- return s;
82
- }
83
- /**
84
- * Execute complete asset scanning
85
- */
86
- async scanAllAssets() {
87
- console.log("🔍 Scanning for static assets...");
88
- const s = [], t = await this.scanExternalFiles();
89
- if (s.push(...t), this.options.deepScan) {
90
- console.log("🔍 Deep scanning file contents...");
91
- const [n, o, i] = await Promise.all([
92
- this.scanHtmlFiles(),
93
- this.scanJsFiles(),
94
- this.scanCssFiles()
95
- ]);
96
- s.push(...n, ...o, ...i);
14
+ return t;
15
+ }
16
+ async function g(s, t) {
17
+ const n = [], c = await l(s, [".ts", ".tsx", ".js", ".jsx"]);
18
+ for (const e of c)
19
+ try {
20
+ const o = await i.readFile(e, "utf-8"), a = r(o, "js", t);
21
+ n.push(...a);
22
+ } catch (o) {
23
+ console.warn(`⚠️ Failed to read JS file: ${e}`, o);
24
+ }
25
+ return n;
26
+ }
27
+ async function h(s, t) {
28
+ const n = [], c = await l(s, [".css", ".scss", ".sass", ".less"]);
29
+ for (const e of c)
30
+ try {
31
+ const o = await i.readFile(e, "utf-8"), a = r(o, "css", t);
32
+ n.push(...a);
33
+ } catch (o) {
34
+ console.warn(`⚠️ Failed to read CSS file: ${e}`, o);
97
35
  }
98
- return [...new Set(s)];
36
+ return n;
37
+ }
38
+ async function m(s, t) {
39
+ const n = [], c = await l(s, [".json"]);
40
+ for (const e of c)
41
+ try {
42
+ const o = await i.readFile(e, "utf-8"), a = r(o, "js", t);
43
+ n.push(...a);
44
+ } catch (o) {
45
+ console.warn(`⚠️ Failed to read JSON file: ${e}`, o);
46
+ }
47
+ return n;
48
+ }
49
+ async function j(s, t, n) {
50
+ console.log("🔍 Scanning source files for static assets...");
51
+ const c = [];
52
+ if (n) {
53
+ console.log("🔍 Deep scanning source file contents...");
54
+ const [e, o, a, p] = await Promise.all([
55
+ d(t),
56
+ g(s, t),
57
+ h(s, t),
58
+ m(s, t)
59
+ ]);
60
+ c.push(...e, ...o, ...a, ...p);
99
61
  }
62
+ return [...new Set(c)];
100
63
  }
101
- function m(e) {
102
- return e.map((s) => ` <meta content="${s}" name="aippy:preload">`).join(`
64
+ const f = "<head>", F = f.length;
65
+ function w(s) {
66
+ return s.map((t) => ` <meta content="${t}" name="aippy:preload">`).join(`
103
67
  `);
104
68
  }
105
- const d = "<head>", w = d.length;
106
- function j(e, s) {
107
- const t = e.indexOf(d);
108
- if (t === -1)
69
+ function y(s, t) {
70
+ const n = s.indexOf(f);
71
+ if (n === -1)
109
72
  throw new Error("Could not find <head> tag in HTML");
110
- const n = t + w;
111
- return e.slice(0, n) + `
112
- ` + s + `
113
- ` + e.slice(n);
73
+ const c = n + F;
74
+ return s.slice(0, c) + `
75
+ ` + t + `
76
+ ` + s.slice(c);
114
77
  }
115
- function x(e) {
116
- if (console.log(`📁 Found ${e.length} static assets`), e.length === 0) {
117
- console.log("⚠️ No static assets found. This might be because all assets are inlined.");
78
+ function A(s) {
79
+ if (console.log(`📁 Found ${s.length} static assets in source files`), s.length === 0) {
80
+ console.log("⚠️ No static assets found in source files.");
118
81
  return;
119
82
  }
120
- console.log("📋 Assets found:"), e.forEach((s) => console.log(` - ${s}`));
83
+ console.log("📋 Assets found:"), s.forEach((t) => console.log(` - ${t}`));
121
84
  }
122
- function A(e) {
123
- console.log(`✅ Injected ${e} preload meta tags into index.html`);
85
+ function x(s) {
86
+ console.log(`✅ Injected ${s} preload meta tags into index.html`);
124
87
  }
125
- function P(e = {}) {
88
+ function C(s = {}) {
89
+ const t = {
90
+ extensions: [".png", ".jpg", ".jpeg", ".gif", ".svg", ".mp4", ".mp3", ".wav", ".ogg", ".webm"],
91
+ srcDir: "src",
92
+ outDir: "dist",
93
+ deepScan: !0,
94
+ ...s
95
+ };
126
96
  return {
127
97
  name: "vite-plugin-aippy-preload",
128
98
  apply: "build",
99
+ // Ensure this plugin runs after other plugins (like viteSingleFile)
100
+ enforce: "post",
129
101
  async closeBundle() {
130
102
  try {
131
- const t = await new F(e).scanAllAssets();
132
- if (x(t), t.length === 0)
103
+ const n = await j(
104
+ t.srcDir,
105
+ t.extensions,
106
+ t.deepScan
107
+ );
108
+ if (A(n), n.length === 0)
133
109
  return;
134
- const n = a.join(e.outDir || "dist", "index.html");
135
- let o = await r.readFile(n, "utf-8");
136
- const i = m(t);
137
- o = j(o, i), await r.writeFile(n, o, "utf-8"), A(t.length);
138
- } catch (s) {
139
- console.error("❌ Error in asset preload plugin:", s);
110
+ const c = u.join(t.outDir, "index.html");
111
+ let e = await i.readFile(c, "utf-8");
112
+ const o = w(n);
113
+ e = y(e, o), await i.writeFile(c, e, "utf-8"), x(n.length);
114
+ } catch (n) {
115
+ console.error("❌ Error in aippy preload plugin:", n);
140
116
  }
141
117
  }
142
118
  };
143
119
  }
144
120
  export {
145
- P as aippyPreloadPlugin,
146
- P as default
121
+ C as aippyPreloadPlugin,
122
+ C as default
147
123
  };
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Source file scanning utilities for aippy preload plugin
3
+ */
4
+ /**
5
+ * Scan HTML files in project root directory
6
+ * @param extensions - Asset extensions to look for
7
+ * @returns Array of asset URLs
8
+ */
9
+ export declare function scanHtmlFiles(extensions: string[]): Promise<string[]>;
10
+ /**
11
+ * Scan TypeScript/JavaScript files in source directory
12
+ * @param srcDir - Source directory
13
+ * @param extensions - Asset extensions to look for
14
+ * @returns Array of asset URLs
15
+ */
16
+ export declare function scanJsFiles(srcDir: string, extensions: string[]): Promise<string[]>;
17
+ /**
18
+ * Scan CSS files in source directory
19
+ * @param srcDir - Source directory
20
+ * @param extensions - Asset extensions to look for
21
+ * @returns Array of asset URLs
22
+ */
23
+ export declare function scanCssFiles(srcDir: string, extensions: string[]): Promise<string[]>;
24
+ /**
25
+ * Scan JSON files in source directory for asset URLs
26
+ * @param srcDir - Source directory
27
+ * @param extensions - Asset extensions to look for
28
+ * @returns Array of asset URLs
29
+ */
30
+ export declare function scanJsonFiles(srcDir: string, extensions: string[]): Promise<string[]>;
31
+ /**
32
+ * Scan all source files for asset references
33
+ * @param srcDir - Source directory
34
+ * @param extensions - Asset extensions to look for
35
+ * @param deepScan - Whether to deep scan file contents
36
+ * @returns Array of unique asset URLs
37
+ */
38
+ export declare function scanAllSourceAssets(srcDir: string, extensions: string[], deepScan: boolean): Promise<string[]>;
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Type definitions for aippy preload plugin
3
+ */
4
+ export interface AssetPreloadOptions {
5
+ extensions?: string[];
6
+ srcDir?: string;
7
+ outDir?: string;
8
+ deepScan?: boolean;
9
+ }
@@ -0,0 +1,22 @@
1
+ import { AssetInfo } from './types';
2
+ /**
3
+ * Generate assets.json file content from asset info
4
+ * @param assets - Map of assets
5
+ * @param existingAssets - Map of existing assets from previous runs
6
+ * @returns JSON string
7
+ */
8
+ export declare function generateAssetsFileContent(assets: Map<string, AssetInfo>, existingAssets: Map<string, string>): string;
9
+ /**
10
+ * Parse existing assets.json file
11
+ * @param content - File content
12
+ * @returns Map of URI to constant name
13
+ */
14
+ export declare function parseExistingAssetsContent(content: string): Map<string, string>;
15
+ /**
16
+ * Log generation statistics
17
+ * @param totalAssets - Total number of assets
18
+ * @param existingAssets - Map of existing assets
19
+ * @param assets - Map of current assets
20
+ * @param outputFile - Output file path
21
+ */
22
+ export declare function logGenerationStats(totalAssets: number, existingAssets: Map<string, string>, assets: Map<string, AssetInfo>, outputFile: string): void;
@@ -1,9 +1,4 @@
1
1
  import { Plugin } from 'vite';
2
- interface AssetConstantsOptions {
3
- extensions?: string[];
4
- srcDir?: string;
5
- outputFile?: string;
6
- devMode?: boolean;
7
- }
2
+ import { AssetConstantsOptions } from './types';
8
3
  export declare function assetConstantsPlugin(options?: AssetConstantsOptions): Plugin;
9
4
  export default assetConstantsPlugin;
@@ -1,19 +1,50 @@
1
- var v = Object.defineProperty;
2
- var $ = (l, s, t) => s in l ? v(l, s, { enumerable: !0, configurable: !0, writable: !0, value: t }) : l[s] = t;
3
- var g = (l, s, t) => $(l, typeof s != "symbol" ? s + "" : s, t);
4
- import { promises as f } from "fs";
5
- import p from "path";
6
- import { parse as F } from "@babel/parser";
7
- import d from "@babel/traverse";
1
+ var C = Object.defineProperty;
2
+ var v = (a, s, t) => s in a ? C(a, s, { enumerable: !0, configurable: !0, writable: !0, value: t }) : a[s] = t;
3
+ var f = (a, s, t) => v(a, typeof s != "symbol" ? s + "" : s, t);
4
+ import { promises as g } from "fs";
5
+ import d from "path";
6
+ import { parse as N } from "@babel/parser";
7
+ import h from "@babel/traverse";
8
8
  import * as u from "@babel/types";
9
9
  import m from "@babel/generator";
10
- import { generateConstantName as j, extractAssetsFromContent as N, processAssetURL as C } from "../utils/index.js";
11
- const A = typeof d == "function" ? d : d.default, U = typeof m == "function" ? m : m.default;
12
- class E {
10
+ import { generateConstantName as U, extractAssetsFromContent as $, processAssetURL as j } from "../utils/index.js";
11
+ import { F as E, g as A, a as b } from "../file-scanner-DHkDSQm8.js";
12
+ function D(a, s) {
13
+ const t = {};
14
+ for (const [i, o] of s.entries())
15
+ t[o] = i;
16
+ return Array.from(a.values()).forEach((i) => {
17
+ t[i.constantName] = i.originalUri;
18
+ }), JSON.stringify(t, null, 2) + `
19
+ `;
20
+ }
21
+ function I(a) {
22
+ const s = /* @__PURE__ */ new Map();
23
+ try {
24
+ if (!a.trim())
25
+ return s;
26
+ const t = JSON.parse(a);
27
+ for (const [e, i] of Object.entries(t))
28
+ typeof i == "string" && s.set(i, e);
29
+ s.size > 0 && console.log(`📋 Found ${s.size} existing constants in assets.json`);
30
+ } catch (t) {
31
+ console.warn("Warning: Failed to parse existing assets.json:", t);
32
+ }
33
+ return s;
34
+ }
35
+ function S(a, s, t, e) {
36
+ const i = Array.from(t.values()).filter(
37
+ (n) => s.has(n.originalUri)
38
+ ).length, o = a - i;
39
+ o > 0 ? console.log(`✅ Generated ${a} asset constants (${o} new, ${i} reused) in ${e}`) : a > 0 ? console.log(`✅ Generated ${a} asset constants (all reused from existing) in ${e}`) : console.log("✅ No asset constants found");
40
+ }
41
+ const x = typeof h == "function" ? h : h.default, W = typeof m == "function" ? m : m.default;
42
+ class R {
13
43
  constructor(s = {}) {
14
- g(this, "options");
15
- g(this, "assets", /* @__PURE__ */ new Map());
16
- g(this, "existingAssets", /* @__PURE__ */ new Map());
44
+ f(this, "options");
45
+ f(this, "assets", /* @__PURE__ */ new Map());
46
+ f(this, "existingAssets", /* @__PURE__ */ new Map());
47
+ f(this, "fileCache", new E());
17
48
  this.options = {
18
49
  extensions: [".png", ".jpg", ".jpeg", ".gif", ".svg", ".mp4", ".mp3", ".wav", ".ogg", ".webm"],
19
50
  srcDir: "src",
@@ -22,157 +53,115 @@ class E {
22
53
  ...s
23
54
  };
24
55
  }
56
+ clearCache() {
57
+ this.fileCache.clear();
58
+ }
25
59
  generateConstantName(s) {
26
60
  const t = /* @__PURE__ */ new Set([
27
61
  ...Array.from(this.assets.values()).map((e) => e.constantName),
28
62
  ...Array.from(this.existingAssets.values())
29
63
  ]);
30
- return j(s, t);
64
+ return U(s, t);
31
65
  }
32
66
  async scanTsFile(s) {
33
67
  try {
34
- const t = await f.readFile(s, "utf-8");
35
- F(t, {
36
- sourceType: "module",
37
- plugins: ["typescript", "jsx", "decorators-legacy"]
38
- });
39
- const e = [];
40
- return N(t, "js", this.options.extensions).forEach((i) => {
41
- const n = this.generateConstantName(i), a = t.split(`
42
- `).findIndex((h) => h.includes(i)) + 1;
68
+ const t = await this.fileCache.read(s), e = [], i = $(t, "js", this.options.extensions), o = t.split(`
69
+ `);
70
+ return i.forEach((n) => {
71
+ const r = this.generateConstantName(n), c = o.findIndex((p) => p.includes(n)) + 1;
43
72
  e.push({
44
- originalUri: i,
45
- constantName: n,
73
+ originalUri: n,
74
+ constantName: r,
46
75
  filePath: s,
47
- line: a,
76
+ line: c,
48
77
  column: 1
49
78
  });
50
79
  }), e;
51
80
  } catch (t) {
52
- return console.warn(`Warning: Failed to parse ${s}:`, t), [];
81
+ return console.warn(`Warning: Failed to scan ${s}:`, t), [];
53
82
  }
54
83
  }
55
84
  async scanAllTsFiles() {
56
85
  const s = this.options.srcDir;
57
86
  try {
58
- const t = await this.getAllTsFiles(s);
87
+ const t = await A(s, [".ts", ".tsx"]);
59
88
  for (const e of t) {
60
89
  if (e.endsWith("assets.json") || e.endsWith("assets.ts"))
61
90
  continue;
62
- (await this.scanTsFile(e)).forEach((i) => {
63
- this.existingAssets.has(i.originalUri) && (i.constantName = this.existingAssets.get(i.originalUri));
64
- const n = i.originalUri;
65
- this.assets.has(n) || this.assets.set(n, i);
91
+ (await this.scanTsFile(e)).forEach((o) => {
92
+ this.existingAssets.has(o.originalUri) && (o.constantName = this.existingAssets.get(o.originalUri));
93
+ const n = o.originalUri;
94
+ this.assets.has(n) || this.assets.set(n, o);
66
95
  });
67
96
  }
68
97
  } catch (t) {
69
98
  console.error("Error scanning TypeScript files:", t);
70
99
  }
71
100
  }
72
- async getAllTsFiles(s) {
73
- const t = [];
74
- try {
75
- const e = await f.readdir(s, { withFileTypes: !0 });
76
- for (const o of e) {
77
- const i = p.join(s, o.name);
78
- if (o.isDirectory()) {
79
- const n = await this.getAllTsFiles(i);
80
- t.push(...n);
81
- } else o.isFile() && /\.(ts|tsx)$/.test(o.name) && t.push(i);
82
- }
83
- } catch (e) {
84
- console.warn(`Warning: Failed to read directory ${s}:`, e);
85
- }
86
- return t;
87
- }
88
- generateAssetsFileContent() {
89
- const s = Array.from(this.assets.values()), t = {};
90
- return s.forEach((e) => {
91
- t[e.constantName] = e.originalUri;
92
- }), JSON.stringify(t, null, 2) + `
93
- `;
94
- }
95
101
  async readExistingAssetsFile() {
96
102
  try {
97
- return await f.readFile(this.options.outputFile, "utf-8");
103
+ return await g.readFile(this.options.outputFile, "utf-8");
98
104
  } catch {
99
105
  return "";
100
106
  }
101
107
  }
102
108
  async parseExistingAssets() {
103
- try {
104
- const s = await this.readExistingAssetsFile();
105
- if (!s.trim())
106
- return;
107
- const t = JSON.parse(s);
108
- for (const [e, o] of Object.entries(t))
109
- typeof o == "string" && this.existingAssets.set(o, e);
110
- this.existingAssets.size > 0 && console.log(`📋 Found ${this.existingAssets.size} existing constants in assets.json`);
111
- } catch (s) {
112
- console.warn("Warning: Failed to parse existing assets.json:", s);
113
- }
109
+ const s = await this.readExistingAssetsFile();
110
+ this.existingAssets = I(s);
114
111
  }
115
112
  async generateAssetsFile() {
116
113
  await this.parseExistingAssets(), await this.scanAllTsFiles();
117
- const s = this.generateAssetsFileContent(), t = p.dirname(this.options.outputFile);
118
- await f.mkdir(t, { recursive: !0 }), await f.writeFile(this.options.outputFile, s, "utf-8");
119
- const e = Array.from(this.assets.values()).filter(
120
- (i) => this.existingAssets.has(i.originalUri)
121
- ).length, o = this.assets.size - e;
122
- o > 0 ? console.log(`✅ Generated ${this.assets.size} asset constants (${o} new, ${e} reused) in ${this.options.outputFile}`) : this.assets.size > 0 ? console.log(`✅ Generated ${this.assets.size} asset constants (all reused from existing) in ${this.options.outputFile}`) : console.log("✅ No asset constants found");
114
+ const s = D(this.assets, this.existingAssets), t = d.dirname(this.options.outputFile);
115
+ await g.mkdir(t, { recursive: !0 }), await g.writeFile(this.options.outputFile, s, "utf-8"), S(this.assets.size, this.existingAssets, this.assets, this.options.outputFile);
123
116
  }
124
117
  getAssets() {
125
118
  return Array.from(this.assets.values());
126
119
  }
127
120
  async replaceUrisInFile(s, t) {
128
121
  try {
129
- const e = await f.readFile(s, "utf-8"), o = F(e, {
122
+ const e = await this.fileCache.read(s), i = N(e, {
130
123
  sourceType: "module",
131
124
  plugins: ["typescript", "jsx", "decorators-legacy"]
132
125
  });
133
- let i = !1;
134
- if (A(o, {
126
+ let o = !1;
127
+ if (x(i, {
135
128
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
136
- StringLiteral: (c) => {
137
- const h = c.node.value, w = C(h);
129
+ StringLiteral: (l) => {
130
+ const p = l.node.value, w = j(p);
138
131
  if (t.has(w)) {
139
- const x = t.get(w), y = u.memberExpression(
132
+ const F = t.get(w), y = u.memberExpression(
140
133
  u.identifier("assetsData"),
141
- u.identifier(x)
134
+ u.identifier(F)
142
135
  );
143
- c.parent && u.isJSXAttribute(c.parent) ? c.replaceWith(u.jsxExpressionContainer(y)) : c.replaceWith(y), i = !0;
136
+ l.parent && u.isJSXAttribute(l.parent) ? l.replaceWith(u.jsxExpressionContainer(y)) : l.replaceWith(y), o = !0;
144
137
  }
145
138
  }
146
- }), !i)
139
+ }), !o)
147
140
  return;
148
- const n = this.getRelativeImportPath(s, this.options.outputFile) + ".json";
141
+ const n = b(s, this.options.outputFile) + ".json";
149
142
  let r = !1;
150
- if (A(o, {
143
+ if (x(i, {
151
144
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
152
- ImportDeclaration: (c) => {
153
- c.node.source.value === n && (r = !0, c.stop());
145
+ ImportDeclaration: (l) => {
146
+ l.node.source.value === n && (r = !0, l.stop());
154
147
  }
155
148
  }), !r) {
156
- const c = u.importDeclaration(
149
+ const l = u.importDeclaration(
157
150
  [u.importDefaultSpecifier(u.identifier("assetsData"))],
158
151
  u.stringLiteral(n)
159
152
  );
160
- o.program.body.unshift(c);
153
+ i.program.body.unshift(l);
161
154
  }
162
- const a = U(o, {
155
+ const c = W(i, {
163
156
  retainLines: !1,
164
157
  comments: !0,
165
158
  compact: !1
166
159
  }, e);
167
- await f.writeFile(s, a.code, "utf-8"), console.log(` ✓ Replaced URIs in ${p.relative(process.cwd(), s)}`);
160
+ await g.writeFile(s, c.code, "utf-8"), this.fileCache.invalidate(s), console.log(` ✓ Replaced URIs in ${d.relative(process.cwd(), s)}`);
168
161
  } catch (e) {
169
162
  console.warn(`Warning: Failed to replace URIs in ${s}:`, e);
170
163
  }
171
164
  }
172
- getRelativeImportPath(s, t) {
173
- const o = p.relative(p.dirname(s), t).replace(/\.(ts|json)$/, "");
174
- return o.startsWith(".") ? o : `./${o}`;
175
- }
176
165
  async replaceAllUris() {
177
166
  const s = /* @__PURE__ */ new Map(), t = /* @__PURE__ */ new Set();
178
167
  for (const e of this.assets.values())
@@ -188,35 +177,35 @@ class E {
188
177
  const t = /* @__PURE__ */ new Map();
189
178
  try {
190
179
  const n = JSON.parse(s);
191
- for (const [r, a] of Object.entries(n))
192
- typeof a == "string" && t.set(r, a);
180
+ for (const [r, c] of Object.entries(n))
181
+ typeof c == "string" && t.set(r, c);
193
182
  } catch (n) {
194
183
  console.warn("Warning: Failed to parse assets.json:", n);
195
184
  return;
196
185
  }
197
186
  if (t.size === 0)
198
187
  return;
199
- const e = /* @__PURE__ */ new Set(), o = await this.getAllTsFiles(this.options.srcDir);
200
- for (const n of o)
188
+ const e = /* @__PURE__ */ new Set(), i = await A(this.options.srcDir, [".ts", ".tsx"]);
189
+ for (const n of i)
201
190
  if (!(n.endsWith("assets.json") || n.endsWith("assets.ts")))
202
191
  try {
203
- const r = await f.readFile(n, "utf-8");
204
- for (const a of t.keys())
205
- r.includes(a) && e.add(a);
192
+ const r = await this.fileCache.read(n);
193
+ for (const c of t.keys())
194
+ r.includes(c) && e.add(c);
206
195
  } catch (r) {
207
196
  console.warn(`Warning: Failed to read ${n}:`, r);
208
197
  }
209
- const i = [];
198
+ const o = [];
210
199
  for (const n of t.keys())
211
- e.has(n) || i.push(n);
212
- if (i.length > 0) {
213
- console.log(`🧹 Removing ${i.length} unused constant(s):`), i.forEach((r) => {
200
+ e.has(n) || o.push(n);
201
+ if (o.length > 0) {
202
+ console.log(`🧹 Removing ${o.length} unused constant(s):`), o.forEach((r) => {
214
203
  console.log(` - ${r}`);
215
204
  });
216
205
  const n = [];
217
- for (const r of i) {
218
- const a = t.get(r);
219
- a && n.push(a);
206
+ for (const r of o) {
207
+ const c = t.get(r);
208
+ c && n.push(c);
220
209
  }
221
210
  for (const r of n)
222
211
  this.assets.delete(r);
@@ -227,22 +216,24 @@ class E {
227
216
  }
228
217
  }
229
218
  }
230
- function z(l = {}) {
219
+ function q(a = {}) {
231
220
  return {
232
221
  name: "vite-plugin-asset-constants",
233
222
  apply: "build",
223
+ // Ensure this plugin runs before other plugins to modify source files before build
224
+ enforce: "pre",
234
225
  async buildStart() {
235
- if (l.devMode)
226
+ if (a.devMode)
236
227
  try {
237
- const s = new E(l);
228
+ const s = new R(a);
238
229
  await s.generateAssetsFile();
239
230
  const t = s.getAssets();
240
231
  t.length > 0 && (console.log(`📦 Found ${t.length} asset references:`), t.forEach((e) => {
241
- console.log(` ${e.constantName} = '${e.originalUri}' (${p.relative(process.cwd(), e.filePath)}:${e.line})`);
232
+ console.log(` ${e.constantName} = '${e.originalUri}' (${d.relative(process.cwd(), e.filePath)}:${e.line})`);
242
233
  }), console.log(`
243
234
  🔄 Replacing URIs with constants...`), await s.replaceAllUris(), console.log("✅ URI replacement completed!")), console.log(`
244
235
  🧹 Checking for unused constants...`), await s.cleanupUnusedConstants(), await s.generateAssetsFile(), console.log(`✅ Asset constants finalized!
245
- `);
236
+ `), s.clearCache();
246
237
  } catch (s) {
247
238
  console.error("❌ Error in asset constants plugin:", s);
248
239
  }
@@ -250,6 +241,6 @@ function z(l = {}) {
250
241
  };
251
242
  }
252
243
  export {
253
- z as assetConstantsPlugin,
254
- z as default
244
+ q as assetConstantsPlugin,
245
+ q as default
255
246
  };
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Type definitions for asset constants plugin
3
+ */
4
+ export interface AssetConstantsOptions {
5
+ extensions?: string[];
6
+ srcDir?: string;
7
+ outputFile?: string;
8
+ devMode?: boolean;
9
+ }
10
+ export interface AssetInfo {
11
+ originalUri: string;
12
+ constantName: string;
13
+ filePath: string;
14
+ line: number;
15
+ column: number;
16
+ }
@@ -0,0 +1,50 @@
1
+ var l = Object.defineProperty;
2
+ var u = (e, t, a) => t in e ? l(e, t, { enumerable: !0, configurable: !0, writable: !0, value: a }) : e[t] = a;
3
+ var o = (e, t, a) => u(e, typeof t != "symbol" ? t + "" : t, a);
4
+ import { promises as h } from "fs";
5
+ import i from "path";
6
+ async function f(e, t) {
7
+ const a = [];
8
+ try {
9
+ const s = await h.readdir(e, { withFileTypes: !0 });
10
+ for (const r of s) {
11
+ const c = i.join(e, r.name);
12
+ if (r.isDirectory()) {
13
+ const n = await f(c, t);
14
+ a.push(...n);
15
+ } else if (r.isFile()) {
16
+ const n = i.extname(r.name);
17
+ t.includes(n) && a.push(c);
18
+ }
19
+ }
20
+ } catch (s) {
21
+ console.warn(`Warning: Failed to read directory ${e}:`, s);
22
+ }
23
+ return a;
24
+ }
25
+ function y(e, t) {
26
+ const s = i.relative(i.dirname(e), t).replace(/\.(ts|tsx|js|jsx|json)$/, "");
27
+ return s.startsWith(".") ? s : `./${s}`;
28
+ }
29
+ class F {
30
+ constructor() {
31
+ o(this, "cache", /* @__PURE__ */ new Map());
32
+ }
33
+ async read(t) {
34
+ if (this.cache.has(t))
35
+ return this.cache.get(t);
36
+ const a = await h.readFile(t, "utf-8");
37
+ return this.cache.set(t, a), a;
38
+ }
39
+ invalidate(t) {
40
+ this.cache.delete(t);
41
+ }
42
+ clear() {
43
+ this.cache.clear();
44
+ }
45
+ }
46
+ export {
47
+ F,
48
+ y as a,
49
+ f as g
50
+ };
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Common file scanning utilities for vite plugins
3
+ */
4
+ /**
5
+ * Recursively get all files in a directory matching specified extensions
6
+ * @param dir - Directory to scan
7
+ * @param extensions - File extensions to match (e.g., ['.ts', '.tsx', '.js'])
8
+ * @returns Array of file paths
9
+ */
10
+ export declare function getFilesByExtension(dir: string, extensions: string[]): Promise<string[]>;
11
+ /**
12
+ * Get relative import path from one file to another
13
+ * @param fromFile - Source file path
14
+ * @param toFile - Target file path
15
+ * @returns Relative import path (without extension)
16
+ */
17
+ export declare function getRelativeImportPath(fromFile: string, toFile: string): string;
18
+ /**
19
+ * Read file with caching support
20
+ */
21
+ export declare class FileContentCache {
22
+ private cache;
23
+ read(filePath: string): Promise<string>;
24
+ invalidate(filePath: string): void;
25
+ clear(): void;
26
+ }
@@ -3,8 +3,9 @@
3
3
  */
4
4
  /**
5
5
  * Process asset URL to ensure it's properly formatted
6
+ * Keep the original path format to preserve context-dependent paths
6
7
  * @param url - The asset URL to process
7
- * @returns Processed URL
8
+ * @returns Processed URL (trimmed and cleaned)
8
9
  */
9
10
  export declare function processAssetURL(url: string): string;
10
11
  /**
@@ -1,114 +1,96 @@
1
- import { existsSync as h } from "fs";
1
+ import { existsSync as g } from "fs";
2
2
  import f from "path";
3
- const u = [".png", ".jpg", ".jpeg", ".gif", ".svg", ".webp"], w = [".mp4", ".webm", ".mov", ".avi"], d = [".mp3", ".wav", ".ogg", ".m4a"];
4
- function g(e) {
5
- return e.match(/^https?:\/\//) || e.match(/^data:/) || e.match(/^blob:/) || e.startsWith("/") ? e : `/${e.replace(/^(\.\.\/)+/, "").replace(/^\.\//, "")}`;
3
+ const u = [".png", ".jpg", ".jpeg", ".gif", ".svg", ".webp"], d = [".mp4", ".webm", ".mov", ".avi"], w = [".mp3", ".wav", ".ogg", ".m4a"];
4
+ function m(t) {
5
+ return t = t.trim(), t.match(/^https?:\/\//) || t.match(/^data:/) || t.match(/^blob:/), t;
6
6
  }
7
- function p(e) {
8
- if (!e || e.length < 4 || e.includes("node_modules") || e.startsWith("./") && e.length < 10)
7
+ function h(t) {
8
+ if (!t || t.length < 4 || t.includes("node_modules") || t.startsWith("./") && t.length < 10)
9
9
  return !1;
10
- let t;
11
- if (e.match(/^https?:\/\//)) {
12
- const n = e.split("/");
13
- t = n[n.length - 1];
10
+ let e;
11
+ if (t.match(/^https?:\/\//)) {
12
+ const r = t.split("/");
13
+ e = r[r.length - 1];
14
14
  } else {
15
- const n = e.split("/");
16
- t = n[n.length - 1];
15
+ const r = t.split("/");
16
+ e = r[r.length - 1];
17
17
  }
18
- if (t = t.split("?")[0].split("#")[0], !t || t.startsWith("."))
18
+ if (e = e.split("?")[0].split("#")[0], !e || e.startsWith("."))
19
19
  return !1;
20
- const r = t.split(".");
21
- return !(r.length < 2 || r[0].length === 0 || r[r.length - 1].toLowerCase() === "json");
20
+ const s = e.split(".");
21
+ return !(s.length < 2 || s[0].length === 0 || s[s.length - 1].toLowerCase() === "json");
22
22
  }
23
- function A(e, t = /* @__PURE__ */ new Set()) {
24
- let r = "ASSET";
25
- u.some((s) => e.endsWith(s)) ? r = "IMAGE" : w.some((s) => e.endsWith(s)) ? r = "VIDEO" : d.some((s) => e.endsWith(s)) && (r = "AUDIO");
23
+ function C(t, e = /* @__PURE__ */ new Set()) {
24
+ let s = "ASSET";
25
+ u.some((n) => t.endsWith(n)) ? s = "IMAGE" : d.some((n) => t.endsWith(n)) ? s = "VIDEO" : w.some((n) => t.endsWith(n)) && (s = "AUDIO");
26
26
  let o;
27
- const n = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
27
+ const r = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
28
28
  do {
29
- let s = "";
30
- for (let c = 0; c < 4; c++)
31
- s += n[Math.floor(Math.random() * n.length)];
32
- o = `${r}_${s}`;
33
- } while (t.has(o));
29
+ let n = "";
30
+ for (let i = 0; i < 4; i++)
31
+ n += r[Math.floor(Math.random() * r.length)];
32
+ o = `${s}_${n}`;
33
+ } while (e.has(o));
34
34
  return o;
35
35
  }
36
- function E(e) {
37
- return e.replace(
36
+ function E(t) {
37
+ return t.replace(
38
38
  /(["'])(?:(?=(\\?))\2.)*?\1|\/\*[\s\S]*?\*\/|\/\/.*/g,
39
- (r) => r.startsWith('"') || r.startsWith("'") ? r : ""
39
+ (s) => s.startsWith('"') || s.startsWith("'") ? s : ""
40
40
  );
41
41
  }
42
- function x(e) {
43
- return e.replace(/\/\*[\s\S]*?\*\//g, "");
42
+ function S(t) {
43
+ return t.replace(/\/\*[\s\S]*?\*\//g, "");
44
44
  }
45
- function S(e, t, r = [".js", ".css", ".png", ".jpg", ".jpeg", ".gif", ".svg", ".woff", ".woff2", ".ttf", ".eot"]) {
45
+ function j(t, e, s = [".js", ".css", ".png", ".jpg", ".jpeg", ".gif", ".svg", ".woff", ".woff2", ".ttf", ".eot"]) {
46
46
  const o = /* @__PURE__ */ new Set();
47
- let n = e;
48
- t === "js" ? n = E(e) : t === "css" && (n = x(e));
49
- const s = r.map((c) => c.replace(/^\./, "")).join("|");
50
- if (t === "html")
47
+ let r = t;
48
+ e === "js" ? r = E(t) : e === "css" && (r = S(t));
49
+ const n = s.map((i) => i.replace(/^\./, "")).join("|");
50
+ if (e === "html")
51
51
  [
52
52
  // src/href attributes for img, script, link, video, audio tags
53
- new RegExp(`(?:src|href)=["']([^"']*\\.(?:${s}))["']`, "g"),
53
+ new RegExp(`(?:src|href)=["']([^"']*\\.(?:${n}))["']`, "g"),
54
54
  // url() in CSS
55
- new RegExp(`url\\(["']?([^"']*\\.(?:${s}))["']?\\)`, "g")
56
- ].forEach((i) => {
57
- let l;
58
- for (; (l = i.exec(n)) !== null; )
59
- l[1] && p(l[1]) && o.add(g(l[1]));
60
- }), (n.match(/<script[^>]*>[\s\S]*?<\/script>/g) || []).forEach((i) => {
61
- const l = i.replace(/<script[^>]*>/, "").replace(/<\/script>/, "");
62
- S(l, "js", r).forEach((m) => o.add(m));
55
+ new RegExp(`url\\(["']?([^"']*\\.(?:${n}))["']?\\)`, "g")
56
+ ].forEach((l) => {
57
+ let a;
58
+ for (; (a = l.exec(r)) !== null; )
59
+ a[1] && h(a[1]) && o.add(m(a[1]));
60
+ }), (r.match(/<script[^>]*>[\s\S]*?<\/script>/g) || []).forEach((l) => {
61
+ const a = l.replace(/<script[^>]*>/, "").replace(/<\/script>/, "");
62
+ j(a, "js", s).forEach((p) => o.add(p));
63
63
  });
64
- else if (t === "js")
65
- [
66
- // Dynamic import()
67
- new RegExp(`import\\(["']([^"']*\\.(?:${s}))["']\\)`, "g"),
68
- // fetch() requests
69
- new RegExp(`fetch\\(["']([^"']*\\.(?:${s}))["']\\)`, "g"),
70
- // new Image() creation
71
- new RegExp(`new\\s+Image\\(\\)\\.src\\s*=\\s*["']([^"']*\\.(?:${s}))["']`, "g"),
72
- // Direct src assignment
73
- new RegExp(`\\.src\\s*=\\s*["']([^"']*\\.(?:${s}))["']`, "g"),
74
- // Resource paths in variable assignments
75
- new RegExp(`=\\s*["']([^"']*\\.(?:${s}))["']`, "g"),
76
- // Resource paths in variable declarations
77
- new RegExp(`const\\s+\\w+\\s*=\\s*["']([^"']*\\.(?:${s}))["']`, "g"),
78
- // Variable assignments in minified code
79
- new RegExp(`\\w+\\s*=\\s*["']([^"']*\\.(?:${s}))["']`, "g"),
80
- // Resource paths in string literals (more precise matching)
81
- new RegExp(`["']([^"']*\\.(?:${s}))["']`, "g")
82
- ].forEach((a) => {
83
- let i;
84
- for (; (i = a.exec(n)) !== null; )
85
- i[1] && p(i[1]) && o.add(g(i[1]));
86
- });
87
- else if (t === "css") {
88
- const c = new RegExp(`url\\(["']?([^"']*\\.(?:${s}))["']?\\)`, "g");
89
- let a;
90
- for (; (a = c.exec(n)) !== null; )
91
- a[1] && p(a[1]) && o.add(g(a[1]));
64
+ else if (e === "js") {
65
+ const i = new RegExp(`["']([^"']*\\.(?:${n}))["']`, "g");
66
+ let c;
67
+ for (; (c = i.exec(r)) !== null; )
68
+ c[1] && h(c[1]) && o.add(m(c[1]));
69
+ } else if (e === "css") {
70
+ const i = new RegExp(`url\\(["']?([^"']*\\.(?:${n}))["']?\\)`, "g");
71
+ let c;
72
+ for (; (c = i.exec(r)) !== null; )
73
+ c[1] && h(c[1]) && o.add(m(c[1]));
92
74
  }
93
75
  return Array.from(o);
94
76
  }
95
- function I(e = process.cwd()) {
77
+ function N(t = process.cwd()) {
96
78
  try {
97
- let t = e, r = 0;
98
- for (; t !== f.parse(t).root && r < 20; ) {
99
- if (h(f.join(t, "package.json")))
100
- return t;
101
- t = f.dirname(t), r++;
79
+ let e = t, s = 0;
80
+ for (; e !== f.parse(e).root && s < 20; ) {
81
+ if (g(f.join(e, "package.json")))
82
+ return e;
83
+ e = f.dirname(e), s++;
102
84
  }
103
85
  return process.cwd();
104
- } catch (t) {
105
- return console.error("Error finding project root:", t), process.cwd();
86
+ } catch (e) {
87
+ return console.error("Error finding project root:", e), process.cwd();
106
88
  }
107
89
  }
108
90
  export {
109
- S as extractAssetsFromContent,
110
- I as findProjectRoot,
111
- A as generateConstantName,
112
- p as isValidAsset,
113
- g as processAssetURL
91
+ j as extractAssetsFromContent,
92
+ N as findProjectRoot,
93
+ C as generateConstantName,
94
+ h as isValidAsset,
95
+ m as processAssetURL
114
96
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aippy/vite-plugins",
3
- "version": "0.2.1",
3
+ "version": "0.2.4",
4
4
  "description": "Vite plugins for Aippy projects - Asset management and component tagging",
5
5
  "private": false,
6
6
  "type": "module",