【问题标题】:Deploy Angular 8 Universal (SSR) application on Firebase在 Firebase 上部署 Angular 8 Universal (SSR) 应用程序
【发布时间】:2020-02-15 06:00:44
【问题描述】:

我最近将 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" 部分中找到。

谁能帮我解决这个问题?

【问题讨论】:

    标签: angular firebase google-cloud-functions angular-universal


    【解决方案1】:

    重要提示:此解决方案取自 Udemy (here) 的 Angular 课程的问答部分。我试了一下,做了一些修改才成功。


    因此,首先通过运行 npm run build:ssrnpm 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: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 应用。

    希望这会有所帮助...

    【讨论】:

    • 冒险真是太有趣了。谢谢!!
    • Firebase 部署完成后。动态生成的元标记和备用链接不会反映在 firebase 链接上。但它在 firebase 服务中工作
    • 这会覆盖/删除我现有的 firebase 函数吗?
    • 这只会在部署后为您的特定项目创建/更新名为 ssr 的函数。它不会触及您在其他项目中定义的功能。
    • Max 的精彩课程,@miselking 我们已经完成了同样的自学 :)
    【解决方案2】:

    @miselking 的回答基本上很棒,我只想补充一点,Angular 现在是(Angular 9 及更高版本)使用 CLI Builders 构建和服务 SSR 应用程序,因此在我的如果从Angular 8 升级后它甚至根本不起作用。问题#16348 解释了现在如何管理外部依赖项(如果需要添加)。在angular.json 现在您可以添加externalDependencies,这是webpackexternals/nodeExternals 相关的自定义配置的替代品。

    除此之外,@miselking 的答案仍然是最新的。

    【讨论】:

      【解决方案3】:

      Angular Firebase 刚刚发布了 new simple way 以使用 ng deploy 进行部署!我认为他们仍在解决这些错误......

      【讨论】:

        猜你喜欢
        • 2019-10-22
        • 1970-01-01
        • 2018-05-31
        • 2020-04-30
        • 2016-05-23
        • 2020-02-12
        • 2018-02-11
        • 1970-01-01
        • 2020-08-17
        相关资源
        最近更新 更多