@nerest/nerest 0.0.7 → 0.0.9

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.
Files changed (43) hide show
  1. package/README.md +15 -0
  2. package/bin/build.ts +1 -1
  3. package/bin/index.ts +2 -2
  4. package/bin/watch.ts +1 -1
  5. package/build/index.ts +6 -6
  6. package/client/index.ts +5 -1
  7. package/dist/bin/build.js +3 -7
  8. package/dist/bin/index.js +5 -7
  9. package/dist/bin/watch.js +3 -7
  10. package/dist/build/excludes/index.js +1 -5
  11. package/dist/build/index.js +17 -24
  12. package/dist/client/index.d.ts +1 -0
  13. package/dist/client/index.js +32 -0
  14. package/dist/server/development.js +35 -39
  15. package/dist/server/hooks/props.d.ts +1 -0
  16. package/dist/server/hooks/props.js +12 -0
  17. package/dist/server/hooks/runtime.d.ts +2 -0
  18. package/dist/server/hooks/runtime.js +28 -0
  19. package/dist/server/loaders/assets.js +1 -5
  20. package/dist/server/loaders/examples.js +10 -17
  21. package/dist/server/loaders/manifest.js +5 -12
  22. package/dist/server/loaders/schema.js +7 -14
  23. package/dist/server/parts/apps.d.ts +1 -0
  24. package/dist/server/parts/apps.js +16 -22
  25. package/dist/server/parts/k8s-probes.js +1 -5
  26. package/dist/server/parts/preview.js +1 -5
  27. package/dist/server/parts/props-hook.d.ts +1 -0
  28. package/dist/server/parts/props-hook.js +8 -0
  29. package/dist/server/parts/render.js +6 -13
  30. package/dist/server/parts/runtime-hook.d.ts +1 -1
  31. package/dist/server/parts/runtime-hook.js +1 -5
  32. package/dist/server/parts/swagger.js +8 -15
  33. package/dist/server/parts/validator.d.ts +1 -1
  34. package/dist/server/parts/validator.js +9 -12
  35. package/dist/server/production.d.ts +1 -0
  36. package/dist/server/production.js +93 -0
  37. package/package.json +4 -3
  38. package/server/development.ts +20 -13
  39. package/server/hooks/props.ts +22 -0
  40. package/server/{parts/runtime-hook.ts → hooks/runtime.ts} +1 -1
  41. package/server/parts/apps.ts +6 -4
  42. package/server/parts/validator.ts +5 -2
  43. package/server/production.ts +19 -15
package/README.md CHANGED
@@ -37,6 +37,21 @@ The app directory should contain a `schema.json` file that describes the schema
37
37
 
38
38
  OpenAPI specification is compiled automatically based on the provided schemas and becomes available at `/api/json`. It can also be explored through Swagger UI that becomes available at `/api`.
39
39
 
40
+ ### Props Hook (`/props.ts`)
41
+
42
+ The app directory may contain a `props.ts` module that exports a default function. If it exists, this function will be executed on the server for every incoming request, receiving a single object as an argument -- the body of the request. You can use this hook to modify and return a new object, which will be passed down to the `index.tsx` entrypoint component instead. For example:
43
+
44
+ ```typescript
45
+ export default function (props: Props) {
46
+ return {
47
+ ...props,
48
+ greeting: `${props.greeting} (modified in props.ts)`,
49
+ };
50
+ }
51
+ ```
52
+
53
+ The exported function may be async, in which case nerest will wait for the Promise to resolve, then pass the result object to the entrypoint component.
54
+
40
55
  ## Configuration
41
56
 
42
57
  Different aspects of Nerest apps can be configured via environment variables, JSON configuration and runtime hooks written in TypeScript. Examples of all kinds of configuration can be viewed in the [nerest-harness](https://gitlab.tcsbank.ru/tj/nerest-harness) repository.
package/bin/build.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { buildMicroFrontend } from '../build';
1
+ import { buildMicroFrontend } from '../build/index.js';
2
2
 
3
3
  // Produce the production build of the Nerest micro frontend
4
4
  export async function build() {
package/bin/index.ts CHANGED
@@ -2,8 +2,8 @@
2
2
  // All executions of `nerest <command>` get routed through here
3
3
  import 'dotenv/config';
4
4
 
5
- import { build } from './build';
6
- import { watch } from './watch';
5
+ import { build } from './build.js';
6
+ import { watch } from './watch.js';
7
7
 
8
8
  // TODO: add CLI help and manual, maybe use a CLI framework like oclif
9
9
  async function cliEntry(args: string[]) {
package/bin/watch.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { runDevelopmentServer } from '../server/development';
1
+ import { runDevelopmentServer } from '../server/development.js';
2
2
 
3
3
  // Start dev server in watch mode, that restarts on file change
4
4
  // and rebuilds the client static files
package/build/index.ts CHANGED
@@ -2,13 +2,13 @@ import path from 'path';
2
2
  import fs from 'fs/promises';
3
3
  import { existsSync } from 'fs';
4
4
 
5
- import vite from 'vite';
5
+ import { build } from 'vite';
6
6
  import type { InlineConfig } from 'vite';
7
7
  import { viteExternalsPlugin } from 'vite-plugin-externals';
8
8
 
9
- import { loadApps } from '../server/parts/apps';
10
- import type { BuildConfiguration } from '../schemas/nerest-build.schema';
11
- import { excludes } from './excludes';
9
+ import { loadApps } from '../server/parts/apps.js';
10
+ import type { BuildConfiguration } from '../schemas/nerest-build.schema.js';
11
+ import { excludes } from './excludes/index.js';
12
12
 
13
13
  export async function buildMicroFrontend() {
14
14
  const root = process.cwd();
@@ -57,7 +57,7 @@ export async function buildMicroFrontend() {
57
57
  };
58
58
 
59
59
  console.log('Producing production client build...');
60
- await vite.build(clientConfig);
60
+ await build(clientConfig);
61
61
 
62
62
  console.log('Producing Nerest manifest file...');
63
63
  await buildAppsManifest(root, staticPath);
@@ -83,7 +83,7 @@ export async function buildMicroFrontend() {
83
83
  };
84
84
 
85
85
  console.log('Producing production server build...');
86
- await vite.build(serverConfig);
86
+ await build(serverConfig);
87
87
  }
88
88
 
89
89
  async function buildAppsManifest(root: string, staticPath: string) {
package/client/index.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  // Shared client entrypoint that bootstraps all of the apps supplied
2
2
  // by current microfrontend
3
3
  import React from 'react';
4
+ import type { ComponentType } from 'react';
4
5
  import ReactDOM from 'react-dom/client';
5
6
 
6
7
  // Since this is a shared entrypoint, it dynamically imports all of the
@@ -28,7 +29,10 @@ async function runHydration() {
28
29
  // TODO: more robust error handling and error logging
29
30
  const props = JSON.parse(propsContainer?.textContent ?? '{}');
30
31
 
31
- const reactElement = React.createElement(await appModuleLoader(), props);
32
+ const reactElement = React.createElement(
33
+ (await appModuleLoader()) as ComponentType,
34
+ props
35
+ );
32
36
  ReactDOM.hydrateRoot(container, reactElement);
33
37
  }
34
38
  }
package/dist/bin/build.js CHANGED
@@ -1,11 +1,7 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.build = void 0;
4
- const build_1 = require("../build");
1
+ import { buildMicroFrontend } from '../build/index.js';
5
2
  // Produce the production build of the Nerest micro frontend
6
- async function build() {
3
+ export async function build() {
7
4
  console.log('Nerest is preparing production build...');
8
- await (0, build_1.buildMicroFrontend)();
5
+ await buildMicroFrontend();
9
6
  console.log('Nerest build is finished');
10
7
  }
11
- exports.build = build;
package/dist/bin/index.js CHANGED
@@ -1,17 +1,15 @@
1
1
  #!/usr/bin/env node
2
- "use strict";
3
- Object.defineProperty(exports, "__esModule", { value: true });
4
2
  // All executions of `nerest <command>` get routed through here
5
- require("dotenv/config");
6
- const build_1 = require("./build");
7
- const watch_1 = require("./watch");
3
+ import 'dotenv/config';
4
+ import { build } from './build.js';
5
+ import { watch } from './watch.js';
8
6
  // TODO: add CLI help and manual, maybe use a CLI framework like oclif
9
7
  async function cliEntry(args) {
10
8
  if (args[0] === 'build') {
11
- await (0, build_1.build)();
9
+ await build();
12
10
  }
13
11
  else if (args[0] === 'watch') {
14
- await (0, watch_1.watch)();
12
+ await watch();
15
13
  }
16
14
  }
17
15
  // [<path to node>, <path to nerest binary>, ...args]
package/dist/bin/watch.js CHANGED
@@ -1,12 +1,8 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.watch = void 0;
4
- const development_1 = require("../server/development");
1
+ import { runDevelopmentServer } from '../server/development.js';
5
2
  // Start dev server in watch mode, that restarts on file change
6
3
  // and rebuilds the client static files
7
- async function watch() {
4
+ export async function watch() {
8
5
  // TODO: will be replaced with nerest logger
9
6
  console.log('Starting Nerest watch...');
10
- await (0, development_1.runDevelopmentServer)();
7
+ await runDevelopmentServer();
11
8
  }
12
- exports.watch = watch;
@@ -1,11 +1,8 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.excludes = void 0;
4
1
  /**
5
2
  * Maps list of imports into a list of rollup aliases that resolve
6
3
  * into an empty module.
7
4
  */
8
- function excludes(list) {
5
+ export function excludes(list) {
9
6
  return list?.map((exclude) => ({
10
7
  // Excluding '@some/package' should exclude both '@some/package' and
11
8
  // '@some/package/...` imports
@@ -13,7 +10,6 @@ function excludes(list) {
13
10
  replacement: '@nerest/nerest/build/excludes/empty-module',
14
11
  }));
15
12
  }
16
- exports.excludes = excludes;
17
13
  /**
18
14
  * Escapes string to use inside of a regular expression.
19
15
  * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#escaping
@@ -1,17 +1,11 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.buildMicroFrontend = void 0;
7
- const path_1 = __importDefault(require("path"));
8
- const promises_1 = __importDefault(require("fs/promises"));
9
- const fs_1 = require("fs");
10
- const vite_1 = __importDefault(require("vite"));
11
- const vite_plugin_externals_1 = require("vite-plugin-externals");
12
- const apps_1 = require("../server/parts/apps");
13
- const excludes_1 = require("./excludes");
14
- async function buildMicroFrontend() {
1
+ import path from 'path';
2
+ import fs from 'fs/promises';
3
+ import { existsSync } from 'fs';
4
+ import { build } from 'vite';
5
+ import { viteExternalsPlugin } from 'vite-plugin-externals';
6
+ import { loadApps } from '../server/parts/apps.js';
7
+ import { excludes } from './excludes/index.js';
8
+ export async function buildMicroFrontend() {
15
9
  const root = process.cwd();
16
10
  const staticPath = process.env.NEREST_STATIC_PATH;
17
11
  // TODO: The path where the client files are deployed is built-in during
@@ -44,15 +38,15 @@ async function buildMicroFrontend() {
44
38
  },
45
39
  resolve: {
46
40
  // excludes - map buildConfig.excludes packages to an empty module
47
- alias: (0, excludes_1.excludes)(buildConfig?.excludes),
41
+ alias: excludes(buildConfig?.excludes),
48
42
  },
49
43
  plugins: [
50
44
  // externals - map buildConfig.externals packages to a global variable on window
51
- (0, vite_plugin_externals_1.viteExternalsPlugin)(buildConfig?.externals, { useWindow: false }),
45
+ viteExternalsPlugin(buildConfig?.externals, { useWindow: false }),
52
46
  ],
53
47
  };
54
48
  console.log('Producing production client build...');
55
- await vite_1.default.build(clientConfig);
49
+ await build(clientConfig);
56
50
  console.log('Producing Nerest manifest file...');
57
51
  await buildAppsManifest(root, staticPath);
58
52
  // Build server using the client manifest
@@ -75,18 +69,17 @@ async function buildMicroFrontend() {
75
69
  },
76
70
  };
77
71
  console.log('Producing production server build...');
78
- await vite_1.default.build(serverConfig);
72
+ await build(serverConfig);
79
73
  }
80
- exports.buildMicroFrontend = buildMicroFrontend;
81
74
  async function buildAppsManifest(root, staticPath) {
82
- const apps = await (0, apps_1.loadApps)(root, staticPath);
83
- await promises_1.default.writeFile(path_1.default.join(root, 'build/nerest-manifest.json'), JSON.stringify(apps), { encoding: 'utf-8' });
75
+ const apps = await loadApps(root, staticPath);
76
+ await fs.writeFile(path.join(root, 'build/nerest-manifest.json'), JSON.stringify(apps), { encoding: 'utf-8' });
84
77
  }
85
78
  // TODO: error handling
86
79
  async function readBuildConfig(root) {
87
- const configPath = path_1.default.join(root, 'nerest-build.json');
88
- if ((0, fs_1.existsSync)(configPath)) {
89
- const content = await promises_1.default.readFile(configPath, { encoding: 'utf-8' });
80
+ const configPath = path.join(root, 'nerest-build.json');
81
+ if (existsSync(configPath)) {
82
+ const content = await fs.readFile(configPath, { encoding: 'utf-8' });
90
83
  return JSON.parse(content);
91
84
  }
92
85
  }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,32 @@
1
+ // Shared client entrypoint that bootstraps all of the apps supplied
2
+ // by current microfrontend
3
+ import React from 'react';
4
+ import ReactDOM from 'react-dom/client';
5
+ // Since this is a shared entrypoint, it dynamically imports all of the
6
+ // available apps. They will be built as separate chunks and only loaded
7
+ // if needed.
8
+ const modules = import.meta.glob('/apps/*/index.tsx', { import: 'default' });
9
+ async function runHydration() {
10
+ for (const container of document.querySelectorAll('div[data-app-name]')) {
11
+ const appName = container.getAttribute('data-app-name');
12
+ const appModuleLoader = modules[`/apps/${appName}/index.tsx`];
13
+ if (!appModuleLoader || container.hasAttribute('data-app-hydrated')) {
14
+ continue;
15
+ }
16
+ // Mark container as hydrated, in case there are multiple instances
17
+ // of the same microfrontend script on the page
18
+ container.setAttribute('data-app-hydrated', 'true');
19
+ const appId = container.getAttribute('data-app-id');
20
+ const propsContainer = document.querySelector(`script[data-app-id="${appId}"]`);
21
+ // TODO: more robust error handling and error logging
22
+ const props = JSON.parse(propsContainer?.textContent ?? '{}');
23
+ const reactElement = React.createElement((await appModuleLoader()), props);
24
+ ReactDOM.hydrateRoot(container, reactElement);
25
+ }
26
+ }
27
+ if (document.readyState !== 'complete') {
28
+ document.addEventListener('DOMContentLoaded', runHydration);
29
+ }
30
+ else {
31
+ runHydration();
32
+ }
@@ -1,24 +1,19 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.runDevelopmentServer = void 0;
7
1
  // This is the nerest development server entrypoint
8
- const path_1 = __importDefault(require("path"));
9
- const vite_1 = __importDefault(require("vite"));
10
- const fastify_1 = __importDefault(require("fastify"));
11
- const static_1 = __importDefault(require("@fastify/static"));
12
- const fastify_graceful_shutdown_1 = __importDefault(require("fastify-graceful-shutdown"));
13
- const apps_1 = require("./parts/apps");
14
- const render_1 = require("./parts/render");
15
- const preview_1 = require("./parts/preview");
16
- const validator_1 = require("./parts/validator");
17
- const swagger_1 = require("./parts/swagger");
18
- const k8s_probes_1 = require("./parts/k8s-probes");
19
- const runtime_hook_1 = require("./parts/runtime-hook");
2
+ import path from 'path';
3
+ import { build, createServer } from 'vite';
4
+ import fastify from 'fastify';
5
+ import fastifyStatic from '@fastify/static';
6
+ import fastifyGracefulShutdown from 'fastify-graceful-shutdown';
7
+ import { loadApps } from './parts/apps.js';
8
+ import { renderApp } from './parts/render.js';
9
+ import { renderPreviewPage } from './parts/preview.js';
10
+ import { validator } from './parts/validator.js';
11
+ import { setupSwagger } from './parts/swagger.js';
12
+ import { setupK8SProbes } from './parts/k8s-probes.js';
13
+ import { runRuntimeHook } from './hooks/runtime.js';
14
+ import { runPropsHook } from './hooks/props.js';
20
15
  // eslint-disable-next-line max-statements
21
- async function runDevelopmentServer() {
16
+ export async function runDevelopmentServer() {
22
17
  const root = process.cwd();
23
18
  // TODO: move build config into a separate file
24
19
  // TODO: look at @vitejs/plugin-react (everything seems fine without it though)
@@ -55,17 +50,17 @@ async function runDevelopmentServer() {
55
50
  await startClientBuildWatcher(config);
56
51
  // Load app entries following the `apps/{name}/index.tsx` convention
57
52
  // TODO: remove hardcoded port
58
- const apps = await (0, apps_1.loadApps)(root, 'http://0.0.0.0:3000/');
53
+ const apps = await loadApps(root, 'http://0.0.0.0:3000/');
59
54
  // Start vite server that will be rendering SSR components
60
- const viteSsr = await vite_1.default.createServer(config);
61
- const app = (0, fastify_1.default)();
55
+ const viteSsr = await createServer(config);
56
+ const app = fastify();
62
57
  // Setup schema validation. We have to use our own ajv instance that
63
58
  // we can use both to validate request bodies and examples against
64
59
  // app schemas
65
- app.setValidatorCompiler(({ schema }) => validator_1.validator.compile(schema));
66
- await (0, swagger_1.setupSwagger)(app);
60
+ app.setValidatorCompiler(({ schema }) => validator.compile(schema));
61
+ await setupSwagger(app);
67
62
  for (const appEntry of Object.values(apps)) {
68
- const { name, entry, examples, schema } = appEntry;
63
+ const { name, entry, propsHookEntry, examples, schema } = appEntry;
69
64
  const routeOptions = {};
70
65
  // TODO: report error if schema is missing, unless this app is client-only
71
66
  if (schema) {
@@ -88,17 +83,18 @@ async function runDevelopmentServer() {
88
83
  const ssrComponent = await viteSsr.ssrLoadModule(entry, {
89
84
  fixStacktrace: true,
90
85
  });
91
- return (0, render_1.renderApp)({
86
+ const props = await runPropsHook(request.body, () => viteSsr.ssrLoadModule(propsHookEntry));
87
+ return renderApp({
92
88
  name,
93
89
  assets: appEntry.assets,
94
90
  component: ssrComponent.default,
95
- }, request.body);
91
+ }, props);
96
92
  });
97
93
  for (const [exampleName, example] of Object.entries(examples)) {
98
94
  // Validate example against schema when specified
99
- if (schema && !validator_1.validator.validate(schema, example)) {
95
+ if (schema && !validator.validate(schema, example)) {
100
96
  // TODO: use logger and display errors more prominently
101
- console.error(`Example "${exampleName}" of app "${name}" does not satisfy schema: ${validator_1.validator.errorsText()}`);
97
+ console.error(`Example "${exampleName}" of app "${name}" does not satisfy schema: ${validator.errorsText()}`);
102
98
  }
103
99
  // GET /api/{name}/examples/{example} -> render a preview page
104
100
  // with a predefined example body
@@ -113,24 +109,25 @@ async function runDevelopmentServer() {
113
109
  const ssrComponent = await viteSsr.ssrLoadModule(entry, {
114
110
  fixStacktrace: true,
115
111
  });
116
- const { html, assets } = (0, render_1.renderApp)({
112
+ const props = await runPropsHook(example, () => viteSsr.ssrLoadModule(propsHookEntry));
113
+ const { html, assets } = renderApp({
117
114
  name,
118
115
  assets: appEntry.assets,
119
116
  component: ssrComponent.default,
120
- }, example);
117
+ }, props);
121
118
  reply.type('text/html');
122
- return (0, preview_1.renderPreviewPage)(html, assets);
119
+ return renderPreviewPage(html, assets);
123
120
  });
124
121
  }
125
122
  }
126
123
  // Add graceful shutdown handler to prevent requests errors
127
- await app.register(fastify_graceful_shutdown_1.default);
124
+ await app.register(fastifyGracefulShutdown);
128
125
  if (process.env.ENABLE_K8S_PROBES) {
129
- await (0, k8s_probes_1.setupK8SProbes)(app);
126
+ await setupK8SProbes(app);
130
127
  }
131
128
  // TODO: only do this locally, load from CDN in production
132
- await app.register(static_1.default, {
133
- root: path_1.default.join(root, 'build'),
129
+ await app.register(fastifyStatic, {
130
+ root: path.join(root, 'build'),
134
131
  // TODO: maybe use @fastify/cors instead
135
132
  setHeaders(res) {
136
133
  res.setHeader('Access-Control-Allow-Origin', '*');
@@ -139,7 +136,7 @@ async function runDevelopmentServer() {
139
136
  },
140
137
  });
141
138
  // Execute runtime hook in nerest-runtime.ts if it exists
142
- await (0, runtime_hook_1.runRuntimeHook)(app, () => viteSsr.ssrLoadModule('/nerest-runtime.ts'));
139
+ await runRuntimeHook(app, () => viteSsr.ssrLoadModule('/nerest-runtime.ts'));
143
140
  // TODO: remove hardcoded port
144
141
  await app.listen({
145
142
  host: '0.0.0.0',
@@ -147,10 +144,9 @@ async function runDevelopmentServer() {
147
144
  });
148
145
  console.log('Nerest is listening on 0.0.0.0:3000');
149
146
  }
150
- exports.runDevelopmentServer = runDevelopmentServer;
151
147
  // TODO: this should probably be moved from here
152
148
  async function startClientBuildWatcher(config) {
153
- const watcher = (await vite_1.default.build(config));
149
+ const watcher = (await build(config));
154
150
  return new Promise((resolve) => {
155
151
  // We need to have a built manifest.json to provide assets
156
152
  // links in SSR. We will wait for rollup to report when it
@@ -0,0 +1 @@
1
+ export declare function runPropsHook(props: unknown, loader: () => Promise<unknown>): Promise<Record<string, unknown>>;
@@ -0,0 +1,12 @@
1
+ // Load the props hook module and run it if it exists, passing down app's
2
+ // props object. This hook can be used to modify props before they are passed
3
+ // to the root app component.
4
+ export async function runPropsHook(props, loader) {
5
+ let module;
6
+ try {
7
+ module = (await loader());
8
+ }
9
+ catch { }
10
+ // If module exists and exports a default function, run it to modify props
11
+ return (typeof module?.default === 'function' ? module.default(props) : props);
12
+ }
@@ -0,0 +1,2 @@
1
+ import type { FastifyInstance } from 'fastify';
2
+ export declare function runRuntimeHook(app: FastifyInstance, loader: () => Promise<unknown>): Promise<void>;
@@ -0,0 +1,28 @@
1
+ // Load the runtime hook module and run it if it exists, passing down our
2
+ // fastify instance. This hook can be used to modify fastify settings, add
3
+ // plugins or routes on an individual app level.
4
+ export async function runRuntimeHook(app, loader) {
5
+ let module;
6
+ try {
7
+ module = (await loader());
8
+ }
9
+ catch { }
10
+ if (typeof module?.default === 'function') {
11
+ // If module exists and exports a default function, execute it and
12
+ // pass down the fastify instance
13
+ try {
14
+ await module.default(app);
15
+ }
16
+ catch (e) {
17
+ console.error('Failed to execute runtime hook', e);
18
+ process.exit(1);
19
+ }
20
+ }
21
+ else if (module) {
22
+ console.error("Runtime hook found, but doesn't export default function!");
23
+ process.exit(1);
24
+ }
25
+ else {
26
+ console.log('Runtime hook not found, skipping...');
27
+ }
28
+ }
@@ -1,8 +1,5 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.loadAppAssets = void 0;
4
1
  // Extracts the list of assets for a given app from the manifest file
5
- function loadAppAssets(appName, manifest, staticPath) {
2
+ export function loadAppAssets(appName, manifest, staticPath) {
6
3
  // TODO: handling errors and potentially missing entries
7
4
  // All apps share the same JS entry that dynamically imports the chunks of the apps
8
5
  // that are used on the page based on their name
@@ -11,4 +8,3 @@ function loadAppAssets(appName, manifest, staticPath) {
11
8
  const appCss = manifest[`apps/${appName}/index.tsx`].css ?? [];
12
9
  return [clientEntryJs, ...appCss].map((x) => staticPath + x);
13
10
  }
14
- exports.loadAppAssets = loadAppAssets;
@@ -1,31 +1,24 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.loadAppExamples = void 0;
7
- const path_1 = __importDefault(require("path"));
8
- const fs_1 = require("fs");
9
- const promises_1 = __importDefault(require("fs/promises"));
1
+ import path from 'path';
2
+ import { existsSync } from 'fs';
3
+ import fs from 'fs/promises';
10
4
  // Loads and parses the example json files for providing
11
5
  // `/examples/` routes of the dev server
12
- async function loadAppExamples(appRoot) {
13
- const examplesRoot = path_1.default.join(appRoot, 'examples');
6
+ export async function loadAppExamples(appRoot) {
7
+ const examplesRoot = path.join(appRoot, 'examples');
14
8
  // Examples are optional and may not exist
15
- if (!(0, fs_1.existsSync)(examplesRoot)) {
9
+ if (!existsSync(examplesRoot)) {
16
10
  return {};
17
11
  }
18
- const exampleFiles = (await promises_1.default.readdir(examplesRoot, { withFileTypes: true }))
12
+ const exampleFiles = (await fs.readdir(examplesRoot, { withFileTypes: true }))
19
13
  .filter((d) => d.isFile() && d.name.endsWith('.json'))
20
14
  .map((d) => d.name);
21
15
  const examples = {};
22
16
  // TODO: error handling and reporting
23
17
  for (const filename of exampleFiles) {
24
- const file = path_1.default.join(examplesRoot, filename);
25
- const content = await promises_1.default.readFile(file, { encoding: 'utf8' });
18
+ const file = path.join(examplesRoot, filename);
19
+ const content = await fs.readFile(file, { encoding: 'utf8' });
26
20
  const json = JSON.parse(content);
27
- examples[path_1.default.basename(filename, '.json')] = json;
21
+ examples[path.basename(filename, '.json')] = json;
28
22
  }
29
23
  return examples;
30
24
  }
31
- exports.loadAppExamples = loadAppExamples;
@@ -1,17 +1,10 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.loadAppManifest = void 0;
7
- const path_1 = __importDefault(require("path"));
8
- const promises_1 = __importDefault(require("fs/promises"));
1
+ import path from 'path';
2
+ import fs from 'fs/promises';
9
3
  // Manifest is used to provide assets list for every app
10
4
  // for use with SSR
11
- async function loadAppManifest(root) {
5
+ export async function loadAppManifest(root) {
12
6
  // TODO: error handling
13
- const manifestPath = path_1.default.join(root, 'build', 'manifest.json');
14
- const manifestData = await promises_1.default.readFile(manifestPath, { encoding: 'utf8' });
7
+ const manifestPath = path.join(root, 'build', 'manifest.json');
8
+ const manifestData = await fs.readFile(manifestPath, { encoding: 'utf8' });
15
9
  return JSON.parse(manifestData);
16
10
  }
17
- exports.loadAppManifest = loadAppManifest;
@@ -1,21 +1,14 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.loadAppSchema = void 0;
7
- const path_1 = __importDefault(require("path"));
8
- const fs_1 = require("fs");
9
- const promises_1 = __importDefault(require("fs/promises"));
1
+ import path from 'path';
2
+ import { existsSync } from 'fs';
3
+ import fs from 'fs/promises';
10
4
  // Loads and parses the schema file for a specific app
11
- async function loadAppSchema(appRoot) {
12
- const schemaPath = path_1.default.join(appRoot, 'schema.json');
5
+ export async function loadAppSchema(appRoot) {
6
+ const schemaPath = path.join(appRoot, 'schema.json');
13
7
  let schema = null;
14
8
  // TODO: error handling and reporting
15
- if ((0, fs_1.existsSync)(schemaPath)) {
16
- const file = await promises_1.default.readFile(schemaPath, { encoding: 'utf-8' });
9
+ if (existsSync(schemaPath)) {
10
+ const file = await fs.readFile(schemaPath, { encoding: 'utf-8' });
17
11
  schema = JSON.parse(file);
18
12
  }
19
13
  return schema;
20
14
  }
21
- exports.loadAppSchema = loadAppSchema;
@@ -2,6 +2,7 @@ export type AppEntry = {
2
2
  name: string;
3
3
  root: string;
4
4
  entry: string;
5
+ propsHookEntry: string;
5
6
  assets: string[];
6
7
  examples: Record<string, unknown>;
7
8
  schema: Record<string, unknown> | null;