@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.
- package/build/cjs/context/provider.cjs +2 -1
- package/build/cjs/context/server.cjs +4 -1
- package/build/cjs/index.cjs +28 -23
- package/build/cjs/middleware/bundle-middleware.cjs +1 -2
- package/build/cjs/middleware/module-middleware.cjs +1 -1
- package/build/cjs/middleware/view-middleware.cjs +12 -16
- package/build/cjs/tools/plugins/build-server-plugin.cjs +137 -0
- package/build/cjs/{context/services.cjs → tools/plugins/generate-entry-plugin.cjs} +26 -21
- package/build/cjs/tools/server-build.cjs +15 -129
- package/build/cjs/tools/server-warmup.cjs +2 -9
- package/build/cjs/tools/static-generation.cjs +8 -11
- package/build/es/context/provider.js +1 -0
- package/build/es/context/server.js +4 -0
- package/build/es/index.js +36 -25
- package/build/es/middleware/bundle-middleware.js +3 -2
- package/build/es/middleware/module-middleware.js +3 -1
- package/build/es/middleware/view-middleware.d.ts +2 -2
- package/build/es/middleware/view-middleware.js +12 -16
- package/build/es/tools/plugins/build-server-plugin.d.ts +18 -0
- package/build/es/tools/plugins/build-server-plugin.js +132 -0
- package/build/es/tools/plugins/generate-entry-plugin.d.ts +11 -0
- package/build/es/tools/plugins/generate-entry-plugin.js +45 -0
- package/build/es/tools/server-build.d.ts +5 -6
- package/build/es/tools/server-build.js +22 -152
- package/build/es/tools/server-warmup.js +3 -10
- package/build/es/tools/static-generation.js +10 -12
- package/package.json +28 -28
- package/build/cjs/context/configurations.cjs +0 -82
- package/build/cjs/context/global-data.cjs +0 -54
- package/build/es/context/configurations.d.ts +0 -9
- package/build/es/context/configurations.js +0 -53
- package/build/es/context/global-data.d.ts +0 -3
- package/build/es/context/global-data.js +0 -29
- package/build/es/context/services.d.ts +0 -3
- 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
|
-
|
|
39
|
-
|
|
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 =
|
|
45
|
+
const moduleProviders = createServices(services.moduleProviders, providerContext);
|
|
46
46
|
moduleRegistry.addModuleProviders(moduleProviders);
|
|
47
47
|
// Resource Providers
|
|
48
|
-
const resourceProviders = await
|
|
48
|
+
const resourceProviders = await createServices(services.resourceProviders, providerContext);
|
|
49
49
|
resourceRegistry.addResourceProviders(resourceProviders);
|
|
50
50
|
// View Providers
|
|
51
|
-
const viewProviders = await
|
|
51
|
+
const viewProviders = await createServices(services.viewProviders, providerContext);
|
|
52
52
|
// View Transformers
|
|
53
|
-
const viewTransformers = await
|
|
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
|
|
59
|
-
const assetTransformers = await
|
|
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 (
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
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
|
|
31
|
-
|
|
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,
|
|
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
|
|
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
|
|
111
|
-
|
|
112
|
-
|
|
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
|
|
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
|
|
8
|
-
* the LWR server. The bundled server will be written to the
|
|
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
|
|
11
|
-
* @param {BuildOptions} options - server build
|
|
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 {
|
|
5
|
-
import {
|
|
6
|
-
import
|
|
7
|
-
import
|
|
8
|
-
function
|
|
9
|
-
|
|
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: [
|
|
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
|
-
|
|
150
|
-
|
|
151
|
-
|
|
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
|
|
156
|
-
* the LWR server. The bundled server will be written to the
|
|
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
|
|
159
|
-
* @param {BuildOptions} options - server build
|
|
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
|
-
|
|
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
|
|
179
|
-
|
|
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
|