@nerest/nerest 0.0.9 → 1.5.0
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/LICENSE.md +178 -0
- package/README.md +148 -39
- package/bin/index.ts +3 -0
- package/bin/typegen.ts +35 -0
- package/bin/watch.ts +3 -2
- package/build/configs/development.ts +63 -0
- package/build/configs/production.ts +59 -0
- package/build/configs/shared.ts +51 -0
- package/build/configs/vite-logger.development.ts +30 -0
- package/build/index.ts +53 -76
- package/client/index.ts +14 -2
- package/dist/bin/index.js +4 -0
- package/dist/bin/typegen.d.ts +1 -0
- package/dist/bin/typegen.js +31 -0
- package/dist/bin/watch.js +1 -2
- package/dist/build/configs/development.d.ts +4 -0
- package/dist/build/configs/development.js +53 -0
- package/dist/build/configs/production.d.ts +4 -0
- package/dist/build/configs/production.js +50 -0
- package/dist/build/configs/shared.d.ts +10 -0
- package/dist/build/configs/shared.js +24 -0
- package/dist/build/configs/vite-logger.development.d.ts +2 -0
- package/dist/build/configs/vite-logger.development.js +25 -0
- package/dist/build/index.js +39 -69
- package/dist/client/index.js +9 -2
- package/dist/server/development.d.ts +1 -1
- package/dist/server/development.js +52 -130
- package/dist/server/hooks/logger.d.ts +1 -0
- package/dist/server/hooks/logger.js +24 -0
- package/dist/server/hooks/props.d.ts +2 -1
- package/dist/server/hooks/props.js +6 -4
- package/dist/server/hooks/runtime.js +3 -3
- package/dist/server/{parts → loaders}/apps.d.ts +2 -1
- package/dist/server/loaders/apps.js +36 -0
- package/dist/server/loaders/assets.js +25 -2
- package/dist/server/loaders/build.d.ts +2 -0
- package/dist/server/loaders/build.js +11 -0
- package/dist/server/loaders/examples.js +7 -13
- package/dist/server/loaders/manifest.d.ts +8 -1
- package/dist/server/loaders/manifest.js +12 -4
- package/dist/server/loaders/preview.d.ts +4 -0
- package/dist/server/loaders/preview.js +11 -0
- package/dist/server/loaders/project.d.ts +16 -0
- package/dist/server/loaders/project.js +11 -0
- package/dist/server/loaders/schema.d.ts +2 -1
- package/dist/server/loaders/schema.js +12 -8
- package/dist/server/parts/k8s-probes.js +10 -6
- package/dist/server/parts/preview.d.ts +2 -1
- package/dist/server/parts/preview.js +5 -4
- package/dist/server/parts/render.d.ts +5 -3
- package/dist/server/parts/render.js +8 -8
- package/dist/server/parts/swagger.d.ts +2 -1
- package/dist/server/parts/swagger.js +8 -19
- package/dist/server/parts/validator.d.ts +3 -1
- package/dist/server/parts/validator.js +13 -0
- package/dist/server/production.js +17 -80
- package/dist/server/shared.d.ts +14 -0
- package/dist/server/shared.js +94 -0
- package/dist/server/utils.d.ts +1 -0
- package/dist/server/utils.js +5 -0
- package/package.json +46 -43
- package/schemas/nerest-build.schema.d.ts +19 -1
- package/schemas/nerest-build.schema.json +21 -1
- package/server/development.ts +67 -164
- package/server/hooks/logger.ts +31 -0
- package/server/hooks/props.ts +11 -6
- package/server/hooks/runtime.ts +3 -3
- package/server/loaders/apps.ts +58 -0
- package/server/loaders/assets.ts +30 -2
- package/server/loaders/build.ts +14 -0
- package/server/loaders/examples.ts +7 -15
- package/server/loaders/manifest.ts +23 -4
- package/server/loaders/preview.ts +17 -0
- package/server/loaders/project.ts +33 -0
- package/server/loaders/schema.ts +12 -10
- package/server/parts/k8s-probes.ts +26 -13
- package/server/parts/preview.ts +11 -4
- package/server/parts/render.ts +13 -9
- package/server/parts/swagger.ts +10 -29
- package/server/parts/validator.ts +14 -0
- package/server/production.ts +22 -106
- package/server/shared.ts +150 -0
- package/server/utils.ts +6 -0
- package/dist/server/parts/apps.js +0 -37
- package/dist/server/parts/props-hook.d.ts +0 -1
- package/dist/server/parts/props-hook.js +0 -8
- package/dist/server/parts/runtime-hook.d.ts +0 -2
- package/dist/server/parts/runtime-hook.js +0 -28
- package/server/parts/apps.ts +0 -59
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
import
|
|
1
|
+
import type { ComponentType } from 'react';
|
|
2
|
+
import type { Project } from '../loaders/project.js';
|
|
2
3
|
type RenderProps = {
|
|
3
4
|
name: string;
|
|
4
5
|
assets: string[];
|
|
5
|
-
component:
|
|
6
|
+
component: ComponentType;
|
|
7
|
+
project: Project;
|
|
6
8
|
};
|
|
7
|
-
export declare function renderApp({ name, assets, component }: RenderProps, props?: Record<string, unknown>): {
|
|
9
|
+
export declare function renderApp({ name, assets, component, project }: RenderProps, props?: Record<string, unknown>): {
|
|
8
10
|
html: string;
|
|
9
11
|
assets: string[];
|
|
10
12
|
};
|
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { createElement } from 'react';
|
|
2
2
|
import { renderToString } from 'react-dom/server';
|
|
3
|
-
import {
|
|
4
|
-
export function renderApp({ name, assets, component }, props = {}) {
|
|
5
|
-
const html = renderSsrComponent(name, component, props);
|
|
3
|
+
import { randomId } from '../utils.js';
|
|
4
|
+
export function renderApp({ name, assets, component, project }, props = {}) {
|
|
5
|
+
const html = renderSsrComponent(name, component, project, props);
|
|
6
6
|
return { html, assets };
|
|
7
7
|
}
|
|
8
|
-
function renderSsrComponent(appName, appComponent, props) {
|
|
9
|
-
const html = renderToString(
|
|
8
|
+
function renderSsrComponent(appName, appComponent, project, props) {
|
|
9
|
+
const html = renderToString(createElement(appComponent, props));
|
|
10
10
|
// There may be multiple instances of the same app on the page,
|
|
11
11
|
// so we will use a randomized id to avoid collisions
|
|
12
|
-
const appId =
|
|
12
|
+
const appId = randomId();
|
|
13
13
|
// data-app-name and data-app-id are used by client entrypoint to hydrate
|
|
14
14
|
// apps using correct serialized props
|
|
15
|
-
const container = `<div data-app-name="${appName}" data-app-id="${appId}">${html}</div>`;
|
|
15
|
+
const container = `<div data-project-name="${project.name}" data-app-name="${appName}" data-app-id="${appId}">${html}</div>`;
|
|
16
16
|
const script = `<script type="application/json" data-app-id="${appId}">${JSON.stringify(props)}</script>`;
|
|
17
17
|
return container + script;
|
|
18
18
|
}
|
|
@@ -1,2 +1,3 @@
|
|
|
1
1
|
import type { FastifyInstance } from 'fastify';
|
|
2
|
-
|
|
2
|
+
import type { Project } from '../loaders/project.js';
|
|
3
|
+
export declare function setupSwagger(app: FastifyInstance, project: Project): Promise<void>;
|
|
@@ -1,29 +1,18 @@
|
|
|
1
|
-
import path from 'path';
|
|
2
|
-
import fs from 'fs';
|
|
3
1
|
import fastifySwagger from '@fastify/swagger';
|
|
4
2
|
import fastifySwaggerUi from '@fastify/swagger-ui';
|
|
5
3
|
// Setup automatic OpenAPI specification compilation and enable
|
|
6
4
|
// Swagger UI at the `/api` route
|
|
7
|
-
export async function setupSwagger(app) {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
}
|
|
13
|
-
catch (e) {
|
|
14
|
-
// We only use package.json info to setup Swagger info and links,
|
|
15
|
-
// if we are unable to load them -- that's fine
|
|
16
|
-
}
|
|
17
|
-
const homepage = appInfo.homepage ||
|
|
18
|
-
(typeof appInfo.repository === 'string'
|
|
19
|
-
? appInfo.repository
|
|
20
|
-
: appInfo.repository?.url);
|
|
5
|
+
export async function setupSwagger(app, project) {
|
|
6
|
+
const homepage = project.homepage ||
|
|
7
|
+
(typeof project.repository === 'string'
|
|
8
|
+
? project.repository
|
|
9
|
+
: project.repository?.url);
|
|
21
10
|
await app.register(fastifySwagger, {
|
|
22
11
|
openapi: {
|
|
23
12
|
info: {
|
|
24
|
-
title:
|
|
25
|
-
description:
|
|
26
|
-
version:
|
|
13
|
+
title: project.name || 'Nerest micro frontend',
|
|
14
|
+
description: project.description,
|
|
15
|
+
version: project.version ?? '',
|
|
27
16
|
contact: homepage
|
|
28
17
|
? {
|
|
29
18
|
name: 'Homepage',
|
|
@@ -18,3 +18,16 @@ export const validator = new Ajv.default({
|
|
|
18
18
|
// `email`, `url`, etc. Used by default in fastify
|
|
19
19
|
// https://www.npmjs.com/package/ajv-formats
|
|
20
20
|
addFormats.default(validator);
|
|
21
|
+
// Setup schema validation. We have to use our own ajv instance that
|
|
22
|
+
// we can use both to validate request bodies and examples against
|
|
23
|
+
// app schemas
|
|
24
|
+
export function setupValidator(app) {
|
|
25
|
+
if (process.env.DISABLE_SCHEMA_VALIDATION) {
|
|
26
|
+
// If schema validation is disabled, return data as is without any checks
|
|
27
|
+
app.setValidatorCompiler(() => (data) => ({ value: data }));
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
// If schema validation is enabled, validate and coerce data via ajv
|
|
31
|
+
app.setValidatorCompiler(({ schema }) => validator.compile(schema));
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -1,22 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
import
|
|
5
|
-
|
|
6
|
-
import { renderApp } from './parts/render.js';
|
|
7
|
-
import { setupSwagger } from './parts/swagger.js';
|
|
8
|
-
import { validator } from './parts/validator.js';
|
|
9
|
-
import { renderPreviewPage } from './parts/preview.js';
|
|
10
|
-
import { setupK8SProbes } from './parts/k8s-probes.js';
|
|
11
|
-
import { runRuntimeHook } from './hooks/runtime.js';
|
|
12
|
-
import { runPropsHook } from './hooks/props.js';
|
|
13
|
-
// TODO: refactor to merge the similar parts between production and development server?
|
|
14
|
-
async function runProductionServer() {
|
|
1
|
+
import { createServer } from './shared.js';
|
|
2
|
+
import { loadNerestManifest } from './loaders/manifest.js';
|
|
3
|
+
// Important: this file is the server entrypoint that will be built by vite
|
|
4
|
+
// in `build/index.ts`. All of the import.meta.glob's will be resolved at build time
|
|
5
|
+
async function runProductionServer(port) {
|
|
15
6
|
const root = process.cwd();
|
|
16
|
-
//
|
|
17
|
-
const apps =
|
|
18
|
-
encoding: 'utf-8',
|
|
19
|
-
}));
|
|
7
|
+
// Load project information from the manifest generated during production build
|
|
8
|
+
const { project, apps } = await loadNerestManifest(root);
|
|
20
9
|
const components = import.meta.glob('/apps/*/index.tsx', {
|
|
21
10
|
import: 'default',
|
|
22
11
|
eager: true,
|
|
@@ -24,70 +13,18 @@ async function runProductionServer() {
|
|
|
24
13
|
const propsHooks = import.meta.glob('/apps/*/props.ts', {
|
|
25
14
|
eager: true,
|
|
26
15
|
});
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
const component = components[`/apps/${name}/index.tsx`];
|
|
36
|
-
const propsHook = async () => propsHooks[`/apps/${name}/props.ts`];
|
|
37
|
-
const routeOptions = {};
|
|
38
|
-
// TODO: report error if schema is missing, unless this app is client-only
|
|
39
|
-
// TODO: disallow apps without schemas in production build
|
|
40
|
-
if (schema) {
|
|
41
|
-
routeOptions.schema = {
|
|
42
|
-
// Use description as Swagger summary, since summary is visible
|
|
43
|
-
// even when the route is collapsed in the UI
|
|
44
|
-
summary: schema.description,
|
|
45
|
-
// TODO: do we need to mix in examples like in the development server?
|
|
46
|
-
body: schema,
|
|
47
|
-
};
|
|
48
|
-
}
|
|
49
|
-
// POST /api/{name} -> render app with request.body as props
|
|
50
|
-
app.post(`/api/${name}`, routeOptions, async (request) => {
|
|
51
|
-
const props = await runPropsHook(request.body, propsHook);
|
|
52
|
-
return renderApp({ name, assets, component }, props);
|
|
53
|
-
});
|
|
54
|
-
for (const [exampleName, example] of Object.entries(examples)) {
|
|
55
|
-
// GET /api/{name}/examples/{example} -> render a preview page
|
|
56
|
-
// with a predefined example body
|
|
57
|
-
const exampleRoute = `/api/${name}/examples/${exampleName}`;
|
|
58
|
-
app.get(exampleRoute, {
|
|
59
|
-
schema: {
|
|
60
|
-
// Add a clickable link to the example route in route's Swagger
|
|
61
|
-
// description so it's easier to navigate to
|
|
62
|
-
description: `Open sandbox: [${exampleRoute}](${exampleRoute})`,
|
|
63
|
-
},
|
|
64
|
-
}, async (_, reply) => {
|
|
65
|
-
const props = await runPropsHook(example, propsHook);
|
|
66
|
-
const { html, assets: outAssets } = renderApp({
|
|
67
|
-
name,
|
|
68
|
-
assets,
|
|
69
|
-
component,
|
|
70
|
-
}, props);
|
|
71
|
-
reply.type('text/html');
|
|
72
|
-
return renderPreviewPage(html, outAssets);
|
|
73
|
-
});
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
// Add graceful shutdown handler to prevent requests errors
|
|
77
|
-
await app.register(fastifyGracefulShutdown);
|
|
78
|
-
if (process.env.ENABLE_K8S_PROBES) {
|
|
79
|
-
await setupK8SProbes(app);
|
|
80
|
-
}
|
|
81
|
-
// Execute runtime hook in nerest-runtime.ts if it exists
|
|
82
|
-
await runRuntimeHook(app, async () => {
|
|
83
|
-
const glob = import.meta.glob('/nerest-runtime.ts', { eager: true });
|
|
84
|
-
return glob['/nerest-runtime.ts'];
|
|
16
|
+
const runtimeHook = import.meta.glob('/nerest/runtime.ts', { eager: true });
|
|
17
|
+
const app = await createServer({
|
|
18
|
+
root,
|
|
19
|
+
project,
|
|
20
|
+
apps,
|
|
21
|
+
loadComponent: async (entry) => components[`/apps/${entry}/index.tsx`],
|
|
22
|
+
loadPropsHook: async (entry) => propsHooks[`/apps/${entry}/props.ts`],
|
|
23
|
+
loadRuntimeHook: async () => runtimeHook['/nerest/runtime.ts'],
|
|
85
24
|
});
|
|
86
|
-
// TODO: remove hardcoded port
|
|
87
25
|
await app.listen({
|
|
88
26
|
host: '0.0.0.0',
|
|
89
|
-
port
|
|
27
|
+
port,
|
|
90
28
|
});
|
|
91
|
-
console.log('Nerest is listening on 0.0.0.0:3000');
|
|
92
29
|
}
|
|
93
|
-
runProductionServer();
|
|
30
|
+
runProductionServer(process.env.PORT ? Number(process.env.PORT) : 3000);
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import fastify from 'fastify';
|
|
2
|
+
import type { ComponentType } from 'react';
|
|
3
|
+
import type { Project } from './loaders/project.js';
|
|
4
|
+
import type { AppEntry } from './loaders/apps.js';
|
|
5
|
+
type ServerOptions = {
|
|
6
|
+
root: string;
|
|
7
|
+
project: Project;
|
|
8
|
+
apps: Record<string, AppEntry>;
|
|
9
|
+
loadComponent: (entry: string) => Promise<ComponentType>;
|
|
10
|
+
loadPropsHook: (entry: string) => Promise<unknown>;
|
|
11
|
+
loadRuntimeHook: () => Promise<unknown>;
|
|
12
|
+
};
|
|
13
|
+
export declare function createServer(options: ServerOptions): Promise<fastify.FastifyInstance<fastify.RawServerDefault, import("http").IncomingMessage, import("http").ServerResponse<import("http").IncomingMessage>, fastify.FastifyBaseLogger, fastify.FastifyTypeProviderDefault>>;
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import fastify from 'fastify';
|
|
2
|
+
import fastifyGracefulShutdown from 'fastify-graceful-shutdown';
|
|
3
|
+
import { renderApp } from './parts/render.js';
|
|
4
|
+
import { setupSwagger } from './parts/swagger.js';
|
|
5
|
+
import { setupValidator, validator } from './parts/validator.js';
|
|
6
|
+
import { renderPreviewPage } from './parts/preview.js';
|
|
7
|
+
import { setupK8SProbes } from './parts/k8s-probes.js';
|
|
8
|
+
import { runRuntimeHook } from './hooks/runtime.js';
|
|
9
|
+
import { runPropsHook } from './hooks/props.js';
|
|
10
|
+
import { runLoggerHook } from './hooks/logger.js';
|
|
11
|
+
import { loadPreviewParts } from './loaders/preview.js';
|
|
12
|
+
import { randomId } from './utils.js';
|
|
13
|
+
export async function createServer(options) {
|
|
14
|
+
const { project, root, loadRuntimeHook } = options;
|
|
15
|
+
const app = fastify({
|
|
16
|
+
logger: (await runLoggerHook(loadRuntimeHook)) ?? true,
|
|
17
|
+
ignoreTrailingSlash: true,
|
|
18
|
+
useSemicolonDelimiter: false,
|
|
19
|
+
// JSON parsing can take a long time and blocks the event loop,
|
|
20
|
+
// so we need to limit the size of the body. 10MB is a good compromise
|
|
21
|
+
// baseline that was chosen by experimenting with real world usage
|
|
22
|
+
bodyLimit: 10 * 1024 * 1024,
|
|
23
|
+
genReqId(req) {
|
|
24
|
+
return String(req.headers['x-request-id'] || randomId());
|
|
25
|
+
},
|
|
26
|
+
});
|
|
27
|
+
// Setup payload validation and Swagger based on apps' JSON Schema
|
|
28
|
+
setupValidator(app);
|
|
29
|
+
await setupSwagger(app, project);
|
|
30
|
+
// Load preview parts from `nerest/preview-{part}.html` files
|
|
31
|
+
const previewParts = await loadPreviewParts(root);
|
|
32
|
+
await setupRoutes(app, { ...options, previewParts });
|
|
33
|
+
// Add graceful shutdown handler to prevent requests errors
|
|
34
|
+
await app.register(fastifyGracefulShutdown);
|
|
35
|
+
if (process.env.ENABLE_K8S_PROBES) {
|
|
36
|
+
await setupK8SProbes(app);
|
|
37
|
+
}
|
|
38
|
+
// Execute runtime hook in nerest/runtime.ts if it exists
|
|
39
|
+
await runRuntimeHook(app, loadRuntimeHook);
|
|
40
|
+
return app;
|
|
41
|
+
}
|
|
42
|
+
async function setupRoutes(app, options) {
|
|
43
|
+
const { project, apps, previewParts, loadComponent, loadPropsHook } = options;
|
|
44
|
+
for (const appEntry of Object.values(apps)) {
|
|
45
|
+
const { name, examples, schema, assets } = appEntry;
|
|
46
|
+
const routeOptions = {};
|
|
47
|
+
// TODO: report error if schema is missing, making it mandatory
|
|
48
|
+
if (schema) {
|
|
49
|
+
routeOptions.schema = {
|
|
50
|
+
summary: schema.description,
|
|
51
|
+
// Tags are used to group routes in Swagger UI
|
|
52
|
+
tags: [name],
|
|
53
|
+
body: {
|
|
54
|
+
...schema,
|
|
55
|
+
// Examples are also displayed in Swagger UI
|
|
56
|
+
examples: Object.values(examples),
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
// POST /api/{name} -> render app with request.body as props
|
|
61
|
+
app.post(`/api/${name}`, routeOptions, async (request) => {
|
|
62
|
+
const component = await loadComponent(name);
|
|
63
|
+
const props = await runPropsHook(app, () => loadPropsHook(name), request.body);
|
|
64
|
+
return renderApp({ name, assets, component, project }, props);
|
|
65
|
+
});
|
|
66
|
+
for (const [exampleName, example] of Object.entries(examples)) {
|
|
67
|
+
// Validate examples against schema
|
|
68
|
+
if (schema && !validator.validate(schema, example)) {
|
|
69
|
+
app.log.error(`Example "${exampleName}" of app "${name}" does not satisfy schema: ${validator.errorsText()}`);
|
|
70
|
+
}
|
|
71
|
+
// GET /api/{name}/examples/{example} -> render a preview page
|
|
72
|
+
const exampleRoute = `/api/${name}/examples/${exampleName}`;
|
|
73
|
+
app.get(exampleRoute, {
|
|
74
|
+
schema: {
|
|
75
|
+
// Add clickable link to go to the example in Swagger UI
|
|
76
|
+
description: `Open sandbox: [${exampleRoute}](${exampleRoute})`,
|
|
77
|
+
// Place examples under the same tag as the app
|
|
78
|
+
tags: [name],
|
|
79
|
+
},
|
|
80
|
+
}, async (request, reply) => {
|
|
81
|
+
const component = await loadComponent(name);
|
|
82
|
+
const props = await runPropsHook(app, () => loadPropsHook(name), example);
|
|
83
|
+
const { html, assets: outAssets } = renderApp({
|
|
84
|
+
name,
|
|
85
|
+
assets,
|
|
86
|
+
component,
|
|
87
|
+
project,
|
|
88
|
+
}, props);
|
|
89
|
+
reply.type('text/html');
|
|
90
|
+
return renderPreviewPage(html, outAssets, previewParts);
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function randomId(): string;
|
package/package.json
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nerest/nerest",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "1.5.0",
|
|
4
4
|
"description": "React micro frontend framework",
|
|
5
|
-
"homepage": "https://github.com/nerestjs/nerest
|
|
5
|
+
"homepage": "https://github.com/nerestjs/nerest",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
8
8
|
"url": "https://github.com/nerestjs/nerest.git"
|
|
9
9
|
},
|
|
10
|
+
"license": "Apache-2.0",
|
|
10
11
|
"type": "module",
|
|
11
12
|
"bin": {
|
|
12
13
|
"nerest": "dist/bin/index.js"
|
|
@@ -18,16 +19,23 @@
|
|
|
18
19
|
"/client",
|
|
19
20
|
"/schemas",
|
|
20
21
|
"/server",
|
|
21
|
-
"/README.md"
|
|
22
|
+
"/README.md",
|
|
23
|
+
"/LICENSE.md"
|
|
22
24
|
],
|
|
23
25
|
"scripts": {
|
|
24
26
|
"build": "tsc -p tsconfig.json -d",
|
|
25
|
-
"
|
|
27
|
+
"docs": "scripts/docs.sh",
|
|
28
|
+
"lint": "eslint --ext .ts .",
|
|
26
29
|
"prepare": "simple-git-hooks",
|
|
30
|
+
"test": "npm run test:module && npm run test:integration:dev && npm run test:integration:prod",
|
|
31
|
+
"test:integration:dev": "node tests/integration/run.development.js",
|
|
32
|
+
"test:integration:prod": "node tests/integration/run.production.js",
|
|
33
|
+
"test:module": "vitest run tests/module/**",
|
|
27
34
|
"typegen": "json2ts -i 'schemas/**/*.json' -o schemas --bannerComment ''"
|
|
28
35
|
},
|
|
29
36
|
"simple-git-hooks": {
|
|
30
|
-
"pre-commit": "npx lint-staged"
|
|
37
|
+
"pre-commit": "npx lint-staged",
|
|
38
|
+
"commit-msg": "npx commitlint --edit ${1}"
|
|
31
39
|
},
|
|
32
40
|
"lint-staged": {
|
|
33
41
|
"*.ts": [
|
|
@@ -41,51 +49,46 @@
|
|
|
41
49
|
"sort-package-json"
|
|
42
50
|
]
|
|
43
51
|
},
|
|
44
|
-
"prettier": "@tinkoff/prettier-config",
|
|
45
|
-
"eslintConfig": {
|
|
46
|
-
"parserOptions": {
|
|
47
|
-
"project": true
|
|
48
|
-
},
|
|
49
|
-
"extends": [
|
|
50
|
-
"@tinkoff/eslint-config/lib",
|
|
51
|
-
"@tinkoff/eslint-config/jest",
|
|
52
|
-
"@tinkoff/eslint-config-react"
|
|
53
|
-
]
|
|
54
|
-
},
|
|
55
52
|
"dependencies": {
|
|
56
|
-
"@
|
|
57
|
-
"@fastify/
|
|
58
|
-
"@fastify/
|
|
59
|
-
"
|
|
60
|
-
"
|
|
61
|
-
"
|
|
62
|
-
"
|
|
63
|
-
"
|
|
64
|
-
"
|
|
65
|
-
"
|
|
66
|
-
"
|
|
53
|
+
"@apidevtools/json-schema-ref-parser": "^11.9.3",
|
|
54
|
+
"@fastify/middie": "^9.0.3",
|
|
55
|
+
"@fastify/static": "^8.1.1",
|
|
56
|
+
"@fastify/swagger": "^9.4.2",
|
|
57
|
+
"@fastify/swagger-ui": "^5.2.2",
|
|
58
|
+
"ajv": "^8.17.1",
|
|
59
|
+
"ajv-formats": "^3.0.1",
|
|
60
|
+
"dotenv": "^16.4.7",
|
|
61
|
+
"fast-glob": "^3.3.3",
|
|
62
|
+
"fast-uri": "^3.0.6",
|
|
63
|
+
"fastify": "^5.2.1",
|
|
64
|
+
"fastify-graceful-shutdown": "^4.0.1",
|
|
65
|
+
"json-schema-to-typescript": "^15.0.4",
|
|
66
|
+
"vite": "^6.2.2",
|
|
67
67
|
"vite-plugin-externals": "^0.6.2"
|
|
68
68
|
},
|
|
69
69
|
"devDependencies": {
|
|
70
|
-
"@
|
|
71
|
-
"@
|
|
72
|
-
"@
|
|
73
|
-
"@
|
|
74
|
-
"@
|
|
75
|
-
"
|
|
76
|
-
"
|
|
77
|
-
"
|
|
78
|
-
"
|
|
79
|
-
"
|
|
80
|
-
"
|
|
81
|
-
"
|
|
82
|
-
"
|
|
70
|
+
"@commitlint/cli": "^19.8.0",
|
|
71
|
+
"@commitlint/config-conventional": "^19.8.0",
|
|
72
|
+
"@playwright/test": "^1.51.0",
|
|
73
|
+
"@tinkoff/eslint-config": "^5.0.1",
|
|
74
|
+
"@tinkoff/eslint-config-react": "^5.0.1",
|
|
75
|
+
"@tinkoff/prettier-config": "^5.0.0",
|
|
76
|
+
"@types/react": "^19.0.10",
|
|
77
|
+
"@types/react-dom": "^19.0.4",
|
|
78
|
+
"execa": "^9.5.2",
|
|
79
|
+
"lint-staged": "^15.5.0",
|
|
80
|
+
"react": "^19.0.0",
|
|
81
|
+
"react-dom": "^19.0.0",
|
|
82
|
+
"simple-git-hooks": "^2.11.1",
|
|
83
|
+
"sort-package-json": "^3.0.0",
|
|
84
|
+
"typescript": "^5.8.2",
|
|
85
|
+
"vitest": "^3.0.8"
|
|
83
86
|
},
|
|
84
87
|
"peerDependencies": {
|
|
85
|
-
"react": "^18.0.0",
|
|
86
|
-
"react-dom": "^18.0.0"
|
|
88
|
+
"react": "^18.0.0 || ^19.0.0",
|
|
89
|
+
"react-dom": "^18.0.0 || ^19.0.0"
|
|
87
90
|
},
|
|
88
91
|
"engines": {
|
|
89
|
-
"node": ">=
|
|
92
|
+
"node": ">=v20.17.0"
|
|
90
93
|
}
|
|
91
94
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Build configuration placed as nerest
|
|
2
|
+
* Build configuration placed as nerest/build.json in the root of the application.
|
|
3
3
|
*/
|
|
4
4
|
export interface BuildConfiguration {
|
|
5
5
|
/**
|
|
@@ -12,5 +12,23 @@ export interface BuildConfiguration {
|
|
|
12
12
|
externals?: {
|
|
13
13
|
[k: string]: string;
|
|
14
14
|
};
|
|
15
|
+
/**
|
|
16
|
+
* Additional PostCSS configuration. Nerest uses the standard vite PostCSS configuration by default.
|
|
17
|
+
*/
|
|
18
|
+
postcss?: {
|
|
19
|
+
/**
|
|
20
|
+
* List packages and options of PostCSS plugins to use. They will be added to the default plugin list.
|
|
21
|
+
*/
|
|
22
|
+
plugins?: {
|
|
23
|
+
[k: string]: {
|
|
24
|
+
[k: string]: unknown;
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
[k: string]: unknown;
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* List of names of apps that have client side-effects, for example have their own self-initialization code that runs on import. Their entries will be loaded when hydration starts to run side-effect code.
|
|
31
|
+
*/
|
|
32
|
+
clientSideEffects?: string[];
|
|
15
33
|
[k: string]: unknown;
|
|
16
34
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json-schema.org/draft-07/schema",
|
|
3
3
|
"title": "Build Configuration",
|
|
4
|
-
"description": "Build configuration placed as nerest
|
|
4
|
+
"description": "Build configuration placed as nerest/build.json in the root of the application.",
|
|
5
5
|
"type": "object",
|
|
6
6
|
"properties": {
|
|
7
7
|
"excludes": {
|
|
@@ -17,6 +17,26 @@
|
|
|
17
17
|
"additionalProperties": {
|
|
18
18
|
"type": "string"
|
|
19
19
|
}
|
|
20
|
+
},
|
|
21
|
+
"postcss": {
|
|
22
|
+
"description": "Additional PostCSS configuration. Nerest uses the standard vite PostCSS configuration by default.",
|
|
23
|
+
"type": "object",
|
|
24
|
+
"properties": {
|
|
25
|
+
"plugins": {
|
|
26
|
+
"description": "List packages and options of PostCSS plugins to use. They will be added to the default plugin list.",
|
|
27
|
+
"type": "object",
|
|
28
|
+
"additionalProperties": {
|
|
29
|
+
"type": "object"
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
"clientSideEffects": {
|
|
35
|
+
"description": "List of names of apps that have client side-effects, for example have their own self-initialization code that runs on import. Their entries will be loaded when hydration starts to run side-effect code.",
|
|
36
|
+
"type": "array",
|
|
37
|
+
"items": {
|
|
38
|
+
"type": "string"
|
|
39
|
+
}
|
|
20
40
|
}
|
|
21
41
|
}
|
|
22
42
|
}
|