hyperspan 1.0.0-alpha.3 → 1.0.0-alpha.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.
- package/package.json +1 -1
- package/src/server.ts +68 -50
package/package.json
CHANGED
package/src/server.ts
CHANGED
|
@@ -5,6 +5,7 @@ import { join } from 'node:path';
|
|
|
5
5
|
import tailwind from "bun-plugin-tailwind"
|
|
6
6
|
|
|
7
7
|
import type { Hyperspan as HS } from '@hyperspan/framework';
|
|
8
|
+
|
|
8
9
|
type startConfig = {
|
|
9
10
|
development?: boolean;
|
|
10
11
|
};
|
|
@@ -38,20 +39,28 @@ export async function startServer(startConfig: startConfig = {}): Promise<HS.Ser
|
|
|
38
39
|
const config = await loadConfig();
|
|
39
40
|
const server = await createServer(config);
|
|
40
41
|
console.log('[Hyperspan] Adding routes...');
|
|
41
|
-
await
|
|
42
|
+
await addDirectoryAsRoutes(server, 'routes', startConfig);
|
|
43
|
+
console.log('[Hyperspan] Adding actions...');
|
|
44
|
+
await addDirectoryAsRoutes(server, 'actions', startConfig);
|
|
42
45
|
return server;
|
|
43
46
|
}
|
|
44
47
|
|
|
45
|
-
export async function
|
|
48
|
+
export async function addDirectoryAsRoutes(
|
|
49
|
+
server: HS.Server,
|
|
50
|
+
relativeDirectory: string,
|
|
51
|
+
startConfig: startConfig = {}
|
|
52
|
+
) {
|
|
46
53
|
const routesGlob = new Glob('**/*.ts');
|
|
47
|
-
const
|
|
54
|
+
const files: string[] = [];
|
|
48
55
|
const appDir = server._config.appDir || './app';
|
|
49
|
-
const
|
|
56
|
+
const relativeAppPath = join(appDir, relativeDirectory);
|
|
57
|
+
const directoryPath = join(CWD, appDir, relativeDirectory);
|
|
50
58
|
const buildDir = join(CWD, '.build');
|
|
51
59
|
const cssPublicDir = join(CWD, server._config.publicDir, CSS_PUBLIC_PATH);
|
|
52
60
|
|
|
53
|
-
|
|
54
|
-
|
|
61
|
+
// Scan directory for TypeScript files
|
|
62
|
+
for await (const file of routesGlob.scan(directoryPath)) {
|
|
63
|
+
const filePath = join(directoryPath, file);
|
|
55
64
|
|
|
56
65
|
// Hidden directories and files start with a double underscore.
|
|
57
66
|
// These do not get added to the routes. Nothing nested under them gets added to the routes either.
|
|
@@ -59,63 +68,72 @@ export async function addRoutes(server: HS.Server, startConfig: startConfig) {
|
|
|
59
68
|
continue;
|
|
60
69
|
}
|
|
61
70
|
|
|
62
|
-
|
|
71
|
+
files.push(filePath);
|
|
63
72
|
}
|
|
64
73
|
|
|
65
74
|
const routeMap: { route: string; file: string }[] = [];
|
|
66
|
-
const routes: HS.Route
|
|
67
|
-
|
|
68
|
-
.
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
75
|
+
const routes: Array<HS.Route> = (await Promise.all(
|
|
76
|
+
files.map(async (filePath) => {
|
|
77
|
+
const relativeFilePath = filePath.split(relativeAppPath).pop() || '';
|
|
78
|
+
if (!isValidRoutePath(relativeFilePath)) {
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
const module = await import(filePath);
|
|
82
|
+
const route = getRunnableRoute(module);
|
|
83
|
+
const parsedPath = parsePath(relativeFilePath);
|
|
84
|
+
|
|
85
|
+
// If route has a _path() method that returns a meaningful path, use it
|
|
86
|
+
// Otherwise, parse path from file path
|
|
87
|
+
let path = parsedPath.path;
|
|
88
|
+
if (typeof route._path === 'function') {
|
|
89
|
+
const routePath = route._path();
|
|
90
|
+
// If _path() returns a meaningful path (not just '/'), use it
|
|
91
|
+
if (routePath && routePath !== '/') {
|
|
92
|
+
path = routePath;
|
|
74
93
|
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
let cssFiles: string[] = [];
|
|
97
|
+
|
|
98
|
+
// Build the route just for the CSS files (expensive, but easiest way to do CSS compilation by route)
|
|
99
|
+
// @TODO: Optimize this at some later date... This is O(n) for each route and doesn't scale well for large projects.
|
|
100
|
+
// @TODO: This will also currently re-compile the same CSS file(s) that are included in multiple routes, which is dumb.
|
|
101
|
+
const buildResult = await Bun.build({
|
|
102
|
+
plugins: [tailwind],
|
|
103
|
+
entrypoints: [filePath],
|
|
104
|
+
outdir: buildDir,
|
|
105
|
+
naming: `${relativeAppPath}/${path.endsWith('/') ? path + 'index' : path}-[hash].[ext]`,
|
|
106
|
+
minify: IS_PROD,
|
|
107
|
+
format: 'esm',
|
|
108
|
+
target: 'node',
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
// Move CSS files to the public directory
|
|
112
|
+
for (const output of buildResult.outputs) {
|
|
113
|
+
if (output.path.endsWith('.css')) {
|
|
114
|
+
const cssFileName = output.path.split('/').pop()!;
|
|
115
|
+
await Bun.write(join(cssPublicDir, cssFileName), Bun.file(output.path));
|
|
116
|
+
cssFiles.push(cssFileName);
|
|
98
117
|
}
|
|
118
|
+
}
|
|
99
119
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
// Set route path based on the file path
|
|
120
|
+
// Set route path based on the file path (if not already set)
|
|
121
|
+
if (!route._config.path) {
|
|
104
122
|
route._config.path = path;
|
|
123
|
+
}
|
|
105
124
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
125
|
+
if (cssFiles.length > 0) {
|
|
126
|
+
route._config.cssImports = cssFiles;
|
|
127
|
+
CSS_ROUTE_MAP.set(path, cssFiles);
|
|
128
|
+
}
|
|
110
129
|
|
|
111
|
-
|
|
130
|
+
routeMap.push({ route: path, file: filePath.replace(CWD, '') });
|
|
112
131
|
|
|
113
|
-
|
|
114
|
-
|
|
132
|
+
return route;
|
|
133
|
+
})
|
|
115
134
|
)).filter((route) => route !== null);
|
|
116
135
|
|
|
117
136
|
if (startConfig.development) {
|
|
118
|
-
console.log('[Hyperspan] Loaded routes:');
|
|
119
137
|
console.table(routeMap);
|
|
120
138
|
}
|
|
121
139
|
|