Skip to content

Commit

Permalink
feat(examples): Svelte integration
Browse files Browse the repository at this point in the history
  • Loading branch information
basmasking authored Mar 6, 2023
1 parent 3cb2845 commit f87f106
Show file tree
Hide file tree
Showing 21 changed files with 2,033 additions and 2,543 deletions.
24 changes: 24 additions & 0 deletions examples/4-integrations/3-svelte/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

node_modules
dist
dist-ssr
*.local

# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
192 changes: 192 additions & 0 deletions examples/4-integrations/3-svelte/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
# svelte-jitar

The example contains a step-by-step guide to integrate Jitar with Svelte using Vite.

## Step 1: Setup a Svelte Project

For creating the Svelte app, use Vite with the `svelte-ts` template.

```bash
npm create -y vite@latest svelte-jitar -- --template svelte-ts
cd svelte-jitar
npm install
npm run dev
```

When opening http://localhost:5173/ in a web browser it should show the Svelte and Vite logos.

Next, the app will be extended by adding a simple function that generates a welcome message. To hook Jitar later in the app, a shared folder needs to be created in the src folder. This folder holds all components that are shared between the client and server.

```bash
cd src
mkdir shared
```

Now, the first shared function needs to be created. Call it `sayHello` and give it the following content.

```ts
// src/shared/sayHello.ts
export async function sayHello(name: string): Promise<string>
{
return `Hello, ${name}!`;
}
```

Note that this function is async. This is an important addition that makes the function distributable across the network.

Use this function to welcome you. To do so, the await block will be used. Update the `App.svelte` file to use the new function. This is a very simple example but feel free to extend it.

```svelte
<script lang="ts">
import svelteLogo from './assets/svelte.svg'
import { sayHello } from './shared/sayHello';
async function runComponent()
{
return await sayHello('Vite + Svelte + Jitar');
}
const promise = runComponent();
</script>
<main>
<div>
<a href="https://vitejs.dev" target="_blank" rel="noreferrer">
<img src="/vite.svg" class="logo" alt="Vite Logo" />
</a>
<a href="https://svelte.dev" target="_blank" rel="noreferrer">
<img src={svelteLogo} class="logo svelte" alt="Svelte Logo" />
</a>
</div>
{#await promise then message}
<h1>{ message }</h1>
{/await}
</main>
```

After saving the file, the browser should show the welcome message.

The function currently lives and runs on the client. Next, it will be moved to the server without touching a single line of code.

## Step 2: Add Jitar to the Project

To use Jitar as runtime, add its Node.js server as a dependency.

```bash
npm install jitar-nodejs-server
```

For easy integration with web apps, a Vite plugin is available.

```bash
npm install --save-dev jitar-vite-plugin
```

To enable the plugin, it needs to be added to the Vite config file.

```ts
// vite.config.ts
import { defineConfig } from 'vite'
import { svelte } from '@sveltejs/vite-plugin-svelte'
import jitar from 'jitar-vite-plugin'

// https://vitejs.dev/config/
export default defineConfig({
plugins: [
svelte(),
jitar('src', 'shared', 'http://localhost:3000')
],
})
```

The three parameters set the `root source` folder, the shared components folder (relative to the root folder), and the URL of the Jitar server.

Vite is now all set up, time for the configuration of Jitar. For this, two JSON files are required. The first is the server configuration. This simple example doesn’t need the [cluster options](https://docs.jitar.dev/03_runtime_services) provided by Jitar, so a simple standalone setup will be used. Create a new file in the project root (outside the source root) with the name jitar.json and the following content:

```json
{
"url": "http://127.0.0.1:3000",
"standalone":
{
"source": "./dist",
"cache": "./cache",
"index": "index.html",
"assets": ["index.html", "main.js", "App.js", "vite.svg", "assets/**/*"]
}
}
```

This configuration tells Jitar to read the compiled JavaScript from the dist folder and write its `cache` to the cache folder. It serves the `index.html` file when accessing it with a web browser. The `assets` whitelist the files that are accessible from the outside world. Other files will be hidden by default.

The second configuration is a [segment configuration](https://docs.jitar.dev/04_basic_features#segmentation). A segment defines the components grouped to form a deployable package. For example, you only need a single segment to place the function on the server. Create a new file in the project root with the name `server.segment.json` and the following content.

```ts
{
"./shared/sayHello.js": { "sayHello": { "access": "public" } }
}
```

The structure of a segment file is very similar to the JavaScript module system. In this case, Jitar imports `sayHello` from `./shared/sayHello.js`. Additionally, the access is set to public (private by default).

Note that the file path is relative to the source root of the application and that it imports the compiled JavaScript file (ends with .js).

That’s almost it. The only thing that’s missing is a bootstrapper for starting a Jitar server. For this, add a new code file to the source root folder. Here’s what that looks like:

```ts
// src/jitar.ts
import { startServer } from 'jitar-nodejs-server';

const moduleImporter = async (specifier: string) => import(specifier);

startServer(moduleImporter);
```

With the start of a server, Jitar needs a module importer that imports Node dependencies from the local application context instead of the Jitar context.

## Step 3: Build and Run

With Jitar all set up, get ready for its first run. The current plugin implementation requires some additional configuration which will be optimised in later versions.

The `tsconfig.js` file needs to be updated with the following properties.

```js
/* tsconfig.json */
{
"compilerOptions":
{
/* other properties */
"sourceMap": false, /* add this property */
"noEmit": false, /* add this property */
"outDir": "dist", /* add this property */
}
}
```

In the package.json file, the build script needs to be updated to include the TypeScript compiler. This is required to compile the Jitar bootstrapper and the shared functions.

```json
"build": "vite build && tsc",
```

Lastly, add the following script for starting the Jitar server.

```json
"jitar": "node --experimental-network-imports --experimental-fetch dist/jitar.js --config=jitar.json"
```

And that's it. The server has been configured and is ready to go. Both scripts can be executed with the following commands:

```bash
npm run build
npm run jitar
```

Note that the function has been registered successfully by Jitar. This means that it has moved from the client to the server. Run the app by navigating to http://localhost:3000/. The Jitar log should indicate that it has run our function.

When inspecting the network traffic of the browser (in the developer tools), an API request to the server should be visible, indicating that the function is called from the server.

Congratulations! The app just executed a fully automated API. From here, the app can be extended with more functions.

Note that port 3000 is running the deployable version of the app. It’s also possible to start Vite in dev mode by running `npm run dev` again. Keep in mind that Jitar needs to run in the background. Otherwise, the server functions won’t be available.
13 changes: 13 additions & 0 deletions examples/4-integrations/3-svelte/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + Svelte + TS</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>
10 changes: 10 additions & 0 deletions examples/4-integrations/3-svelte/jitar.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"url": "http://127.0.0.1:3000",
"standalone":
{
"source": "./dist",
"cache": "./cache",
"index": "index.html",
"assets": ["index.html", "main.js", "App.js", "vite.svg", "assets/**/*"]
}
}
26 changes: 26 additions & 0 deletions examples/4-integrations/3-svelte/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"name": "3-svelte",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build && tsc",
"preview": "vite preview",
"check": "svelte-check --tsconfig ./tsconfig.json",
"jitar": "node --experimental-network-imports --experimental-fetch dist/jitar.js --config=jitar.json"
},
"devDependencies": {
"@sveltejs/vite-plugin-svelte": "^2.0.2",
"@tsconfig/svelte": "^3.0.0",
"jitar-vite-plugin": "^0.3.7",
"svelte": "^3.55.1",
"svelte-check": "^2.10.3",
"tslib": "^2.5.0",
"typescript": "^4.9.3",
"vite": "^4.1.0"
},
"dependencies": {
"jitar-nodejs-server": "^0.3.8"
}
}
1 change: 1 addition & 0 deletions examples/4-integrations/3-svelte/public/vite.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
43 changes: 43 additions & 0 deletions examples/4-integrations/3-svelte/src/App.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<script lang="ts">
import svelteLogo from './assets/svelte.svg'
import { sayHello } from './shared/sayHello';
async function runComponent()
{
return await sayHello('Vite + Svelte + Jitar');
}
const promise = runComponent();
</script>

<main>
<div>
<a href="https://vitejs.dev" target="_blank" rel="noreferrer">
<img src="/vite.svg" class="logo" alt="Vite Logo" />
</a>
<a href="https://svelte.dev" target="_blank" rel="noreferrer">
<img src={svelteLogo} class="logo svelte" alt="Svelte Logo" />
</a>
</div>

{#await promise then message}
<h1>{ message }</h1>
{/await}
</main>

<style>
.logo {
height: 6em;
padding: 1.5em;
will-change: filter;
transition: filter 300ms;
}
.logo:hover {
filter: drop-shadow(0 0 2em #646cffaa);
}
.logo.svelte:hover {
filter: drop-shadow(0 0 2em #ff3e00aa);
}
</style>
80 changes: 80 additions & 0 deletions examples/4-integrations/3-svelte/src/app.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
:root {
font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
line-height: 1.5;
font-weight: 400;

color-scheme: light dark;
color: rgba(255, 255, 255, 0.87);
background-color: #242424;

font-synthesis: none;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
-webkit-text-size-adjust: 100%;
}

a {
font-weight: 500;
color: #646cff;
text-decoration: inherit;
}
a:hover {
color: #535bf2;
}

body {
margin: 0;
display: flex;
place-items: center;
min-width: 320px;
min-height: 100vh;
}

h1 {
font-size: 3.2em;
line-height: 1.1;
}

.card {
padding: 2em;
}

#app {
max-width: 1280px;
margin: 0 auto;
padding: 2rem;
text-align: center;
}

button {
border-radius: 8px;
border: 1px solid transparent;
padding: 0.6em 1.2em;
font-size: 1em;
font-weight: 500;
font-family: inherit;
background-color: #1a1a1a;
cursor: pointer;
transition: border-color 0.25s;
}
button:hover {
border-color: #646cff;
}
button:focus,
button:focus-visible {
outline: 4px auto -webkit-focus-ring-color;
}

@media (prefers-color-scheme: light) {
:root {
color: #213547;
background-color: #ffffff;
}
a:hover {
color: #747bff;
}
button {
background-color: #f9f9f9;
}
}
Loading

0 comments on commit f87f106

Please sign in to comment.