{"id":5636,"date":"2023-09-21T12:32:51","date_gmt":"2023-09-21T16:32:51","guid":{"rendered":"https:\/\/ionic.io\/blog\/?p=5636"},"modified":"2023-09-21T12:32:53","modified_gmt":"2023-09-21T16:32:53","slug":"automate-firebase-deployments-for-web-builds-with-appflow","status":"publish","type":"post","link":"https:\/\/ionic.io\/blog\/automate-firebase-deployments-for-web-builds-with-appflow","title":{"rendered":"Automate Firebase Deployments for Web Builds with Appflow"},"content":{"rendered":"\n<p><em>This is a guest post by Tim Wills, CTO at <\/em><a href=\"http:\/\/uckers.com\"><em>Uckers.com<\/em><\/a><em>. Connect with Tim at <\/em><a href=\"https:\/\/twitter.com\/TimW_Tech\"><em>@TimW_Tech<\/em><\/a><em>.<\/em><\/p>\n\n\n\n<p>Are you building an app that deploys to both mobile and web from the same codebase? Do you want to automate your CI\/CD process? If so, Ionic\u2019s mobile CI\/CD platform <a href=\"http:\/\/ionic.io\/appflow\">Appflow<\/a> with Firebase can provide all you need to automate front and back end deployments.<\/p>\n\n\n\n<!--more-->\n\n\n\n<p>Why Appflow? If, like me, you want to simplify your CI\/CD workflow and are deploying the same code to web and mobile, environments can become messy. Appflow allows you to set up one single source of truth for your environments.&nbsp;<\/p>\n\n\n\n<p>Sure, we could set up a GitHub Action to deploy to Firebase hosting, but then you\u2019ve got to manage another set of environments for that web build. Added to that, if you have separate environments for the back end, you can greatly simplify things by using Firebase Functions and deploying those from Appflow too (other steps required after this walkthrough).<\/p>\n\n\n\n<p>Appflow is primarily for mobile app deployments, but the Appflow documentation for mobile deployments is easy to follow if you get stuck. Automatic deployment to Firebase requires a bit more work, so I\u2019ll cover this in detail.&nbsp;<\/p>\n\n\n\n<p>Here\u2019s what we\u2019ll do:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Start an Ionic template app using Git for source control<\/li>\n\n\n\n<li>Connect it to a Firebase back end<\/li>\n\n\n\n<li>Run web builds from the Appflow dashboard<\/li>\n\n\n\n<li>Create a post-deploy script to deploy to Firebase Hosting on completion of each web build in Appflow<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Getting Started<\/h2>\n\n\n\n<p>Open a Terminal window:<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-bash\">npm install -g @ionic\/cli\nionic start<\/code><\/pre>\n\n\n\n<p>Press Y to use the App Creation Wizard and start a \u201cmenu\u201d template app using your preferred framework (I used React). Give it a name like \u201cMy Great App\u201d. You\u2019ll be directed to create an account which you need to do to use Appflow \u2014 we will come back to this later.<\/p>\n\n\n\n<p>Go back to your terminal window, change to your new app directory and serve the app:<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-bash\">cd my-great-app\nionic serve<\/code><\/pre>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><img decoding=\"async\" data-src=\"https:\/\/lh3.googleusercontent.com\/QWVax1fovTyCkXNiOhVp4IIycKF1tzDrwuF4jdt95G7Vi13M6JHSbNGCGbz4dqofevd9EGVybR13sk_ymhR_FgUTlNTqBmQ6H5s0aE9muM0rRIz_PVY7XDYcGcsXhqGgXr42mKIU5xcSddV18Siuc18\" alt=\"\" src=\"data:image\/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\" class=\"lazyload\" \/><noscript><img decoding=\"async\" src=\"https:\/\/lh3.googleusercontent.com\/QWVax1fovTyCkXNiOhVp4IIycKF1tzDrwuF4jdt95G7Vi13M6JHSbNGCGbz4dqofevd9EGVybR13sk_ymhR_FgUTlNTqBmQ6H5s0aE9muM0rRIz_PVY7XDYcGcsXhqGgXr42mKIU5xcSddV18Siuc18\" alt=\"\"\/><\/noscript><figcaption class=\"wp-element-caption\"><em>Congrats, you just created an email app<\/em><\/figcaption><\/figure>\n<\/div>\n\n\n<p>Let&#8217;s get this app checked into source control.<\/p>\n\n\n\n<p>Go to your Git provider account (I used GitHub) and create a new repo called \u201cmy-great-app\u201d.\u00a0 Don\u2019t add a readme or license, as we\u2019re going to overwrite it with the code below. Go to your app\u2019s directory in Terminal and set up your new repo as the remote:<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-bash\">git init\ntouch README.md\ngit add README.md\ngit commit -m &quot;first commit&quot;\ngit remote add origin https:\/\/github.com\/[GIT_USERNAME]\/my-great-app.git\ngit push -u -f origin main<\/code><\/pre>\n\n\n\n<p>Be careful with the <code>-f<\/code> (force) flag, I\u2019ve just used it to help get set up quickly here.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Setting up Firebase<\/h2>\n\n\n\n<p>Next we need to install Firebase and deploy to hosting from a local machine. Go to the <a href=\"https:\/\/console.firebase.google.com\/\">Firebase Console<\/a> and create a new project called \u201cMy Great App\u201d. Choose whether or not to enable analytics and create the project.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><img decoding=\"async\" data-src=\"https:\/\/lh6.googleusercontent.com\/PzDPTYu7MRIDqR0FUCyu4dcjsGHMTtv8_hViiGHBOx6pM3KLXTyRVgHkXoiOZXRWnfy4qi8SaCFjqEBVvwcaRnzr4r-vF5mMJv203i90kVtcmV5VaCFx4j4ylKHLoSoNoSK78zELKWOgbBOlTnuGYfo\" alt=\"\" src=\"data:image\/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\" class=\"lazyload\" \/><noscript><img decoding=\"async\" src=\"https:\/\/lh6.googleusercontent.com\/PzDPTYu7MRIDqR0FUCyu4dcjsGHMTtv8_hViiGHBOx6pM3KLXTyRVgHkXoiOZXRWnfy4qi8SaCFjqEBVvwcaRnzr4r-vF5mMJv203i90kVtcmV5VaCFx4j4ylKHLoSoNoSK78zELKWOgbBOlTnuGYfo\" alt=\"\"\/><\/noscript><figcaption class=\"wp-element-caption\"><em>Firebase project Home Screen<\/em><\/figcaption><\/figure>\n<\/div>\n\n\n<p>Create a web app by clicking on the \u201c&lt;\/&gt;\u201d icon. Give your app a nickname, check the \u201cAlso set up Firebase Hosting\u201d box, and register the app. Follow the instructions to add the Firebase SDK and install the CLI.&nbsp;<\/p>\n\n\n\n<p>Next, login and initialize Firebase in the root directory of your app:<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-bash\">firebase login\nfirebase init<\/code><\/pre>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><img decoding=\"async\" data-src=\"https:\/\/lh4.googleusercontent.com\/LKjjCbnZt5OXzcpYPTVU-0bYz8AVD0LRbYJcWGr5EIxwCkBRRGMGGG9VxJ-CobedfvxqpLngVDiWq08UgwVAq9poJrvqnhxXd8CHq_v5Nark4al5Rtet1IVxvz6KmbBz6E2DqCopYwgRYTJJ_dHYlS8\" alt=\"\" src=\"data:image\/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\" class=\"lazyload\" \/><noscript><img decoding=\"async\" src=\"https:\/\/lh4.googleusercontent.com\/LKjjCbnZt5OXzcpYPTVU-0bYz8AVD0LRbYJcWGr5EIxwCkBRRGMGGG9VxJ-CobedfvxqpLngVDiWq08UgwVAq9poJrvqnhxXd8CHq_v5Nark4al5Rtet1IVxvz6KmbBz6E2DqCopYwgRYTJJ_dHYlS8\" alt=\"\"\/><\/noscript><figcaption class=\"wp-element-caption\"><em>Set up Firebase Hosting<\/em><\/figcaption><\/figure>\n<\/div>\n\n\n<p>The <code>firebase init<\/code> command takes you through the options, so use the spacebar to select Firebase Hosting only. You can set up anything else later by running <code>firebase init<\/code> again. Select the Firebase project that you created just now (my-great-app).\u00a0<\/p>\n\n\n\n<p>The next step is important\u2013 you\u2019ll need to provide the public directory of the web build folder. The current version of the ionic template app uses <code>dist<\/code> so be sure to type that in correctly.\u00a0<\/p>\n\n\n\n<p>Answer \u201cy\u201d to configure as a single page app but select \u201cn\u201d for automatic deployments with GitHub to complete setup. Now you have an app that can be deployed to Firebase Hosting. However, we\u2019ve not actually built the Ionic app.&nbsp;<\/p>\n\n\n\n<p>Go back to your root directory and type:<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-bash\">ionic build<\/code><\/pre>\n\n\n\n<p>Now you\u2019ve built the app we can deploy it:<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-bash\">firebase deploy --only hosting<\/code><\/pre>\n\n\n\n<p>The terminal will then show the live web address of your site and also the Firebase hosting console page.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Enter Appflow<\/h2>\n\n\n\n<p>We\u2019ve now got the web app up and running and could automate CI\/CD with GitHub Actions if we want, so what\u2019s the point in using Appflow? Let\u2019s imagine this app is much more involved, with iOS and Android deployment targets and multiple environments.&nbsp;<\/p>\n\n\n\n<p>Just running a deploy from GitHub actions or a local machine will require duplication of all sorts of information. Ideally, we want one platform to define how the build is made and then send it to multiple targets. Fortunately, we can do this with Appflow.<\/p>\n\n\n\n<p>We made an Appflow account earlier so let&#8217;s go back to the <a href=\"https:\/\/dashboard.ionicframework.com\/\">Appflow Dashboard<\/a>. From the Apps screen, click on the \u201cNew app\u201d button in the upper right and then \u201cImport app.\u201d On the next screen, choose Capacitor as the framework (all Ionic apps use Capacitor, even if we aren\u2019t using Capacitor specifically in this walkthrough).&nbsp;<\/p>\n\n\n\n<p>Connect your GitHub account and link Appflow with the repository you created above. Once your repo is connected, create a build from the commit we made above (\u201cfirst commit\u201d).<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><img decoding=\"async\" data-src=\"https:\/\/lh5.googleusercontent.com\/TkfPgLss7QVGI455Y07_N6Do5tyXokMJKde2lc-LzysfdQRPsG4OD6OK23qSF26BuvvRCcf4mtSJeJFNqiW1I7V465Rm4Z7JGlN5s3HU4wRkxGsTbIvRSi3xC3Snzt3NURmIZVsXIqT4YIDNI2VY2Fw\" alt=\"\" src=\"data:image\/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\" class=\"lazyload\" \/><noscript><img decoding=\"async\" src=\"https:\/\/lh5.googleusercontent.com\/TkfPgLss7QVGI455Y07_N6Do5tyXokMJKde2lc-LzysfdQRPsG4OD6OK23qSF26BuvvRCcf4mtSJeJFNqiW1I7V465Rm4Z7JGlN5s3HU4wRkxGsTbIvRSi3xC3Snzt3NURmIZVsXIqT4YIDNI2VY2Fw\" alt=\"\"\/><\/noscript><figcaption class=\"wp-element-caption\"><em>Creating your first web build with Appflow<\/em><\/figcaption><\/figure>\n<\/div>\n\n\n<p>Choose \u2018Web\u2019, use the latest build stack, but leave the web preview and live update options unselected. Go ahead and build the web app.<\/p>\n\n\n\n<p>This will create the web app on the Appflow servers, however it is not deployed anywhere yet. You can download the <code>.zip<\/code> from the build page if you want to, or read on for how to deploy from Appflow to Firebase.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Setting up Firebase Deployments<\/h2>\n\n\n\n<p>Well done for getting this far! Let\u2019s look at some code.&nbsp;<\/p>\n\n\n\n<p>Open the app in your preferred IDE. Create a new file in the root directory called <code>web-deploy.sh<\/code>.\u00a0<\/p>\n\n\n\n<p>Paste in the following code:<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-bash\">#!\/usr\/bin\/env bash\necho &quot;Deploying to Firebase Hosting...&quot;\nfirebase deploy --only hosting<\/code><\/pre>\n\n\n\n<p>This is customizable. You can, if you wish, use any of the Firebase CLI tools but would need additional configuration for functionality beyond hosting alone.<\/p>\n\n\n\n<p>We also need the Firebase Tools in the <code>package.json<\/code> file to make them available on the Appflow server.\u00a0<\/p>\n\n\n\n<p>Go back to the a terminal window in the app root directory and install the tools:<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-bash\">npm install firebase-tools<\/code><\/pre>\n\n\n\n<p>Now we need to ensure the <code>web-deploy.sh<\/code> script we just created is executed in Appflow once your app has finished building.\u00a0<\/p>\n\n\n\n<p>We need to add two scripts to the <code>package.json<\/code> file:\u00a0<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>A post-build script to deploy to Firebase<\/li>\n\n\n\n<li>A pre-build script to get the credentials for a service worker account and make them available to the post build script<\/li>\n<\/ul>\n\n\n\n<p>Add the following to the <code>scripts:<\/code> section:<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-json\">&quot;prebuild&quot;: &quot;if [ \\&quot;$CI_PLATFORM\\&quot; = \\&quot;web\\&quot; ]; then node .\/gen-firebase-key-json.js; fi&quot;,\n&quot;postbuild&quot;: &quot;if [ \\&quot;$CI_PLATFORM\\&quot; = \\&quot;web\\&quot; ]; then chmod +x .\/web-deploy.sh &amp;&amp; .\/web-deploy.sh; fi&quot;<\/code><\/pre>\n\n\n\n<p><code>$CI_PLATFORM<\/code> is an environment variable passed by Appflow so we can check that we are only deploying on a web build and not a native mobile app build. We also need to alter the permissions to execute the <code>web-deploy<\/code> script.<\/p>\n\n\n\n<p>Create the other file mentioned in the root of the project called <code>gen-firebase-key-json.js<\/code>. This will contain your JSON key from the Google Cloud service account giving you access to deploy to hosting.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Setting the Google Cloud Credentials<\/h2>\n\n\n\n<p>For security, we don\u2019t want to put private keys in our repo and check them in to source control. Instead, we\u2019re going to create a private key, add it to Appflow secrets, and then bring it into the <code>gen-firebase-key-json.js<\/code> file through an environment variable.\u00a0<\/p>\n\n\n\n<p>We can\u2019t bring environment variables directly into a JSON file, so we need this file to be a JavaScript file that <em>generates<\/em> the JSON file with the correct key when it is run from the pre-build script. Still with me? Ok, let\u2019s create the credentials needed.<\/p>\n\n\n\n<p>Go back to the Firebase console project settings at the top left and click the service accounts tab. Follow the \u201cManage service account permissions\u201d link on the right.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><img decoding=\"async\" data-src=\"https:\/\/lh3.googleusercontent.com\/AZUNV35qN6dPgHVfH5OCjUo5Fs78DD4oUq9ZFvVJRr7kdxj1Zz2F_eRMFz3-bkeHnpImIxzQJkadDmNWTU53ytSNPNfEIb_q5om5cLbEcX--IPIkrTwcKvwMJsga83cwtsWvb3ZVbcT3eLUMUmAdz5I\" alt=\"\" src=\"data:image\/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\" class=\"lazyload\" \/><noscript><img decoding=\"async\" src=\"https:\/\/lh3.googleusercontent.com\/AZUNV35qN6dPgHVfH5OCjUo5Fs78DD4oUq9ZFvVJRr7kdxj1Zz2F_eRMFz3-bkeHnpImIxzQJkadDmNWTU53ytSNPNfEIb_q5om5cLbEcX--IPIkrTwcKvwMJsga83cwtsWvb3ZVbcT3eLUMUmAdz5I\" alt=\"\"\/><\/noscript><figcaption class=\"wp-element-caption\"><em>Service account settings for Firebase<\/em><\/figcaption><\/figure>\n<\/div>\n\n\n<p>This will take you to the relevant Google Cloud project. We now need to create a service account following <a href=\"https:\/\/firebase.google.com\/docs\/app-distribution\/authenticate-service-account?platform=ios\">these instructions<\/a>. Click \u201cCreate service account\u201d at the top of the Google Cloud page you just opened. Add the details shown below (the ID is auto-generated) and click Create and continue.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><img decoding=\"async\" data-src=\"https:\/\/lh3.googleusercontent.com\/vzcGem2gBWdsltcpVRX3r7e05o4OLmRgjCc9v2ObXmyu-mq-RQg_maiuEUWP35lNr6_vpF1Wmzf4iGc6FxkwY73m1Xj1g9Vj4jC0DwFDMMFK6HC-PLmlbPNwRMw5FboGP6saK3ofuZ1_HRM3tY8sVEg\" alt=\"\" src=\"data:image\/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\" class=\"lazyload\" \/><noscript><img decoding=\"async\" src=\"https:\/\/lh3.googleusercontent.com\/vzcGem2gBWdsltcpVRX3r7e05o4OLmRgjCc9v2ObXmyu-mq-RQg_maiuEUWP35lNr6_vpF1Wmzf4iGc6FxkwY73m1Xj1g9Vj4jC0DwFDMMFK6HC-PLmlbPNwRMw5FboGP6saK3ofuZ1_HRM3tY8sVEg\" alt=\"\"\/><\/noscript><figcaption class=\"wp-element-caption\"><em>Create a service account<\/em><\/figcaption><\/figure>\n<\/div>\n\n\n<p>Next we need to add the Firebase Hosting Admin role to the account. Search for it in the role box and make sure it is exactly that wording (it is different to the Google instructions). Click continue and then done.<\/p>\n\n\n\n<p>Now, click the 3 dots at the end of the row of your newly created service account (appflow-web-deployer) and click manage keys. Add a key, (select create new key) and choose the JSON option. It will be downloaded for you.<\/p>\n\n\n\n<p>This key allows access to deploy to your Firebase hosting site, so keep it safe or ideally destroy it once it has been uploaded to Appflow.&nbsp;<\/p>\n\n\n\n<p>Your key will look like this:<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-json\">{\n\u00a0&quot;type&quot;: &quot;service_account&quot;,\n\u00a0&quot;project_id&quot;: &quot;my-great-app-bdb14&quot;,\n\u00a0&quot;private_key_id&quot;: &quot;[YOUR_PRIVATE_KEY_ID]&quot;,\n\u00a0&quot;private_key&quot;: &quot;[YOUR_PRIVATE_KEY]&quot;,\n\u00a0&quot;client_email&quot;: &quot;[YOUR_ACCOUNT]&quot;,\n\u00a0&quot;client_id&quot;: &quot;[YOUR_CLIENT_ID]&quot;,\n\u00a0&quot;auth_uri&quot;: &quot;https:\/\/accounts.google.com\/o\/oauth2\/auth&quot;,\n\u00a0&quot;token_uri&quot;: &quot;https:\/\/oauth2.googleapis.com\/token&quot;,\n\u00a0&quot;auth_provider_x509_cert_url&quot;: &quot;https:\/\/www.googleapis.com\/oauth2\/v1\/certs&quot;,\n\u00a0&quot;client_x509_cert_url&quot;: &quot;https:\/\/www.googleapis.com\/robot\/v1\/metadata\/x509\/[YOUR_ACCOUNT]&quot;,\n\u00a0&quot;universe_domain&quot;: &quot;googleapis.com&quot;\n}<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Adding Credentials to Appflow<\/h2>\n\n\n\n<p>First we need to take the private key alone and add that as an Appflow secret. Start by creating an environment in Appflow.&nbsp;<\/p>\n\n\n\n<p>Go to the Appflow Dashboard &gt; Environments &gt; New environment. Name your environment \u201cDev environment\u201d and add the following:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>To Secrets:\n<ul class=\"wp-block-list\">\n<li><strong>Key:<\/strong> FIREBASE_PRIVATE_KEY<\/li>\n\n\n\n<li><strong>Value: <\/strong>everything between the quotation marks from the \u201cprivate_key\u201d field in the JSON file created in the last step<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>To Variables:\n<ul class=\"wp-block-list\">\n<li><strong>Key:<\/strong> GOOGLE_APPLICATION_CREDENTIALS<\/li>\n\n\n\n<li><strong>Value:<\/strong> .\/firebase-key.json<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><img decoding=\"async\" data-src=\"https:\/\/lh4.googleusercontent.com\/PtYsHhxVtGm4zxmdyO_xOIkh6RqU2ZoCX7TbD62s5VkIP8oa_5n31c131hsfsSMg3djJfhKVcOe8Qvc-muoxpq3P9zXj6yFlZnHB36aUfmM14d_q1f73pjT8g5X6WV7u-6BC7_xUKJSIE7k_lM_d2hI\" alt=\"\" src=\"data:image\/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\" class=\"lazyload\" \/><noscript><img decoding=\"async\" src=\"https:\/\/lh4.googleusercontent.com\/PtYsHhxVtGm4zxmdyO_xOIkh6RqU2ZoCX7TbD62s5VkIP8oa_5n31c131hsfsSMg3djJfhKVcOe8Qvc-muoxpq3P9zXj6yFlZnHB36aUfmM14d_q1f73pjT8g5X6WV7u-6BC7_xUKJSIE7k_lM_d2hI\" alt=\"\"\/><\/noscript><figcaption class=\"wp-element-caption\"><em>Create a new environment in Appflow<\/em><\/figcaption><\/figure>\n<\/div>\n\n\n<p>You can set this environment up how you wish with variables for deploying to other platforms, for example. This is why it is so useful to deploy to Firebase from here \u2013&nbsp; you can have one single source of truth for the environment your builds are built in regardless of platform. Go ahead and create the environment.<\/p>\n\n\n\n<p>The final step (we\u2019re nearly there!) is to create the JavaScript file that will generate the <code>firebase-key.json<\/code> in the pre-build phase. All you need to do is go back to the JSON key you downloaded, turn it into a <code>.js<\/code> format (no quotes for field names), remove the actual private key and replace it with the environment variable (secret) we just created.\u00a0<\/p>\n\n\n\n<p>The last line (and the import) saves the file so it will be present at the <code>GOOGLE_APPLICATION_CREDENTIALS<\/code> path when the post-build script runs. You should end up with a file looking like this:<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-javascript\">import fs from &#039;fs&#039;;\n\nconst credentials = {\n\u00a0\u00a0\u00a0type: &quot;service_account&quot;,\n\u00a0\u00a0\u00a0project_id: &quot;[YOUR_PROJECT_ID]&quot;,\n\u00a0\u00a0\u00a0private_key_id: &quot;[YOUR_PRIVATE_KEY_ID]&quot;,\n\u00a0\u00a0\u00a0private_key: process.env.FIREBASE_PRIVATE_KEY?.replace(\/\\\\n\/g, &#039;\\n&#039;),\n\u00a0\u00a0\u00a0client_email: &quot;[YOUR_ACCOUNT]&quot;,\n\u00a0\u00a0\u00a0client_id: &quot;[YOUR_CLIENT_ID]&quot;,\n\u00a0\u00a0\u00a0auth_uri: &quot;https:\/\/accounts.google.com\/o\/oauth2\/auth&quot;,\n\u00a0\u00a0\u00a0token_uri: &quot;https:\/\/oauth2.googleapis.com\/token&quot;,\n\u00a0\u00a0\u00a0auth_provider_x509_cert_url: &quot;https:\/\/www.googleapis.com\/oauth2\/v1\/certs&quot;,\n\u00a0\u00a0\u00a0client_x509_cert_url: &quot;https:\/\/www.googleapis.com\/robot\/v1\/metadata\/x509\/[YOUR_ACCOUNT]&quot;,\n\u00a0\u00a0\u00a0universe_domain: &quot;googleapis.com&quot;\n\u00a0}\n\n\u00a0fs.writeFileSync(&#039;.\/firebase-key.json&#039;, JSON.stringify(credentials, null, 2));<\/code><\/pre>\n\n\n\n<p>Save it to your project root as <code>gen-firebase-key-json.js<\/code>.<\/p>\n\n\n\n<p>Now we need to commit the changes but before we do, just make sure we\u2019re not committing pointless files. Alter the <code>.gitignore<\/code> file and add <code>\/dist<\/code> on a new line. You should now have just some changes from Firebase and the files you added earlier waiting for a commit.\u00a0<\/p>\n\n\n\n<p>Add a commit message like \u201cautomated firebase hosting deploy\u201d, commit and push to the remote.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Deploying the Web Build<\/h2>\n\n\n\n<p>Go back to the <a href=\"https:\/\/dashboard.ionicframework.com\/\">Appflow Dashboard<\/a> to the Commits screen and you should now see your commit at the top of the list. Click start build, select Web and this time, make sure you select the \u201cDev Environment\u201d you just created under the Environment option.<\/p>\n\n\n\n<p>As the build progresses, you should see the pre-build script run immediately following <code>npm run build<\/code> in the build log. After the build completes, you will then see the rather verbose logging of Firebase Hosting doing its thing and then hopefully a successful job. There may be a couple of errors regarding not having iOS and Android targets but that\u2019s ok, we don\u2019t need them for now.<\/p>\n\n\n\n<p>Once the job completes, verify that the update has actually taken place by going back to the Firebase console and selecting Hosting from the left-hand side. You should see the most recent release was uploaded by your service account just now. Congrats for your first successful deployment!<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Where to Go from Here<\/h2>\n\n\n\n<p>Now that you\u2019ve set up hosting, if you\u2019re using other Firebase services like Firestore and Functions, you can deploy to these as well using your <code>web-deploy.sh<\/code> script. This means Functions can have access to all your Appflow environments, greatly simplifying cross platform CI\/CD.<\/p>\n\n\n\n<p>\u2014<\/p>\n\n\n\n<p><em>Not using Appflow for web and native mobile builds yet? <\/em><a href=\"https:\/\/ionic.io\/signup?source=appflow&amp;product=appflow\"><em>Get started with a free account today<\/em><\/a><em>!<\/em><\/p>\n","protected":false},"excerpt":{"rendered":"<p>This is a guest post by Tim Wills, CTO at Uckers.com. Connect with Tim at @TimW_Tech. Are you building an app that deploys to both mobile and web from the same codebase? Do you want to automate your CI\/CD process? If so, Ionic\u2019s mobile CI\/CD platform Appflow with Firebase can provide all you need to [&hellip;]<\/p>\n","protected":false},"author":108,"featured_media":5637,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"publish_to_discourse":"1","publish_post_category":"20","wpdc_auto_publish_overridden":"","wpdc_topic_tags":"","wpdc_pin_topic":"","wpdc_pin_until":"","discourse_post_id":"568343","discourse_permalink":"http:\/\/forum.ionicframework.com\/t\/automate-firebase-deployments-for-web-builds-with-appflow\/236486","wpdc_publishing_response":"success","wpdc_publishing_error":"","_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[1,124],"tags":[128,73],"class_list":["post-5636","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-all","category-tutorials","tag-appflow","tag-firebase"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v23.0 (Yoast SEO v23.0) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Automate Firebase Deployments for Web Builds with Appflow - Ionic Blog<\/title>\n<meta name=\"description\" content=\"Automate deployments of your mobile web builds using Firebase and Appflow for automated cross-platform CI\/CD.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/ionic.io\/blog\/automate-firebase-deployments-for-web-builds-with-appflow\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Automate Firebase Deployments for Web Builds with Appflow\" \/>\n<meta property=\"og:description\" content=\"Automate deployments of your mobile web builds using Firebase and Appflow for automated cross-platform CI\/CD.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/ionic.io\/blog\/automate-firebase-deployments-for-web-builds-with-appflow\" \/>\n<meta property=\"og:site_name\" content=\"Ionic Blog\" \/>\n<meta property=\"article:published_time\" content=\"2023-09-21T16:32:51+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2023-09-21T16:32:53+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2023\/09\/firebase-appflow-feature-image.png\" \/>\n\t<meta property=\"og:image:width\" content=\"2240\" \/>\n\t<meta property=\"og:image:height\" content=\"1120\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Tim Wills\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@ionicframework\" \/>\n<meta name=\"twitter:site\" content=\"@ionicframework\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Tim Wills\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"11 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/ionic.io\/blog\/automate-firebase-deployments-for-web-builds-with-appflow#article\",\"isPartOf\":{\"@id\":\"https:\/\/ionic.io\/blog\/automate-firebase-deployments-for-web-builds-with-appflow\"},\"author\":{\"name\":\"Tim Wills\",\"@id\":\"https:\/\/ionic.io\/blog\/#\/schema\/person\/57e937a864a3182fc573d7c549c7c871\"},\"headline\":\"Automate Firebase Deployments for Web Builds with Appflow\",\"datePublished\":\"2023-09-21T16:32:51+00:00\",\"dateModified\":\"2023-09-21T16:32:53+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/ionic.io\/blog\/automate-firebase-deployments-for-web-builds-with-appflow\"},\"wordCount\":1991,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/ionic.io\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/ionic.io\/blog\/automate-firebase-deployments-for-web-builds-with-appflow#primaryimage\"},\"thumbnailUrl\":\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2023\/09\/firebase-appflow-feature-image.png\",\"keywords\":[\"Appflow\",\"firebase\"],\"articleSection\":[\"All\",\"Tutorials\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/ionic.io\/blog\/automate-firebase-deployments-for-web-builds-with-appflow#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/ionic.io\/blog\/automate-firebase-deployments-for-web-builds-with-appflow\",\"url\":\"https:\/\/ionic.io\/blog\/automate-firebase-deployments-for-web-builds-with-appflow\",\"name\":\"Automate Firebase Deployments for Web Builds with Appflow - Ionic Blog\",\"isPartOf\":{\"@id\":\"https:\/\/ionic.io\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/ionic.io\/blog\/automate-firebase-deployments-for-web-builds-with-appflow#primaryimage\"},\"image\":{\"@id\":\"https:\/\/ionic.io\/blog\/automate-firebase-deployments-for-web-builds-with-appflow#primaryimage\"},\"thumbnailUrl\":\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2023\/09\/firebase-appflow-feature-image.png\",\"datePublished\":\"2023-09-21T16:32:51+00:00\",\"dateModified\":\"2023-09-21T16:32:53+00:00\",\"description\":\"Automate deployments of your mobile web builds using Firebase and Appflow for automated cross-platform CI\/CD.\",\"breadcrumb\":{\"@id\":\"https:\/\/ionic.io\/blog\/automate-firebase-deployments-for-web-builds-with-appflow#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/ionic.io\/blog\/automate-firebase-deployments-for-web-builds-with-appflow\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/ionic.io\/blog\/automate-firebase-deployments-for-web-builds-with-appflow#primaryimage\",\"url\":\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2023\/09\/firebase-appflow-feature-image.png\",\"contentUrl\":\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2023\/09\/firebase-appflow-feature-image.png\",\"width\":2240,\"height\":1120},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/ionic.io\/blog\/automate-firebase-deployments-for-web-builds-with-appflow#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/ionic.io\/blog\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Automate Firebase Deployments for Web Builds with Appflow\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/ionic.io\/blog\/#website\",\"url\":\"https:\/\/ionic.io\/blog\/\",\"name\":\"ionic.io\/blog\",\"description\":\"Build amazing native and progressive web apps with the web\",\"publisher\":{\"@id\":\"https:\/\/ionic.io\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/ionic.io\/blog\/?s={search_term_string}\"},\"query-input\":\"required name=search_term_string\"}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/ionic.io\/blog\/#organization\",\"name\":\"Ionic\",\"url\":\"https:\/\/ionic.io\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/ionic.io\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2020\/10\/white-on-color.png\",\"contentUrl\":\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2020\/10\/white-on-color.png\",\"width\":1920,\"height\":854,\"caption\":\"Ionic\"},\"image\":{\"@id\":\"https:\/\/ionic.io\/blog\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/x.com\/ionicframework\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/ionic.io\/blog\/#\/schema\/person\/57e937a864a3182fc573d7c549c7c871\",\"name\":\"Tim Wills\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/ionic.io\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2023\/09\/IMG_0688-150x150.jpeg\",\"contentUrl\":\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2023\/09\/IMG_0688-150x150.jpeg\",\"caption\":\"Tim Wills\"},\"url\":\"https:\/\/ionic.io\/blog\/author\/timwills\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Automate Firebase Deployments for Web Builds with Appflow - Ionic Blog","description":"Automate deployments of your mobile web builds using Firebase and Appflow for automated cross-platform CI\/CD.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/ionic.io\/blog\/automate-firebase-deployments-for-web-builds-with-appflow","og_locale":"en_US","og_type":"article","og_title":"Automate Firebase Deployments for Web Builds with Appflow","og_description":"Automate deployments of your mobile web builds using Firebase and Appflow for automated cross-platform CI\/CD.","og_url":"https:\/\/ionic.io\/blog\/automate-firebase-deployments-for-web-builds-with-appflow","og_site_name":"Ionic Blog","article_published_time":"2023-09-21T16:32:51+00:00","article_modified_time":"2023-09-21T16:32:53+00:00","og_image":[{"width":2240,"height":1120,"url":"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2023\/09\/firebase-appflow-feature-image.png","type":"image\/png"}],"author":"Tim Wills","twitter_card":"summary_large_image","twitter_creator":"@ionicframework","twitter_site":"@ionicframework","twitter_misc":{"Written by":"Tim Wills","Est. reading time":"11 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/ionic.io\/blog\/automate-firebase-deployments-for-web-builds-with-appflow#article","isPartOf":{"@id":"https:\/\/ionic.io\/blog\/automate-firebase-deployments-for-web-builds-with-appflow"},"author":{"name":"Tim Wills","@id":"https:\/\/ionic.io\/blog\/#\/schema\/person\/57e937a864a3182fc573d7c549c7c871"},"headline":"Automate Firebase Deployments for Web Builds with Appflow","datePublished":"2023-09-21T16:32:51+00:00","dateModified":"2023-09-21T16:32:53+00:00","mainEntityOfPage":{"@id":"https:\/\/ionic.io\/blog\/automate-firebase-deployments-for-web-builds-with-appflow"},"wordCount":1991,"commentCount":0,"publisher":{"@id":"https:\/\/ionic.io\/blog\/#organization"},"image":{"@id":"https:\/\/ionic.io\/blog\/automate-firebase-deployments-for-web-builds-with-appflow#primaryimage"},"thumbnailUrl":"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2023\/09\/firebase-appflow-feature-image.png","keywords":["Appflow","firebase"],"articleSection":["All","Tutorials"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/ionic.io\/blog\/automate-firebase-deployments-for-web-builds-with-appflow#respond"]}]},{"@type":"WebPage","@id":"https:\/\/ionic.io\/blog\/automate-firebase-deployments-for-web-builds-with-appflow","url":"https:\/\/ionic.io\/blog\/automate-firebase-deployments-for-web-builds-with-appflow","name":"Automate Firebase Deployments for Web Builds with Appflow - Ionic Blog","isPartOf":{"@id":"https:\/\/ionic.io\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/ionic.io\/blog\/automate-firebase-deployments-for-web-builds-with-appflow#primaryimage"},"image":{"@id":"https:\/\/ionic.io\/blog\/automate-firebase-deployments-for-web-builds-with-appflow#primaryimage"},"thumbnailUrl":"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2023\/09\/firebase-appflow-feature-image.png","datePublished":"2023-09-21T16:32:51+00:00","dateModified":"2023-09-21T16:32:53+00:00","description":"Automate deployments of your mobile web builds using Firebase and Appflow for automated cross-platform CI\/CD.","breadcrumb":{"@id":"https:\/\/ionic.io\/blog\/automate-firebase-deployments-for-web-builds-with-appflow#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/ionic.io\/blog\/automate-firebase-deployments-for-web-builds-with-appflow"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/ionic.io\/blog\/automate-firebase-deployments-for-web-builds-with-appflow#primaryimage","url":"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2023\/09\/firebase-appflow-feature-image.png","contentUrl":"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2023\/09\/firebase-appflow-feature-image.png","width":2240,"height":1120},{"@type":"BreadcrumbList","@id":"https:\/\/ionic.io\/blog\/automate-firebase-deployments-for-web-builds-with-appflow#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/ionic.io\/blog"},{"@type":"ListItem","position":2,"name":"Automate Firebase Deployments for Web Builds with Appflow"}]},{"@type":"WebSite","@id":"https:\/\/ionic.io\/blog\/#website","url":"https:\/\/ionic.io\/blog\/","name":"ionic.io\/blog","description":"Build amazing native and progressive web apps with the web","publisher":{"@id":"https:\/\/ionic.io\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/ionic.io\/blog\/?s={search_term_string}"},"query-input":"required name=search_term_string"}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/ionic.io\/blog\/#organization","name":"Ionic","url":"https:\/\/ionic.io\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/ionic.io\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2020\/10\/white-on-color.png","contentUrl":"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2020\/10\/white-on-color.png","width":1920,"height":854,"caption":"Ionic"},"image":{"@id":"https:\/\/ionic.io\/blog\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/x.com\/ionicframework"]},{"@type":"Person","@id":"https:\/\/ionic.io\/blog\/#\/schema\/person\/57e937a864a3182fc573d7c549c7c871","name":"Tim Wills","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/ionic.io\/blog\/#\/schema\/person\/image\/","url":"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2023\/09\/IMG_0688-150x150.jpeg","contentUrl":"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2023\/09\/IMG_0688-150x150.jpeg","caption":"Tim Wills"},"url":"https:\/\/ionic.io\/blog\/author\/timwills"}]}},"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2023\/09\/firebase-appflow-feature-image.png","_links":{"self":[{"href":"https:\/\/ionic.io\/blog\/wp-json\/wp\/v2\/posts\/5636","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/ionic.io\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/ionic.io\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/ionic.io\/blog\/wp-json\/wp\/v2\/users\/108"}],"replies":[{"embeddable":true,"href":"https:\/\/ionic.io\/blog\/wp-json\/wp\/v2\/comments?post=5636"}],"version-history":[{"count":3,"href":"https:\/\/ionic.io\/blog\/wp-json\/wp\/v2\/posts\/5636\/revisions"}],"predecessor-version":[{"id":5642,"href":"https:\/\/ionic.io\/blog\/wp-json\/wp\/v2\/posts\/5636\/revisions\/5642"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/ionic.io\/blog\/wp-json\/wp\/v2\/media\/5637"}],"wp:attachment":[{"href":"https:\/\/ionic.io\/blog\/wp-json\/wp\/v2\/media?parent=5636"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/ionic.io\/blog\/wp-json\/wp\/v2\/categories?post=5636"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/ionic.io\/blog\/wp-json\/wp\/v2\/tags?post=5636"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}