<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Christopher Spradlin</title>
    <description>The latest articles on DEV Community by Christopher Spradlin (@crspradlin).</description>
    <link>https://dev.to/crspradlin</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F913058%2F8d84b28b-7ff1-411a-95ad-8b575d2e1402.png</url>
      <title>DEV Community: Christopher Spradlin</title>
      <link>https://dev.to/crspradlin</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/crspradlin"/>
    <language>en</language>
    <item>
      <title>Google App Script React Template</title>
      <dc:creator>Christopher Spradlin</dc:creator>
      <pubDate>Tue, 14 May 2024 00:29:07 +0000</pubDate>
      <link>https://dev.to/crspradlin/google-app-script-react-template-489p</link>
      <guid>https://dev.to/crspradlin/google-app-script-react-template-489p</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwmk39yl8pj1on0l8kc8d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwmk39yl8pj1on0l8kc8d.png" alt="Google App Script Web App" width="800" height="575"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Starting a web project always seems so difficult. Hundreds of questions seem to inject themselves into my mind. What language and technologies should I use? Where will I deploy the result? (Basically all the questions that have nothing to do with the project itself).&lt;/p&gt;

&lt;p&gt;After running through this cycle a number of times, I decided to create a template to allow me to focus on the project implementation rather than project infrastructure. &lt;/p&gt;

&lt;p&gt;At its initial state the template gives you a baseline javascript web app that runs a React frontend hosted by a Google App Script (GAS) backend. While Google App Script is usually used for automating business processes across multiple Google Services, it can also be a platform for hosting web applications. Unfortunately, the App Script Web-based IDE is not very user friendly when it comes to building performant SPAs. Luckily webpack allows transpilation of modern JavaScript syntax and functionality to more native and widely supported versions of the JavaScript language. By combining the power of webpack, react and Google App Script (via the Clasp CLI), we can create modern-looking web apps with your already familiar Google Services. This template comes pre-built with an example call to the GAS backend which updates a single cell within a Google Spreadsheet but gives you the bare framework to add as many Google Service integrations you want.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqj36m2q9cggtrfh9b37y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqj36m2q9cggtrfh9b37y.png" alt="Google App Script Web App with Filled Form" width="800" height="575"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2sb80f8tcarnpozmwu7r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2sb80f8tcarnpozmwu7r.png" alt="Google Spreadsheet Result with Form Value Saved" width="800" height="575"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Essentially, think of this as a React SPA with a Google Sheets database. And while it does sound a little in-formal and definitely less cool than setting up a Kubernetes cluster of five different images spread over twenty containers, this GCP React Template is honestly all you need to build efficiency in your small business or even your daily life without any major technical hurdles.&lt;/p&gt;

&lt;p&gt;All code for the "frontend" is stored under &lt;code&gt;src/client&lt;/code&gt; and all code for the "backend" is stored under &lt;code&gt;src/server&lt;/code&gt;. To make calls between the client and server directories, a global function must be declared within the &lt;code&gt;code.ts&lt;/code&gt; file of the server directory, and the client calls this function via a &lt;code&gt;google.script.run&lt;/code&gt; function call as shown below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/server/code.ts&lt;/span&gt;

&lt;span class="c1"&gt;// @ts-ignore&lt;/span&gt;
&lt;span class="nb"&gt;global&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FormSubmit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;formData&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;scriptProps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;PropertiesService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getScriptProperties&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sheetId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scriptProps&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;MAIN_SHEET_ID&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sheet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;SpreadsheetApp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;openById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sheetId&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;getSheets&lt;/span&gt;&lt;span class="p"&gt;()[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

    &lt;span class="nx"&gt;sheet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getRange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;setValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;formData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;newValue&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/client/root.tsx&lt;/span&gt;

&lt;span class="kr"&gt;public&lt;/span&gt; &lt;span class="nx"&gt;handleSubmit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
    &lt;span class="c1"&gt;// @ts-ignore&lt;/span&gt;
    &lt;span class="nx"&gt;google&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;script&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;run&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;withSuccessHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;handleFormSuccess&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;withFailureHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;handleFailure&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;FormSubmit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;form&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;withSuccessHandler&lt;/code&gt; and &lt;code&gt;withFailureHandler&lt;/code&gt; functions allow you to set callbacks for both a successful and unsuccessful response from your backend &lt;code&gt;FormSubmit&lt;/code&gt; call. As you can see the last function to be called is the function you defined within the server side &lt;code&gt;code.ts&lt;/code&gt; file. For more information about the client side API for &lt;code&gt;run&lt;/code&gt; please reference &lt;a href="https://developers.google.com/apps-script/guides/html/reference/run"&gt;Google's Documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;With some of the basics out of the way, you should be able to hit the ground running by setting up your very own Google App Script Web App. Keep in mind this is just a template so feel free to add more complex UI dependencies or more Google Service integrations into your very own implementation! Hopefully this template helps you worry less about the backend and gets you more time implementing your awesome ideas!&lt;/p&gt;

&lt;h3&gt;
  
  
  Check out the project here: &lt;a href="https://github.com/CRSpradlin/gcp-react-template"&gt;GCP React Template&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Related Projects:&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://github.com/enuchi/React-Google-Apps-Script/blob/main/webpack.config.js"&gt;React-Google-Apps-Script&lt;/a&gt;: Really helped kickstart this project and aided with my own perils of how webpack works.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/CRSpradlin/budget-app"&gt;budget-app&lt;/a&gt;: An example use case of this template; created by me to help aid recording and budgeting my monthly expenses. I use this nearly every day.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/CRSpradlin/dirtyspokes-series-app"&gt;dirtyspokes-series-app&lt;/a&gt;: A more niche use case of this template; created by me to help a local trail running company keep track of series points for semi-annual awards to top runners in the district.&lt;/p&gt;

</description>
      <category>gas</category>
      <category>react</category>
      <category>javascript</category>
      <category>webapp</category>
    </item>
  </channel>
</rss>
