action-hosting-deploy icon indicating copy to clipboard operation
action-hosting-deploy copied to clipboard

Support Preview Deployments with Hosting rewrites to Cloud Functions

Open jthegedus opened this issue 4 years ago • 4 comments

The use case you're trying to solve

Deploy SSR web apps with Preview Deployments.

Current solutions require an entire separate project for dev and prod with dev being shared amongst developers, or relying solely on local emulation which is not quite as robust as a full env deployment.

Change to the action that would solve that use case

There would need to be a new Cloud Function for the Preview Deployment (PR prefix etc) with the rewrite config updated on deployment for the Hosting Preview Channel.

Other considerations

I believe I requested this feature about a year ago, perhaps in the Google Group, but have seen no update.

Additional info

I have written about SSR web apps on Firebase with various frameworks and authored the Firebase adapter for SvelteKit.

jthegedus avatar Jun 22 '21 11:06 jthegedus

It's a pity that there is no easy way on how to do previews with the SSR function.

Is this a limitation of firebase preview itself that it doesn't support functions with rewrites for preview hosting? Is there a feature request for this somewhere or should we create one?

vmasek avatar Jul 08 '21 20:07 vmasek

The preview website uses the same firebase.json:hosting.* config so I believe rewrites still work, just they all point to the same Cloud Function.

I could be wrong, but assuming not, this is what would need to change:

The deployment of a preview site would need to check if it relies on hosting.rewrites.function and if so, deploy a copy of function X with the --CHANNEL_ID-RANDOM_HASH suffix and then modify the rewrite rule to use the that copy function name.

EG:

This would be my configuration:

{
  "hosting": [
    {
      "site": "site1",
      "public": "cdn",
      "cleanUrls": true,
      "rewrites": [
        {
          "source": "**",
          "function": "mySSR"
        }
      ],
      "predeploy": []
    }
  ],
  "functions": {
    "source": "functions",
  },
}
// functions/index.js
exports.mySSR = functions.https.onRequest(async (request, response) => {});

This would be what the preview process deploys:

{
  "hosting": [
    {
      "site": "site1--CHANNEL_ID-RANDOM_HASH",
      "public": "cdn",
      "cleanUrls": true,
      "rewrites": [
        {
          "source": "**",
          "function": "mySSR--CHANNEL_ID-RANDOM_HASH"
        }
      ],
      "predeploy": []
    }
  ],
  "functions": {
    "source": "functions",
  },
}
// functions/index.js
exports.mySSR = functions.https.onRequest(async (request, response) => {});
exports.mySSR--CHANNEL_ID-RANDOM_HASH = mySSR;

And then when the preview channel is destroyed it removes mySSR--CHANNEL_ID-RANDOM_HASH

Even better would be if for each preview channel we got our entire functions/index.js wrapped in a Function Group with the CHANNEL_ID-RANDOM_HASH resulting in copies of all our functions

jthegedus avatar Jul 09 '21 00:07 jthegedus

  • id: auth name: Authenticate to Google Cloud uses: google-github-actions/[email protected] with: - uses: FirebaseExtended/action-hosting-deploy@v0 with: repoToken: "${{ secrets.GITHUB_TOKEN }}" firebaseServiceAccount: "${{ secrets.FIREBASE_SERVICE_ACCOUNT_LAWVITE_DEV }}" expires: 20d projectId: lawvite create_credentials_file: true workload_identity_provider: ... service_account: ${{ secrets.SERVICE_ACCOUNT_EMAIL }}
  • name: 🚀 Firebase Deploy uses: FirebaseExtended/action-hosting-deploy@v0 with: repoToken: '${{ secrets.GITHUB_TOKEN }}' credentials_file_path: ${{ steps.auth.output.credentials_file_path }} projectId: '${{ secrets.PROJECT_ID }}' channelId: live env: FIREBASE_CLI_PREVIEWS: hostingchannels
  - uses: FirebaseExtended/action-hosting-deploy@v0
    with:
      repoToken: "${{ secrets.GITHUB_TOKEN }}"
      firebaseServiceAccount: "${{ secrets.FIREBASE_SERVICE_ACCOUNT_LAWVITE_DEV }}"
      expires: 20d
      projectId: lawvite

package-lock.json

Hallerf avatar Feb 09 '22 19:02 Hallerf

What I do is provide an SSR-free version for preview, only deploy SSR on main branch

First I create a new firebase.preview.json for preview environment, which provides only client-side rendering

// firebase.preview.json
{
  "hosting": {
    "rewrites": [
      {
        "source": "**",
        "destination": "/index.html"
      }
    ]
    // ...
  }
}

Keep your SSR settings in the old firebase.json:

// firebase.json
{
  "hosting": {
    "rewrites": [
      {
        "source": "**",
        "function": "ssr"
      }
    ]
  },
  "functions": {
    "predeploy": [
      "npm --prefix \"$RESOURCE_DIR\" run lint"
    ]
  }
  // ...
}

and overwrite firebase.json with it when building preview channels

name: Deploy to Firebase Hosting on PR
'on': pull_request
jobs:
  build_and_preview_dev:
    if: '${{ github.event.pull_request.head.repo.full_name == github.repository }}'
    runs-on: ubuntu-latest
    steps:
      - run: npm ci && cp ./firebase.preview.json ./firebase.json && FIREBASE_ENV=development npm run build
      - ...

Though I can't preview SSR results in preview channels, but this prevents rendering wrong result an bundles in preview channels.

HaoCherHong avatar Apr 23 '22 15:04 HaoCherHong