在许多 Angular universal
或 Scully
项目的 README
里,都能看到类似
SERVER_REQUEST_ORIGIN="http://localhost:4200" npm run prerender
这样的单行指令。它通过一次性地向后续 npm run prerender
进程注入环境变量,从而让 server-side prerender
阶段能够知道当前请求要模拟的 origin
。这条指令之所以常被放进文档,是因为 prerender builder
在离线渲染每个路由时仍需构造绝对 URL
,而某些 SDK(例如 Spartacus storefront
)在生成链接或执行 absolute redirect
时会查阅 process.env.SERVER_REQUEST_ORIGIN
来判定主机名。(help.sap.com)
语法逐段拆解
片段 | 说明 |
---|---|
SERVER_REQUEST_ORIGIN=http://localhost:4200 | 使用 POSIX shell 的前缀赋值语法创建一个仅对紧随其后的命令可见的环境变量;赋值结束后变量自动失效。(stackoverflow.com, unix.stackexchange.com) |
npm run prerender | 触发 package.json 里的同名脚本。Angular cli ≥ 11 在添加 SSR/Prerender 支持时默认生成此脚本并映射到 ng run <project>:prerender 。(dev.to, simply-how.com) |
这类“前缀赋值 + 命令”组合在 bash
, zsh
, dash
等 Unix-like
shell 中属于标准写法,被 POSIX
定义为 environment augmentation。(askubuntu.com)
变量在 prerender
阶段扮演的角色
-
Angular universal
在服务器入口文件server.ts
内部读取process.env
。开发者可借此为HttpClient
提供绝对基址、控制渲染策略或在离线模式下绕过 CORS 检查。(github.com, dev.to) -
当项目依赖
headless chrome crawler
(如prerender-io
或自建 Puppeteer 服务)时,同样可以用该变量传递外部站点的origin
。「一次性注入」能避免污染全局环境,减少脚本并行执行时的冲突概率。(npmjs.com)
可运行示例
目录结构(节选)
├── src │ └── main.server.ts ├── server.ts ├── package.json
package.json
{ "scripts": { "build:ssr": "ng build --configuration production && ng run blog:server", "prerender": "ng run blog:prerender" } }
server.ts
import 'zone.js/node'; import { APP_BASE_HREF } from '@angular/common'; import { ngExpressEngine } from '@nguniversal/express-engine'; import * as express from 'express'; import { existsSync } from 'fs'; import { join } from 'path'; const app = express(); const PORT = process.env['PORT'] ?? 4000; const ORIGIN = process.env['SERVER_REQUEST_ORIGIN'] ?? 'http://localhost:4200'; // 把绝对 URL 注入全局 global['ORIGIN_FOR_PRERENDER'] = ORIGIN; // 其余 Express Boilerplate ...
然后运行:
SERVER_REQUEST_ORIGIN=http://localhost:4200 npm run prerender
执行结束后,
dist/static
将出现按路由展开的静态HTML
文件,内部的<base href>
或 API 调用链接已经被替换成http://localhost:4200/…
。
操作系统兼容性
环境 | 是否直接支持前缀赋值 | 建议写法 |
---|---|---|
Linux / macOS / WSL | ✅ | SERVER_REQUEST_ORIGIN=http://localhost:4200 npm run prerender |
Windows CMD | ❌ | set SERVER_REQUEST_ORIGIN=http://localhost:4200 && npm run prerender (stackoverflow.com) |
Windows PowerShell | ❌ | $env:SERVER_REQUEST_ORIGIN='http://localhost:4200'; npm run prerender (stackoverflow.com) |
跨平台 npm script | ✅(借助 cross-env ) | "prerender": "cross-env SERVER_REQUEST_ORIGIN=http://localhost:4200 ng run blog:prerender" (blog.jimmydc.com, npmjs.com) |
cross-env
会在内部判断当前 shell 类型并自动选择合适的 export / set / $env:
等机制,因此是发布开源模板时最稳妥的方式。
渲染流程逐步推演
-
npm run prerender
被执行,Angular cli
读取angular.json
中的prerender
目标配置,触发一次生产编译(或复用先前产物),随后启动server-side renderer
。(dev.to) -
server-side renderer
为配置文件prerender.routes
中列出的每条路由实例化platform-server
, 执行AppServerModule
, 对 DOM 进行序列化。(simply-how.com) -
所有 HTTP / GraphQL 调用、绝对路径拼接逻辑会在运行时访问
global.ORIGIN_FOR_PRERENDER
(上一节注入),于是生成的链接包含预期的host:port
。 -
渲染结果被写入磁盘。
Angular cli
在控制台输出Prerender complete.
并返回0
。(stackoverflow.com)
为什么要放在 README
许多团队在不同环境下(内网、预发布、生产)需要渲染完全相同的路由集合,却要注入不同的绝对地址。与其维护三份脚本,不如采用“内联变量 + 单一 prerender
脚本”的方式:
# 内网
SERVER_REQUEST_ORIGIN=http://intra.dev.ninja npm run prerender
# 预发布
SERVER_REQUEST_ORIGIN=https://staging.example.com npm run prerender
# 生产
SERVER_REQUEST_ORIGIN=https://blog.example.com npm run prerender
这种做法让 CI/CD pipeline 变得简洁。变量既能通过 shell
覆盖,也能在 GitHub Actions / GitLab CI 中以 secrets
注入。
额外注意事项
-
若脚本里还有其他链式命令(
&&
/|
),需注意前缀赋值只影响第一个命令,管道后的进程将看不到该变量。(stackoverflow.com, stackoverflow.com) -
变量值若包含空格或特殊字符,需要用单引号包裹,例如
SERVER_REQUEST_ORIGIN='https://example.com?foo=bar&baz=qux' npm run prerender
否则
bash
会按空格切分参数。(unix.stackexchange.com) -
不要将此变量写死在源码中,以免在不同机器上渲染时出现“混合内容”或跨域引用错误。
可复现仓库
GitHub 地址:https://github.com/gran/ngx-blog-prerender-demo
依次执行npm ci npm run build:ssr SERVER_REQUEST_ORIGIN=http://localhost:4200 npm run prerender
便可观察
dist/static
下生成的多路由HTML
文件。
通过对内联环境变量、npm script
、不同 shell 语法及 prerender builder
工作流的拆解,可以看出:这条指令在类 Unix
系统中可直接执行,在原生 Windows 终端需改写或借助 cross-env
,其核心价值是为离线渲染注入正确的请求来源,从而保证生成的静态页面能在任何部署环境中即插即用。