2.4 A gentle introduction to SvelteKit for Google Cloud developers
Tags: sveltekit, javascript, googlecloud, beginners
Published: 2024-07-16 10:23:16

---
title: "2.4 A gentle introduction to SvelteKit for Google Cloud developers"
---
### Introduction

An earlier post in this series ([A very gentle introduction to React](https://dev.to/mjoycemilburn/23-a-students-guide-to-firebase-v9-a-very-gentle-introduction-to-reactjs-d67)) introduced readers to the excellent **React** framework system for developing webapps. **SvelteKit** is an alternative framework. How does it differ from React and is it any better?

Functionally, I guess there's not that much difference. Most things you can do in React you can do in SvelteKit. And vice-versa. But when you get down to the details, many people feel that SvelteKit has the edge in terms of the ease with which you achieve your "reactive" goals. Svelte means "elegant" - and that's just what it is - a slender, highly adaptable and practical tool. 

Personally, I was attracted to SvelteKit because it also tends to push you towards server-side design - ie code that runs on your webapp's Cloud servers rather than in your user's web browser. This is ironic because it was the ease with which you could write and debug client-side code that originally got me hooked on webapp development. But then I discovered how reluctant indexing spiders are to invest effort in "hydrating" client-side code and realised I would just have to put more effort in here (see debugging in SvelteKit, below, to see what's entailed). But there are other reasons why you might consider using server-side code too. Here are a couple:

* Once you start using third-party services such as Postmark (email despatch) or Paypal (payment collection), you'll realise that it's not a good idea to include their security codes in client-side code. If **you** can use the "inspector" to view these, so can anyone else. Code that runs server-side is inaccessible.

* server-side code lives closer to your data and runs faster here than on a client laptop. 

SvelteKit makes it easy to play tunes on specifying which bits of your webapp are to run locally and which are to run remotely. 
* In some cases, pages may be entirely server-side rendered - if they contain only static information, Sveltekit will enable you to "pre-render" them. Pre-rendered pages are constructed at build time and downloaded as slabs of pure HTML. 
* Alternatively, they may be entirely client-side rendered. 
* Or yet again,  they may run on both. A SvelteKit webapp aiming to deliver optimal response times may initially display just a server-sourced "placeholder" screen to get something, anything, visible (you get great credit with Google's indexing bots here, apparently). This is then "hydrated" by client-side code with information specific to the user-instance.

Let's get down to something a bit more concrete.

## Routing in Svelte

Externally, a Sveltekit webapp will look exactly like any classic browser application - a hierarchy of "pages" such as `mywebapp/dosomethingwithmyfiles`. It's like this because client users expect, and rely on this type of arrangement. But below the surface, a SvelteKit webapp delivers this arrangement in a totally different way to a React webapp. In React these pages are actually all parts of one giant slab of code and requests are routed thither by re-directs operating at the web interface (if that sentence doesn't make any sense to you, have a look at [Whats a 'Single-page' webapp?](https://dev.to/mjoycemilburn/61-polishing-your-firebase-webapp-whats-with-this-single-page-app-stuff-learn-about-react-routes-nb2)). SvelteKit achieves this by using your project structure to define your page structure. So, if you want to have a `mywebapp/dosomethingwithmyfiles` page, you need to have a folder named `dosomethingwithmyfiles` with a `+page.svelte` file inside it. Once this arrangement is in place, your deployed app delivers a separate physical page for each of its URLs.

Here's a sample source folder structure for a SvelteKit project:

myproject
├───src
│   └───routes
│       └───dosomethingwithmyfiles


Once you've installed SvelteKit (see [Svelte for New Developers](https://svelte.dev/blog/svelte-for-new-developers)), this structure will be augmented by a mass of complicated `config` files and `build` folders etc. But, for the present, the focus is on the `routes` folder.  This is where you store your page code - and here is where you might start to wonder whether SvelteKit is the right thing for you. Take a tight grip now because this is where things get a bit complicated.

SvelteKit requires you to follow a **very strict naming convention** for the content of a page folder. Here's a list of the filenames that might see in a `dosomethingwithmyfiles` folder:

* **dosomethingwithmyfiles/+page.svelte**. This file would contain the source for the code that displays the page for URL `myproject/dosomethingwithmyfiles`on the browser screen. Whoah - let that sink in for a moment. When you're working in your VSCode editor on a SvelteKit project with half a dozen different pages, your filebar may display half a dozen tabs all named `+page.svelte`. Confusing? Yes, I agree.
 
At first sight, you might feel that this is simply unacceptable. But note that each `+page.svelte` file is qualified on the editor bar by the name of its folder owner, `dosomethingwithmyfiles`, or whatever. It's not so difficult to discipline yourself to check for the owner of a `+page.svelte` before you dive in and start editing. And once you've developed a SvelteKit project or two you'll begin to appreciate the value of the convention in declaring the *purpose* of the arrangement (as you'll see in a moment there are quite a few variations)
 
While you're absorbing this shock, let me give you a bit of encouragement. **Within** a `+page.svelte` file you might expect to find the same sort of code you'd see in an equivalent React file - a mixture of exotic `useState` calls to manipulate page state, and JSX to 'react' to this and generate HTML. While a `+page.svelte` file certainly does the same job, it manages to discard the "exotic" bit and uses plain javascript and pure, undiluted HTMl salted with a sprinkling of special keywords. You may find this refreshing.

Here are a few more standard filenames you might find in a `dosomethingwithmyfiles` folder:

* **dosomethingwithmyfiles/+page.js**, This would contain the source for a file that delivers **data** to a `+page.svelte` file (ie, the equivalent of a React `useEffect`). Code here will run on the server when the page is initially loaded. Subsequently, if the page is re-referenced, the `+page.js` code runs in the browser with the advantages listed earlier.
<p>&nbsp;</p>
Interestingly, if you've suffered in the past from having to "re-program" your javascript brain whenever you switch between writing `Web API` code to run in the browser and `Node.js` style to run server-side in a Firebase function you'll be delighted to hear that, in Sveltekit, the `Web API` version is now perfectly happy to run server-side as well.
<p>&nbsp;</p>
Naturally, you'll want to know just how you organise things so that data read by a `+page.js` file ends up in the associated `+page.svelte`. Let me say that, for the present, this arrives by SvelteKit magic. The exact mechanism will only become clear once I've described SvelteKit's arrangements for defining "reactive" variables. Hang onto your hat for now.
<p>&nbsp;</p>
* **dosomethingwithmyfiles/+page.server.js**. This is where you would place code that you want to run only on the server (typically for security or performance reasons). As mentioned earlier, you can request that this is pre-rendered and thus constructed at build-time. In this case, performance is simply startling.
<p>&nbsp;</p>
* **dosomethingwithmyfiles/+layout.svelte**. This is where you would place code that sets up those bits of a page common to a whole set of other pages - toolbar headers, for example. A `+layout.svelte` file applies to every child route and any sibling `+page.svelte`. You can nest layouts to arbitrary depth. Again, the precise arrangement for inserting the common layout into the recipient pages will be left for later - more Svelte magic. 
<p>&nbsp;</p>
If a `+layout.svelte` page needs some data, it can have an attendant `+layout.server.js` file
<p>&nbsp;</p>
* **dosomethingwithmyfiles/+server.js**. This is where you would place code that you wanted to be available as an "API endpoint" via a parameterised URL such as `myProject/dosomethingwithmyfiles?type="pdf"`. I'll provide more details on this arrangement later.

### 'Reactive variables' and 'Reactive HTML' in SvelteKit

By 'reactive variables' I mean data items that cause the browser page to re-render when they change. By 'reactive HTML' I mean HTML instrumented to make it respond to these changes. 

In React, you'll recall, reactive variables are declared using a `useState` expression that defines the variables as properties of a state object. The declaration also specifies initial property values and a function to change them.

Here's an example - a React webapp that displays a popup that disappears when you click it:

```javascript
import React, { useState } from "react";

const [screenState, setScreenState] = useState({popupVisible: true,});

return (
    <div>
        <h1 style={{textAlign: "center"}}
            onClick = {() => {setScreenState({popupVisible: !screenState.popupVisible})}}>
        Main Page - Click to toggle popup
        </h1>
  
    {screenState.popupVisible && 
        <div 
            style={{ textAlign: "center", marginLeft: "auto", marginRight: "auto", height: "2rem", width: "25rem", backgroundColor: "gainsboro" }}
            onClick = {() => {setScreenState({popupVisible: !screenState.popupVisible})}}>
            <h2> Popup Window - Click to Hide popup</h2>
        </div>  
    }
    </div>
)
```

 In Svelte (I'm now talking about the *language* as opposed to the *framework* in which it operates) you might achieve this effect in a `src/routes/demo/+page.svelte` file  by simply declaring `popupVisible` as a javascript variable

```javascript
<script>
    let popupVisible = false;
</script>

 <div>
    <h1 style="text-align: center" 
        on:click={() => (popupVisible = !popupVisible)}>
        Main Page - Click to toggle popup
    </h1>

    {#if popupVisible}
        <div
            style="text-align: center; margin-left: auto; margin-right: auto; height: 2rem; width: 25rem; background-color: gainsboro"
            on:click={() => (popupVisible = !popupVisible)}
        >
            <h2>Popup Window - Click to Hide popup</h2>
        </div>
    {/if}
</div>
```

Here's a summary of the key differences:

* Svelte uses a standard Javascript `let` declaration to introduce state variables instead of the strange React `useState` expression

* Svelte uses a down to earth `#if 'logical expression'` keyword to replace  the awkward JSX `{'logical expression'  &&`syntax. This makes your code much more readable. Svelte also provides associated `else` and `each` keywords.  

* Svelte uses plain CSS to define HTML classes rather than the perplexing JSX style objects (eg `{{textAlign: "center"}}`). 

Note also that the `demo/+pagesvelte` file defined above will run directly in the browser as `/demo`. To run the React version you would have to put some code into an associated `src/main.jsx` file to define the new route. 

### Inputs: Local Functions, Actions and API endpoints

Keyboard input in React generally uses the following pattern:
```javascript
const [myState, setMyState] = useState({myProperty: "",});

function handleChange({ target }) {
    setMyState({ ...myState, [target.name]: target.value });
};

return (
    <input name="myProperty"
        value={myState.myProperty}
        onChange={handleChange} />
)
```

Here, an input labelled as "myProperty" fires a general-purpose `handleChange` function every time you press a key. In `handleChange` its value is extracted and applied to the page's state to trigger a re-render.

Svelte thinks this is too complicated and introduces a "bind" keyword to its input syntax. This automatically transmits changes to an associated state variable. A Svelte version of the above thus looks like this:
```javascript
<script>
    let myProperty = "";
</script>
<input bind:value={myProperty} />
```
The bind keyword is also used to enable you to create two-way communication between parent and child components. This is a powerful feature. 

An interesting feature of Svelte is that it encourages you to use forms and server-side processing for input handling. Thus it's perfectly permissible in Svelte to launch a client-side function like this:
```javascript
<script>
    let myProperty = "";
    function commitChange() {
        // Use the global myProperty variable to update server storage
    }
</script>

<span>myProperty = </span><input bind:value={myProperty}  />
<button on:click={commitChange}>Commit Change</button>
/>
```
Svelte docs correctly insist that interactions like this are better handled by forms and server-side processing in a `+page.server.js` file. Here the validation and submission of the user input can be safely protected from the sort of interference possible in client-based code. Here also, any subsequent processing can be performed with maximum efficiency.

To implement this view, Svelte provide a neat automatic link between a form reading data on a `+page.svelte` and a function handling the processing of that data in the associated `+page.server.js` file. Here's an example:
```javascript
src/routes/login/+page.svelte
<form method="POST">
	<span>myProperty = </span><input name="myProperty">
    <button>Commit Change</button>
</form>

src/routes/login/+page.server.js
export const actions = {
	default: async (event) => {
		// TODO handle the processing for the input read by the form on +page.svelte
	}
};
```
Note that no Javascript has been used in the form - no "on click" or "on submit", for example. The linkage has been established entirely through "Svelte magic". 

In practice, of course, a `+page.svelte` file is likely to want to be the source of multiple "actions". See [Svelte Form Actions](https://kit.svelte.dev/docs/form-actions) for details of how Svelte manages this. (Note that Svelte docs are organised under two URLs:  `kit.svelte.dev` for framework topics like routing and `svelte.dev` for elements of the language itself)

Finally, to conclude this section, suppose you wanted users to be able to call on the service of an action by referencing it directly through a javascript "fetch" (or, at its simplest by launching a parameterised url via the browser - eg `https:// mySite/myPage?param1=3` etc). This is where you would use a `+server.js` file to create an API "endpoint" function. Firebase users might well use such an arrangement where they had previously used a Firebase function. Not the least advantage of this would be that testing and debugging could be done in the Sveltekit server rather than the Firebase emulator.

### Components

* 1-way bindings

Each `+page.svelte` file defines a component, and you mark variables declared here as "props" - ie make them accessible to "consumers" of the component - by adding the `export` keyword to their declarations. So, if you're still wondering how a `+page.svelte` file gets its data from `+page.server.js` - this is how it's done. A `+page.svelte` file wanting to receive "load" data from its `+page.server.js` (or `+page.js`) file just needs to put something like the following  in its `<script>` section:

```
export let data
```

Svelte magic will then ensure that if the 'load' function exported by the `+page.server.js` file returns an object such as {name: "Benny", } then `+page.svelte` will find that `data.name` contains "Benny".

But suppose that the `+page.svelte` file wanted to reference its own child component. How would that child be configured and linked to its parent?

Let's say that this child component needs parameters `param1` and `param2` to build its output. It's usually most convenient to store the component in a `src/lib` folder - say `src/lib/MyComponent.svelte` - and its content might then look something like:
```javascript
<script.
  export let param1;
  export let param2;
</script>

  ... Svelte html referencing param1 and param2 ...

```

The parent `+page.svelte` could then engage the component like this:
```javascript
<script>
	import { MyComponent } from "$lib/myComponent.svelte";

let param1 = "Type A";
let param2 = 10;

<script/>
<h1>
	Component-Access Demo Page
</h1>
<myComponent> {param1} {param2};
```

This arrangement will be perfectly familiar if you've previously used React. Also, as with React, once the child component has received a parameter passed in this way, it's free to modify it at will - the parent will be oblivious of the change. This arrangement is known as a one-way binding

Note the "$" shortcut used in the child component import declaration. Svelte works out the actual route automatically, saving you working out all the conventional "./" and "//" designators.

* 2-way bindings

Suppose the child component creates a form designed to serve both Create and Edit parents. In this case, it needs to be able to receive parameters supplying initial values for form elements and return the user inputs. Data is thus required to pass both down and up the component hierarchy.

In React you might have used a Context here. Svelte provides several alternatives, each with different characteristics, but the simplest is a `bind:` keyword applied to the parameter references in the parent's component call.

Let's say we've created the following shared input layout in a lib/MySharedInputPanel.svelte file:

```javascript
<script>
    export let input1;
    export let input2;
</script>

<div>
    <span>Input1 value<span/>
        <input type="text" bind:value={input1} />&nbsp;&nbsp;
    <span>Input2 value<span/>
        <input type="text" bind:value={input2} />
</div>
```

This creates a default export for a MySharedInputPanel component that  a `routes/editrecord/+page.svelte` file can import and use to build an edit 'form' for the named, exported inputs as follows:
```javascript
<script>
    import MySharedInputPanel from "$lib/componentsMySharedInputPanel.svelte";

    let input1 = "Initial Text";
    let input2 = 3;
</script>

<h1>Edit Record</h1>
<div>
    <MySharedInputPanel bind:input1 bind:input2 />
    <p>Latest values: Input1 = {input1} : Input2 = {input2}</p>>
</div>
```

If you try this out yourself, you'll see that the shared panel initially displays the input1 and input2 values specified in the edit record route and that the parent `editrecord/+page.svelte` view of these changes when new values are entered. This confirms that the route is automatically rerendering when changes occur.

A `routes/createrecord/+page.svelte` could use the same form component to collect inputs and create a record.

Note that, for brevity, I've used neither the `<form>` nor `<label>` elements that good practices would require. My code also assumes that the parents and child use the same variable names. See Svelte's "component directive" docs for a more general version of the bind: syntax.

### Svelte `store`

Sometimes you'll find that you need a global state object to serve components that are not hierarchically related. Svelte `store` is designed to meet this need - and much more besides. A `store`, particularly a writable store (several variants exist), is an object with a `set()` method that allows you to set new values for its content. 

Why is this any different from good old Chrome `localStorage`? Potential readers of the store register their interest via a subscribe() method that sets a callback function that notifies them whenever the store value changes - Svelte store is reactive!

I'll only describe the "writable" version of Svelte store here - the one that I, myself, have found most useful. In brief:

A writable store is created using the following code pattern:
```javascript
import { writable } from "svelte/store";

let myStoreContent = {myStoreField:"Welcome to SvelteStore"}

export const myStore = writable(myStoreContent);
```
Now, if a component (or, indeed, a regular JavaScript module) needs to know if anything changes in the store, it can register its interest by supplying a callback function with a  `subscribe` command along the lines of the following:

```javascript
let currentMyStoreFieldValue

myStore.subscribe((store) => {
        currentMyStoreFieldValue =  store.myStoreField;
	});
```
Note that, once you've created this arrangement, you never have to explicitly *read* your store, its current value remains available in your page's `currentMyStoreFieldsValue` for the duration of a browser session. A typical arrangement will be to use a `stores.js` file (usually positioned at the root of the src folder) to create a `store` object and then import this wherever it's needed. The javascript module system will ensure that the store is initialized the first time it is imported during the browser session.

To update the store's value you can use the `set()` method again, but it may often be more convenient to use Svelte store's `update()` method as this gives you access to the current value of the store. Check out Svelte's docs at [Writable Stores](https://learn.svelte.dev/tutorial/writable-stores) if you'd like to see an example (and much else besides).

### Debugging techniques for SvelteKit webapps
So, you've blasted your code through the myriad of shrieks and groans displayed by VSCode and Vite when they find errors such as undeclared variables and missing files. These are all usually easily fixed. But now you've got a webapp that runs - but all it does is sit and sulk. What now?

The first thing, of course, is to open the browser's Inspector and see what the Console tab offers - there's almost always something to get a handle on here. Oh dear - CORS, Permissions, or similar error. What now?. 

Debugging a SvelteKit webapp tends to be a bit more complicated than, say, a React codebase because so much of your code is likely to be running "server-side". If you've followed this series rigorously, you'll likely now be a world expert in debugging client-side code using the Browser's Inspector. This, above all else, makes my own coding life the purest pleasure.

But when you try to set breakpoints in a SvelteKit `+page.server.js` file, you'll find that the browser won't let you. Think about this for a moment. How can it? Code here runs either in the development server launched by npm run dev or in the live server where you've just deployed a package. This is just a black hole as far as the browser is concerned. So what do you do now?

While you're still working on development code, VSCode offers you browser-like debugging facilities directly within your IDE. But personally. I've found these clunky and in practice I tend to rely simply on sprinkling `console.log` instructions over my code. Output for these appears in whatever terminal session you've used to launch your run npm dev.

But what if you've got a problem that can only be investigated on the live host? Where would you go to look for log messages launched here? The answer, for a Google Cloud webapp is the "Google Cloud Logs Explorer" console.

This, on first experience, is also quite a clunky brute. But, with experience, you'll appreciate that (rather like the browser's Inspector) it's a fine piece of software engineering that provides infinitely adaptable tools in one neat package. Embrace it!

### Building and Deploying a SvelteKit webapp to the Google Cloud 

If your webapp had been using React, as a Firebase developer you'd know that the next step is to use `npm run build` to create a runtime version of your code, followed by a `firebase deploy` to upload this to Google Cloud's Firebase hosting servers.

But if you're using Svelte there's a problem. If your Sveltekit webapp uses server-side code to achieve its effects, you will need hosting for a Svelte server. Firebase hosting only serves webapp pages. You need a different type of hosting altogether - one that effectively lets you mimic the operation of the local Svelte server you've been running on your PC.

Once you start looking closely, you'll discover that the Google Cloud provides a bewildering variety of facilities in this area. Typically, you might be interested in Google's "App Engine" and "Cloud Run" services. 

SvelteKit docs at [Building your App](https://kit.svelte.dev/docs/building-your-app) describe a build process that creates a "yaml" file that "provides an optimized production build of your server code and your browser code" serviced by an "adapter" to run on your specific environment (eg Google Cloud Run). But where would you find the necessary "adapter" and how would you choose the "specific environment"?

Although Svelte provides official adapters for numerous environments (eg Netlify and Vercel) this list unfortunately doesn't include the Google Cloud. But "community" developers have stepped in and the one I've been using is called `svelte-adapter-appengine`, courtesy of Jonas Jongejan (HalfdanJ). This targets the Google Cloud App Engine environment (as described at [svelte-adapter-appengine README](https://github.com/HalfdanJ/svelte-adapter-appengine)) and so my requirement list is complete. Here's the procedure.

1. Install the package as a development dependency:
`npm install --save-dev svelte-adapter-appengine`

2. Update your svelte.config.js to use the adapter:
```javascript
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
import adapter from "svelte-adapter-appengine";
/** @type {import('@sveltejs/kit').Config} */
const config = {
  preprocess: vitePreprocess(),

  kit: {
   adapter: adapter(),
  },
};

export default config;
```
3. Build your application:
`npm run build`

4. Deploy your application to App Engine:
`gcloud app deploy --project <CLOUD_PROJECT_ID> build/app.yaml`

Output from the deployment process will provide a url for your deployed webapp (eg https://myProject.nw.r.appspot.com). Feed that to the browser and be electrified by the shockingly fast response of your Sveltekit webapp.

### Postscript

I hope you've enjoyed reading this post. Check out [NgateSystems](https://ngatesystems.com) for an index to the whole series and a super-useful keyword search facility. 

I'm conscious that I've only scratched the surface of what Svelte has to offer. This post has covered the basics and should be enough to enable you to develop a functional database access/maintenance system, but there's lots more to learn. Make sure that you check out Svelte docs for more information. Good luck with your coding. I, for one, shall certainly be using Svelte in future!