logo hsb.horse
← Back to blog index

Blog

Building a Full-Featured Google Apps Script Web App with Svelte

How to combine Google Apps Script web app publishing with Svelte to build a feature-rich SPA that uses a spreadsheet as its database.

Published:

There was a case where I wanted to build a lightweight app or tool that used a spreadsheet as its database by publishing a Google Apps Script web application.

It was too small to justify deploying to S3 or another hosting platform, but editing the spreadsheet directly was also not ideal. In that kind of situation, this approach lets you build a web app with Svelte, React, or Vue.

Repository

svelte-with-tailwindcss-on-gas

It is set up so you can use GitHub’s template repository feature.

If you do not need TailwindCSS, you can remove it without any problem.

Tech stack

Directory structure

The client directory is the layer that contains the frontend implementation created with Svelte.

The server directory contains the server-side implementation that runs on GAS.

src/
├── client/
│ ├── api/
│ │ ├── mocks
│ │ └── index.ts
│ ├── components
│ ├── features
│ ├── stores
│ ├── types
│ ├── utils
│ ├── App.svelte
│ └── main.ts
├── server/
│ ├── main.ts
│ └── types.ts
└── vite-env.d.ts

Server side

Use the GAS web app feature to serve HTML

Add a doGet function in server/main.ts.

Even if you change the title tag or favicon in the frontend, those changes are not reflected, so if you need them, set them in doGet.

const HTML_TITLE = "App name";
const HTML_FAVICON_URL = "https://example.com/favicon.ico";
function doGet() {
const html = HtmlService.createTemplateFromFile("index.html").evaluate();
html.setTitle(HTML_TITLE);
html.setFaviconUrl(HTML_FAVICON_URL);
return html;
}

Create API endpoints

In server/main.ts, you only need to export the functions you want to expose as endpoints.

type APIResult<T> =
| {
ok: true;
data: T;
}
| {
ok: false;
error: Error;
};
const doSomething = (): APIResult<string> => {
return {
ok: true,
data: "success",
};
};
export { doSomething };

Frontend

Bind to the server-side API in src/client/api/index.ts.

Internally, this uses google.script.run.

import { GASClient } from "gas-client";
import type * as Server from "../../server/main";
const { serverFunctions } = new GASClient<typeof Server>();
export const APIClient = serverFunctions;

Call the server-side API

<script lang="ts">
import { APIClient } from "./api";
const promise = APIClient.doSomething();
</script>
{#await promise}
<div>Loading...</div>
{:then result}
<p>{result}</p>
{:catch error}
<p>error</p>
{/await}

Summary

By combining Google Apps Script with Svelte, you can build a capable web app that uses a spreadsheet as the backend.

With gas-client, you can call GAS functions in a type-safe way, which also makes the developer experience much better.