@absolutejs/absolute 0.5.0 → 0.5.2

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/index.js CHANGED
@@ -1,4 +1,227 @@
1
1
  // @bun
2
- var it=60,C=1000,O=60000,et=60,_t=24,ct=86400000,x=2,b=3000;import{rm as T,mkdir as $,writeFile as J}from"fs/promises";import{join as _,basename as K}from"path";import{cwd as Q,exit as V}from"process";var{$:d,build:X,Glob:B}=globalThis.Bun;import{readFile as q,writeFile as z}from"fs/promises";var{Glob:G}=globalThis.Bun;var y=async(n,s)=>{let o=new G("*.html"),t=[];for await(let c of o.scan({cwd:s,absolute:!0}))t.push(c);for(let c of t){let N=await q(c,"utf8");for(let[I,i]of Object.entries(n)){let r=I.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),E=new RegExp(`(<script[^>]+src=["'])(/?(?:.*\\/)?${r})(?:\\.[^."'/]+)?(\\.js)(["'][^>]*>)`,"g");N=N.replace(E,(a,f,p,A,L)=>{return`${f}${i}${L}`})}await z(c,N,"utf8")}};var xt=async({buildDirectory:n="build",assetsDirectory:s,reactDirectory:o,html:t,htmxDirectory:c,tailwind:N})=>{let I=performance.now(),i=Q(),r=_(i,n),E=s&&_(i,s),a=o&&_(i,o,"indexes"),f=o&&_(i,o,"pages"),p=t?.directory?_(i,t.directory):void 0,A=c&&_(i,c);await T(r,{force:!0,recursive:!0}),await $(r),f&&a&&await Z(f,a);let U=[...(a&&await k(a,"*.tsx"))??[]];if(U.length===0)return console.warn("No entry points found, skipping build"),null;let{logs:h,outputs:v}=await X({entrypoints:U,format:"esm",naming:"[dir]/[name].[hash].[ext]",outdir:r,target:"bun"}).catch((e)=>{console.error("Build failed:",e),V(1)});if(h.forEach((e)=>{if(e.level==="error")console.error(e);else if(e.level==="warning")console.warn(e);else if(e.level==="info"||e.level==="debug")console.info(e)}),E&&await d`cp -R ${E} ${r}`,p)await $(_(r,"html")),await d`cp -R ${p} ${_(r)}`;if(A)await $(_(r,"htmx")),await d`cp -R ${A} ${_(r)}`;if(N)await d`tailwindcss -i ${N.input} -o ${_(r,N.output)}`;let R=v.reduce((e,g)=>{let u=g.path;if(u.startsWith(r))u=u.slice(r.length);u=u.replace(/^\/+/,"");let l=u.split("/").pop();if(!l)return e;let M=`.${g.hash}.`;if(!l.includes(M))throw new Error(`Expected hash delimiter ${M} in ${l}`);let[W]=l.split(M);return e[W]="/"+u,e},{});p&&await y(R,p);let m=performance.now()-I,S;if(m<C)S=`${m.toFixed(x)}ms`;else if(m<O)S=`${(m/C).toFixed(x)}s`;else S=`${(m/O).toFixed(x)}m`;return console.log(`Build completed in ${S}`),R},Z=async(n,s)=>{await T(s,{force:!0,recursive:!0}),await $(s);let o=new B("*.*"),t=[];for await(let N of o.scan({cwd:n}))t.push(N);let c=t.map(async(N)=>{let I=K(N),[i]=I.split("."),r=["import { hydrateRoot } from 'react-dom/client';",`import { ${i} } from '../pages/${i}';
3
- `,`hydrateRoot(document, <${i} />);`].join(`
4
- `);return J(_(s,`${i}Index.tsx`),r)});await Promise.all(c)},k=async(n,s)=>{let o=[],t=new B(s);for await(let c of t.scan({absolute:!0,cwd:n}))o.push(c);return o};import{createElement as F}from"react";import{renderToReadableStream as tt}from"react-dom/server.browser";var Mt=async(n,s)=>{let o=F(n),t=await tt(o,{bootstrapModules:[s]});return new Response(t,{headers:{"Content-Type":"text/html"}})},Ct=(n)=>Bun.file(n);import{argv as nt}from"process";var{env:j}=globalThis.Bun;import ot from"os";var H=()=>{let n=ot.networkInterfaces(),o=Object.values(n).flat().filter((t)=>t!==void 0).find((t)=>t.family==="IPv4"&&!t.internal);if(o)return o.address;return console.warn("No IP address found, falling back to localhost"),"localhost"};var D=j.HOST??"localhost",w=j.PORT??b,P,rt=nt,Y=rt.includes("--host");if(Y)P=H(),D="0.0.0.0";var Ht=(n)=>n.listen({hostname:D,port:w},()=>{if(Y)console.log(`Server started on http://localhost:${w}`),console.log(`Server started on network: http://${P}:${w}`);else console.log(`Server started on http://${D}:${w}`)});export{y as updateScriptTags,Ht as networkingPlugin,Mt as handleReactPageRequest,Ct as handleHTMLPageRequest,H as getLocalIPAddress,xt as build,x as TIME_PRECISION,it as SECONDS_IN_A_MINUTE,et as MINUTES_IN_AN_HOUR,C as MILLISECONDS_IN_A_SECOND,O as MILLISECONDS_IN_A_MINUTE,ct as MILLISECONDS_IN_A_DAY,_t as HOURS_IN_A_DAY,b as DEFAULT_PORT};
2
+ // src/constants.ts
3
+ var SECONDS_IN_A_MINUTE = 60;
4
+ var MILLISECONDS_IN_A_SECOND = 1000;
5
+ var MILLISECONDS_IN_A_MINUTE = MILLISECONDS_IN_A_SECOND * SECONDS_IN_A_MINUTE;
6
+ var MINUTES_IN_AN_HOUR = 60;
7
+ var HOURS_IN_A_DAY = 24;
8
+ var MILLISECONDS_IN_A_DAY = MILLISECONDS_IN_A_SECOND * SECONDS_IN_A_MINUTE * MINUTES_IN_AN_HOUR * HOURS_IN_A_DAY;
9
+ var TIME_PRECISION = 2;
10
+ var DEFAULT_PORT = 3000;
11
+ // src/core/build.ts
12
+ import { rm, mkdir, writeFile as writeFile2 } from "fs/promises";
13
+ import { join, basename } from "path";
14
+ import { cwd, exit } from "process";
15
+ var {$, build: bunBuild, Glob: Glob2 } = globalThis.Bun;
16
+
17
+ // src/utils/updateScriptTags.ts
18
+ import { readFile, writeFile } from "fs/promises";
19
+ var {Glob } = globalThis.Bun;
20
+ var updateScriptTags = async (manifest, htmlDir) => {
21
+ const htmlGlob = new Glob("*.html");
22
+ const htmlFiles = [];
23
+ for await (const file of htmlGlob.scan({
24
+ cwd: htmlDir,
25
+ absolute: true
26
+ })) {
27
+ htmlFiles.push(file);
28
+ }
29
+ for (const filePath of htmlFiles) {
30
+ let content = await readFile(filePath, "utf8");
31
+ for (const [scriptName, newPath] of Object.entries(manifest)) {
32
+ const escapedScriptName = scriptName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
33
+ const regex = new RegExp(`(<script[^>]+src=["'])(/?(?:.*\\/)?${escapedScriptName})(?:\\.[^."'/]+)?(\\.js)(["'][^>]*>)`, "g");
34
+ content = content.replace(regex, (_, prefix, _oldBase, _ext, suffix) => {
35
+ return `${prefix}${newPath}${suffix}`;
36
+ });
37
+ }
38
+ await writeFile(filePath, content, "utf8");
39
+ }
40
+ };
41
+
42
+ // src/core/build.ts
43
+ var build = async ({
44
+ buildDirectory = "build",
45
+ assetsDirectory,
46
+ reactDirectory,
47
+ html,
48
+ htmxDirectory,
49
+ tailwind
50
+ }) => {
51
+ const start = performance.now();
52
+ const projectRoot = cwd();
53
+ const buildDirAbsolute = join(projectRoot, buildDirectory);
54
+ const assetsDirAbsolute = assetsDirectory && join(projectRoot, assetsDirectory);
55
+ const reactIndexDirAbsolute = reactDirectory && join(projectRoot, reactDirectory, "indexes");
56
+ const reactPagesDirAbsolute = reactDirectory && join(projectRoot, reactDirectory, "pages");
57
+ const htmlDirAbsolute = html?.directory ? join(projectRoot, html.directory) : undefined;
58
+ const htmxDirAbsolute = htmxDirectory && join(projectRoot, htmxDirectory);
59
+ await rm(buildDirAbsolute, { force: true, recursive: true });
60
+ await mkdir(buildDirAbsolute);
61
+ reactPagesDirAbsolute && reactIndexDirAbsolute && await generateReactIndexFiles(reactPagesDirAbsolute, reactIndexDirAbsolute);
62
+ const reactEntryPaths = reactIndexDirAbsolute && await scanEntryPoints(reactIndexDirAbsolute, "*.tsx");
63
+ const entryPaths = [...reactEntryPaths ?? []];
64
+ if (entryPaths.length === 0) {
65
+ console.warn("No entry points found, skipping build");
66
+ return null;
67
+ }
68
+ const { logs, outputs } = await bunBuild({
69
+ entrypoints: entryPaths,
70
+ format: "esm",
71
+ naming: `[dir]/[name].[hash].[ext]`,
72
+ outdir: buildDirAbsolute,
73
+ target: "bun"
74
+ }).catch((error) => {
75
+ console.error("Build failed:", error);
76
+ exit(1);
77
+ });
78
+ logs.forEach((log) => {
79
+ if (log.level === "error")
80
+ console.error(log);
81
+ else if (log.level === "warning")
82
+ console.warn(log);
83
+ else if (log.level === "info" || log.level === "debug")
84
+ console.info(log);
85
+ });
86
+ assetsDirAbsolute && await $`cp -R ${assetsDirAbsolute} ${buildDirAbsolute}`;
87
+ if (htmlDirAbsolute) {
88
+ await mkdir(join(buildDirAbsolute, "html"));
89
+ await $`cp -R ${htmlDirAbsolute} ${join(buildDirAbsolute)}`;
90
+ }
91
+ if (htmxDirAbsolute) {
92
+ await mkdir(join(buildDirAbsolute, "htmx"));
93
+ await $`cp -R ${htmxDirAbsolute} ${join(buildDirAbsolute)}`;
94
+ }
95
+ if (tailwind) {
96
+ await $`tailwindcss -i ${tailwind.input} -o ${join(buildDirAbsolute, tailwind.output)}`;
97
+ }
98
+ const manifest = outputs.reduce((acc, artifact) => {
99
+ let relativePath = artifact.path;
100
+ if (relativePath.startsWith(buildDirAbsolute)) {
101
+ relativePath = relativePath.slice(buildDirAbsolute.length);
102
+ }
103
+ relativePath = relativePath.replace(/^\/+/, "");
104
+ const baseName = relativePath.split("/").pop();
105
+ if (!baseName)
106
+ return acc;
107
+ const hashDelimiter = `.${artifact.hash}.`;
108
+ if (!baseName.includes(hashDelimiter)) {
109
+ throw new Error(`Expected hash delimiter ${hashDelimiter} in ${baseName}`);
110
+ }
111
+ const [fileName] = baseName.split(hashDelimiter);
112
+ acc[fileName] = "/" + relativePath;
113
+ return acc;
114
+ }, {});
115
+ htmlDirAbsolute && await updateScriptTags(manifest, htmlDirAbsolute);
116
+ const end = performance.now();
117
+ const durationMs = end - start;
118
+ let duration;
119
+ if (durationMs < MILLISECONDS_IN_A_SECOND) {
120
+ duration = `${durationMs.toFixed(TIME_PRECISION)}ms`;
121
+ } else if (durationMs < MILLISECONDS_IN_A_MINUTE) {
122
+ duration = `${(durationMs / MILLISECONDS_IN_A_SECOND).toFixed(TIME_PRECISION)}s`;
123
+ } else {
124
+ duration = `${(durationMs / MILLISECONDS_IN_A_MINUTE).toFixed(TIME_PRECISION)}m`;
125
+ }
126
+ console.log(`Build completed in ${duration}`);
127
+ return manifest;
128
+ };
129
+ var generateReactIndexFiles = async (reactPagesDirAbsolute, reactIndexDirAbsolute) => {
130
+ await rm(reactIndexDirAbsolute, { force: true, recursive: true });
131
+ await mkdir(reactIndexDirAbsolute);
132
+ const pagesGlob = new Glob2("*.*");
133
+ const files = [];
134
+ for await (const file of pagesGlob.scan({ cwd: reactPagesDirAbsolute })) {
135
+ files.push(file);
136
+ }
137
+ const promises = files.map(async (file) => {
138
+ const fileName = basename(file);
139
+ const [componentName] = fileName.split(".");
140
+ const content = [
141
+ `import { hydrateRoot } from 'react-dom/client';`,
142
+ `import { ${componentName} } from '../pages/${componentName}';
143
+ `,
144
+ `hydrateRoot(document, <${componentName} />);`
145
+ ].join(`
146
+ `);
147
+ return writeFile2(join(reactIndexDirAbsolute, `${componentName}Index.tsx`), content);
148
+ });
149
+ await Promise.all(promises);
150
+ };
151
+ var scanEntryPoints = async (dir, pattern) => {
152
+ const entryPaths = [];
153
+ const glob = new Glob2(pattern);
154
+ for await (const file of glob.scan({ absolute: true, cwd: dir })) {
155
+ entryPaths.push(file);
156
+ }
157
+ return entryPaths;
158
+ };
159
+ // src/core/pageHandlers.ts
160
+ import { createElement } from "react";
161
+ import { renderToReadableStream } from "react-dom/server.browser";
162
+ var handleReactPageRequest = async (pageComponent, index) => {
163
+ const page = createElement(pageComponent);
164
+ const stream = await renderToReadableStream(page, {
165
+ bootstrapModules: [index]
166
+ });
167
+ return new Response(stream, {
168
+ headers: { "Content-Type": "text/html" }
169
+ });
170
+ };
171
+ var handleHTMLPageRequest = (html) => Bun.file(html);
172
+ // src/plugins/networkingPlugin.ts
173
+ import { argv } from "process";
174
+ var {env } = globalThis.Bun;
175
+
176
+ // src/utils/networking.ts
177
+ import os from "os";
178
+ var getLocalIPAddress = () => {
179
+ const interfaces = os.networkInterfaces();
180
+ const addresses = Object.values(interfaces).flat().filter((iface) => iface !== undefined);
181
+ const ipAddress = addresses.find((iface) => iface.family === "IPv4" && !iface.internal);
182
+ if (ipAddress)
183
+ return ipAddress.address;
184
+ console.warn("No IP address found, falling back to localhost");
185
+ return "localhost";
186
+ };
187
+
188
+ // src/plugins/networkingPlugin.ts
189
+ var host = env.HOST ?? "localhost";
190
+ var port = env.PORT ?? DEFAULT_PORT;
191
+ var localIP;
192
+ var args = argv;
193
+ var hostFlag = args.includes("--host");
194
+ if (hostFlag) {
195
+ localIP = getLocalIPAddress();
196
+ host = "0.0.0.0";
197
+ }
198
+ var networkingPlugin = (app) => app.listen({
199
+ hostname: host,
200
+ port
201
+ }, () => {
202
+ if (hostFlag) {
203
+ console.log(`Server started on http://localhost:${port}`);
204
+ console.log(`Server started on network: http://${localIP}:${port}`);
205
+ } else {
206
+ console.log(`Server started on http://${host}:${port}`);
207
+ }
208
+ });
209
+ export {
210
+ updateScriptTags,
211
+ networkingPlugin,
212
+ handleReactPageRequest,
213
+ handleHTMLPageRequest,
214
+ getLocalIPAddress,
215
+ build,
216
+ TIME_PRECISION,
217
+ SECONDS_IN_A_MINUTE,
218
+ MINUTES_IN_AN_HOUR,
219
+ MILLISECONDS_IN_A_SECOND,
220
+ MILLISECONDS_IN_A_MINUTE,
221
+ MILLISECONDS_IN_A_DAY,
222
+ HOURS_IN_A_DAY,
223
+ DEFAULT_PORT
224
+ };
225
+
226
+ //# debugId=99CA190BCF91F46D64756E2164756E21
227
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,15 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/constants.ts", "../src/core/build.ts", "../src/utils/updateScriptTags.ts", "../src/core/pageHandlers.ts", "../src/plugins/networkingPlugin.ts", "../src/utils/networking.ts"],
4
+ "sourcesContent": [
5
+ "export const SECONDS_IN_A_MINUTE = 60;\nexport const MILLISECONDS_IN_A_SECOND = 1000;\nexport const MILLISECONDS_IN_A_MINUTE =\n\tMILLISECONDS_IN_A_SECOND * SECONDS_IN_A_MINUTE;\nexport const MINUTES_IN_AN_HOUR = 60;\nexport const HOURS_IN_A_DAY = 24;\nexport const MILLISECONDS_IN_A_DAY =\n\tMILLISECONDS_IN_A_SECOND *\n\tSECONDS_IN_A_MINUTE *\n\tMINUTES_IN_AN_HOUR *\n\tHOURS_IN_A_DAY;\nexport const TIME_PRECISION = 2;\nexport const DEFAULT_PORT = 3000;\n",
6
+ "import { rm, mkdir, writeFile } from \"node:fs/promises\";\nimport { join, basename } from \"node:path\";\nimport { cwd, exit } from \"node:process\";\nimport { $, build as bunBuild, Glob } from \"bun\";\nimport {\n\tMILLISECONDS_IN_A_MINUTE,\n\tMILLISECONDS_IN_A_SECOND,\n\tTIME_PRECISION\n} from \"../constants\";\nimport { updateScriptTags } from \"../utils/updateScriptTags\";\nimport { BuildConfig } from \"../types\";\n\nexport const build = async ({\n\tbuildDirectory = \"build\",\n\tassetsDirectory,\n\treactDirectory,\n\thtml,\n\thtmxDirectory,\n\ttailwind\n}: BuildConfig) => {\n\tconst start = performance.now();\n\n\tconst projectRoot = cwd();\n\tconst buildDirAbsolute = join(projectRoot, buildDirectory);\n\tconst assetsDirAbsolute =\n\t\tassetsDirectory && join(projectRoot, assetsDirectory);\n\tconst reactIndexDirAbsolute =\n\t\treactDirectory && join(projectRoot, reactDirectory, \"indexes\");\n\tconst reactPagesDirAbsolute =\n\t\treactDirectory && join(projectRoot, reactDirectory, \"pages\");\n\tconst htmlDirAbsolute = html?.directory\n\t\t? join(projectRoot, html.directory)\n\t\t: undefined;\n\n\tconst htmxDirAbsolute = htmxDirectory && join(projectRoot, htmxDirectory);\n\n\tawait rm(buildDirAbsolute, { force: true, recursive: true });\n\tawait mkdir(buildDirAbsolute);\n\n\treactPagesDirAbsolute &&\n\t\treactIndexDirAbsolute &&\n\t\t(await generateReactIndexFiles(\n\t\t\treactPagesDirAbsolute,\n\t\t\treactIndexDirAbsolute\n\t\t));\n\n\tconst reactEntryPaths =\n\t\treactIndexDirAbsolute &&\n\t\t(await scanEntryPoints(reactIndexDirAbsolute, \"*.tsx\"));\n\n\tconst entryPaths = [...(reactEntryPaths ?? [])];\n\n\tif (entryPaths.length === 0) {\n\t\tconsole.warn(\"No entry points found, skipping build\");\n\t\treturn null;\n\t}\n\n\tconst { logs, outputs } = await bunBuild({\n\t\tentrypoints: entryPaths,\n\t\tformat: \"esm\",\n\t\tnaming: `[dir]/[name].[hash].[ext]`,\n\t\toutdir: buildDirAbsolute,\n\t\ttarget: \"bun\"\n\t}).catch((error) => {\n\t\tconsole.error(\"Build failed:\", error);\n\t\texit(1);\n\t});\n\n\tlogs.forEach((log) => {\n\t\tif (log.level === \"error\") console.error(log);\n\t\telse if (log.level === \"warning\") console.warn(log);\n\t\telse if (log.level === \"info\" || log.level === \"debug\")\n\t\t\tconsole.info(log);\n\t});\n\n\tassetsDirAbsolute &&\n\t\t(await $`cp -R ${assetsDirAbsolute} ${buildDirAbsolute}`);\n\n\tif (htmlDirAbsolute) {\n\t\tawait mkdir(join(buildDirAbsolute, \"html\"));\n\t\tawait $`cp -R ${htmlDirAbsolute} ${join(buildDirAbsolute)}`;\n\t}\n\n\tif (htmxDirAbsolute) {\n\t\tawait mkdir(join(buildDirAbsolute, \"htmx\"));\n\t\tawait $`cp -R ${htmxDirAbsolute} ${join(buildDirAbsolute)}`;\n\t}\n\n\tif (tailwind) {\n\t\tawait $`tailwindcss -i ${tailwind.input} -o ${join(buildDirAbsolute, tailwind.output)}`;\n\t}\n\n\tconst manifest = outputs.reduce<Record<string, string>>((acc, artifact) => {\n\t\tlet relativePath = artifact.path;\n\n\t\tif (relativePath.startsWith(buildDirAbsolute)) {\n\t\t\trelativePath = relativePath.slice(buildDirAbsolute.length);\n\t\t}\n\n\t\trelativePath = relativePath.replace(/^\\/+/, \"\");\n\n\t\tconst baseName = relativePath.split(\"/\").pop();\n\t\tif (!baseName) return acc;\n\n\t\tconst hashDelimiter = `.${artifact.hash}.`;\n\t\tif (!baseName.includes(hashDelimiter)) {\n\t\t\tthrow new Error(\n\t\t\t\t`Expected hash delimiter ${hashDelimiter} in ${baseName}`\n\t\t\t);\n\t\t}\n\n\t\tconst [fileName] = baseName.split(hashDelimiter);\n\t\tacc[fileName] = \"/\" + relativePath;\n\t\treturn acc;\n\t}, {});\n\n\thtmlDirAbsolute && (await updateScriptTags(manifest, htmlDirAbsolute));\n\n\tconst end = performance.now();\n\tconst durationMs = end - start;\n\tlet duration;\n\tif (durationMs < MILLISECONDS_IN_A_SECOND) {\n\t\tduration = `${durationMs.toFixed(TIME_PRECISION)}ms`;\n\t} else if (durationMs < MILLISECONDS_IN_A_MINUTE) {\n\t\tduration = `${(durationMs / MILLISECONDS_IN_A_SECOND).toFixed(TIME_PRECISION)}s`;\n\t} else {\n\t\tduration = `${(durationMs / MILLISECONDS_IN_A_MINUTE).toFixed(TIME_PRECISION)}m`;\n\t}\n\tconsole.log(`Build completed in ${duration}`);\n\n\treturn manifest;\n};\n\nconst generateReactIndexFiles = async (\n\treactPagesDirAbsolute: string,\n\treactIndexDirAbsolute: string\n) => {\n\tawait rm(reactIndexDirAbsolute, { force: true, recursive: true });\n\tawait mkdir(reactIndexDirAbsolute);\n\n\tconst pagesGlob = new Glob(\"*.*\");\n\tconst files: string[] = [];\n\tfor await (const file of pagesGlob.scan({ cwd: reactPagesDirAbsolute })) {\n\t\tfiles.push(file);\n\t}\n\tconst promises = files.map(async (file) => {\n\t\tconst fileName = basename(file);\n\t\tconst [componentName] = fileName.split(\".\");\n\t\tconst content = [\n\t\t\t`import { hydrateRoot } from 'react-dom/client';`,\n\t\t\t`import { ${componentName} } from '../pages/${componentName}';\\n`,\n\t\t\t`hydrateRoot(document, <${componentName} />);`\n\t\t].join(\"\\n\");\n\n\t\treturn writeFile(\n\t\t\tjoin(reactIndexDirAbsolute, `${componentName}Index.tsx`),\n\t\t\tcontent\n\t\t);\n\t});\n\tawait Promise.all(promises);\n};\n\nconst scanEntryPoints = async (dir: string, pattern: string) => {\n\tconst entryPaths: string[] = [];\n\tconst glob = new Glob(pattern);\n\tfor await (const file of glob.scan({ absolute: true, cwd: dir })) {\n\t\tentryPaths.push(file);\n\t}\n\treturn entryPaths;\n};\n",
7
+ "// TODO : this script seems to only work after building twice maybe due to the async nature of it\n\nimport { readFile, writeFile } from \"node:fs/promises\";\nimport { Glob } from \"bun\";\n\n/**\n * Updates <script> tags in all HTML files within htmlDir.\n * For each script tag whose src file base (with or without a hash) is a key in the manifest,\n * the src attribute is replaced with the new hashed file path.\n *\n * @param manifest - An object mapping script base names to the new file path.\n * @param htmlDir - The directory that contains the HTML files.\n */\nexport const updateScriptTags = async (\n\tmanifest: Record<string, string>,\n\thtmlDir: string\n) => {\n\t// Use Glob to find all HTML files in the specified directory\n\tconst htmlGlob = new Glob(\"*.html\");\n\tconst htmlFiles: string[] = [];\n\tfor await (const file of htmlGlob.scan({\n\t\tcwd: htmlDir,\n\t\tabsolute: true\n\t})) {\n\t\thtmlFiles.push(file);\n\t}\n\n\t// Process each HTML file\n\tfor (const filePath of htmlFiles) {\n\t\tlet content = await readFile(filePath, \"utf8\");\n\n\t\t// For each script in the manifest, update matching <script> tags\n\t\tfor (const [scriptName, newPath] of Object.entries(manifest)) {\n\t\t\t// Escape special regex characters in the scriptName\n\t\t\tconst escapedScriptName = scriptName.replace(\n\t\t\t\t/[.*+?^${}()|[\\]\\\\]/g,\n\t\t\t\t\"\\\\$&\"\n\t\t\t);\n\t\t\t// The regex explanation:\n\t\t\t// (1) (<script[^>]+src=[\"']) — capture the opening of the script tag up to the src attribute value\n\t\t\t// (2) (\\/?(?:.*\\\\/)?${escapedScriptName}) — capture any preceding path and the base script name\n\t\t\t// (3) (?:\\.[^.\"'/]+)? — optionally capture a dot and hash (if already hashed)\n\t\t\t// (4) (\\.js) — then capture the js extension\n\t\t\t// (5) ([\"'][^>]*>) — capture the closing quote and remainder of the script tag\n\t\t\tconst regex = new RegExp(\n\t\t\t\t`(<script[^>]+src=[\"'])(\\/?(?:.*\\\\/)?${escapedScriptName})(?:\\\\.[^.\"'/]+)?(\\\\.js)([\"'][^>]*>)`,\n\t\t\t\t\"g\"\n\t\t\t);\n\t\t\t// Replace the matched src attribute with the new value from the manifest\n\t\t\tcontent = content.replace(\n\t\t\t\tregex,\n\t\t\t\t(_, prefix, _oldBase, _ext, suffix) => {\n\t\t\t\t\treturn `${prefix}${newPath}${suffix}`;\n\t\t\t\t}\n\t\t\t);\n\t\t}\n\n\t\tawait writeFile(filePath, content, \"utf8\");\n\t}\n};\n",
8
+ "import { ComponentType, createElement } from \"react\";\n//@ts-expect-error - TODO: Remove this when we upgrade to React 19\nimport { renderToReadableStream } from \"react-dom/server.browser\";\n\nexport const handleReactPageRequest = async (\n\tpageComponent: ComponentType,\n\tindex: string\n) => {\n\tconst page = createElement(pageComponent);\n\tconst stream = await renderToReadableStream(page, {\n\t\tbootstrapModules: [index]\n\t});\n\n\treturn new Response(stream, {\n\t\theaders: { \"Content-Type\": \"text/html\" }\n\t});\n};\n\nexport const handleHTMLPageRequest = (html: string) => Bun.file(html);\n",
9
+ "import { argv } from \"node:process\";\nimport { env } from \"bun\";\nimport { Elysia } from \"elysia\";\nimport { getLocalIPAddress } from \"../utils/networking\";\nimport { DEFAULT_PORT } from \"../constants\";\n\nlet host = env.HOST ?? \"localhost\";\nconst port = env.PORT ?? DEFAULT_PORT;\nlet localIP: string | undefined;\n\nconst args = argv;\nconst hostFlag = args.includes(\"--host\");\n\nif (hostFlag) {\n\tlocalIP = getLocalIPAddress();\n\thost = \"0.0.0.0\";\n}\n\nexport const networkingPlugin = (app: Elysia) =>\n\tapp.listen(\n\t\t{\n\t\t\thostname: host,\n\t\t\tport: port\n\t\t},\n\t\t() => {\n\t\t\t//TODO: I dont think this works properly\n\t\t\tif (hostFlag) {\n\t\t\t\tconsole.log(`Server started on http://localhost:${port}`);\n\t\t\t\tconsole.log(\n\t\t\t\t\t`Server started on network: http://${localIP}:${port}`\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tconsole.log(`Server started on http://${host}:${port}`);\n\t\t\t}\n\t\t}\n\t);\n",
10
+ "import os from \"os\";\n\nexport const getLocalIPAddress = () => {\n\tconst interfaces = os.networkInterfaces();\n\tconst addresses = Object.values(interfaces)\n\t\t.flat()\n\t\t.filter(\n\t\t\t(iface): iface is os.NetworkInterfaceInfo => iface !== undefined\n\t\t);\n\tconst ipAddress = addresses.find(\n\t\t(iface) => iface.family === \"IPv4\" && !iface.internal\n\t);\n\n\tif (ipAddress) return ipAddress.address; // Return the first non-internal IPv4 address\n\n\tconsole.warn(\"No IP address found, falling back to localhost\");\n\n\treturn \"localhost\"; // Fallback to localhost if no IP found\n};\n"
11
+ ],
12
+ "mappings": "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",
13
+ "debugId": "99CA190BCF91F46D64756E2164756E21",
14
+ "names": []
15
+ }
@@ -1,2 +1,2 @@
1
- import { BuildConfig } from "./types";
1
+ import { BuildConfig } from "../types";
2
2
  export declare const build: ({ buildDirectory, assetsDirectory, reactDirectory, html, htmxDirectory, tailwind }: BuildConfig) => Promise<Record<string, string> | null>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@absolutejs/absolute",
3
- "version": "0.5.0",
3
+ "version": "0.5.2",
4
4
  "description": "A fullstack meta-framework for building web applications with TypeScript",
5
5
  "repository": {
6
6
  "type": "git",
@@ -11,7 +11,7 @@
11
11
  "license": "CC BY-NC 4.0",
12
12
  "author": "Alex Kahn",
13
13
  "scripts": {
14
- "build": "rm -rf dist && bun build src/index.ts --outdir dist --minify --splitting --target=bun --external react --external react-dom --external elysia && tsc --emitDeclarationOnly --project tsconfig.json",
14
+ "build": "rm -rf dist && bun build src/index.ts --outdir dist --sourcemap --target=bun --external react --external react-dom --external elysia && tsc --emitDeclarationOnly --project tsconfig.json",
15
15
  "test": "echo \"Error: no test specified\" && exit 1",
16
16
  "format": "prettier --write \"./**/*.{js,jsx,ts,tsx,css,json}\"",
17
17
  "dev": "bun run --watch example/server.ts",
package/src/core/build.ts CHANGED
@@ -8,7 +8,7 @@ import {
8
8
  TIME_PRECISION
9
9
  } from "../constants";
10
10
  import { updateScriptTags } from "../utils/updateScriptTags";
11
- import { BuildConfig } from "./types";
11
+ import { BuildConfig } from "../types";
12
12
 
13
13
  export const build = async ({
14
14
  buildDirectory = "build",
File without changes
File without changes