重要提示:此解决方案取自 Udemy (here) 的 Angular 课程的问答部分。我试了一下,做了一些修改才成功。
因此,首先通过运行 npm run build:ssr 和 npm run serve:ssr 确保 SSR 确实有效。
然后安装 Firebase Tools 并初始化项目:
- 如果您之前没有安装 Firebase 命令行工具,请运行
npm install -g firebase-tools
- 运行
firebase login,根据要求提供您的 Firebase 凭据(电子邮件/密码)。
- 运行
firebase init
回答一些问题...
-
“你准备好继续了吗?”
输入y 并按回车键。
-
“您要设置哪些 firebase CLI 功能?”
选择...
(*) Functions
(*) Hosting
... ,使用 SPACE 键选择两者,然后按 ENTER。
-
“为此目录选择一个默认的 Firebase 项目?”
用箭头键选择一个,然后按 ENTER。
-
“您想使用哪种语言来编写 Cloud Functions?”
用箭头键选择TypeScript,然后按回车键。
-
“你想使用 TSLint 吗?”
输入y 并按回车键。
-
“你想现在用 npm 安装依赖吗?”
输入y 并按回车键。
-
“你想用什么作为你的公共目录?”
输入 dist/browser 并按 ENTER 键(请注意:这与在没有 Universal 的情况下部署应用不同!)。
-
“配置为单页应用?”
输入y 并按回车键。
-
文件 index.html 已经存在。覆盖?
输入n(重要!)并按回车键。
修改一些文件...
-
在 firebase.json 中将 "destination": "/index.html" 替换为 "function": "ssr"
(ssr 指向这个export const ssr = functions.https.onRequest(universal); 变量,你会在下面找到它)。
在 server.ts 中将 export 添加到 app 初始化:export const app = express(); 而不是 const app = express();
在 server.ts 中注释掉最后三行 (app.listen(...)) 或将它们替换为:
// If we're not in the Cloud Functions environment, spin up a Node server
if (!process.env.FUNCTION_NAME) {
// Start up the Node server
app.listen(PORT, () => {
console.log(`Node Express server listening on http://localhost:${PORT}`);
});
}
您可以在部署到 Firebase 时删除它们,但在运行 npm run serve:ssr 时需要它们才能在 localhost 上托管您的应用。
- 在 webpack.server.config.js 中修改
output 如下:
output: {
// Puts the output at the root of the dist folder
path: path.join(__dirname, 'dist'),
// Export a UMD of the webpacked server.ts & dependencies for rendering in Cloud Functions
library: 'app',
libraryTarget: 'umd',
filename: '[name].js',
},
并像这样修改externals:
externals: [
// Firebase has some troubles being webpacked when it's in the Node environment, so we will skip it.
/^firebase/
],
这将修复一个错误:
找不到模块'require("./server/main")'
在运行 npm run serve:ssr 或 firebase serve 命令时。
通过运行 npm run build:ssr 重新构建您的应用程序。
使用终端移动到functions文件夹:cd functions
安装用于文件系统访问的 npm 包:npm i fs-extra
在 functions 文件夹中创建一个名为 copy-angular-app.js 的新文件,其内容如下:
const fs = require('fs-extra');
fs.copy('../dist', './dist').then(() => {
// We should remove the original "index.html" since Firebase will use it when SSR is enabled (instead of calling SSR functions),
// and because of that, SSR won't work for the initial page.
fs.remove('../dist/browser/index.html').catch(e => console.error('REMOVE ERROR: ', e));
}).catch(err => {
console.error('COPY ERROR: ', err)
});
此修复初始页面未作为 SSR 加载(而不是显示初始页面的内容,它仍显示 <app-root></app-root>)。
注意:由于我们删除了index.html 文件,运行npm run serve:ssr 将无法工作,除非您首先重建您的应用程序(通过运行npm run build:ssr -> 这个将重新创建index.html 文件)。
- 在 functions/package.json 中(不在项目的 package.json 中!)像这样更改构建条目:
"build": "node copy-angular-app && tsc",
- 在 functions/src/index.ts 中将内容替换为:
import * as functions from 'firebase-functions';
const universal = require(`${process.cwd()}/dist/server`).app;
export const ssr = functions.https.onRequest(universal);
- 在终端确保你在functions目录下,运行
npm run build将dist文件夹复制到functions文件夹中。
附加说明:为了更轻松地构建 Firebase,您可以在主项目的 package.json 文件中创建一个脚本:
"build:ssr": "npm run build:client-and-server-bundles && npm run compile:server", // this one should already exist
"build:ssr-firebase": "npm run build:ssr && npm --prefix functions/ run build",
此脚本将首先构建您的 Angular SSR 应用程序 (npm run build:ssr),然后它将在您的 functions 文件夹中运行 npm run build(这样它会将项目的 dist 文件夹复制到您的functions dist 文件夹,并将删除项目的 index.html 文件)。
部署您的应用...
通过这种方式,我设法在 Firebase 上部署了我的 Angular SSR 应用。
希望这会有所帮助...