Repository: angular/angular-cli
File: packages/angular/ssr/node/src/common-engine/common-engine.ts (TypeScript)

Code before:

  constructor(private options?: CommonEngineOptions) {
    this.allowedHosts = new Set([
      ...getAllowedHostsFromEnv(),
      ...(this.options?.allowedHosts ?? []),
    ]);

    attachNodeGlobalErrorHandlers();
  }

  /**
   * Render an HTML document for a specific URL with specified
   * render options
   */
  async render(opts: CommonEngineRenderOptions): Promise<string> {
    const { url } = opts;

    if (url && URL.canParse(url)) {
      const urlObj = new URL(url);
      try {
        validateUrl(urlObj, this.allowedHosts);
      } catch (error) {
        const isAllowedHostConfigured = this.allowedHosts.size > 0;
        // eslint-disable-next-line no-console
        console.error(
          `ERROR: ${(error as Error).message}` +
            'Please provide a list of allowed hosts in the "allowedHosts" option in the "CommonEngine" constructor.',
          isAllowedHostConfigured
            ? ''
            : '\nFalling back to client side rendering. This will become a 400 Bad Request in a future major version.',
        );

        if (!isAllowedHostConfigured) {
          // Fallback to CSR to avoid a breaking change.
          // TODO(alanagius): Return a 400 and remove this fallback in the next major version (v22).
          let document = opts.document;
          if (!document && opts.documentFilePath) {
            document = opts.document ?? (await this.getDocument(opts.documentFilePath));
          }

          if (document) {
            return document;
          }
        }

        throw error;
      }
    }

    const enablePerformanceProfiler = this.options?.enablePerformanceProfiler;


Review comment (suggestion):
Consider: Do we still want a separate log statement since we have an unconditional`throw` below? I feel like this would result in double-logging this error under more circumstances.

Code after:

  constructor(private options?: CommonEngineOptions) {
    this.allowedHosts = new Set([
      ...getAllowedHostsFromEnv(),
      ...(this.options?.allowedHosts ?? []),
    ]);

    attachNodeGlobalErrorHandlers();
  }

  /**
   * Render an HTML document for a specific URL with specified
   * render options
   */
  async render(opts: CommonEngineRenderOptions): Promise<string> {
    const { url } = opts;

    if (url && URL.canParse(url)) {
      const urlObj = new URL(url);
      try {
        validateUrl(urlObj, this.allowedHosts);
      } catch (error) {
        // eslint-disable-next-line no-console
        console.error(
          `ERROR: ${(error as Error).message}` +
            'Please provide a list of allowed hosts in the "allowedHosts" option in the "CommonEngine" constructor.',
        );

        throw error;
      }
    }

    const enablePerformanceProfiler = this.options?.enablePerformanceProfiler;

    const runMethod = enablePerformanceProfiler
      ? runMethodAndMeasurePerf
      : noopRunMethodAndMeasurePerf;

    let html = await runMethod('Retrieve SSG Page', () => this.retrieveSSGPage(opts));

    if (html === undefined) {
      html = await runMethod('Render Page', () => this.renderApplication(opts));

      if (opts.inlineCriticalCss !== false) {
        const content = await runMethod('Inline Critical CSS', () =>
          // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
          this.inlineCriticalCss(html!, opts),
        );

        html = content;
      }