diff --git a/src/app/index.ts b/src/app/index.ts index c4df687..4e91d2f 100644 --- a/src/app/index.ts +++ b/src/app/index.ts @@ -72,6 +72,22 @@ export default class IlcAppSdk implements IIlcAppSdk { const intlAdapter = this.adapter.intl ? this.adapter.intl : defaultIntlAdapter; this.intl = new IlcIntl(this.appId, intlAdapter); } + /** + * Isomorphic method to render 404 page. + * At SSR in processResponse it sets 404 status code to response. + * At CSR it triggers global event which ILC listens and renders 404 page. + */ + render404 = () => { + if (this.adapter.setStatusCode) { + this.adapter.setStatusCode(404); + } else { + window.dispatchEvent( + new CustomEvent('ilc:404', { + detail: { appId: this.appId }, + }), + ); + } + }; unmount() { this.intl.unmount(); diff --git a/src/app/interfaces/common.ts b/src/app/interfaces/common.ts index ded121b..da6a850 100644 --- a/src/app/interfaces/common.ts +++ b/src/app/interfaces/common.ts @@ -27,8 +27,12 @@ export interface AppSdkAdapter { /** Unique application ID, if same app will be rendered twice on a page - it will get different IDs */ appId: string; intl: IntlAdapter | null; + setStatusCode: (code: number) => void; + getStatusCode: () => number | undefined; } +export type Render404 = () => void; + export interface IntlConfig { locale?: string; currency?: string; diff --git a/src/server/IlcSdk.ts b/src/server/IlcSdk.ts index 6dfedb9..8080a2c 100644 --- a/src/server/IlcSdk.ts +++ b/src/server/IlcSdk.ts @@ -55,6 +55,8 @@ export class IlcSdk { originalUri = '/'; } + let statusCode: number | undefined; + return { getCurrentReqHost: () => host, getCurrentReqUrl: () => requestedUrls.requestUrl, @@ -63,6 +65,10 @@ export class IlcSdk { getCurrentPathProps: () => passedProps, appId, intl: this.parseIntl(req), + setStatusCode: (code) => { + statusCode = code; + }, + getStatusCode: () => statusCode, }; } @@ -72,6 +78,11 @@ export class IlcSdk { * **WARNING:** this method should be called before response headers were send. */ public processResponse(reqData: types.RequestData, res: ServerResponse, data?: types.ResponseData): void { + const statusCode = reqData.getStatusCode(); + if (statusCode) { + res.statusCode = statusCode; + } + if (!data) { return; } diff --git a/test/server/IlcSdk.spec.ts b/test/server/IlcSdk.spec.ts index 82dd233..fd047bf 100644 --- a/test/server/IlcSdk.spec.ts +++ b/test/server/IlcSdk.spec.ts @@ -292,6 +292,19 @@ describe('IlcSdk', () => { ); }); + it('should set 404 status code', () => { + const NotFound = 404; + + const req = new MockReq(merge({}, defReq)); + const res = new MockRes(); + + const pRes = ilcSdk.processRequest(req); + pRes.setStatusCode(NotFound); + ilcSdk.processResponse(pRes, res); + + expect(res.statusCode).to.eq(NotFound); + }); + describe('appAssets', () => { it('should handle absolute URLs', () => { const req = new MockReq(merge({}, defReq));