在 Firebase 上部署 Angular 8 个通用 (SSR) 应用程序
Deploy Angular 8 Universal (SSR) application on Firebase
我最近将我的 Angular 8 应用程序升级为通用应用程序 (SSR)。在它成为 SSR 应用程序之前,我已将其部署到 Firebase,但后来我发现使用常规 Firebase 托管无法在 Firebase 上部署 SSR 应用程序。我做了一些研究,发现我必须使用 Firebase Cloud Functions.
我使用以下方法创建了一个 SSR 应用程序:
ng add @nguniversal/express-engine --clientProject PROJECT_NAME
PROJECT_NAME
可以在 angular.json
文件的 "projects"
部分下面找到。
谁能帮我解决这个问题?
重要说明:此解决方案摘自 Udemy (here) 的 Angular 课程的问答部分。我试了一下,经过一些修改后成功了。
所以,首先要确保 SSR 在 运行ning npm run build:ssr
和 npm run serve:ssr
确实有效。
然后安装Firebase Tools并初始化项目:
- 如果您之前没有安装 Firebase 命令行工具,运行
npm install -g firebase-tools
- 运行
firebase login
,如果需要,请提供您的 Firebase 凭据 (email/password)。
- 运行
firebase init
回答一些问题...
"Are you ready to proceed?"
键入 y
并按 ENTER。
"Which firebase CLI features do you want to setup?"
选择...
(*) Functions
(*) Hosting
... ,使用 SPACE 键选择两者,然后按 ENTER。
"Select a default Firebase project for this directory?"
Select 使用箭头键并按 ENTER。
"What language would you like to use to write Cloud Functions?"
Select TypeScript
使用箭头键并按 ENTER。
"Do you want to use TSLint?"
键入 y
并按 ENTER。
"Do you want to install dependencies with npm now?"
键入 y
并按 ENTER。
"What do you want to use as your public directory?"
键入 dist/browser
并按 ENTER(请注意:这与部署没有 Universal 的应用程序不同!)。
"Configure as a single page app?"
键入 y
并按 ENTER。
文件 index.html 已经存在。覆盖?
键入 n
(重要!)并按 ENTER。
修改部分文件...
在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/
],
这将修复一个错误:
Cannot find module 'require("./server/main")'
当运行宁npm run serve:ssr
或firebase serve
命令时。
通过 运行ning npm run build:ssr
重建您的应用程序。
使用终端移动到函数文件夹:cd functions
安装用于文件系统访问的 npm 包:npm i fs-extra
在 functions 文件夹中创建一个名为 copy-angular-app.js[=215 的新文件=],内容为:
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
不会'除非您首先重建您的应用程序(通过 运行ning 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
),然后它会 运行 npm run build
在您的 函数中 文件夹(这样它会将项目的 dist
文件夹复制到您的 functions dist
文件夹并删除项目的 index.html
文件)。
部署您的应用程序...
您可以在部署前通过 运行ning firebase serve
在 localhost:5000 上本地提供您的应用程序(如果您想要).
停止服务器(Ctrl + C)。
然后就可以通过运行ning firebase deploy
部署应用,通过终端显示的url访问
通过这种方式,我成功地在 Firebase 上部署了我的 Angular SSR 应用程序。
希望这对您有所帮助...
Angular Firebase 刚刚推出 new simple way 以使用 ng deploy 部署它!我认为他们仍在解决错误...
@miselking 的回答基本上很棒,我只想补充一点 Angular
现在是(Angular 9
及以上)使用 CLI Builders 来构建和提供 SSR 应用程序,因此 webpack.server.config.js
不再需要,在我的情况下,从 Angular 8
升级后它甚至根本不起作用。如果需要添加,问题 #16348 解释了现在如何管理外部依赖项的方式。在 angular.json
中,现在您可以添加 externalDependencies
,这是 webpack
与 externals
/nodeExternals
.
相关的自定义配置的替代品
除此之外,@miselking 的回答仍然是up-to-date。
我最近将我的 Angular 8 应用程序升级为通用应用程序 (SSR)。在它成为 SSR 应用程序之前,我已将其部署到 Firebase,但后来我发现使用常规 Firebase 托管无法在 Firebase 上部署 SSR 应用程序。我做了一些研究,发现我必须使用 Firebase Cloud Functions.
我使用以下方法创建了一个 SSR 应用程序:
ng add @nguniversal/express-engine --clientProject PROJECT_NAME
PROJECT_NAME
可以在 angular.json
文件的 "projects"
部分下面找到。
谁能帮我解决这个问题?
重要说明:此解决方案摘自 Udemy (here) 的 Angular 课程的问答部分。我试了一下,经过一些修改后成功了。
所以,首先要确保 SSR 在 运行ning npm run build:ssr
和 npm run serve:ssr
确实有效。
然后安装Firebase Tools并初始化项目:
- 如果您之前没有安装 Firebase 命令行工具,运行
npm install -g firebase-tools
- 运行
firebase login
,如果需要,请提供您的 Firebase 凭据 (email/password)。 - 运行
firebase init
回答一些问题...
"Are you ready to proceed?"
键入
y
并按 ENTER。"Which firebase CLI features do you want to setup?"
选择...
(*) Functions (*) Hosting
... ,使用 SPACE 键选择两者,然后按 ENTER。
"Select a default Firebase project for this directory?"
Select 使用箭头键并按 ENTER。
"What language would you like to use to write Cloud Functions?"
Select
TypeScript
使用箭头键并按 ENTER。"Do you want to use TSLint?"
键入
y
并按 ENTER。"Do you want to install dependencies with npm now?"
键入
y
并按 ENTER。"What do you want to use as your public directory?"
键入
dist/browser
并按 ENTER(请注意:这与部署没有 Universal 的应用程序不同!)。"Configure as a single page app?"
键入
y
并按 ENTER。文件 index.html 已经存在。覆盖?
键入
n
(重要!)并按 ENTER。
修改部分文件...
在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/
],
这将修复一个错误:
Cannot find module 'require("./server/main")'
当运行宁npm run serve:ssr
或firebase serve
命令时。
通过 运行ning
npm run build:ssr
重建您的应用程序。使用终端移动到函数文件夹:
cd functions
安装用于文件系统访问的 npm 包:
npm i fs-extra
在 functions 文件夹中创建一个名为 copy-angular-app.js[=215 的新文件=],内容为:
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
不会'除非您首先重建您的应用程序(通过 运行ning 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
),然后它会 运行 npm run build
在您的 函数中 文件夹(这样它会将项目的 dist
文件夹复制到您的 functions dist
文件夹并删除项目的 index.html
文件)。
部署您的应用程序...
您可以在部署前通过 运行ning
firebase serve
在 localhost:5000 上本地提供您的应用程序(如果您想要).停止服务器(Ctrl + C)。
然后就可以通过运行ning
firebase deploy
部署应用,通过终端显示的url访问
通过这种方式,我成功地在 Firebase 上部署了我的 Angular SSR 应用程序。
希望这对您有所帮助...
Angular Firebase 刚刚推出 new simple way 以使用 ng deploy 部署它!我认为他们仍在解决错误...
@miselking 的回答基本上很棒,我只想补充一点 Angular
现在是(Angular 9
及以上)使用 CLI Builders 来构建和提供 SSR 应用程序,因此 webpack.server.config.js
不再需要,在我的情况下,从 Angular 8
升级后它甚至根本不起作用。如果需要添加,问题 #16348 解释了现在如何管理外部依赖项的方式。在 angular.json
中,现在您可以添加 externalDependencies
,这是 webpack
与 externals
/nodeExternals
.
除此之外,@miselking 的回答仍然是up-to-date。