在Firebase上部署Angular 8通用(SSR)应用程序

4
我最近将我的Angular 8应用程序升级为通用应用程序(SSR)。在它成为SSR应用程序之前,我已经将其部署到Firebase上,但后来我发现在Firebase上部署SSR应用程序不能使用常规的Firebase Hosting。我进行了一些研究,发现我必须使用Firebase Cloud Functions
我使用以下内容创建了一个SSR应用程序:
ng add @nguniversal/express-engine --clientProject PROJECT_NAME

"PROJECT_NAME 可在 angular.json 文件的 "projects" 部分下找到。"
"有人能帮我吗?"
3个回答

14

重要提示:本解决方案来自Udemy上的Angular课程的问答部分(这里)。我尝试了一下并进行了一些修改,最终使其成功运行。


首先确保SSR实际可用,通过运行npm run build:ssrnpm run serve:ssr来实现。

然后安装Firebase工具并初始化项目:

  • 如果你之前没有安装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 上托管您的应用程序时需要它们。

  • 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:ssrfirebase 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 builddist文件夹复制到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 文件)。
部署你的应用程序...
  • 如果需要,你可以在部署之前在本地服务器上提供服务,访问地址为 localhost:5000,运行 firebase serve

  • 关闭服务器 (Ctrl + C)。

  • 然后你可以通过运行 firebase deploy 部署应用程序,并通过终端显示的 url 访问它。

这样,我成功地在 Firebase 上部署了我的 Angular SSR 应用程序。
希望这能帮到你...

2
这是一次非常有趣的冒险。谢谢! - Selast Lambou
1
只有在部署后,此操作才会为您的特定项目创建/更新名为“_ssr_” 的函数。它不会影响您在其他项目中定义的函数。 - miselking
我按照你的答案部署后出现了这个错误:https://imgur.com/a/rQhzncu - Yash
1
Max的课程非常棒,@miselking我们也进行了相同的自学 :) - Daniel Danielecki
完美的答案,对我帮助很大,特别是在复制Angular应用程序脚本方面。 - Omar Hasan
显示剩余6条评论

2
基本上,@miselking 的回答非常棒,我只是想补充一下,现在(Angular 9及以上版本)使用CLI构建器来构建和提供SSR应用程序,因此不再需要webpack.server.config.js,在我的情况下,升级自Angular 8后它甚至根本无法工作。问题#16348解释了如何管理外部依赖项(如果需要添加)。现在,您可以在angular.json中添加externalDependencies,这是webpack的自定义配置相关的externals/nodeExternals的替代品。
除此之外,@miselking的答案仍然是最新的。

1
Angular Firebase 刚刚推出了一种 新的简单方式,可以使用 ng deploy 进行部署!不过我认为他们仍在解决其中的问题...

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接