Angular Universal SSR 在预渲染阶段加载静态资源

问题描述 投票:0回答:2

我正在寻找一种访问

/assets/
文件夹中资源的方法,该文件夹用于在预渲染应用程序时在组件中构建内容。我正在使用 Angular 14 和
@nguniversal/express-engine
包。运行时我似乎无法在应用程序中读取静态资源
npm run prerender

我已经在#858看到了讨论,但是最后一个评论指出这在预渲染时不起作用。

我有一个最小的例子来说明我的意思: https://stackblitz.com/edit/angular-ivy-dxb32y?file=src%2Fapp%2Fapp.service.ts

你看到我的服务将路径变成了绝对URL:

  public getContents(path: string): Observable<string> {
    if (isPlatformServer(this.platformId) && path.includes('./')) {
      path = `http://localhost:4200/${path.replace('./', '')}`
    }
    return this.http.get(path, {
      observe: 'body',
      responseType: 'text',
    });
  }

并且

ssr:dev
命令可以正确提供此内容。 但是,在
prerender
下,我收到以下错误:

⠸ Prerendering 1 route(s) to C:\Users\***\preloading\dist\preloading\browser...ERROR HttpErrorResponse {
  headers: HttpHeaders {
    normalizedNames: Map(0) {},
    lazyUpdate: null,
    headers: Map(0) {}
  },
  status: 0,
  statusText: 'Unknown Error',
  url: 'http://localhost:4200/assets/file.txt',
  ok: false,
  name: 'HttpErrorResponse',
  message: 'Http failure response for http://localhost:4200/assets/file.txt: 0 Unknown Error',

我尝试了一些方法,例如:

  1. 将相对 URL 转换为绝对 URL (https://github.com/angular/universal/issues/858),但这在
    prerender
  2. 期间不起作用
  3. 使用
    fs
    读取静态资源,但是在
    prerender
    阶段找不到这些节点模块:
if (isPlatformServer(this.platformId) && path.includes('./')) {
     import("fs")
     path = `http://localhost:4200/${path.replace('./', '')}`
   }

给予:


✔ Browser application bundle generation complete.
⠦ Generating server application bundles (phase: sealing)...
./src/app/app.service.ts:14:8-20 - Error: Module not found: Error: Can't resolve 'fs' in 'C:\Users\***\preloading\src\app'

Error: src/app/app.service.ts:12:14 - error TS2307: Cannot find module 'fs' or its corresponding type declarations.

12       import("fs")

关于我能做什么还有其他想法吗?

node.js angular server-side-rendering angular-universal pre-rendering
2个回答
0
投票

所以我设法使用相对简单的解决方案来破解这个问题,即使用节点脚本运行

ng serve
npm run prerender

https://stackblitz.com/edit/angular-ivy-uy7wy9?file=prerender.js

var error = false;

function sleep(miliseconds) {
    console.log(`Sleeping for ${miliseconds} ms`);
    if (miliseconds == 0)
        return Promise.resolve();
    return new Promise(resolve => setTimeout(() => resolve(), miliseconds))
}

async function run() {
    try {

        console.log("Running Angular server");
        var proc = require('child_process').spawn('ng', ['serve']);
        await sleep(20000)

        console.log("Running prerender");
        var prerender = require('child_process').spawn('npm', ['run', 'prerender']);
        var prerenderTimeoutSeconds = 120;
        var timeoutObject;
        var timeoutResolve;
        var timeoutReject;
        var timeout = new Promise((resolve, reject) => {
            timeoutResolve = resolve;
            timeoutReject = reject;
            timeoutObject = setTimeout(() => {
                console.log('Timed out, killing prerender');
                try {
                    prerender.kill("SIGKILL")
                    reject(Error("Timed out running prerender"))
                } catch (e) {
                    console.error(e)
                    reject(Error('Cannot kill prerender'));
                }
            }, prerenderTimeoutSeconds * 1000)
        });

        prerender.stdout.on('data', (data) => {
            console.log(`prerender stdout: ${data}`);
        });

        prerender.stderr.on('data', (data) => {
            console.error(`prerender stderr: ${data}`);
        });

        prerender.on('close', (code) => {
            clearTimeout(timeoutObject);
            console.log(`prerender exited with code ${code}`)
            if (code === 0) {
                timeoutResolve()
            } else {
                timeoutReject(Error(`prerender exited with code ${code}`));
            }
        });

        await timeout

    } catch (err) {
        console.error(err);
        console.error(err.stack);
        error = true;
    } finally {
        if (proc) {
            console.log("Killing Angular server");
            var angularKilled = proc.kill("SIGKILL")
            console.log(`kill -9 on Angular success [${angularKilled}]`)
        }
    }
}

(async () => await run())();

if (error) {
    throw new Error("Exception during execution")
}

0
投票

您是否尝试禁用

outputHashing

© www.soinside.com 2019 - 2024. All rights reserved.