xpine 0.0.45 → 0.0.46
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 +61 -2
- package/TODO +2 -0
- package/dist/index.js +18 -13
- package/dist/src/express.d.ts.map +1 -1
- package/dist/src/runDevServer.d.ts.map +1 -1
- package/dist/src/scripts/xpine-build.js +2 -2
- package/dist/src/scripts/xpine-dev.js +5 -3
- package/dist/types.d.ts +2 -1
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/types.ts +2 -1
package/README.md
CHANGED
|
@@ -13,7 +13,6 @@ XPine uses page based routing. Render an HTML page using JSX components, for exa
|
|
|
13
13
|
```
|
|
14
14
|
import { WrapperProps } from 'xpine/dist/types';
|
|
15
15
|
import Base from '../components/Base';
|
|
16
|
-
import Navbar from '../components/Navbar';
|
|
17
16
|
|
|
18
17
|
export const config = {
|
|
19
18
|
data() {
|
|
@@ -156,6 +155,19 @@ You can create catch all routes by naming the file \_all\_.(jsx|tsx|js|ts). You
|
|
|
156
155
|
|
|
157
156
|
You can get the route param in your function with req.params[0], such as how express handles catch all routes.
|
|
158
157
|
|
|
158
|
+
### Route specific middleware
|
|
159
|
+
|
|
160
|
+
If you need route specific middleware, e.g. for file uploads, you can specify a `routeMiddleware` function in a config variable in the endpoint file:
|
|
161
|
+
|
|
162
|
+
```
|
|
163
|
+
export const config = {
|
|
164
|
+
routeMiddleware(req, res, next) {
|
|
165
|
+
console.log('route middleware');
|
|
166
|
+
next();
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
```
|
|
170
|
+
|
|
159
171
|
### Static Site Generation
|
|
160
172
|
|
|
161
173
|
Generate path specific static pages by specifying in the config of either the page's file, such as `/src/pages/about.tsx` with a config export:
|
|
@@ -296,14 +308,61 @@ export default async function startServer() {
|
|
|
296
308
|
}
|
|
297
309
|
```
|
|
298
310
|
|
|
311
|
+
Add a directory in `/src/server` called `run`, and create two files: `/src/server/dev.ts` and `/src/server/prod.ts`.
|
|
312
|
+
|
|
313
|
+
`dev.ts` should look like this:
|
|
314
|
+
|
|
315
|
+
```
|
|
316
|
+
import { runDevServer } from 'xpine';
|
|
317
|
+
|
|
318
|
+
runDevServer();
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
and can be run with an npm command like this in your package.json scripts: `"dev": "PORT=8888 LOCALHOST=1 xpine-dev"`.
|
|
322
|
+
|
|
323
|
+
The `prod.ts` should look like this:
|
|
324
|
+
|
|
325
|
+
```
|
|
326
|
+
import startServer from '../app';
|
|
327
|
+
|
|
328
|
+
await startServer();
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
and can be run with an npm command in your package.json scripts like this, after the app has been built with `xpine-build`:
|
|
332
|
+
|
|
333
|
+
`"start": "PORT=8888 node ./dist/server/run/prod.js"`
|
|
334
|
+
|
|
299
335
|
### xpine.config.mjs file
|
|
300
336
|
|
|
301
|
-
Add an xpine.config.mjs file to your root directory. This is used primarily for configuring file paths
|
|
337
|
+
Add an xpine.config.mjs file to your root directory. This is used primarily for configuring/changing file paths. Configs can be imported with `import { config } from "xpine"`.
|
|
302
338
|
|
|
303
339
|
```
|
|
304
340
|
export default {}
|
|
305
341
|
```
|
|
306
342
|
|
|
343
|
+
These are the following default paths:
|
|
344
|
+
|
|
345
|
+
```
|
|
346
|
+
rootDir: process.cwd
|
|
347
|
+
srcDir: rootDir + ./src
|
|
348
|
+
distDir: rootDir + ./dist
|
|
349
|
+
packageJsonPath: rootDir + ./package.json
|
|
350
|
+
distPublicDir: distDir + ./public
|
|
351
|
+
distPublicScriptsDir: distPublicDir + ./scripts
|
|
352
|
+
distTempFolder: distDir + ./temp
|
|
353
|
+
clientJSBundlePath: distPublicScriptsDir + ./app.js
|
|
354
|
+
alpineDataPath: distTempFolder + ./alpine-data.ts
|
|
355
|
+
serverDistDir: distDir + ./server
|
|
356
|
+
serverDistAppPath: serverDistDir + ./app.js
|
|
357
|
+
pagesDir: srcDir + ./pages
|
|
358
|
+
distPagesDir: distDir + ./pages
|
|
359
|
+
publicDir: srcDir + ./public
|
|
360
|
+
serverDir: srcDir + ./server
|
|
361
|
+
runDir: serverDir + ./run
|
|
362
|
+
serverAppPath: serverDir + ./app.ts
|
|
363
|
+
globalCSSFile: publicDir + ./styles/global.css
|
|
364
|
+
```
|
|
365
|
+
|
|
307
366
|
### SPA interactivity
|
|
308
367
|
|
|
309
368
|
- data-spa="true"
|
package/TODO
CHANGED
package/dist/index.js
CHANGED
|
@@ -531,14 +531,12 @@ async function createRouteFunction(route, configFiles) {
|
|
|
531
531
|
}
|
|
532
532
|
let config2 = {};
|
|
533
533
|
const configFilePaths = getConfigFiles(route.originalRoute, configFiles);
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
config2
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
};
|
|
541
|
-
}
|
|
534
|
+
config2 = configFilePaths && await getCompleteConfig(configFilePaths, Date.now());
|
|
535
|
+
if (componentImport?.config) {
|
|
536
|
+
config2 = {
|
|
537
|
+
...config2,
|
|
538
|
+
...componentImport.config
|
|
539
|
+
};
|
|
542
540
|
}
|
|
543
541
|
async function routeFn(req, res) {
|
|
544
542
|
const urlPath = req?.route?.path || "/";
|
|
@@ -588,6 +586,7 @@ async function createRouteFunction(route, configFiles) {
|
|
|
588
586
|
formattedRouteItem,
|
|
589
587
|
foundMethod,
|
|
590
588
|
route,
|
|
589
|
+
config: config2,
|
|
591
590
|
routeFn
|
|
592
591
|
};
|
|
593
592
|
}
|
|
@@ -599,8 +598,12 @@ async function createRouter() {
|
|
|
599
598
|
await triggerXPineOnLoad();
|
|
600
599
|
for (const route of routeMap) {
|
|
601
600
|
try {
|
|
602
|
-
const { formattedRouteItem, foundMethod, routeFn } = await createRouteFunction(route, configFiles);
|
|
603
|
-
|
|
601
|
+
const { formattedRouteItem, foundMethod, config: config2, routeFn } = await createRouteFunction(route, configFiles);
|
|
602
|
+
if (config2?.routeMiddleware) {
|
|
603
|
+
router[foundMethod || "get"](formattedRouteItem, config2.routeMiddleware, routeFn);
|
|
604
|
+
} else {
|
|
605
|
+
router[foundMethod || "get"](formattedRouteItem, routeFn);
|
|
606
|
+
}
|
|
604
607
|
routeResults.push({
|
|
605
608
|
formattedRouteItem,
|
|
606
609
|
foundMethod,
|
|
@@ -787,7 +790,7 @@ async function buildAppFiles(files, isDev2) {
|
|
|
787
790
|
const fileName = file.split("/").at(-1).split(".").shift();
|
|
788
791
|
return fileName === "+config";
|
|
789
792
|
});
|
|
790
|
-
const backendFiles = files.filter((file) => extensions
|
|
793
|
+
const backendFiles = files.filter((file) => extensions?.find((ext) => file.endsWith(ext))).filter((file) => !file.startsWith(config.publicDir));
|
|
791
794
|
fs7.ensureDirSync(config.distDir);
|
|
792
795
|
await build({
|
|
793
796
|
entryPoints: backendFiles,
|
|
@@ -918,7 +921,7 @@ async function buildPublicFolderSymlinks() {
|
|
|
918
921
|
async function logSize(pathName, type, validExtensions = [".js", ".css"]) {
|
|
919
922
|
const files = globSync3(pathName + "/**/*" + (type === "css" ? ".css" : ""));
|
|
920
923
|
const fileSizes = files.map((file) => {
|
|
921
|
-
if (!validExtensions
|
|
924
|
+
if (!validExtensions?.find((ext) => file.endsWith(ext))) return false;
|
|
922
925
|
return {
|
|
923
926
|
file,
|
|
924
927
|
size: fs7.statSync(file).size / (1024 * 1e3)
|
|
@@ -1108,7 +1111,9 @@ async function runDevServer() {
|
|
|
1108
1111
|
ignored: (pathName) => pathName.endsWith(".map") || pathName.startsWith(path8.join(config.serverDir, "./prisma"))
|
|
1109
1112
|
});
|
|
1110
1113
|
watcher.on("all", async (event, path9) => {
|
|
1111
|
-
const
|
|
1114
|
+
const isRegularExpressRoute = path9.startsWith(config.pagesDir) && (path9.endsWith(".ts") || path9.endsWith(".js"));
|
|
1115
|
+
const isServerDir = path9.startsWith(config.serverDir) && !path9.startsWith(config.runDir);
|
|
1116
|
+
const shouldReloadServer = isServerDir || isRegularExpressRoute || ["add", "unlink"].includes(event) && path9.startsWith(config.pagesDir);
|
|
1112
1117
|
if (shouldReloadServer) {
|
|
1113
1118
|
await asyncServerClose(appServer.server);
|
|
1114
1119
|
rebuildEmitter.emit("rebuild-server");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"express.d.ts","sourceRoot":"","sources":["../../src/express.ts"],"names":[],"mappings":"AAAA,OAAgB,EAAgB,OAAO,EAAqB,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"express.d.ts","sourceRoot":"","sources":["../../src/express.ts"],"names":[],"mappings":"AAAA,OAAgB,EAAgB,OAAO,EAAqB,MAAM,SAAS,CAAC;AAqJ5E,wBAAsB,YAAY;;;GAkCjC;AAiBD,wBAAsB,iBAAiB,CAAC,GAAG,EAAE,GAAG,EAAE,gBAAgB,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,IAAI,iBAyB1F;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;CAAE,GAAG,MAAM,GAAG,KAAK,CAanG;AAED,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,GAAE,OAAc,UAQzE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runDevServer.d.ts","sourceRoot":"","sources":["../../src/runDevServer.ts"],"names":[],"mappings":"AAYA,wBAAsB,YAAY,
|
|
1
|
+
{"version":3,"file":"runDevServer.d.ts","sourceRoot":"","sources":["../../src/runDevServer.ts"],"names":[],"mappings":"AAYA,wBAAsB,YAAY,kBA+DjC"}
|
|
@@ -583,7 +583,7 @@ async function buildAppFiles(files, isDev3) {
|
|
|
583
583
|
const fileName = file.split("/").at(-1).split(".").shift();
|
|
584
584
|
return fileName === "+config";
|
|
585
585
|
});
|
|
586
|
-
const backendFiles = files.filter((file) => extensions
|
|
586
|
+
const backendFiles = files.filter((file) => extensions?.find((ext) => file.endsWith(ext))).filter((file) => !file.startsWith(config.publicDir));
|
|
587
587
|
fs7.ensureDirSync(config.distDir);
|
|
588
588
|
await build({
|
|
589
589
|
entryPoints: backendFiles,
|
|
@@ -714,7 +714,7 @@ async function buildPublicFolderSymlinks() {
|
|
|
714
714
|
async function logSize(pathName, type, validExtensions = [".js", ".css"]) {
|
|
715
715
|
const files = globSync3(pathName + "/**/*" + (type === "css" ? ".css" : ""));
|
|
716
716
|
const fileSizes = files.map((file) => {
|
|
717
|
-
if (!validExtensions
|
|
717
|
+
if (!validExtensions?.find((ext) => file.endsWith(ext))) return false;
|
|
718
718
|
return {
|
|
719
719
|
file,
|
|
720
720
|
size: fs7.statSync(file).size / (1024 * 1e3)
|
|
@@ -590,7 +590,7 @@ async function buildAppFiles(files, isDev2) {
|
|
|
590
590
|
const fileName = file.split("/").at(-1).split(".").shift();
|
|
591
591
|
return fileName === "+config";
|
|
592
592
|
});
|
|
593
|
-
const backendFiles = files.filter((file) => extensions
|
|
593
|
+
const backendFiles = files.filter((file) => extensions?.find((ext) => file.endsWith(ext))).filter((file) => !file.startsWith(config.publicDir));
|
|
594
594
|
fs7.ensureDirSync(config.distDir);
|
|
595
595
|
await build({
|
|
596
596
|
entryPoints: backendFiles,
|
|
@@ -721,7 +721,7 @@ async function buildPublicFolderSymlinks() {
|
|
|
721
721
|
async function logSize(pathName, type, validExtensions = [".js", ".css"]) {
|
|
722
722
|
const files = globSync3(pathName + "/**/*" + (type === "css" ? ".css" : ""));
|
|
723
723
|
const fileSizes = files.map((file) => {
|
|
724
|
-
if (!validExtensions
|
|
724
|
+
if (!validExtensions?.find((ext) => file.endsWith(ext))) return false;
|
|
725
725
|
return {
|
|
726
726
|
file,
|
|
727
727
|
size: fs7.statSync(file).size / (1024 * 1e3)
|
|
@@ -911,7 +911,9 @@ async function runDevServer() {
|
|
|
911
911
|
ignored: (pathName) => pathName.endsWith(".map") || pathName.startsWith(path7.join(config.serverDir, "./prisma"))
|
|
912
912
|
});
|
|
913
913
|
watcher.on("all", async (event, path8) => {
|
|
914
|
-
const
|
|
914
|
+
const isRegularExpressRoute = path8.startsWith(config.pagesDir) && (path8.endsWith(".ts") || path8.endsWith(".js"));
|
|
915
|
+
const isServerDir = path8.startsWith(config.serverDir) && !path8.startsWith(config.runDir);
|
|
916
|
+
const shouldReloadServer = isServerDir || isRegularExpressRoute || ["add", "unlink"].includes(event) && path8.startsWith(config.pagesDir);
|
|
915
917
|
if (shouldReloadServer) {
|
|
916
918
|
await asyncServerClose(appServer.server);
|
|
917
919
|
rebuildEmitter.emit("rebuild-server");
|
package/dist/types.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Request, Response } from 'express';
|
|
1
|
+
import { NextFunction, Request, Response } from 'express';
|
|
2
2
|
import ts from 'typescript';
|
|
3
3
|
export type XPineConfig = {
|
|
4
4
|
[key: string]: any;
|
|
@@ -24,6 +24,7 @@ export type ConfigFile = {
|
|
|
24
24
|
}[]>);
|
|
25
25
|
wrapper?: (props: WrapperProps) => Promise<any>;
|
|
26
26
|
data?: (req: ServerRequest) => Promise<any>;
|
|
27
|
+
routeMiddleware?: (req: ServerRequest, res: Response, next: NextFunction) => void;
|
|
27
28
|
};
|
|
28
29
|
export type PageProps = {
|
|
29
30
|
req: ServerRequest;
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC1D,OAAO,EAAE,MAAM,YAAY,CAAC;AAE5B,MAAM,MAAM,WAAW,GAAG;IACxB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACpB,CAAA;AAED,MAAM,MAAM,SAAS,GAAG;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAA;AAED,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG;IACpC,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAA;AAED,MAAM,MAAM,YAAY,GAAG;IACzB,GAAG,EAAE,aAAa,CAAC;IACnB,QAAQ,EAAE,GAAG,CAAC;IACd,MAAM,EAAE,UAAU,CAAC;IACnB,IAAI,CAAC,EAAE,GAAG,CAAC;IACX,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAA;AAED,MAAM,MAAM,UAAU,GAAG;IACvB,WAAW,CAAC,EAAE,OAAO,GAAG,CAAC,MAAM,OAAO,CAAC;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,EAAE,CAAC,CAAC,CAAC;IACrE,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,OAAO,CAAC,GAAG,CAAC,CAAC;IAChD,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,aAAa,KAAK,OAAO,CAAC,GAAG,CAAC,CAAC;IAC5C,eAAe,CAAC,EAAE,CAAC,GAAG,EAAE,aAAa,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,KAAK,IAAI,CAAC;CACnF,CAAA;AAED,MAAM,MAAM,SAAS,GAAG;IACtB,GAAG,EAAE,aAAa,CAAC;IACnB,GAAG,EAAE,QAAQ,CAAC;IACd,IAAI,EAAE,GAAG,CAAC;IACV,SAAS,EAAE,MAAM,CAAC;CACnB,CAAA;AAED,MAAM,MAAM,QAAQ,GAAG;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd,CAAA;AAED,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,MAAM,EAAE,EAAE,CAAC,UAAU,CAAC;CACvB,CAAA"}
|
package/package.json
CHANGED
package/types.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Request, Response } from 'express';
|
|
1
|
+
import { NextFunction, Request, Response } from 'express';
|
|
2
2
|
import ts from 'typescript';
|
|
3
3
|
|
|
4
4
|
export type XPineConfig = {
|
|
@@ -27,6 +27,7 @@ export type ConfigFile = {
|
|
|
27
27
|
staticPaths?: boolean | (() => Promise<{ [key: string]: string }[]>);
|
|
28
28
|
wrapper?: (props: WrapperProps) => Promise<any>;
|
|
29
29
|
data?: (req: ServerRequest) => Promise<any>;
|
|
30
|
+
routeMiddleware?: (req: ServerRequest, res: Response, next: NextFunction) => void;
|
|
30
31
|
}
|
|
31
32
|
|
|
32
33
|
export type PageProps = {
|