我正在寻找一种访问
/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',
我尝试了一些方法,例如:
prerender
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")
关于我能做什么还有其他想法吗?
所以我设法使用相对简单的解决方案来破解这个问题,即使用节点脚本运行
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")
}
您是否尝试禁用
outputHashing
?