Skip to content

Commit

Permalink
feat(async-ssr-manager): use Logger Feature Service instead of console (
Browse files Browse the repository at this point in the history
#415)

The integrator can now provide the Logger Feature Service, which the Async SSR Manager then uses for logging. The Async SSR Manager declares the Logger Feature Service as an optional dependency, and uses console as a fallback logger, when the Logger Feature Service is not provided.
  • Loading branch information
unstubbable authored and clebert committed Mar 12, 2019
1 parent a363757 commit e0f0605
Show file tree
Hide file tree
Showing 6 changed files with 99 additions and 14 deletions.
3 changes: 2 additions & 1 deletion packages/async-ssr-manager/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@
"module": "lib/esm/index.js",
"typings": "lib/cjs/index.d.ts",
"dependencies": {
"@feature-hub/core": "^1.1.0"
"@feature-hub/core": "^1.1.0",
"@feature-hub/logger": "^0.0.0"
},
"devDependencies": {
"jest-stub-methods": "^0.2.1"
Expand Down
54 changes: 46 additions & 8 deletions packages/async-ssr-manager/src/__tests__/index.test.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
// tslint:disable:no-implicit-dependencies

import {FeatureAppEnvironment, FeatureServiceBinder} from '@feature-hub/core';
import {stubMethods} from 'jest-stub-methods';
import {Stubbed, stubMethods} from 'jest-stub-methods';
import {
AsyncSsrManagerConfig,
AsyncSsrManagerV1,
asyncSsrManagerDefinition
} from '..';
import {stubbedLogger} from './stubbed-logger';
import {useFakeTimers} from './use-fake-timers';

const queueMacroTask = setImmediate;
Expand All @@ -23,7 +24,7 @@ describe('asyncSsrManagerDefinition', () => {
beforeEach(() => {
mockEnv = {
config: {timeout: 5},
featureServices: {},
featureServices: {'s2:logger': stubbedLogger},
idSpecifier: undefined,
instanceConfig: undefined
};
Expand All @@ -33,9 +34,12 @@ describe('asyncSsrManagerDefinition', () => {
expect(asyncSsrManagerDefinition.id).toBe('s2:async-ssr-manager');
});

it('has no dependencies', () => {
it('defines its dependencies', () => {
expect(asyncSsrManagerDefinition.dependencies).toBeUndefined();
expect(asyncSsrManagerDefinition.optionalDependencies).toBeUndefined();

expect(asyncSsrManagerDefinition.optionalDependencies).toEqual({
featureServices: {'s2:logger': '^1.0.0'}
});
});

describe('#create', () => {
Expand Down Expand Up @@ -292,7 +296,7 @@ describe('asyncSsrManagerDefinition', () => {
beforeEach(() => {
asyncSsrManagerBinder = asyncSsrManagerDefinition.create({
config: undefined,
featureServices: {}
featureServices: {'s2:logger': stubbedLogger}
})['1.0.0'];
});

Expand All @@ -305,13 +309,47 @@ describe('asyncSsrManagerDefinition', () => {
asyncSsrManager.renderUntilCompleted(mockRender)
);

expect(console.warn).toHaveBeenCalledWith(
'No timeout is configured for the Async SSR Manager. This could lead to unexpectedly long render times or, in the worst case, never resolving render calls!'
);
expect(stubbedLogger.warn.mock.calls).toEqual([
[
'No timeout is configured for the Async SSR Manager. This could lead to unexpectedly long render times or, in the worst case, never resolving render calls!'
]
]);

stubbedConsole.restore();
});
});
});

describe('when no Logger Feature Service is provided', () => {
let stubbedConsole: Stubbed<Console>;

beforeEach(() => {
stubbedConsole = stubMethods(console);

asyncSsrManagerBinder = asyncSsrManagerDefinition.create({
config: undefined,
featureServices: {}
})['1.0.0'];
});

afterEach(() => {
stubbedConsole.restore();
});

it('logs messages using the console', async () => {
const asyncSsrManager = asyncSsrManagerBinder('test').featureService;
const mockRender = jest.fn(() => 'testHtml');

await useFakeTimers(async () =>
asyncSsrManager.renderUntilCompleted(mockRender)
);

expect(stubbedConsole.stub.warn.mock.calls).toEqual([
[
'No timeout is configured for the Async SSR Manager. This could lead to unexpectedly long render times or, in the worst case, never resolving render calls!'
]
]);
});
});
});
});
12 changes: 12 additions & 0 deletions packages/async-ssr-manager/src/__tests__/stubbed-logger.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// tslint:disable:no-implicit-dependencies

import {Logger} from '@feature-hub/logger';
import {Stub} from 'jest-stub-methods';

export const stubbedLogger: Stub<Logger> = {
trace: jest.fn(),
debug: jest.fn(),
info: jest.fn(),
warn: jest.fn(),
error: jest.fn()
};
20 changes: 18 additions & 2 deletions packages/async-ssr-manager/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import {
FeatureServiceBinder,
FeatureServiceProviderDefinition,
FeatureServices,
SharedFeatureService
} from '@feature-hub/core';
import {Logger} from '@feature-hub/logger';
import {AsyncSsrManager} from './internal/async-ssr-manager';
import {createAsyncSsrManagerContext} from './internal/async-ssr-manager-context';
import {validateConfig} from './internal/validate-config';

export interface AsyncSsrManagerConfig {
Expand Down Expand Up @@ -83,19 +86,32 @@ export interface SharedAsyncSsrManager extends SharedFeatureService {
readonly '1.0.0': FeatureServiceBinder<AsyncSsrManagerV1>;
}

export interface AsyncSsrManagerDependencies extends FeatureServices {
readonly 's2:logger'?: Logger;
}

/**
* @see {@link AsyncSsrManagerV1} for further information.
*/
export const asyncSsrManagerDefinition: FeatureServiceProviderDefinition<
SharedAsyncSsrManager
SharedAsyncSsrManager,
AsyncSsrManagerDependencies
> = {
id: 's2:async-ssr-manager',

optionalDependencies: {
featureServices: {
's2:logger': '^1.0.0'
}
},

create: env => {
const context = createAsyncSsrManagerContext(env.featureServices);

const {timeout} =
validateConfig(env.config) || ({} as AsyncSsrManagerConfig);

const asyncSsrManager = new AsyncSsrManager(timeout);
const asyncSsrManager = new AsyncSsrManager(context, timeout);

return {
'1.0.0': () => ({featureService: asyncSsrManager})
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import {Logger} from '@feature-hub/logger';
import {AsyncSsrManagerDependencies} from '..';

export interface AsyncSsrManagerContext {
readonly logger: Logger;
}

export function createAsyncSsrManagerContext(
featureServices: AsyncSsrManagerDependencies
): AsyncSsrManagerContext {
const logger = featureServices['s2:logger'] || console;

return {logger};
}
10 changes: 7 additions & 3 deletions packages/async-ssr-manager/src/internal/async-ssr-manager.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {AsyncSsrManagerV1} from '..';
import {AsyncSsrManagerContext} from './async-ssr-manager-context';
import {setTimeoutAsync} from './set-timeout-async';

async function renderingTimeout(timeout: number): Promise<never> {
Expand All @@ -10,13 +11,16 @@ async function renderingTimeout(timeout: number): Promise<never> {
export class AsyncSsrManager implements AsyncSsrManagerV1 {
private readonly asyncOperations = new Set<Promise<unknown>>();

public constructor(private readonly timeout?: number) {}
public constructor(
private readonly context: AsyncSsrManagerContext,
private readonly timeout?: number
) {}

public async renderUntilCompleted(render: () => string): Promise<string> {
const renderPromise = this.renderingLoop(render);

if (typeof this.timeout !== 'number') {
console.warn(
this.context.logger.warn(
'No timeout is configured for the Async SSR Manager. This could lead to unexpectedly long render times or, in the worst case, never resolving render calls!'
);

Expand All @@ -38,7 +42,7 @@ export class AsyncSsrManager implements AsyncSsrManagerV1 {
while (this.asyncOperations.size > 0) {
while (this.asyncOperations.size > 0) {
// Storing a snapshot of the asynchronous operations and clearing them
// afterwards allows that consecutive promises can be added while the
// afterwards, allows that consecutive promises can be added while the
// current asynchronous operations are running.

const asyncOperationsSnapshot = Array.from(
Expand Down

0 comments on commit e0f0605

Please sign in to comment.