@lwrjs/core 0.9.0-alpha.11 → 0.9.0-alpha.13

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 (35) hide show
  1. package/build/cjs/context/provider.cjs +2 -1
  2. package/build/cjs/context/server.cjs +4 -1
  3. package/build/cjs/index.cjs +28 -23
  4. package/build/cjs/middleware/bundle-middleware.cjs +1 -2
  5. package/build/cjs/middleware/module-middleware.cjs +1 -1
  6. package/build/cjs/middleware/view-middleware.cjs +12 -16
  7. package/build/cjs/tools/plugins/build-server-plugin.cjs +137 -0
  8. package/build/cjs/{context/services.cjs → tools/plugins/generate-entry-plugin.cjs} +26 -21
  9. package/build/cjs/tools/server-build.cjs +15 -129
  10. package/build/cjs/tools/server-warmup.cjs +2 -9
  11. package/build/cjs/tools/static-generation.cjs +8 -11
  12. package/build/es/context/provider.js +1 -0
  13. package/build/es/context/server.js +4 -0
  14. package/build/es/index.js +36 -25
  15. package/build/es/middleware/bundle-middleware.js +3 -2
  16. package/build/es/middleware/module-middleware.js +3 -1
  17. package/build/es/middleware/view-middleware.d.ts +2 -2
  18. package/build/es/middleware/view-middleware.js +12 -16
  19. package/build/es/tools/plugins/build-server-plugin.d.ts +18 -0
  20. package/build/es/tools/plugins/build-server-plugin.js +132 -0
  21. package/build/es/tools/plugins/generate-entry-plugin.d.ts +11 -0
  22. package/build/es/tools/plugins/generate-entry-plugin.js +45 -0
  23. package/build/es/tools/server-build.d.ts +5 -6
  24. package/build/es/tools/server-build.js +22 -152
  25. package/build/es/tools/server-warmup.js +3 -10
  26. package/build/es/tools/static-generation.js +10 -12
  27. package/package.json +28 -28
  28. package/build/cjs/context/configurations.cjs +0 -82
  29. package/build/cjs/context/global-data.cjs +0 -54
  30. package/build/es/context/configurations.d.ts +0 -9
  31. package/build/es/context/configurations.js +0 -53
  32. package/build/es/context/global-data.d.ts +0 -3
  33. package/build/es/context/global-data.js +0 -29
  34. package/build/es/context/services.d.ts +0 -3
  35. package/build/es/context/services.js +0 -27
package/build/es/index.js CHANGED
@@ -1,13 +1,11 @@
1
1
  import { getFeatureFlags, DEFAULT_LWR_BOOTSTRAP_CONFIG, logger } from '@lwrjs/shared-utils';
2
2
  import { createInternalServer } from '@lwrjs/server';
3
3
  import { LwrServerError, createSingleDiagnosticError, descriptions } from '@lwrjs/diagnostics';
4
- import { normalizeConfig } from '@lwrjs/config';
5
- import { getServices } from './context/services.js';
6
- import { resolveConfigurations } from './context/configurations.js';
7
- import { createProviderContext } from './context/provider.js';
8
- import { createServerContext } from './context/server.js';
4
+ import { loadConfig, normalizeConfig, loadServices, loadRoutes } from '@lwrjs/config';
9
5
  import SiteGenerator from './tools/static-generation.js';
10
6
  import { warmupServer } from './tools/server-warmup.js';
7
+ import { createServerContext } from './context/server.js';
8
+ import { createProviderContext } from './context/provider.js';
11
9
  import { localeMiddleware } from './middleware/locale-middleware.js';
12
10
  import { moduleMiddleware } from './middleware/module-middleware.js';
13
11
  import { bundleMiddleware } from './middleware/bundle-middleware.js';
@@ -16,7 +14,7 @@ import { assetMiddleware } from './middleware/asset-middleware.js';
16
14
  import { viewMiddleware } from './middleware/view-middleware.js';
17
15
  import { resourceMiddleware } from './middleware/resource-middleware.js';
18
16
  import { hmrMiddleware } from './middleware/hmr-middleware.js';
19
- function initMiddleware(app, server, serverContext) {
17
+ function initMiddleware(app, server, serverContext, routes, errorRoutes) {
20
18
  // all middleware attached AFTER compression will have compressed responses
21
19
  app.useCompression();
22
20
  localeMiddleware(app, serverContext);
@@ -27,7 +25,7 @@ function initMiddleware(app, server, serverContext) {
27
25
  resourceMiddleware(app, serverContext);
28
26
  // view middleware MUST be attached last because it contains a greedy middleware
29
27
  // to handle unsupported routes
30
- viewMiddleware(app, serverContext);
28
+ viewMiddleware(app, serverContext, routes, errorRoutes);
31
29
  // initialize routes MUST be called when using koa
32
30
  app.initRoutes();
33
31
  // hmr uses web sockets, so it doesn't matter when this is attached
@@ -35,28 +33,30 @@ function initMiddleware(app, server, serverContext) {
35
33
  hmrMiddleware(server, serverContext);
36
34
  }
37
35
  }
38
- async function initContext(app, server, rawAppConfig) {
39
- const { appConfig, runtimeEnvironment, globalData } = await resolveConfigurations(rawAppConfig);
36
+ function createServices(entries, providerContext) {
37
+ return entries.map(([ctor, providerConfig = {}]) => new ctor(providerConfig, providerContext));
38
+ }
39
+ async function initContext(appConfig, runtimeEnvironment, globalData, services) {
40
40
  // Initialized PRIVATE server-side context, passed to middleware
41
41
  const serverContext = createServerContext(appConfig, runtimeEnvironment, globalData);
42
42
  const providerContext = createProviderContext(serverContext);
43
43
  const { moduleRegistry, resourceRegistry, viewRegistry, assetRegistry } = serverContext;
44
44
  // Module Providers
45
- const moduleProviders = await getServices(appConfig.moduleProviders, providerContext, appConfig);
45
+ const moduleProviders = createServices(services.moduleProviders, providerContext);
46
46
  moduleRegistry.addModuleProviders(moduleProviders);
47
47
  // Resource Providers
48
- const resourceProviders = await getServices(appConfig.resourceProviders, providerContext, appConfig);
48
+ const resourceProviders = await createServices(services.resourceProviders, providerContext);
49
49
  resourceRegistry.addResourceProviders(resourceProviders);
50
50
  // View Providers
51
- const viewProviders = await getServices(appConfig.viewProviders, providerContext, appConfig);
51
+ const viewProviders = await createServices(services.viewProviders, providerContext);
52
52
  // View Transformers
53
- const viewTransformers = await getServices(appConfig.viewTransformers, providerContext, rawAppConfig);
53
+ const viewTransformers = await createServices(services.viewTransformers, providerContext);
54
54
  viewRegistry.addViewProviders(viewProviders);
55
55
  viewRegistry.addViewTransformers(viewTransformers);
56
56
  await viewRegistry.initializeViewProviders();
57
57
  // Asset Providers
58
- const assetProviders = await getServices(appConfig.assetProviders, providerContext, appConfig);
59
- const assetTransformers = await getServices(appConfig.assetTransformers, undefined, appConfig);
58
+ const assetProviders = await createServices(services.assetProviders, providerContext);
59
+ const assetTransformers = await createServices(services.assetTransformers, providerContext);
60
60
  assetRegistry.addAssetProviders(assetProviders);
61
61
  assetRegistry.addAssetTransformers(assetTransformers);
62
62
  return serverContext;
@@ -76,16 +76,27 @@ export class LwrApp {
76
76
  return this.config;
77
77
  }
78
78
  async init() {
79
- if (!this.initialized) {
80
- this.initialized = true;
81
- try {
82
- const context = await initContext(this.app, this.server, this.config);
83
- initMiddleware(this.app, this.server, context);
84
- }
85
- catch (e) {
86
- this.initialized = false;
87
- throw e;
88
- }
79
+ if (this.initialized) {
80
+ return;
81
+ }
82
+ // preemptively mark the server as initialized
83
+ this.initialized = true;
84
+ try {
85
+ // load and process all application configurations, services, and routes
86
+ const { appConfig, runtimeEnvironment, globalData } = await loadConfig(this.config);
87
+ const services = await loadServices(appConfig);
88
+ const { routes, errorRoutes } = await loadRoutes(appConfig);
89
+ // create the application server context
90
+ const context = await initContext(appConfig, runtimeEnvironment, globalData, services);
91
+ // attach framework middleware to the server
92
+ initMiddleware(this.app, this.server, context, routes, errorRoutes);
93
+ // expose the normalized config after config hooks are applied
94
+ this.config = appConfig;
95
+ }
96
+ catch (e) {
97
+ // reset the initialized property if the server fails to initialize
98
+ this.initialized = false;
99
+ throw e;
89
100
  }
90
101
  }
91
102
  async listen(callback) {
@@ -27,8 +27,9 @@ function createBundleMiddleware(context) {
27
27
  return;
28
28
  }
29
29
  const sourceMapUrl = req.path.replace('/bundle/', '/sourcemaps/bundle/');
30
- const sourceMapRuntimeContext = { ...runtimeEnvironment, sourceMapUrl };
31
- const bundleDefinition = await moduleBundler.getModuleBundle(moduleId, sourceMapRuntimeContext, runtimeParams);
30
+ const bundleDefinition = await moduleBundler.getModuleBundle(moduleId,
31
+ // bundle must be `true` to properly resolve bundles in amd
32
+ { ...runtimeEnvironment, bundle: true, sourceMapUrl }, runtimeParams);
32
33
  if (req.isSiteGeneration()) {
33
34
  res.setSiteGenerationMetadata({
34
35
  moduleDefinition: bundleDefinition,
@@ -25,7 +25,9 @@ function createModuleMiddleware(context) {
25
25
  await unsignedRedirect(req, res, moduleId, runtimeEnvironment, runtimeParams);
26
26
  return;
27
27
  }
28
- const moduleDefinition = await moduleRegistry.getLinkedModule(moduleId, runtimeEnvironment, runtimeParams);
28
+ const moduleDefinition = await moduleRegistry.getLinkedModule(moduleId,
29
+ // bundle must be `false` to resolve amd modules in `prod-compat` mode
30
+ { ...runtimeEnvironment, bundle: false }, runtimeParams);
29
31
  const { ownHash, linkedSource } = moduleDefinition;
30
32
  // validate the requested instances exists
31
33
  if (signature !== LATEST_SIGNATURE && ownHash !== signature) {
@@ -1,3 +1,3 @@
1
- import type { InternalAppServer, ServerContext, ServerTypes } from '@lwrjs/types';
2
- export declare function viewMiddleware<T extends ServerTypes>(app: InternalAppServer<T>, context: ServerContext): void;
1
+ import type { InternalAppServer, LwrErrorRoute, LwrRoute, Route, ServerContext, ServerTypes } from '@lwrjs/types';
2
+ export declare function viewMiddleware<T extends ServerTypes>(app: InternalAppServer<T>, context: ServerContext, routes: Route<LwrRoute>[], errorRoutes: Route<LwrErrorRoute>[]): void;
3
3
  //# sourceMappingURL=view-middleware.d.ts.map
@@ -9,9 +9,8 @@ const CANONICAL_VIEW_ROUTES = [
9
9
  `/:apiVersion/application/:format/ai/:appId`,
10
10
  `/:apiVersion/application/:format/e/:environment/ai/:appId`,
11
11
  ];
12
- function createViewMiddleware(route, context, viewHandler) {
13
- const { appConfig } = context;
14
- const errorRoute = appConfig.errorRoutes.find((route) => route.status === 500);
12
+ function createViewMiddleware(route, errorRoutes, context, viewHandler) {
13
+ const errorRoute = errorRoutes.find((route) => route.status === 500);
15
14
  return async (req, res) => {
16
15
  if (!req.validateEnvironmentRequest(context.appConfig)) {
17
16
  res.status(400);
@@ -68,9 +67,7 @@ function createViewMiddleware(route, context, viewHandler) {
68
67
  res.send(viewResponse.body);
69
68
  };
70
69
  }
71
- function createConfigMiddleware(context, viewHandler) {
72
- const { appConfig } = context;
73
- const { routes } = appConfig;
70
+ function createConfigMiddleware(routes, context, viewHandler) {
74
71
  return async (req, res) => {
75
72
  const { runtimeEnvironment, runtimeParams } = req.getRuntimeContext(context.runtimeEnvironment);
76
73
  const { appId, encodedViewPath } = req.params;
@@ -106,21 +103,20 @@ function createConfigMiddleware(context, viewHandler) {
106
103
  res.send(viewResponse.body);
107
104
  };
108
105
  }
109
- function createNotFoundMiddleware(context, viewHandler) {
110
- const { errorRoutes } = context.appConfig;
111
- const errorRoute = errorRoutes.find((route) => route.status === 404);
112
- if (errorRoute) {
113
- return createViewMiddleware(errorRoute, context, viewHandler);
106
+ function createNotFoundMiddleware(errorRoutes, context, viewHandler) {
107
+ const notFoundRoute = errorRoutes.find((route) => route.status === 404);
108
+ if (notFoundRoute) {
109
+ return createViewMiddleware(notFoundRoute, errorRoutes, context, viewHandler);
114
110
  }
115
111
  return (req, res) => {
116
112
  res.status(404).send(descriptions.UNRESOLVABLE.VIEW(req.originalUrl).message);
117
113
  };
118
114
  }
119
- export function viewMiddleware(app, context) {
115
+ export function viewMiddleware(app, context, routes, errorRoutes) {
120
116
  const { appConfig, viewRegistry, moduleRegistry } = context;
121
117
  const viewHandler = new LwrViewHandler({ viewRegistry, moduleRegistry }, appConfig);
122
118
  // create and attach middleware for each route
123
- for (const route of appConfig.routes) {
119
+ for (const route of routes) {
124
120
  const paths = [route.path];
125
121
  const subRoutes = route.subRoutes && getClientRoutes(route.subRoutes);
126
122
  if (subRoutes) {
@@ -128,12 +124,12 @@ export function viewMiddleware(app, context) {
128
124
  subRoutes.routes.forEach((subRoute) => subRoute.uri !== route.path && paths.push(`${prefix}${subRoute.uri}`));
129
125
  }
130
126
  paths.forEach((routePath) => paths.push(...CANONICAL_VIEW_ROUTES.map((viewRoute) => viewRoute + routePath)));
131
- app.get(paths, handleErrors(createViewMiddleware(route, context, viewHandler)));
127
+ app.get(paths, handleErrors(createViewMiddleware(route, errorRoutes, context, viewHandler)));
132
128
  }
133
129
  // create and attach middleware for bootstrap configurations
134
- app.get(getClientBootstrapConfigurationRoutes(), handleErrors(createConfigMiddleware(context, viewHandler)));
130
+ app.get(getClientBootstrapConfigurationRoutes(), handleErrors(createConfigMiddleware(routes, context, viewHandler)));
135
131
  // create and attach a greedy middleware to handle unsupported paths
136
132
  // NOTE: a greedy `all` is used over `use` due to the way middleware is mounted in the server abstraction
137
- app.get('/' + app.getRegexWildcard(), handleErrors(createNotFoundMiddleware(context, viewHandler)));
133
+ app.get('/' + app.getRegexWildcard(), handleErrors(createNotFoundMiddleware(errorRoutes, context, viewHandler)));
138
134
  }
139
135
  //# sourceMappingURL=view-middleware.js.map
@@ -0,0 +1,18 @@
1
+ import type { Plugin } from 'esbuild';
2
+ import type { LwrGlobalConfig } from '@lwrjs/types';
3
+ /**
4
+ * Creates an esbuild plugin that generates a server build module
5
+ *
6
+ * @remarks
7
+ * The generated server build module contains:
8
+ * - normalized lwr global config(without normalized directories and after config hooks are applied)
9
+ * - runtime environment(after config hooks are applied)
10
+ * - global data(after config hooks are applied)
11
+ * - lwr services(ie. module providers) with static imports
12
+ * - route handlers with static imports
13
+ *
14
+ * @param config - programmatic global config
15
+ * @returns esbuild plugin
16
+ */
17
+ export default function buildLwrServer(config?: LwrGlobalConfig): Plugin;
18
+ //# sourceMappingURL=build-server-plugin.d.ts.map
@@ -0,0 +1,132 @@
1
+ import path from 'path';
2
+ import { loadConfig } from '@lwrjs/config';
3
+ import { normalizeDirectory } from '@lwrjs/shared-utils';
4
+ const services = [
5
+ 'moduleProviders',
6
+ 'assetProviders',
7
+ 'assetTransformers',
8
+ 'viewProviders',
9
+ 'viewTransformers',
10
+ 'resourceProviders',
11
+ ];
12
+ function processServices(kind, entries, rootDir) {
13
+ const output = {
14
+ imports: [],
15
+ entries: [],
16
+ };
17
+ for (const [index, [entry, config]] of entries.entries()) {
18
+ const name = kind + index;
19
+ output.imports.push(`import ${name} from '${normalizeDirectory(entry, rootDir)}';`);
20
+ output.entries.push([name, config]);
21
+ }
22
+ return output;
23
+ }
24
+ function processRoutes(routes, rootDir) {
25
+ const output = {
26
+ imports: [],
27
+ routes: [],
28
+ };
29
+ const handlers = {};
30
+ for (const route of routes) {
31
+ if (!route.routeHandler) {
32
+ output.routes.push(route);
33
+ continue;
34
+ }
35
+ const handler = route.routeHandler;
36
+ if (!handlers[handler]) {
37
+ const name = `routeHandler${Object.keys(handlers).length}`;
38
+ handlers[handler] = name;
39
+ output.imports.push(`import ${name} from '${normalizeDirectory(handler, rootDir)}';`);
40
+ }
41
+ output.routes.push({
42
+ ...route,
43
+ routeHandler: handlers[handler],
44
+ });
45
+ }
46
+ return output;
47
+ }
48
+ function printServices(config) {
49
+ return `{${Object.entries(config)
50
+ .map(([key, value]) => {
51
+ const entries = value;
52
+ return `${key}: [${entries.map(([ctor, config = {}]) => `[${ctor}, ${JSON.stringify(config)}]`)}]`;
53
+ })
54
+ .join(',')}}`;
55
+ }
56
+ function printRoutes(routes) {
57
+ return `[${routes
58
+ .map((route) => {
59
+ return `{${Object.entries(route)
60
+ .map(([key, value]) => {
61
+ if (key !== 'routeHandler') {
62
+ return `${key}: ${JSON.stringify(value)}`;
63
+ }
64
+ return `${key}: ${value}`;
65
+ })
66
+ .join(',')}}`;
67
+ })
68
+ .join(',')}]`;
69
+ }
70
+ /**
71
+ * Creates an esbuild plugin that generates a server build module
72
+ *
73
+ * @remarks
74
+ * The generated server build module contains:
75
+ * - normalized lwr global config(without normalized directories and after config hooks are applied)
76
+ * - runtime environment(after config hooks are applied)
77
+ * - global data(after config hooks are applied)
78
+ * - lwr services(ie. module providers) with static imports
79
+ * - route handlers with static imports
80
+ *
81
+ * @param config - programmatic global config
82
+ * @returns esbuild plugin
83
+ */
84
+ export default function buildLwrServer(config) {
85
+ return {
86
+ name: 'lwr-server-build',
87
+ setup(build) {
88
+ // This file is generated during the build, so it is mapped to a custom namespace
89
+ // to prevent looking for it on the file system.
90
+ build.onResolve({ filter: /.*\/lwr.build.js$/ }, (args) => ({
91
+ path: args.path,
92
+ namespace: 'lwr-server-build',
93
+ }));
94
+ build.onLoad({ filter: /.*/, namespace: 'lwr-server-build' }, async (args) => {
95
+ const { appConfig, runtimeEnvironment, globalData } = await loadConfig(config, {
96
+ skipDirNormalization: true,
97
+ });
98
+ const remoteAppConfig = {
99
+ ...appConfig,
100
+ ignoreLwrConfigFile: true,
101
+ rootDir: undefined,
102
+ port: undefined,
103
+ };
104
+ const serviceImports = [];
105
+ const serviceConfig = {};
106
+ for (const service of services) {
107
+ const entries = processServices(service, appConfig[service], appConfig.rootDir);
108
+ serviceImports.push(...entries.imports);
109
+ serviceConfig[service] = entries.entries;
110
+ }
111
+ const routesConfig = processRoutes(appConfig.routes, appConfig.rootDir);
112
+ const errorRoutesConfig = processRoutes(appConfig.errorRoutes, appConfig.rootDir);
113
+ return {
114
+ contents: [
115
+ ...serviceImports,
116
+ ...routesConfig.imports,
117
+ ...errorRoutesConfig.imports,
118
+ `export const appConfig = ${JSON.stringify(remoteAppConfig)};`,
119
+ `export const runtimeEnvironment = ${JSON.stringify(runtimeEnvironment)};`,
120
+ `export const globalData = ${JSON.stringify(globalData)};`,
121
+ `export const services = ${printServices(serviceConfig)};`,
122
+ `export const routes = ${printRoutes(routesConfig.routes)};`,
123
+ `export const errorRoutes = ${printRoutes(errorRoutesConfig.routes)};`,
124
+ ].join('\n'),
125
+ loader: 'ts',
126
+ resolveDir: path.dirname(args.path),
127
+ };
128
+ });
129
+ },
130
+ };
131
+ }
132
+ //# sourceMappingURL=build-server-plugin.js.map
@@ -0,0 +1,11 @@
1
+ import type { Plugin } from 'esbuild';
2
+ /**
3
+ * Creates an esbuild plugin that generates the application entry point
4
+ *
5
+ * @remarks
6
+ * The generated entry point includes a reference to a generated server build module.
7
+ *
8
+ * @returns esbuild plugin
9
+ */
10
+ export default function generateLwrEntry(): Plugin;
11
+ //# sourceMappingURL=generate-entry-plugin.d.ts.map
@@ -0,0 +1,45 @@
1
+ import path from 'path';
2
+ /**
3
+ * Creates an esbuild plugin that generates the application entry point
4
+ *
5
+ * @remarks
6
+ * The generated entry point includes a reference to a generated server build module.
7
+ *
8
+ * @returns esbuild plugin
9
+ */
10
+ export default function generateLwrEntry() {
11
+ return {
12
+ name: 'lwr-entry',
13
+ setup(build) {
14
+ // This file is generated during the build, so it is mapped to a custom namespace
15
+ // to prevent looking for it on the file system.
16
+ build.onResolve({ filter: /.*\/lwr.entry.js$/ }, ({ kind, path }) => {
17
+ if (kind === 'entry-point') {
18
+ return {
19
+ path,
20
+ namespace: 'lwr-entry',
21
+ };
22
+ }
23
+ });
24
+ build.onLoad({ filter: /.*/, namespace: 'lwr-entry' }, (args) => ({
25
+ contents: [
26
+ `/* This module is generated */`,
27
+ `import { createHandler } from '@lwrjs/lambda';`,
28
+ // Importing the server build module at this point enables support for ESM bundling.
29
+ // If the server build module was imported in `createHandler`, it would need to be exposed
30
+ // as CJS.
31
+ `import * as build from './lwr.build.js';`,
32
+ // The server build module MUST NOT require asynchronous initialization to support running on MRT
33
+ // Once MRT supports ESM, top-level await could be used at this point to perform some asynchronous
34
+ // initialization.
35
+ `const handler = createHandler(build);`,
36
+ // MRT expects the handler to be a named export: `get`
37
+ `export { handler as get };`,
38
+ ].join('\n'),
39
+ loader: 'ts',
40
+ resolveDir: path.dirname(args.path),
41
+ }));
42
+ },
43
+ };
44
+ }
45
+ //# sourceMappingURL=generate-entry-plugin.js.map
@@ -1,14 +1,13 @@
1
- import { LwrGlobalConfig } from '@lwrjs/types';
1
+ import type { LwrGlobalConfig } from '@lwrjs/types';
2
2
  export interface BuildOptions {
3
- target?: string;
4
3
  outputDir?: string;
5
4
  }
6
5
  /**
7
- * Resolve application configurations, generate a server context module, and bundle
8
- * the LWR server. The bundled server will be written to the filesystem.
6
+ * Resolve configurations, generate a server build module, and bundle
7
+ * the LWR server. The bundled server will be written to the file system.
9
8
  *
10
- * @param {LwrGlobalConfig} configArg - programmatic LWR application config
11
- * @param {BuildOptions} options - server build configurations
9
+ * @param {LwrGlobalConfig} configArg - programmatic LWR global config
10
+ * @param {BuildOptions} options - server build options
12
11
  */
13
12
  export declare function buildServer(configArg?: LwrGlobalConfig, options?: BuildOptions): Promise<void>;
14
13
  //# sourceMappingURL=server-build.d.ts.map
@@ -1,135 +1,18 @@
1
1
  import path from 'path';
2
2
  import fs from 'fs-extra';
3
3
  import esbuild from 'esbuild';
4
- import { normalizeConfig } from '@lwrjs/config';
5
- import { resolveConfigurations } from '../context/configurations.js';
6
- import { createProviderContext } from '../context/provider.js';
7
- import { createServerContext } from '../context/server.js';
8
- function getBuildMetadata(appConfig) {
9
- const moduleProviders = processServiceEntries('moduleProvider', appConfig.moduleProviders);
10
- const resourceProviders = processServiceEntries('resourceProvider', appConfig.resourceProviders);
11
- const viewProviders = processServiceEntries('viewProvider', appConfig.viewProviders);
12
- const viewTransformers = processServiceEntries('viewTransformer', appConfig.viewTransformers);
13
- const assetProviders = processServiceEntries('assetProvider', appConfig.assetProviders);
14
- const assetTransformers = processServiceEntries('assetTransformer', appConfig.assetTransformers);
15
- const imports = [
16
- ...moduleProviders.imports,
17
- ...resourceProviders.imports,
18
- ...viewProviders.imports,
19
- ...viewTransformers.imports,
20
- ...assetProviders.imports,
21
- ...assetTransformers.imports,
22
- ];
23
- return {
24
- imports,
25
- moduleProviders: moduleProviders.services,
26
- resourceProviders: resourceProviders.services,
27
- viewProviders: viewProviders.services,
28
- viewTransformers: viewTransformers.services,
29
- assetProviders: assetProviders.services,
30
- assetTransformers: assetTransformers.services,
31
- };
32
- }
33
- function processServiceEntries(serviceType, entries) {
34
- const imports = [];
35
- const services = [];
36
- for (const [index, [pkg, config]] of entries.entries()) {
37
- const name = serviceType + index;
38
- imports.push(`import ${name} from '${pkg}';`);
39
- services.push(`[${name}, ${JSON.stringify(config)}]`);
40
- }
41
- return {
42
- imports,
43
- services,
44
- };
45
- }
46
- function generateServices(providerContext) {
47
- return ([ServiceCtor, serviceConfig = {}]) => new ServiceCtor(serviceConfig, providerContext);
48
- }
49
- function isRemote() {
50
- return process.env.AWS_LAMBDA_FUNCTION_NAME !== undefined;
51
- }
52
- function generateServerContextModule(appConfig, runtimeEnvironment, globalData, metadata) {
53
- const { imports, moduleProviders, resourceProviders, viewProviders, viewTransformers, assetProviders, assetTransformers, } = metadata;
54
- // config will be resolved programmatically and relative to the current machine
55
- const config = {
56
- ...appConfig,
57
- rootDir: undefined,
58
- ignoreLwrConfigFile: true,
59
- };
60
- return [
61
- `/* This module is generated */`,
62
- `import { LwrCompiler } from '@lwrjs/compiler';`,
63
- `import { LwrModuleBundler } from '@lwrjs/module-bundler';`,
64
- `import { LwrModuleRegistry } from '@lwrjs/module-registry';`,
65
- `import { LwrResourceRegistry } from '@lwrjs/resource-registry';`,
66
- `import { LwrAssetRegistry } from '@lwrjs/asset-registry';`,
67
- `import { LwrViewRegistry } from '@lwrjs/view-registry';`,
68
- `import { LwrApplicationObserver, deepFreeze } from '@lwrjs/shared-utils';`,
69
- `import { normalizeConfig } from '@lwrjs/config';`,
70
- // all of the static imports for the services
71
- ...imports,
72
- // reusing context resolution utils
73
- createServerContext.toString(),
74
- createProviderContext.toString(),
75
- // helper function for generically initializing the services
76
- generateServices.toString(),
77
- // helper function to check if running on lambda
78
- isRemote.toString(),
79
- `const config = ${JSON.stringify(config, null, 4)}`,
80
- `const runtimeEnvironment = ${JSON.stringify(runtimeEnvironment, null, 4)}`,
81
- `const globalData = ${JSON.stringify(globalData, null, 4)}`,
82
- // build artifacts are placed into a build dir on MRT
83
- `isRemote() && process.chdir(__dirname);`,
84
- `isRemote() && (config.rootDir = __dirname);`,
85
- // cache dir must be in tmp dir to be able to write to the filesystem on lambda
86
- `isRemote() && (config.cacheDir = '/tmp/__lwr_cache__');`,
87
- // resolve all config config paths relative to the current machine
88
- `const normalizedConfig = normalizeConfig(config);`,
89
- `const serverContext = createServerContext(normalizedConfig, runtimeEnvironment, globalData);`,
90
- `const providerContext = createProviderContext(serverContext);`,
91
- `const generate = generateServices(providerContext);`,
92
- `const moduleProviders = [${moduleProviders}].map(generate);`,
93
- `const resourceProviders = [${resourceProviders}].map(generate);`,
94
- `const viewProviders = [${viewProviders}].map(generate);`,
95
- `const viewTransformers = [${viewTransformers}].map(generate);`,
96
- `const assetProviders = [${assetProviders}].map(generate);`,
97
- `const assetTransformers = [${assetTransformers}].map(generate);`,
98
- `serverContext.moduleRegistry.addModuleProviders(moduleProviders);`,
99
- `serverContext.resourceRegistry.addResourceProviders(resourceProviders);`,
100
- `serverContext.viewRegistry.addViewProviders(viewProviders);`,
101
- `serverContext.viewRegistry.addViewTransformers(viewTransformers);`,
102
- `serverContext.assetRegistry.addAssetProviders(assetProviders);`,
103
- `serverContext.assetRegistry.addAssetTransformers(assetTransformers);`,
104
- `export default serverContext;`,
105
- ].join('\n');
106
- }
107
- function generateServerSource(target) {
108
- // `lambda` is the only supported build target for now
109
- if (target !== 'lambda') {
110
- // TODO: move to diagnostic error
111
- throw `Unsupported server build target: ${target}`;
112
- }
113
- return [
114
- `/* This module is generated */`,
115
- `import { createHandler } from '@lwrjs/lambda';`,
116
- // Importing the server context module at this point enables support for ESM bundling.
117
- // If the server context module was imported in `createHandler`, it would need to be exposed
118
- // as CJS.
119
- `import build from './lwr.build.js';`,
120
- // The server context module MUST NOT require asynchronous initialization to support running on MRT
121
- // Once MRT supports ESM, top-level await could be used at this point to perform some asynchronous
122
- // initialization.
123
- `const handler = createHandler(build);`,
124
- // MRT expects the handler to be a named export: `get`
125
- `export { handler as get };`,
126
- ].join('\n');
127
- }
128
- async function bundleServer(entryPoint, outputPath) {
4
+ import { logger } from '@lwrjs/shared-utils';
5
+ import { LWR_VERSION } from '@lwrjs/config';
6
+ import generateLwrEntry from './plugins/generate-entry-plugin.js';
7
+ import buildLwrServer from './plugins/build-server-plugin.js';
8
+ async function build(outputDir, config) {
9
+ // building specifically for MRT/Lambda
129
10
  await esbuild.build({
130
- entryPoints: [entryPoint],
11
+ entryPoints: ['./lwr.entry.js'],
131
12
  bundle: true,
132
13
  sourcemap: true,
14
+ format: 'cjs',
15
+ platform: 'node',
133
16
  logLevel: 'silent',
134
17
  external: [
135
18
  // issues with native dependencies
@@ -143,40 +26,27 @@ async function bundleServer(entryPoint, outputPath) {
143
26
  'rollup',
144
27
  'rollup-plugin-node-polyfills',
145
28
  // issues resolving relative files after bundling
146
- '@lwrjs/config',
147
29
  '@lwrjs/loader',
148
30
  ],
149
- format: 'cjs',
150
- platform: 'node',
151
- outfile: outputPath,
31
+ banner: {
32
+ js: `globalThis.LWR_VERSION='${LWR_VERSION};'`,
33
+ },
34
+ plugins: [generateLwrEntry(), buildLwrServer(config)],
35
+ // MRT expects an entry point named `ssr.js`
36
+ outfile: path.join(outputDir, 'ssr.js'),
152
37
  });
153
38
  }
154
39
  /**
155
- * Resolve application configurations, generate a server context module, and bundle
156
- * the LWR server. The bundled server will be written to the filesystem.
40
+ * Resolve configurations, generate a server build module, and bundle
41
+ * the LWR server. The bundled server will be written to the file system.
157
42
  *
158
- * @param {LwrGlobalConfig} configArg - programmatic LWR application config
159
- * @param {BuildOptions} options - server build configurations
43
+ * @param {LwrGlobalConfig} configArg - programmatic LWR global config
44
+ * @param {BuildOptions} options - server build options
160
45
  */
161
46
  export async function buildServer(configArg, options) {
162
- // App config will be included in the generated server context module, but all of the config paths
163
- // will not be normalized. The config paths will be normalized at runtime to enable running the
164
- // application on a different machine.
165
- const config = normalizeConfig(configArg, { skipDirNormalization: true, skipCacheDirCreation: true });
166
- // Config hooks are applied during generation because they enable asynchronous modification of
167
- // the LWR configurations. Since config hooks are run at build time, the config hooks MUST NOT be
168
- // responsible for critical application initialization or have dependencies on normalized config paths.
169
- const { appConfig, runtimeEnvironment, globalData } = await resolveConfigurations(config);
170
- // All LWR services are processed and included in the generated server context module. This module will
171
- // statically import the services and initialize all LWR server components(ie. providers and registries).
172
- const metadata = getBuildMetadata(appConfig);
173
- const serverContext = generateServerContextModule(appConfig, runtimeEnvironment, globalData, metadata);
174
- const outputDir = path.join(appConfig.rootDir, options?.outputDir || '/build');
175
- const serverSource = generateServerSource(options?.target || 'lambda');
176
- // HACK: writing the server context module and server entry to a file for debugging
47
+ const outputDir = path.join(configArg?.rootDir || process.cwd(), options?.outputDir || '/build');
177
48
  await fs.ensureDir(outputDir);
178
- await fs.writeFile(path.join(outputDir, 'lwr.build.js'), serverContext);
179
- await fs.writeFile(path.join(outputDir, 'entry.js'), serverSource);
180
- await bundleServer(path.join(outputDir, 'entry.js'), path.join(outputDir, 'ssr.js'));
49
+ await build(outputDir, configArg);
50
+ logger.info('Successfully built the server');
181
51
  }
182
52
  //# sourceMappingURL=server-build.js.map