zuby 1.0.32 → 1.0.34
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/commands/build.js +2 -1
- package/context/index.d.ts +1 -1
- package/context/types.d.ts +1 -1
- package/examples/basic/ts/tsconfig.json +2 -23
- package/package.json +2 -2
- package/pageContext/index.d.ts +10 -2
- package/pageContext/index.js +18 -1
- package/plugins/contextPlugin/index.js +5 -5
- package/plugins/prerenderPlugin/index.js +32 -101
- package/server/index.js +6822 -104
- package/server/types.d.ts +2 -2
- package/server/zubyRenderer.d.ts +23 -0
- package/server/zubyRenderer.js +138 -0
- package/server/zubyServer.d.ts +11 -7
- package/server/zubyServer.js +72 -23
- package/templates/index.d.ts +3 -10
- package/templates/index.js +7 -28
- package/templates/pathUtils.d.ts +8 -0
- package/templates/pathUtils.js +21 -0
- package/templates/types.d.ts +1 -1
- package/templates/types.js +1 -1
- package/types.d.ts +11 -2
- package/types.js +4 -0
package/commands/build.js
CHANGED
|
@@ -80,7 +80,8 @@ export default async function build(options) {
|
|
|
80
80
|
}));
|
|
81
81
|
logger?.info(`${chalk.bgYellow.bold.whiteBright(` Step 4/4 `)} ${chalk.gray(`tracing dependencies...`)}`);
|
|
82
82
|
logger?.info(`Tracing production dependencies...`);
|
|
83
|
-
const
|
|
83
|
+
const serverFiles = await glob(`${normalizePath(outDir)}/server/**/*.js`);
|
|
84
|
+
const { fileList } = await nodeFileTrace(serverFiles, {
|
|
84
85
|
processCwd: process.cwd(),
|
|
85
86
|
ignore: (path) => {
|
|
86
87
|
return path.startsWith(outDir);
|
package/context/index.d.ts
CHANGED
|
@@ -8,7 +8,7 @@ export declare class ZubyContext {
|
|
|
8
8
|
errors?: import("../templates/types.js").LazyTemplate[] | undefined;
|
|
9
9
|
layouts?: import("../templates/types.js").LazyTemplate[] | undefined;
|
|
10
10
|
innerLayouts?: import("../templates/types.js").LazyTemplate[] | undefined;
|
|
11
|
-
|
|
11
|
+
handlers?: import("../templates/types.js").LazyTemplate[] | undefined;
|
|
12
12
|
} | undefined;
|
|
13
13
|
get site(): string | undefined;
|
|
14
14
|
get generator(): string | undefined;
|
package/context/types.d.ts
CHANGED
|
@@ -1,29 +1,8 @@
|
|
|
1
1
|
{
|
|
2
|
+
"extends": "zuby/tsconfigs/default",
|
|
2
3
|
"compilerOptions": {
|
|
3
|
-
"target": "ES2020",
|
|
4
|
-
"useDefineForClassFields": true,
|
|
5
|
-
"module": "ESNext",
|
|
6
|
-
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
|
7
|
-
"skipLibCheck": true,
|
|
8
|
-
"types": ["vite/client", "<jsxProviderName>"],
|
|
9
|
-
|
|
10
|
-
/* Bundler mode */
|
|
11
|
-
"moduleResolution": "bundler",
|
|
12
|
-
"allowImportingTsExtensions": true,
|
|
13
|
-
"resolveJsonModule": true,
|
|
14
|
-
"isolatedModules": true,
|
|
15
|
-
"noEmit": true,
|
|
16
4
|
"jsx": "react-jsx",
|
|
17
|
-
"jsxImportSource": "<jsxProviderName>"
|
|
18
|
-
|
|
19
|
-
/* Linting */
|
|
20
|
-
"strict": true,
|
|
21
|
-
"noUnusedLocals": true,
|
|
22
|
-
"noUnusedParameters": true,
|
|
23
|
-
"noFallthroughCasesInSwitch": true,
|
|
24
|
-
|
|
25
|
-
"composite": true,
|
|
26
|
-
"allowSyntheticDefaultImports": true
|
|
5
|
+
"jsxImportSource": "<jsxProviderName>"
|
|
27
6
|
},
|
|
28
7
|
"include": ["./**/*", "zuby.config.ts"]
|
|
29
8
|
}
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zuby",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.34",
|
|
4
4
|
"description": "Zuby.js is framework for building SPA apps using Vite",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.js",
|
|
7
7
|
"scripts": {
|
|
8
8
|
"release": "cd ./dist && npm publish --access public && cd ..",
|
|
9
9
|
"build": "rm -rf dist/ && tsc && cp -rf package.json README.md src/examples dist/ && npm run bundle-server",
|
|
10
|
-
"bundle-server": "esbuild src/server/index.ts --bundle --platform=node --format=esm
|
|
10
|
+
"bundle-server": "esbuild src/server/index.ts --bundle --minify=false --platform=node --format=esm --outfile=dist/server/index.js",
|
|
11
11
|
"watch-build": "npm run build && tsc --watch",
|
|
12
12
|
"push-build": "npm run build && cd dist && yalc push --force && cd ..",
|
|
13
13
|
"test": "exit 0"
|
package/pageContext/index.d.ts
CHANGED
|
@@ -5,13 +5,17 @@ export declare class ZubyPageContext {
|
|
|
5
5
|
protected _request?: Request;
|
|
6
6
|
protected _params: Record<string, string>;
|
|
7
7
|
protected _clientAddress?: string;
|
|
8
|
+
protected _statusCode: number;
|
|
9
|
+
protected _props: Record<string, any>;
|
|
8
10
|
protected _zubyContext: ZubyContext;
|
|
9
11
|
constructor(options: {
|
|
10
12
|
url?: URL;
|
|
11
13
|
title?: string;
|
|
12
14
|
request?: Request;
|
|
13
|
-
response?: Response;
|
|
14
15
|
clientAddress?: string;
|
|
16
|
+
statusCode?: number;
|
|
17
|
+
props?: Record<string, any>;
|
|
18
|
+
zubyContext?: ZubyContext;
|
|
15
19
|
});
|
|
16
20
|
get url(): URL;
|
|
17
21
|
get title(): string;
|
|
@@ -30,6 +34,10 @@ export declare class ZubyPageContext {
|
|
|
30
34
|
errors?: import("../templates/types.js").LazyTemplate[] | undefined;
|
|
31
35
|
layouts?: import("../templates/types.js").LazyTemplate[] | undefined;
|
|
32
36
|
innerLayouts?: import("../templates/types.js").LazyTemplate[] | undefined;
|
|
33
|
-
|
|
37
|
+
handlers?: import("../templates/types.js").LazyTemplate[] | undefined;
|
|
34
38
|
} | undefined;
|
|
39
|
+
get props(): Record<string, any>;
|
|
40
|
+
set props(value: Record<string, any>);
|
|
41
|
+
get statusCode(): number | undefined;
|
|
42
|
+
set statusCode(value: number | undefined);
|
|
35
43
|
}
|
package/pageContext/index.js
CHANGED
|
@@ -6,7 +6,9 @@ export class ZubyPageContext {
|
|
|
6
6
|
this._request = options?.request;
|
|
7
7
|
this._params = {};
|
|
8
8
|
this._clientAddress = options?.clientAddress;
|
|
9
|
-
this.
|
|
9
|
+
this._statusCode = options?.statusCode || 200;
|
|
10
|
+
this._props = options?.props || {};
|
|
11
|
+
this._zubyContext = options?.zubyContext || getContext();
|
|
10
12
|
}
|
|
11
13
|
get url() {
|
|
12
14
|
if (this.isBrowserEnv) {
|
|
@@ -53,4 +55,19 @@ export class ZubyPageContext {
|
|
|
53
55
|
get templates() {
|
|
54
56
|
return this._zubyContext.templates;
|
|
55
57
|
}
|
|
58
|
+
get props() {
|
|
59
|
+
return this._props;
|
|
60
|
+
}
|
|
61
|
+
set props(value) {
|
|
62
|
+
this._props = value || {};
|
|
63
|
+
}
|
|
64
|
+
get statusCode() {
|
|
65
|
+
return this._statusCode;
|
|
66
|
+
}
|
|
67
|
+
set statusCode(value) {
|
|
68
|
+
if (!value || !Number.isInteger(value) || value < 100 || value > 599) {
|
|
69
|
+
throw new Error(`Invalid status code: ${value}`);
|
|
70
|
+
}
|
|
71
|
+
this._statusCode = value;
|
|
72
|
+
}
|
|
56
73
|
}
|
|
@@ -2,7 +2,7 @@ import { getZubyInternalConfig } from '../../config.js';
|
|
|
2
2
|
import { relative } from 'path';
|
|
3
3
|
import { normalizePath } from '../../utils/pathUtils.js';
|
|
4
4
|
import { getZubyPackageConfig } from '../../packageConfig.js';
|
|
5
|
-
import {
|
|
5
|
+
import { getApps, getErrors, getHandlers, getInnerLayouts, getLayouts, getPages, getTemplates, } from '../../templates/index.js';
|
|
6
6
|
let viteConfig;
|
|
7
7
|
export default function index() {
|
|
8
8
|
return {
|
|
@@ -39,7 +39,7 @@ export async function generateTemplatesCode() {
|
|
|
39
39
|
const layouts = await getLayouts(templates);
|
|
40
40
|
const innerLayouts = await getInnerLayouts(templates);
|
|
41
41
|
const errors = await getErrors(templates);
|
|
42
|
-
const
|
|
42
|
+
const handlers = await getHandlers(templates);
|
|
43
43
|
const pagesCode = await Promise.all(pages.map(generateTemplateCode) || []);
|
|
44
44
|
const appsCode = await Promise.all(apps.map(generateTemplateCode) || []);
|
|
45
45
|
const errorsCode = await Promise.all(errors.map(generateTemplateCode) || []);
|
|
@@ -49,8 +49,8 @@ export async function generateTemplatesCode() {
|
|
|
49
49
|
const innerLayoutsCode = viteConfig?.build.ssr
|
|
50
50
|
? await Promise.all(innerLayouts.map(generateTemplateCode) || [])
|
|
51
51
|
: [];
|
|
52
|
-
const
|
|
53
|
-
? await Promise.all(
|
|
52
|
+
const handlersCode = viteConfig?.build.ssr
|
|
53
|
+
? await Promise.all(handlers.map(generateTemplateCode) || [])
|
|
54
54
|
: [];
|
|
55
55
|
return `{
|
|
56
56
|
pages: [${pagesCode.join(',')}],
|
|
@@ -58,7 +58,7 @@ export async function generateTemplatesCode() {
|
|
|
58
58
|
errors: [${errorsCode.join(',')}],
|
|
59
59
|
layouts: [${layoutsCode.join(',')}],
|
|
60
60
|
innerLayouts: [${innerLayoutsCode.join(',')}],
|
|
61
|
-
|
|
61
|
+
handlers: [${handlersCode.join(',')}],
|
|
62
62
|
}`;
|
|
63
63
|
}
|
|
64
64
|
export async function generateTemplateCode(template) {
|
|
@@ -1,14 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { basename, dirname, join, resolve } from 'path';
|
|
1
|
+
import { existsSync, mkdirSync } from 'fs';
|
|
2
|
+
import { dirname, join } from 'path';
|
|
4
3
|
import { getZubyInternalConfig } from '../../config.js';
|
|
5
|
-
import { getContext } from '../../context/index.js';
|
|
6
4
|
import chalk from 'chalk';
|
|
7
|
-
import { normalizePath } from '../../utils/pathUtils.js';
|
|
8
|
-
import { glob } from 'glob';
|
|
9
|
-
import { ZubyPageContext } from '../../pageContext/index.js';
|
|
10
|
-
import { PATH_TYPES } from '../../templates/types.js';
|
|
11
5
|
import { performance } from 'node:perf_hooks';
|
|
6
|
+
import ZubyRenderer from '../../server/zubyRenderer.js';
|
|
7
|
+
import { writeFile } from 'fs/promises';
|
|
12
8
|
/**
|
|
13
9
|
* This is internal plugin
|
|
14
10
|
* that pre-renders the pages during the build.
|
|
@@ -28,102 +24,37 @@ export default function prerenderPlugin() {
|
|
|
28
24
|
return;
|
|
29
25
|
}
|
|
30
26
|
const startTime = performance.now();
|
|
31
|
-
const { outDir, customLogger, prerenderPaths,
|
|
27
|
+
const { outDir, customLogger, prerenderPaths, site } = await getZubyInternalConfig();
|
|
32
28
|
customLogger?.info(`${chalk.bgYellow.bold.whiteBright(` Step 3/4 `)} ${chalk.gray(`pre-rendering pages...`)}`);
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
const
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
const { pages = [] } = zubyContext.templates || {};
|
|
58
|
-
const { template: page } = findMatchingTemplate(pages, path);
|
|
59
|
-
// App
|
|
60
|
-
const { apps = [] } = zubyContext.templates || {};
|
|
61
|
-
const { template: app } = findMatchingTemplate(apps, path);
|
|
62
|
-
// Nothing to pre-render
|
|
63
|
-
if (!page || !app)
|
|
64
|
-
continue;
|
|
65
|
-
// Load layout template component
|
|
66
|
-
const { layouts = [] } = zubyContext.templates || {};
|
|
67
|
-
const { template: layout } = findMatchingTemplate(layouts, path);
|
|
68
|
-
if (!layout) {
|
|
69
|
-
throw new Error(`No layout found for path: ${path}`);
|
|
70
|
-
}
|
|
71
|
-
const layoutModule = await layout?.component();
|
|
72
|
-
const layoutComponent = layoutModule.default || layoutModule;
|
|
73
|
-
// Load innerLayout template component
|
|
74
|
-
const { innerLayouts = [] } = zubyContext.templates || {};
|
|
75
|
-
const { template: innerLayout } = findMatchingTemplate(innerLayouts, path);
|
|
76
|
-
if (!layout) {
|
|
77
|
-
throw new Error(`No innerLayout found for path: ${path}`);
|
|
78
|
-
}
|
|
79
|
-
const innerLayoutModule = await innerLayout?.component();
|
|
80
|
-
const innerLayoutComponent = innerLayoutModule.default || innerLayoutModule;
|
|
81
|
-
// Render the app first
|
|
82
|
-
let entryHtml = (await zubyContext.renderToString(entry({
|
|
83
|
-
context: zubyPageContext,
|
|
84
|
-
}))) || '';
|
|
85
|
-
// Composition of the page and the layout
|
|
86
|
-
const layoutChildren = layoutComponent({
|
|
87
|
-
children: innerLayoutComponent({
|
|
88
|
-
innerHtml: entryHtml,
|
|
89
|
-
}),
|
|
90
|
-
context: zubyPageContext,
|
|
91
|
-
});
|
|
92
|
-
// Render the layout
|
|
93
|
-
let html = (await zubyContext.renderToString(layoutChildren)) || '';
|
|
94
|
-
const staticImports = [
|
|
95
|
-
...(ssrManifest[app.filename] || []),
|
|
96
|
-
...(ssrManifest[page.filename] || []),
|
|
97
|
-
];
|
|
98
|
-
const cssImports = staticImports.filter((imp) => imp.endsWith('.css'));
|
|
99
|
-
const jsImports = [];
|
|
100
|
-
// Entry css
|
|
101
|
-
if (entryClientCss) {
|
|
102
|
-
cssImports.unshift(`/chunks/${basename(entryClientCss)}`);
|
|
103
|
-
}
|
|
104
|
-
// Entry js
|
|
105
|
-
if (entryClientJs) {
|
|
106
|
-
jsImports.unshift(`/chunks/${basename(entryClientJs)}`);
|
|
107
|
-
}
|
|
108
|
-
// Insert document type
|
|
109
|
-
html = '<!DOCTYPE html>' + html;
|
|
110
|
-
// Insert client CSS imports
|
|
111
|
-
cssImports.forEach((imp) => {
|
|
112
|
-
html = html.replace(/(<\/head>)/, `<link rel='stylesheet' href="${imp}"/>$1`);
|
|
113
|
-
});
|
|
114
|
-
// Insert client JS imports
|
|
115
|
-
jsImports.forEach((imp) => {
|
|
116
|
-
html = html.replace(/(<\/head>)/, `<script type="module" src="${imp}" defer></script>$1`);
|
|
117
|
-
});
|
|
118
|
-
const target = join(outDir, 'client', path, 'index.html');
|
|
119
|
-
const directory = dirname(target);
|
|
120
|
-
if (!existsSync(directory)) {
|
|
121
|
-
mkdirSync(directory, {
|
|
29
|
+
const zubyRenderer = new ZubyRenderer(outDir);
|
|
30
|
+
await zubyRenderer.init();
|
|
31
|
+
const reqBaseUrl = `http://${site || 'localhost'}`;
|
|
32
|
+
const reqOptions = {
|
|
33
|
+
headers: {
|
|
34
|
+
'user-agent': 'zuby-prerender',
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
for (const path of prerenderPaths) {
|
|
38
|
+
const pageReq = new Request(new URL(path, reqBaseUrl), reqOptions);
|
|
39
|
+
const propsReq = new Request(new URL(`/_props${path}`, reqBaseUrl), reqOptions);
|
|
40
|
+
const [pageRes, propsRes] = await Promise.all([
|
|
41
|
+
zubyRenderer.render(pageReq),
|
|
42
|
+
zubyRenderer.render(propsReq),
|
|
43
|
+
]);
|
|
44
|
+
const [page, props] = await Promise.all([pageRes.text(), propsRes.text()]);
|
|
45
|
+
const pageTarget = join(outDir, 'client', path, 'index.html');
|
|
46
|
+
const propsTarget = join(outDir, 'client', '_props', path, 'index.json');
|
|
47
|
+
const pageDir = dirname(pageTarget);
|
|
48
|
+
const propsDir = dirname(propsTarget);
|
|
49
|
+
[pageDir, propsDir].forEach(dir => {
|
|
50
|
+
if (existsSync(dir))
|
|
51
|
+
return;
|
|
52
|
+
mkdirSync(dir, {
|
|
122
53
|
recursive: true,
|
|
123
54
|
});
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
console.log('[prerender]
|
|
55
|
+
});
|
|
56
|
+
await Promise.all([writeFile(pageTarget, page), writeFile(propsTarget, props)]);
|
|
57
|
+
console.log('[prerender] Prerendered page: ' + path);
|
|
127
58
|
}
|
|
128
59
|
const finishTime = performance.now();
|
|
129
60
|
customLogger?.info(chalk.green(`✓ pre-rendered in ${Math.ceil(finishTime - startTime)}ms`));
|