Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[node-xmcloud-proxy] [Angular] /api/editing/config endpoint #1903

Merged
merged 12 commits into from
Aug 26, 2024
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ Our versioning strategy is as follows:
* `[create-sitecore-jss]` Rework Angular initializer to support XMCloud and SXP journeys ([#1845](https://github.com/Sitecore/jss/pull/1845))([#1858](https://github.com/Sitecore/jss/pull/1858))([#1868](https://github.com/Sitecore/jss/pull/1868))([#1881](https://github.com/Sitecore/jss/pull/1881))([#1882](https://github.com/Sitecore/jss/pull/1882))
* `[create-sitecore-jss]` Allow node-xmcloud-proxy app to be installed alongside Angular SPA application
* `proxyAppDestination` arg can be passed into `create-sitecore-jss` command to define path for proxy to be installed in
* `[create-sitecore-jss]` `[template/angular]` `[template/angular-xmcloud]` `[template/node-xmcloud-proxy]` Introduced /api/editing/config endpoint ([#1903](https://github.com/Sitecore/jss/pull/1903))
* `[create-sitecore-jss]``[sitecore-jss-angular]``[template/angular-xmcloud]` Angular SXA components
* Angular placeholder now supports SXA components ([#1870](https://github.com/Sitecore/jss/pull/1870))
* Title component ([#1904](https://github.com/Sitecore/jss/pull/1904))
Expand All @@ -44,6 +45,10 @@ Our versioning strategy is as follows:

### 🛠 Breaking Change

* `[sitecore-jss-proxy]` Updated exports of the module for better extensibility ([#1903](https://github.com/Sitecore/jss/pull/1903))
* `express@^4.19.2` dependency is marked as a peer dependency
* Default `scProxy` middleware export is replaced by `headlessProxy` object that contains the `middleware`, `ProxyConfig`, `ServerBundle` properties

### 🧹 Chores

## 22.1.0
Expand Down
55 changes: 55 additions & 0 deletions docs/upgrades/unreleased.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,31 @@ If you plan to use the Angular SDK with XMCloud, you will need to perform next s
"build:client": "cross-env-shell ng build --configuration=production --base-href $npm_package_config_sitecoreDistPath/browser/ --output-path=$npm_package_config_buildArtifactsPath/browser/"
```

* Update /scripts/bootstrap.ts file to generate a metadata for editing integration:
Assuming that you have a `generate-metadata.ts` file pulled from the "angular-xmcloud" add-on:

```ts
...
/*
METADATA GENERATION
*/
require('./generate-metadata');
...
```

* Update /scripts/generate-component-factory.ts to generate a list of component names for the editing integration, see implementation in the the "angular" template:

```ts
import { AppComponentsSharedModule } from './app-components.shared.module';
${imports.join('\n')}

export const components = [
${components.map((c) => `'${c}'`).join(',\n ')}
];

@NgModule({
```

* Restructure /src/app/lib/client-factory.ts. This is needed in order to separate the GraphQL client factory configuration from the client factory itself, so we have a single source of GraphQL endpoint resolution that can be used in different places. For example node-xmcloud-proxy, scripts/update-graphql-fragment-data.ts, etc.
* Introduce /src/app/lib/graphql-client-factory/config.ts. It should expose the _getGraphQLClientFactoryConfig_ that returns the configuration object for the GraphQL client factory, for example (full code snippet you can find in the "angular-xmcloud" add-on):

Expand Down Expand Up @@ -72,6 +97,8 @@ If you plan to use the Angular SDK with XMCloud, you will need to perform next s
import { getGraphQLClientFactoryConfig } from './src/app/lib/graphql-client-factory/config';
import { dictionaryServiceFactory } from './src/app/lib/dictionary-service-factory';
import { layoutServiceFactory } from './src/app/lib/layout-service-factory';
import { components } from './src/app/components/app-components.module';
import metadata from './src/environments/metadata.json';

...
const defaultLanguage = environment.defaultLanguage;
Expand All @@ -84,9 +111,13 @@ If you plan to use the Angular SDK with XMCloud, you will need to perform next s
dictionaryServiceFactory,
layoutServiceFactory,
defaultLanguage,
components,
metadata
};
```

* Optionally, you can follow our new approach and create a separate file `server.exports.ts` where you can import/export all the necessary properties and then re-export them from `server.bundle.ts`. See the "angular-xmcloud" add-on for more details.

* GraphQL FETCH_WITH method is required to be used, REST is not supported. Update FETCH_WITH environment variable if needed.

* Update /src/app/lib/dictionary-service-factory.ts to use new `useSiteQuery` property. You will be able to use a Site query to get the dictionary data:
Expand All @@ -98,3 +129,27 @@ If you plan to use the Angular SDK with XMCloud, you will need to perform next s
useSiteQuery: true,
});
```

# @sitecore-jss/sitecore-jss-proxy

* Update the import statement

```ts
// from
import scProxy, { ProxyConfig, ServerBundle } from '@sitecore-jss/sitecore-jss-proxy';
// to
import { headlessProxy } from '@sitecore-jss/sitecore-jss-proxy';
...
server.use(
'*',
headlessProxy.middleware(
config.serverBundle.renderView,
config,
config.serverBundle.parseRouteUrl
)
);
```

Now `middleware`, `ProxyConfig`, `ServerBundle` properties are available on the "headlessProxy" object.

* `express` dependency is marked as a peer dependency, so you need to match the required version "^4.19.2".
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import 'dotenv/config';

/*
BOOTSTRAPPING
The bootstrap process runs before build, and generates TS that needs to be
included into the build - specifically, the component name to component mapping,
and the global config module.
*/

/*
PLUGINS GENERATION
*/
require('./generate-plugins');

/*
CONFIG GENERATION
*/
require('./generate-config');

/*
COMPONENT FACTORY GENERATION
*/
require('./generate-component-factory');

/*
METADATA GENERATION
*/
require('./generate-metadata');
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import fs from 'fs';
import path from 'path';
import { Metadata, getMetadata } from '@sitecore-jss/sitecore-jss-dev-tools';

/*
METADATA GENERATION
Generates the /src/environments/metadata.json file which contains application
configuration metadata that is used for Sitecore XM Cloud integration.
*/
generateMetadata();

function generateMetadata(): void {
const metadata: Metadata = getMetadata();
writeMetadata(metadata);
}

/**
* Writes the metadata object to disk.
* @param {Metadata} metadata metadata to write.
*/
function writeMetadata(metadata: Metadata): void {
const filePath = path.resolve('src/environments/metadata.json');
console.log(`Writing metadata to ${filePath}`);
fs.writeFileSync(filePath, JSON.stringify(metadata, null, 2), { encoding: 'utf8' });
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import clientFactory from './src/app/lib/graphql-client-factory';
import { getGraphQLClientFactoryConfig } from './src/app/lib/graphql-client-factory/config';
import { dictionaryServiceFactory } from './src/app/lib/dictionary-service-factory';
import { layoutServiceFactory } from './src/app/lib/layout-service-factory';
import { environment } from './src/environments/environment';
import { components } from './src/app/components/app-components.module';
import metadata from './src/environments/metadata.json';

/**
* Define the required configuration values to be exported from the server.bundle.ts.
*/

const apiKey = environment.sitecoreApiKey;
const siteName = environment.sitecoreSiteName;
const defaultLanguage = environment.defaultLanguage;
const getClientFactoryConfig = getGraphQLClientFactoryConfig;

export {
apiKey,
siteName,
clientFactory,
getClientFactoryConfig,
dictionaryServiceFactory,
layoutServiceFactory,
defaultLanguage,
components,
metadata,
};
Original file line number Diff line number Diff line change
Expand Up @@ -79,12 +79,14 @@ function generateComponentFactory() {
const registrations: string[] = [];
const lazyRegistrations: string[] = [];
const declarations: string[] = [];
const components: string[] = [];

packages.forEach((p) => {
const variables = p.components
.map((c) => {
registrations.push(`{ name: '${c.componentName}', type: ${c.moduleName} },`);
declarations.push(`${c.moduleName},`);
components.push(c.componentName);

return c.moduleName;
})
Expand Down Expand Up @@ -118,6 +120,8 @@ function generateComponentFactory() {
const componentName = componentClassMatch[1];
const importVarName = `${componentName}Component`;

components.push(componentName);

// check for lazy loading needs
const moduleFilePath = path.join(componentRootPath, componentFolder, `${componentFolder}.module.ts`);
const isLazyLoaded = fs.existsSync(moduleFilePath);
Expand All @@ -144,6 +148,10 @@ import { JssModule } from '@sitecore-jss/sitecore-jss-angular';
import { AppComponentsSharedModule } from './app-components.shared.module';
${imports.join('\n')}

export const components = [
${components.map((c) => `'${c}'`).join(',\n ')}
];

@NgModule({
imports: [
AppComponentsSharedModule,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,12 @@ import { join } from 'path';
import 'reflect-metadata';
import 'zone.js';
import { JssRouteBuilderService } from './src/app/routing/jss-route-builder.service';
import { environment } from './src/environments/environment';
import { AppServerModule, renderModule } from './src/main.server';
import clientFactory from './src/app/lib/graphql-client-factory';
import { getGraphQLClientFactoryConfig } from './src/app/lib/graphql-client-factory/config';
import { dictionaryServiceFactory } from './src/app/lib/dictionary-service-factory';
import { layoutServiceFactory } from './src/app/lib/layout-service-factory';

export * from './src/main.server';

export * from './server.exports';

const http = require('http');
const https = require('https');

Expand Down Expand Up @@ -101,20 +98,4 @@ function parseRouteUrl(url: string) {
};
}

const apiKey = environment.sitecoreApiKey;
const siteName = environment.sitecoreSiteName;
const defaultLanguage = environment.defaultLanguage;
const getClientFactoryConfig = getGraphQLClientFactoryConfig;

export {
renderView,
parseRouteUrl,
setUpDefaultAgents,
apiKey,
siteName,
clientFactory,
getClientFactoryConfig,
dictionaryServiceFactory,
layoutServiceFactory,
defaultLanguage,
};
export { renderView, parseRouteUrl, setUpDefaultAgents };
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { environment } from './src/environments/environment';

/**
* Define the required configuration values to be exported from the server.bundle.ts.
*/

const apiKey = environment.sitecoreApiKey;
const siteName = environment.sitecoreSiteName;

export {
apiKey,
siteName,
};
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ProxyConfig, ServerBundle } from '@sitecore-jss/sitecore-jss-proxy';
import { headlessProxy } from '@sitecore-jss/sitecore-jss-proxy';
import fs from 'fs';
import { RestDictionaryService } from '@sitecore-jss/sitecore-jss/i18n';
import { httpAgentsConfig } from './httpAgents';
Expand All @@ -13,7 +13,7 @@ let siteName = process.env.SITECORE_SITE_NAME || appName;

const bundlePath = process.env.SITECORE_JSS_SERVER_BUNDLE || `../dist/${appName}/server.bundle`;

const serverBundle = require(bundlePath) as ServerBundle;
const serverBundle = require(bundlePath) as headlessProxy.ServerBundle;

httpAgentsConfig.setUpDefaultAgents(serverBundle);

Expand All @@ -33,7 +33,7 @@ const dictionaryService = new RestDictionaryService({
/**
* @type {ProxyConfig}
*/
export const config: ProxyConfig = {
export const config: headlessProxy.ProxyConfig = {
/**
* The require'd server.bundle.js file from your pre-built JSS app
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ServerBundle } from '@sitecore-jss/sitecore-jss-proxy';
import { headlessProxy } from '@sitecore-jss/sitecore-jss-proxy';
import keepAlive from 'agentkeepalive';
import http from 'http';
import https from 'https';
Expand All @@ -14,7 +14,7 @@ const httpAgent = new keepAlive(keepAliveConfig);
const httpsAgent = (new keepAlive.HttpsAgent(keepAliveConfig) as unknown) as https.Agent;

interface HttpAgentsConfig {
setUpDefaultAgents: (serverBundle: ServerBundle) => void;
setUpDefaultAgents: (serverBundle: headlessProxy.ServerBundle) => void;
getAgent: (url: string) => http.Agent | https.Agent;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import express from 'express';
import compression from 'compression';
import 'dotenv/config';
import scProxy from '@sitecore-jss/sitecore-jss-proxy';
import { headlessProxy } from '@sitecore-jss/sitecore-jss-proxy';
import { config } from './config';
//import { cacheMiddleware } from './cacheMiddleware';

Expand Down Expand Up @@ -42,7 +42,14 @@ server.use((req, _res, next) => {
});

// For any other requests, we render app routes server-side and return them
server.use('*', scProxy(config.serverBundle.renderView, config, config.serverBundle.parseRouteUrl));
server.use(
'*',
headlessProxy.middleware(
config.serverBundle.renderView,
config,
config.serverBundle.parseRouteUrl
)
);

server.listen(port, () => {
console.log(`server listening on port ${port}!`);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
# To secure the Sitecore editor endpoint exposed by your proxy app
# (`/api/editing/render` by default), a secret token is used.
# The environment variable is used by `editingRouter`
# We recommend an alphanumeric value of at least 16 characters.
JSS_EDITING_SECRET=

# Your proxy port (default: 3001)
PROXY_PORT=

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"start": "ts-node ./src/index.ts"
},
"dependencies": {
"@sitecore-jss/sitecore-jss-proxy": "~22.2.0-canary",
"compression": "^1.7.4",
"express": "^4.18.2",
"dotenv": "^16.0.3",
Expand Down
Loading