create-sitecore-jss 22.3.0-canary.2 → 22.3.0-canary.4
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/dist/templates/angular-xmcloud/package.json +2 -2
- package/dist/templates/angular-xmcloud/server.exports.ts +2 -1
- package/dist/templates/angular-xmcloud/src/app/lib/graphql-client-factory/config.ts +2 -3
- package/dist/templates/nextjs-xmcloud/src/lib/middleware/plugins/personalize.ts +0 -1
- package/dist/templates/node-xmcloud-proxy/.env +11 -0
- package/dist/templates/node-xmcloud-proxy/src/config.ts +67 -1
- package/dist/templates/node-xmcloud-proxy/src/index.ts +20 -31
- package/dist/templates/node-xmcloud-proxy/src/personalize.ts +34 -0
- package/dist/templates/node-xmcloud-proxy/src/types.ts +10 -0
- package/package.json +2 -2
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
"prepare:proxy-build": "ts-node --project src/tsconfig.webpack-server.json ./scripts/proxy-build.ts"
|
|
9
9
|
},
|
|
10
10
|
"dependencies": {
|
|
11
|
-
"@sitecore-cloudsdk/core": "^0.4.0
|
|
12
|
-
"@sitecore-cloudsdk/events": "^0.4.0
|
|
11
|
+
"@sitecore-cloudsdk/core": "^0.4.0",
|
|
12
|
+
"@sitecore-cloudsdk/events": "^0.4.0",
|
|
13
13
|
"font-awesome": "^4.7.0",
|
|
14
14
|
"sass": "^1.52.3",
|
|
15
15
|
"sass-alias": "^1.0.5"
|
|
@@ -5,12 +5,12 @@ import { layoutServiceFactory } from './src/app/lib/layout-service-factory';
|
|
|
5
5
|
import { environment } from './src/environments/environment';
|
|
6
6
|
import { components } from './src/app/components/app-components.module';
|
|
7
7
|
import metadata from './src/environments/metadata.json';
|
|
8
|
-
|
|
9
8
|
/**
|
|
10
9
|
* Define the required configuration values to be exported from the server.bundle.ts.
|
|
11
10
|
*/
|
|
12
11
|
|
|
13
12
|
const defaultLanguage = environment.defaultLanguage;
|
|
13
|
+
const sitecoreSiteName = environment.sitecoreSiteName;
|
|
14
14
|
const getClientFactoryConfig = getGraphQLClientFactoryConfig;
|
|
15
15
|
|
|
16
16
|
export {
|
|
@@ -19,6 +19,7 @@ export {
|
|
|
19
19
|
dictionaryServiceFactory,
|
|
20
20
|
layoutServiceFactory,
|
|
21
21
|
defaultLanguage,
|
|
22
|
+
sitecoreSiteName,
|
|
22
23
|
components,
|
|
23
24
|
metadata,
|
|
24
25
|
};
|
|
@@ -28,10 +28,9 @@ export const getGraphQLClientFactoryConfig = () => {
|
|
|
28
28
|
: getEdgeProxyContentUrl(env.sitecoreEdgeContextId, env.proxyHost),
|
|
29
29
|
};
|
|
30
30
|
} else if (env.graphQLEndpoint && env.sitecoreApiKey) {
|
|
31
|
-
|
|
32
|
-
|
|
31
|
+
// we ignore ssr-proxy and query CM directly in case apiKey is used (i.e. in dev docker deployments)
|
|
33
32
|
clientConfig = {
|
|
34
|
-
endpoint:
|
|
33
|
+
endpoint: env.graphQLEndpoint,
|
|
35
34
|
apiKey: env.sitecoreApiKey,
|
|
36
35
|
};
|
|
37
36
|
}
|
|
@@ -12,3 +12,14 @@ PROXY_BUNDLE_PATH=
|
|
|
12
12
|
|
|
13
13
|
# Set the DEBUG environment variable to 'sitecore-jss:*,sitecore-jss:proxy,http-proxy-middleware*' to see all logs:
|
|
14
14
|
#DEBUG=sitecore-jss:*,http-proxy-middleware*
|
|
15
|
+
|
|
16
|
+
# An optional Sitecore Personalize scope identifier.
|
|
17
|
+
# This can be used to isolate personalization data when multiple XM Cloud Environments share a Personalize tenant.
|
|
18
|
+
# This should match the PAGES_PERSONALIZE_SCOPE environment variable for your connected XM Cloud Environment.
|
|
19
|
+
PERSONALIZE_SCOPE=
|
|
20
|
+
|
|
21
|
+
# Timeout (ms) for Sitecore CDP requests to respond within. Default is 400.
|
|
22
|
+
PERSONALIZE_MIDDLEWARE_CDP_TIMEOUT=
|
|
23
|
+
|
|
24
|
+
# Timeout (ms) for Sitecore Experience Edge requests to respond within. Default is 400.
|
|
25
|
+
PERSONALIZE_MIDDLEWARE_EDGE_TIMEOUT=
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Config, ServerBundle } from './types';
|
|
2
|
-
|
|
2
|
+
import { PersonalizeConfig } from '@sitecore-jss/sitecore-jss-proxy';
|
|
3
3
|
/**
|
|
4
4
|
* The server.bundle.js file from your pre-built SPA app.
|
|
5
5
|
*/
|
|
@@ -13,6 +13,39 @@ try {
|
|
|
13
13
|
throw new Error(`ERROR: The server.bundle.js error. ${error}`);
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
+
const clientFactoryConfig = serverBundle.getClientFactoryConfig();
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* GraphQL endpoint resolution to meet the requirements of the http-proxy-middleware
|
|
20
|
+
*/
|
|
21
|
+
export const graphQLEndpoint = (() => {
|
|
22
|
+
try {
|
|
23
|
+
const graphQLEndpoint = new URL(clientFactoryConfig.endpoint);
|
|
24
|
+
// GraphQL endpoint URL (Edge endpoint for production and GraphQL Sitecore CM endpoint for dev)
|
|
25
|
+
const graphQLEndpointUrl = `${graphQLEndpoint.protocol}//${graphQLEndpoint.hostname}`;
|
|
26
|
+
// Sitecore Edge Context ID - will only be present for production
|
|
27
|
+
const sitecoreEdgeContextId = graphQLEndpoint.searchParams.get('sitecoreContextId');
|
|
28
|
+
// Browser request path to the proxy. Includes only the pathname.
|
|
29
|
+
const pathname = graphQLEndpoint.pathname;
|
|
30
|
+
// Target URL for the proxy. Can't include the query string.
|
|
31
|
+
const target = `${graphQLEndpointUrl}${pathname}`;
|
|
32
|
+
|
|
33
|
+
return {
|
|
34
|
+
target,
|
|
35
|
+
path: pathname,
|
|
36
|
+
graphQLEndpointUrl,
|
|
37
|
+
sitecoreEdgeContextId,
|
|
38
|
+
};
|
|
39
|
+
} catch (error) {
|
|
40
|
+
throw new Error(
|
|
41
|
+
`ERROR: The serverBundle should export a getClientFactoryConfig function with valid GraphQL endpoint URL returned, current value is ${clientFactoryConfig.endpoint}. ` +
|
|
42
|
+
'Please check your server bundle.'
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
})();
|
|
46
|
+
|
|
47
|
+
const { clientFactory } = serverBundle;
|
|
48
|
+
|
|
16
49
|
export const config: Config = {
|
|
17
50
|
/**
|
|
18
51
|
* The require'd server.bundle.js file from your pre-built SPA app.
|
|
@@ -23,3 +56,36 @@ export const config: Config = {
|
|
|
23
56
|
*/
|
|
24
57
|
port: process.env.PROXY_PORT || 3000,
|
|
25
58
|
};
|
|
59
|
+
|
|
60
|
+
export const personalizeConfig: PersonalizeConfig = {
|
|
61
|
+
// Configuration for your Sitecore Experience Edge endpoint
|
|
62
|
+
edgeConfig: {
|
|
63
|
+
clientFactory,
|
|
64
|
+
timeout:
|
|
65
|
+
(process.env.PERSONALIZE_MIDDLEWARE_EDGE_TIMEOUT &&
|
|
66
|
+
parseInt(process.env.PERSONALIZE_MIDDLEWARE_EDGE_TIMEOUT)) ||
|
|
67
|
+
400,
|
|
68
|
+
},
|
|
69
|
+
// Configuration for your Sitecore CDP endpoint
|
|
70
|
+
// Edge URL and ID can be taken from proxy env, or the base SPA app
|
|
71
|
+
cdpConfig: {
|
|
72
|
+
sitecoreEdgeUrl: graphQLEndpoint.graphQLEndpointUrl,
|
|
73
|
+
sitecoreEdgeContextId: graphQLEndpoint.sitecoreEdgeContextId || '',
|
|
74
|
+
timeout:
|
|
75
|
+
(process.env.PERSONALIZE_MIDDLEWARE_CDP_TIMEOUT &&
|
|
76
|
+
parseInt(process.env.PERSONALIZE_MIDDLEWARE_CDP_TIMEOUT)) ||
|
|
77
|
+
400,
|
|
78
|
+
},
|
|
79
|
+
// Optional Sitecore Personalize scope identifier.
|
|
80
|
+
scope: process.env.PERSONALIZE_SCOPE,
|
|
81
|
+
// This function determines if the personalization should be turned off.
|
|
82
|
+
// IMPORTANT: You should implement based on your cookie consent management solution of choice.
|
|
83
|
+
// You may wish to keep it disabled while in development mode.
|
|
84
|
+
// Personalization will also be disabled when edge context id is missing
|
|
85
|
+
disabled: () => process.env.NODE_ENV === 'development' || !graphQLEndpoint.sitecoreEdgeContextId,
|
|
86
|
+
// This function determines if a route should be excluded from personalization.
|
|
87
|
+
excludeRoute: () => false,
|
|
88
|
+
sitecoreSiteName: serverBundle.sitecoreSiteName || '',
|
|
89
|
+
// defaultLanguage will be used as fallback for personalization, if language cannot be read from layout service data
|
|
90
|
+
defaultLanguage: serverBundle.defaultLanguage,
|
|
91
|
+
};
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import 'dotenv/config';
|
|
2
2
|
import express, { Response } from 'express';
|
|
3
3
|
import compression from 'compression';
|
|
4
|
-
import { createProxyMiddleware } from 'http-proxy-middleware';
|
|
4
|
+
import { createProxyMiddleware, fixRequestBody } from 'http-proxy-middleware';
|
|
5
5
|
import { debug } from '@sitecore-jss/sitecore-jss';
|
|
6
|
-
import { editingRouter } from '@sitecore-jss/sitecore-jss-proxy';
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
6
|
+
import { editingRouter, healthCheck } from '@sitecore-jss/sitecore-jss-proxy';
|
|
7
|
+
import { config, graphQLEndpoint } from './config';
|
|
8
|
+
import { personalizeHelper, personalizePlugin } from './personalize';
|
|
9
9
|
|
|
10
10
|
const server = express();
|
|
11
11
|
|
|
@@ -45,31 +45,6 @@ const layoutService = layoutServiceFactory.create();
|
|
|
45
45
|
|
|
46
46
|
const dictionaryService = dictionaryServiceFactory.create();
|
|
47
47
|
|
|
48
|
-
const clientFactoryConfig = config.serverBundle.getClientFactoryConfig();
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* GraphQL endpoint resolution to meet the requirements of the http-proxy-middleware
|
|
52
|
-
*/
|
|
53
|
-
const graphQLEndpoint = (() => {
|
|
54
|
-
try {
|
|
55
|
-
const graphQLEndpoint = new URL(clientFactoryConfig.endpoint);
|
|
56
|
-
// Browser request path to the proxy. Includes only the pathname.
|
|
57
|
-
const pathname = graphQLEndpoint.pathname;
|
|
58
|
-
// Target URL for the proxy. Can't include the query string.
|
|
59
|
-
const target = `${graphQLEndpoint.protocol}//${graphQLEndpoint.hostname}${pathname}`;
|
|
60
|
-
|
|
61
|
-
return {
|
|
62
|
-
target,
|
|
63
|
-
path: pathname,
|
|
64
|
-
};
|
|
65
|
-
} catch (error) {
|
|
66
|
-
throw new Error(
|
|
67
|
-
`ERROR: The serverBundle should export a getClientFactoryConfig function with valid GraphQL endpoint URL returned, current value is ${clientFactoryConfig.endpoint}. ` +
|
|
68
|
-
'Please check your server bundle.'
|
|
69
|
-
);
|
|
70
|
-
}
|
|
71
|
-
})();
|
|
72
|
-
|
|
73
48
|
/**
|
|
74
49
|
* Parse requested url in order to detect current route and language
|
|
75
50
|
* @param {string} reqRoute requested route
|
|
@@ -105,6 +80,8 @@ const handleError = (res: Response, err: unknown) => {
|
|
|
105
80
|
|
|
106
81
|
// enable gzip compression for appropriate file types
|
|
107
82
|
server.use(compression());
|
|
83
|
+
// enable access to req.body
|
|
84
|
+
server.use(graphQLEndpoint.path, express.json());
|
|
108
85
|
|
|
109
86
|
// turn off x-powered-by http header
|
|
110
87
|
server.settings['x-powered-by'] = false;
|
|
@@ -125,6 +102,12 @@ server.use(
|
|
|
125
102
|
createProxyMiddleware({
|
|
126
103
|
target: graphQLEndpoint.target,
|
|
127
104
|
changeOrigin: true,
|
|
105
|
+
selfHandleResponse: true,
|
|
106
|
+
on: {
|
|
107
|
+
proxyReq: fixRequestBody,
|
|
108
|
+
},
|
|
109
|
+
// for client-side routing, personalization is performed by modifying layout service response
|
|
110
|
+
plugins: [personalizePlugin],
|
|
128
111
|
})
|
|
129
112
|
);
|
|
130
113
|
|
|
@@ -165,11 +148,17 @@ server.use(async (req, res) => {
|
|
|
165
148
|
}
|
|
166
149
|
|
|
167
150
|
// Language is required. In case it's not specified in the requested URL, fallback to the default language from the app configuration.
|
|
168
|
-
|
|
151
|
+
let layoutData = await layoutService.fetchLayoutData(
|
|
169
152
|
route,
|
|
170
153
|
lang || config.serverBundle.defaultLanguage
|
|
171
154
|
);
|
|
172
|
-
|
|
155
|
+
// for SSR loading routing, personalization is performed by modifying layoutData directly
|
|
156
|
+
const personalizedLayoutData = await personalizeHelper.personalizeLayoutData(
|
|
157
|
+
req,
|
|
158
|
+
res,
|
|
159
|
+
layoutData
|
|
160
|
+
);
|
|
161
|
+
layoutData = personalizedLayoutData;
|
|
173
162
|
const viewBag = { dictionary: {} };
|
|
174
163
|
|
|
175
164
|
viewBag.dictionary = await dictionaryService.fetchDictionaryData(
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { GRAPHQL_LAYOUT_QUERY_NAME, PersonalizeHelper } from '@sitecore-jss/sitecore-jss-proxy';
|
|
2
|
+
import { personalizeConfig } from './config';
|
|
3
|
+
import { responseInterceptor } from 'http-proxy-middleware';
|
|
4
|
+
import { Plugin } from 'http-proxy-middleware/dist/types';
|
|
5
|
+
import { IncomingMessageWithBody } from './types';
|
|
6
|
+
|
|
7
|
+
export const personalizeHelper = new PersonalizeHelper(personalizeConfig);
|
|
8
|
+
|
|
9
|
+
// personalize plugin to modify intercepted Layout Service request data
|
|
10
|
+
export const personalizePlugin: Plugin = (proxyServer) => {
|
|
11
|
+
proxyServer.on(
|
|
12
|
+
'proxyRes',
|
|
13
|
+
responseInterceptor(async (responseBuffer, _, req, res) => {
|
|
14
|
+
let responseText = responseBuffer.toString('utf8');
|
|
15
|
+
const payload = JSON.stringify((req as IncomingMessageWithBody).body);
|
|
16
|
+
|
|
17
|
+
// only apply personalization onto JSS layout service results
|
|
18
|
+
if (payload.includes(GRAPHQL_LAYOUT_QUERY_NAME)) {
|
|
19
|
+
let layoutDataRaw = JSON.parse(responseText);
|
|
20
|
+
if (!layoutDataRaw?.data?.layout?.item?.rendered?.sitecore) {
|
|
21
|
+
return responseText;
|
|
22
|
+
}
|
|
23
|
+
const personalizedLayout = await personalizeHelper.personalizeLayoutData(
|
|
24
|
+
req as IncomingMessageWithBody,
|
|
25
|
+
res,
|
|
26
|
+
layoutDataRaw?.data?.layout?.item?.rendered
|
|
27
|
+
);
|
|
28
|
+
layoutDataRaw.data.layout.item.rendered = personalizedLayout;
|
|
29
|
+
responseText = JSON.stringify(layoutDataRaw);
|
|
30
|
+
}
|
|
31
|
+
return responseText;
|
|
32
|
+
})
|
|
33
|
+
);
|
|
34
|
+
};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/* eslint-disable no-unused-vars */
|
|
1
2
|
import {
|
|
2
3
|
GraphQLRequestClientFactory,
|
|
3
4
|
GraphQLRequestClientFactoryConfig,
|
|
@@ -6,6 +7,7 @@ import { DictionaryService } from '@sitecore-jss/sitecore-jss/i18n';
|
|
|
6
7
|
import { Metadata } from '@sitecore-jss/sitecore-jss/utils';
|
|
7
8
|
import { LayoutService } from '@sitecore-jss/sitecore-jss/layout';
|
|
8
9
|
import { AppRenderer, RouteUrlParser } from '@sitecore-jss/sitecore-jss-proxy';
|
|
10
|
+
import { IncomingMessage } from 'http';
|
|
9
11
|
|
|
10
12
|
export interface ServerBundle {
|
|
11
13
|
[key: string]: unknown;
|
|
@@ -14,6 +16,7 @@ export interface ServerBundle {
|
|
|
14
16
|
clientFactory: GraphQLRequestClientFactory;
|
|
15
17
|
getClientFactoryConfig: () => GraphQLRequestClientFactoryConfig;
|
|
16
18
|
defaultLanguage: string;
|
|
19
|
+
sitecoreSiteName: string;
|
|
17
20
|
layoutServiceFactory: { create: () => LayoutService };
|
|
18
21
|
dictionaryServiceFactory: { create: () => DictionaryService };
|
|
19
22
|
components: string[] | Map<string, unknown>;
|
|
@@ -25,3 +28,10 @@ export interface Config {
|
|
|
25
28
|
port: string | number;
|
|
26
29
|
serverBundle: ServerBundle;
|
|
27
30
|
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* IncomingMessage type modified with exporess.json() call to include request body
|
|
34
|
+
*/
|
|
35
|
+
export type IncomingMessageWithBody = IncomingMessage & {
|
|
36
|
+
body: ReadableStream<Uint8Array> | null;
|
|
37
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-sitecore-jss",
|
|
3
|
-
"version": "22.3.0-canary.
|
|
3
|
+
"version": "22.3.0-canary.4",
|
|
4
4
|
"description": "Sitecore JSS initializer",
|
|
5
5
|
"bin": "./dist/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -63,5 +63,5 @@
|
|
|
63
63
|
"ts-node": "^10.9.1",
|
|
64
64
|
"typescript": "~4.9.5"
|
|
65
65
|
},
|
|
66
|
-
"gitHead": "
|
|
66
|
+
"gitHead": "41544c7c448dc62a8327fe3d3fe3937b61252226"
|
|
67
67
|
}
|