@absolutejs/absolute 0.5.2 → 0.5.3
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/package.json +1 -1
- package/.prettierignore +0 -4
- package/.prettierrc.json +0 -8
- package/src/constants.ts +0 -13
- package/src/core/build.ts +0 -170
- package/src/core/index.ts +0 -2
- package/src/core/pageHandlers.ts +0 -19
- package/src/index.ts +0 -4
- package/src/plugins/index.ts +0 -2
- package/src/plugins/networkingPlugin.ts +0 -36
- package/src/plugins/pageRouterPlugin.ts +0 -3
- package/src/types.ts +0 -20
- package/src/utils/index.ts +0 -2
- package/src/utils/networking.ts +0 -19
- package/src/utils/updateScriptTags.ts +0 -60
- package/tsconfig.json +0 -17
package/package.json
CHANGED
package/.prettierignore
DELETED
package/.prettierrc.json
DELETED
package/src/constants.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
export const SECONDS_IN_A_MINUTE = 60;
|
|
2
|
-
export const MILLISECONDS_IN_A_SECOND = 1000;
|
|
3
|
-
export const MILLISECONDS_IN_A_MINUTE =
|
|
4
|
-
MILLISECONDS_IN_A_SECOND * SECONDS_IN_A_MINUTE;
|
|
5
|
-
export const MINUTES_IN_AN_HOUR = 60;
|
|
6
|
-
export const HOURS_IN_A_DAY = 24;
|
|
7
|
-
export const MILLISECONDS_IN_A_DAY =
|
|
8
|
-
MILLISECONDS_IN_A_SECOND *
|
|
9
|
-
SECONDS_IN_A_MINUTE *
|
|
10
|
-
MINUTES_IN_AN_HOUR *
|
|
11
|
-
HOURS_IN_A_DAY;
|
|
12
|
-
export const TIME_PRECISION = 2;
|
|
13
|
-
export const DEFAULT_PORT = 3000;
|
package/src/core/build.ts
DELETED
|
@@ -1,170 +0,0 @@
|
|
|
1
|
-
import { rm, mkdir, writeFile } from "node:fs/promises";
|
|
2
|
-
import { join, basename } from "node:path";
|
|
3
|
-
import { cwd, exit } from "node:process";
|
|
4
|
-
import { $, build as bunBuild, Glob } from "bun";
|
|
5
|
-
import {
|
|
6
|
-
MILLISECONDS_IN_A_MINUTE,
|
|
7
|
-
MILLISECONDS_IN_A_SECOND,
|
|
8
|
-
TIME_PRECISION
|
|
9
|
-
} from "../constants";
|
|
10
|
-
import { updateScriptTags } from "../utils/updateScriptTags";
|
|
11
|
-
import { BuildConfig } from "../types";
|
|
12
|
-
|
|
13
|
-
export const build = async ({
|
|
14
|
-
buildDirectory = "build",
|
|
15
|
-
assetsDirectory,
|
|
16
|
-
reactDirectory,
|
|
17
|
-
html,
|
|
18
|
-
htmxDirectory,
|
|
19
|
-
tailwind
|
|
20
|
-
}: BuildConfig) => {
|
|
21
|
-
const start = performance.now();
|
|
22
|
-
|
|
23
|
-
const projectRoot = cwd();
|
|
24
|
-
const buildDirAbsolute = join(projectRoot, buildDirectory);
|
|
25
|
-
const assetsDirAbsolute =
|
|
26
|
-
assetsDirectory && join(projectRoot, assetsDirectory);
|
|
27
|
-
const reactIndexDirAbsolute =
|
|
28
|
-
reactDirectory && join(projectRoot, reactDirectory, "indexes");
|
|
29
|
-
const reactPagesDirAbsolute =
|
|
30
|
-
reactDirectory && join(projectRoot, reactDirectory, "pages");
|
|
31
|
-
const htmlDirAbsolute = html?.directory
|
|
32
|
-
? join(projectRoot, html.directory)
|
|
33
|
-
: undefined;
|
|
34
|
-
|
|
35
|
-
const htmxDirAbsolute = htmxDirectory && join(projectRoot, htmxDirectory);
|
|
36
|
-
|
|
37
|
-
await rm(buildDirAbsolute, { force: true, recursive: true });
|
|
38
|
-
await mkdir(buildDirAbsolute);
|
|
39
|
-
|
|
40
|
-
reactPagesDirAbsolute &&
|
|
41
|
-
reactIndexDirAbsolute &&
|
|
42
|
-
(await generateReactIndexFiles(
|
|
43
|
-
reactPagesDirAbsolute,
|
|
44
|
-
reactIndexDirAbsolute
|
|
45
|
-
));
|
|
46
|
-
|
|
47
|
-
const reactEntryPaths =
|
|
48
|
-
reactIndexDirAbsolute &&
|
|
49
|
-
(await scanEntryPoints(reactIndexDirAbsolute, "*.tsx"));
|
|
50
|
-
|
|
51
|
-
const entryPaths = [...(reactEntryPaths ?? [])];
|
|
52
|
-
|
|
53
|
-
if (entryPaths.length === 0) {
|
|
54
|
-
console.warn("No entry points found, skipping build");
|
|
55
|
-
return null;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
const { logs, outputs } = await bunBuild({
|
|
59
|
-
entrypoints: entryPaths,
|
|
60
|
-
format: "esm",
|
|
61
|
-
naming: `[dir]/[name].[hash].[ext]`,
|
|
62
|
-
outdir: buildDirAbsolute,
|
|
63
|
-
target: "bun"
|
|
64
|
-
}).catch((error) => {
|
|
65
|
-
console.error("Build failed:", error);
|
|
66
|
-
exit(1);
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
logs.forEach((log) => {
|
|
70
|
-
if (log.level === "error") console.error(log);
|
|
71
|
-
else if (log.level === "warning") console.warn(log);
|
|
72
|
-
else if (log.level === "info" || log.level === "debug")
|
|
73
|
-
console.info(log);
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
assetsDirAbsolute &&
|
|
77
|
-
(await $`cp -R ${assetsDirAbsolute} ${buildDirAbsolute}`);
|
|
78
|
-
|
|
79
|
-
if (htmlDirAbsolute) {
|
|
80
|
-
await mkdir(join(buildDirAbsolute, "html"));
|
|
81
|
-
await $`cp -R ${htmlDirAbsolute} ${join(buildDirAbsolute)}`;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
if (htmxDirAbsolute) {
|
|
85
|
-
await mkdir(join(buildDirAbsolute, "htmx"));
|
|
86
|
-
await $`cp -R ${htmxDirAbsolute} ${join(buildDirAbsolute)}`;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
if (tailwind) {
|
|
90
|
-
await $`tailwindcss -i ${tailwind.input} -o ${join(buildDirAbsolute, tailwind.output)}`;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
const manifest = outputs.reduce<Record<string, string>>((acc, artifact) => {
|
|
94
|
-
let relativePath = artifact.path;
|
|
95
|
-
|
|
96
|
-
if (relativePath.startsWith(buildDirAbsolute)) {
|
|
97
|
-
relativePath = relativePath.slice(buildDirAbsolute.length);
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
relativePath = relativePath.replace(/^\/+/, "");
|
|
101
|
-
|
|
102
|
-
const baseName = relativePath.split("/").pop();
|
|
103
|
-
if (!baseName) return acc;
|
|
104
|
-
|
|
105
|
-
const hashDelimiter = `.${artifact.hash}.`;
|
|
106
|
-
if (!baseName.includes(hashDelimiter)) {
|
|
107
|
-
throw new Error(
|
|
108
|
-
`Expected hash delimiter ${hashDelimiter} in ${baseName}`
|
|
109
|
-
);
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
const [fileName] = baseName.split(hashDelimiter);
|
|
113
|
-
acc[fileName] = "/" + relativePath;
|
|
114
|
-
return acc;
|
|
115
|
-
}, {});
|
|
116
|
-
|
|
117
|
-
htmlDirAbsolute && (await updateScriptTags(manifest, htmlDirAbsolute));
|
|
118
|
-
|
|
119
|
-
const end = performance.now();
|
|
120
|
-
const durationMs = end - start;
|
|
121
|
-
let duration;
|
|
122
|
-
if (durationMs < MILLISECONDS_IN_A_SECOND) {
|
|
123
|
-
duration = `${durationMs.toFixed(TIME_PRECISION)}ms`;
|
|
124
|
-
} else if (durationMs < MILLISECONDS_IN_A_MINUTE) {
|
|
125
|
-
duration = `${(durationMs / MILLISECONDS_IN_A_SECOND).toFixed(TIME_PRECISION)}s`;
|
|
126
|
-
} else {
|
|
127
|
-
duration = `${(durationMs / MILLISECONDS_IN_A_MINUTE).toFixed(TIME_PRECISION)}m`;
|
|
128
|
-
}
|
|
129
|
-
console.log(`Build completed in ${duration}`);
|
|
130
|
-
|
|
131
|
-
return manifest;
|
|
132
|
-
};
|
|
133
|
-
|
|
134
|
-
const generateReactIndexFiles = async (
|
|
135
|
-
reactPagesDirAbsolute: string,
|
|
136
|
-
reactIndexDirAbsolute: string
|
|
137
|
-
) => {
|
|
138
|
-
await rm(reactIndexDirAbsolute, { force: true, recursive: true });
|
|
139
|
-
await mkdir(reactIndexDirAbsolute);
|
|
140
|
-
|
|
141
|
-
const pagesGlob = new Glob("*.*");
|
|
142
|
-
const files: string[] = [];
|
|
143
|
-
for await (const file of pagesGlob.scan({ cwd: reactPagesDirAbsolute })) {
|
|
144
|
-
files.push(file);
|
|
145
|
-
}
|
|
146
|
-
const promises = files.map(async (file) => {
|
|
147
|
-
const fileName = basename(file);
|
|
148
|
-
const [componentName] = fileName.split(".");
|
|
149
|
-
const content = [
|
|
150
|
-
`import { hydrateRoot } from 'react-dom/client';`,
|
|
151
|
-
`import { ${componentName} } from '../pages/${componentName}';\n`,
|
|
152
|
-
`hydrateRoot(document, <${componentName} />);`
|
|
153
|
-
].join("\n");
|
|
154
|
-
|
|
155
|
-
return writeFile(
|
|
156
|
-
join(reactIndexDirAbsolute, `${componentName}Index.tsx`),
|
|
157
|
-
content
|
|
158
|
-
);
|
|
159
|
-
});
|
|
160
|
-
await Promise.all(promises);
|
|
161
|
-
};
|
|
162
|
-
|
|
163
|
-
const scanEntryPoints = async (dir: string, pattern: string) => {
|
|
164
|
-
const entryPaths: string[] = [];
|
|
165
|
-
const glob = new Glob(pattern);
|
|
166
|
-
for await (const file of glob.scan({ absolute: true, cwd: dir })) {
|
|
167
|
-
entryPaths.push(file);
|
|
168
|
-
}
|
|
169
|
-
return entryPaths;
|
|
170
|
-
};
|
package/src/core/index.ts
DELETED
package/src/core/pageHandlers.ts
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { ComponentType, createElement } from "react";
|
|
2
|
-
//@ts-expect-error - TODO: Remove this when we upgrade to React 19
|
|
3
|
-
import { renderToReadableStream } from "react-dom/server.browser";
|
|
4
|
-
|
|
5
|
-
export const handleReactPageRequest = async (
|
|
6
|
-
pageComponent: ComponentType,
|
|
7
|
-
index: string
|
|
8
|
-
) => {
|
|
9
|
-
const page = createElement(pageComponent);
|
|
10
|
-
const stream = await renderToReadableStream(page, {
|
|
11
|
-
bootstrapModules: [index]
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
return new Response(stream, {
|
|
15
|
-
headers: { "Content-Type": "text/html" }
|
|
16
|
-
});
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
export const handleHTMLPageRequest = (html: string) => Bun.file(html);
|
package/src/index.ts
DELETED
package/src/plugins/index.ts
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import { argv } from "node:process";
|
|
2
|
-
import { env } from "bun";
|
|
3
|
-
import { Elysia } from "elysia";
|
|
4
|
-
import { getLocalIPAddress } from "../utils/networking";
|
|
5
|
-
import { DEFAULT_PORT } from "../constants";
|
|
6
|
-
|
|
7
|
-
let host = env.HOST ?? "localhost";
|
|
8
|
-
const port = env.PORT ?? DEFAULT_PORT;
|
|
9
|
-
let localIP: string | undefined;
|
|
10
|
-
|
|
11
|
-
const args = argv;
|
|
12
|
-
const hostFlag = args.includes("--host");
|
|
13
|
-
|
|
14
|
-
if (hostFlag) {
|
|
15
|
-
localIP = getLocalIPAddress();
|
|
16
|
-
host = "0.0.0.0";
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export const networkingPlugin = (app: Elysia) =>
|
|
20
|
-
app.listen(
|
|
21
|
-
{
|
|
22
|
-
hostname: host,
|
|
23
|
-
port: port
|
|
24
|
-
},
|
|
25
|
-
() => {
|
|
26
|
-
//TODO: I dont think this works properly
|
|
27
|
-
if (hostFlag) {
|
|
28
|
-
console.log(`Server started on http://localhost:${port}`);
|
|
29
|
-
console.log(
|
|
30
|
-
`Server started on network: http://${localIP}:${port}`
|
|
31
|
-
);
|
|
32
|
-
} else {
|
|
33
|
-
console.log(`Server started on http://${host}:${port}`);
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
);
|
package/src/types.ts
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
export type HTMLScriptOption = "ts" | "js" | "ts+ssr" | "js+ssr" | undefined;
|
|
2
|
-
|
|
3
|
-
export type BuildConfig = {
|
|
4
|
-
buildDirectory?: string;
|
|
5
|
-
assetsDirectory?: string;
|
|
6
|
-
reactDirectory?: string;
|
|
7
|
-
vueDirectory?: string;
|
|
8
|
-
angularDirectory?: string;
|
|
9
|
-
astroDirectory?: string;
|
|
10
|
-
svelteDirectory?: string;
|
|
11
|
-
html?: {
|
|
12
|
-
directory?: string;
|
|
13
|
-
scriptingOption: HTMLScriptOption;
|
|
14
|
-
};
|
|
15
|
-
htmxDirectory?: string;
|
|
16
|
-
tailwind?: {
|
|
17
|
-
input: string;
|
|
18
|
-
output: string;
|
|
19
|
-
};
|
|
20
|
-
};
|
package/src/utils/index.ts
DELETED
package/src/utils/networking.ts
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import os from "os";
|
|
2
|
-
|
|
3
|
-
export const getLocalIPAddress = () => {
|
|
4
|
-
const interfaces = os.networkInterfaces();
|
|
5
|
-
const addresses = Object.values(interfaces)
|
|
6
|
-
.flat()
|
|
7
|
-
.filter(
|
|
8
|
-
(iface): iface is os.NetworkInterfaceInfo => iface !== undefined
|
|
9
|
-
);
|
|
10
|
-
const ipAddress = addresses.find(
|
|
11
|
-
(iface) => iface.family === "IPv4" && !iface.internal
|
|
12
|
-
);
|
|
13
|
-
|
|
14
|
-
if (ipAddress) return ipAddress.address; // Return the first non-internal IPv4 address
|
|
15
|
-
|
|
16
|
-
console.warn("No IP address found, falling back to localhost");
|
|
17
|
-
|
|
18
|
-
return "localhost"; // Fallback to localhost if no IP found
|
|
19
|
-
};
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
// TODO : this script seems to only work after building twice maybe due to the async nature of it
|
|
2
|
-
|
|
3
|
-
import { readFile, writeFile } from "node:fs/promises";
|
|
4
|
-
import { Glob } from "bun";
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Updates <script> tags in all HTML files within htmlDir.
|
|
8
|
-
* For each script tag whose src file base (with or without a hash) is a key in the manifest,
|
|
9
|
-
* the src attribute is replaced with the new hashed file path.
|
|
10
|
-
*
|
|
11
|
-
* @param manifest - An object mapping script base names to the new file path.
|
|
12
|
-
* @param htmlDir - The directory that contains the HTML files.
|
|
13
|
-
*/
|
|
14
|
-
export const updateScriptTags = async (
|
|
15
|
-
manifest: Record<string, string>,
|
|
16
|
-
htmlDir: string
|
|
17
|
-
) => {
|
|
18
|
-
// Use Glob to find all HTML files in the specified directory
|
|
19
|
-
const htmlGlob = new Glob("*.html");
|
|
20
|
-
const htmlFiles: string[] = [];
|
|
21
|
-
for await (const file of htmlGlob.scan({
|
|
22
|
-
cwd: htmlDir,
|
|
23
|
-
absolute: true
|
|
24
|
-
})) {
|
|
25
|
-
htmlFiles.push(file);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
// Process each HTML file
|
|
29
|
-
for (const filePath of htmlFiles) {
|
|
30
|
-
let content = await readFile(filePath, "utf8");
|
|
31
|
-
|
|
32
|
-
// For each script in the manifest, update matching <script> tags
|
|
33
|
-
for (const [scriptName, newPath] of Object.entries(manifest)) {
|
|
34
|
-
// Escape special regex characters in the scriptName
|
|
35
|
-
const escapedScriptName = scriptName.replace(
|
|
36
|
-
/[.*+?^${}()|[\]\\]/g,
|
|
37
|
-
"\\$&"
|
|
38
|
-
);
|
|
39
|
-
// The regex explanation:
|
|
40
|
-
// (1) (<script[^>]+src=["']) — capture the opening of the script tag up to the src attribute value
|
|
41
|
-
// (2) (\/?(?:.*\\/)?${escapedScriptName}) — capture any preceding path and the base script name
|
|
42
|
-
// (3) (?:\.[^."'/]+)? — optionally capture a dot and hash (if already hashed)
|
|
43
|
-
// (4) (\.js) — then capture the js extension
|
|
44
|
-
// (5) (["'][^>]*>) — capture the closing quote and remainder of the script tag
|
|
45
|
-
const regex = new RegExp(
|
|
46
|
-
`(<script[^>]+src=["'])(\/?(?:.*\\/)?${escapedScriptName})(?:\\.[^."'/]+)?(\\.js)(["'][^>]*>)`,
|
|
47
|
-
"g"
|
|
48
|
-
);
|
|
49
|
-
// Replace the matched src attribute with the new value from the manifest
|
|
50
|
-
content = content.replace(
|
|
51
|
-
regex,
|
|
52
|
-
(_, prefix, _oldBase, _ext, suffix) => {
|
|
53
|
-
return `${prefix}${newPath}${suffix}`;
|
|
54
|
-
}
|
|
55
|
-
);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
await writeFile(filePath, content, "utf8");
|
|
59
|
-
}
|
|
60
|
-
};
|
package/tsconfig.json
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "ESNext",
|
|
4
|
-
"module": "ESNext",
|
|
5
|
-
"moduleResolution": "bundler",
|
|
6
|
-
"jsx": "react-jsx",
|
|
7
|
-
"esModuleInterop": true,
|
|
8
|
-
"forceConsistentCasingInFileNames": true,
|
|
9
|
-
"outDir": "dist",
|
|
10
|
-
"strict": true,
|
|
11
|
-
"declaration": true,
|
|
12
|
-
"skipLibCheck": true,
|
|
13
|
-
"lib": ["DOM", "DOM.Iterable", "ESNext"]
|
|
14
|
-
},
|
|
15
|
-
"include": ["src/**/*", "example/**/*"],
|
|
16
|
-
"exclude": ["node_modules"]
|
|
17
|
-
}
|