我使用以下内容创建了一个SSR应用程序:
ng add @nguniversal/express-engine --clientProject PROJECT_NAME
"
PROJECT_NAME
可在 angular.json
文件的 "projects"
部分下找到。""有人能帮我吗?"
ng add @nguniversal/express-engine --clientProject PROJECT_NAME
PROJECT_NAME
可在 angular.json
文件的 "projects"
部分下找到。"重要提示:本解决方案来自Udemy上的Angular课程的问答部分(这里)。我尝试了一下并进行了一些修改,最终使其成功运行。
首先确保SSR实际可用,通过运行npm run build:ssr
和npm run serve:ssr
来实现。
然后安装Firebase工具并初始化项目:
npm install -g firebase-tools
firebase login
,如果需要,请提供你的Firebase凭据(电子邮件/密码)。firebase init
回答一些问题...
"Are you ready to proceed?"
Type y
and hit ENTER.
"Which firebase CLI features do you want to setup?"
Choose ...
(*) Functions
(*) Hosting
... , selecting both with the SPACE key, and hitting ENTER.
"Select a default Firebase project for this directory?"
Select one with the ARROW keys and hit ENTER.
"What language would you like to use to write Cloud Functions?"
Select TypeScript
with the ARROW keys and hit ENTER.
"Do you want to use TSLint?"
Type y
and hit ENTER.
"Do you want to install dependencies with npm now?"
Type y
and hit ENTER.
"What do you want to use as your public directory?"
Type dist/browser
and hit ENTER (Please note: this is different from deploying an app without Universal!).
"Configure as a single page app?"
Type y
and hit ENTER.
File index.html already exists. Overwrite?
Type n
(important!) and hit ENTER.
修改一些文件...
在 firebase.json 中,用 "function": "ssr"
替换 "destination": "/index.html"
(ssr
指向这个 export const ssr = functions.https.onRequest(universal);
变量,你会在下面找到它)。
在 server.ts 中,将 app
初始化中的 const app = express();
改为 export 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
上托管您的应用程序时需要它们。
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
文件)。
"build": "node copy-angular-app && tsc",
import * as functions from 'firebase-functions';
const universal = require(`${process.cwd()}/dist/server`).app;
export const ssr = functions.https.onRequest(universal);
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",
npm run build:ssr
),然后在你的functions文件夹中运行 npm run build
(这样它就会将项目的 dist
文件夹复制到你的functions dist
文件夹,并删除项目的 index.html
文件)。如果需要,你可以在部署之前在本地服务器上提供服务,访问地址为 localhost:5000,运行 firebase serve
。
关闭服务器 (Ctrl + C)。
然后你可以通过运行 firebase deploy
部署应用程序,并通过终端显示的 url 访问它。