sample-apps: add svelte 3 graphql app (#2256)

This commit is contained in:
Praveen Durairaj 2019-05-23 17:00:17 +05:30 committed by Shahidh K Muhammed
parent 8a9901d417
commit cfd61a86a7
16 changed files with 3704 additions and 0 deletions

View File

@ -0,0 +1,3 @@
.DS_Store
node_modules
public/bundle.*

View File

@ -0,0 +1,100 @@
# svelte-graphql-app
A sample [Svelte 3](https://svelte.dev) app to demonstrate usage of GraphQL Queries, Mutations and Subscriptions with [svelte-apollo](https://github.com/timhall/svelte-apollo), Hasura GraphQL engine and Postgres as database. Forked from the standard svelte [template](https://github.com/sveltejs/template)
## Deploy Hasura
- Deploy Postgres and GraphQL Engine on Heroku:
[![Deploy to
heroku](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy?template=https://github.com/hasura/graphql-engine-heroku)
Please checkout our [docs](https://docs.hasura.io/1.0/graphql/manual/deployment/index.html) for other deployment methods
- Get the Heroku app URL (say `my-app.herokuapp.com`)
- Create `author` table:
Open Hasura console: visit https://my-app.herokuapp.com on a browser
Navigate to `Data` section in the top nav bar and create a table as follows:
![Create author table](../gatsby-postgres-graphql/assets/add_table.jpg)
- Insert sample data into `author` table:
![Insert data into author table](../gatsby-postgres-graphql/assets/insert_data.jpg)
Verify if the row is inserted successfully
![Insert data into author table](../gatsby-postgres-graphql/assets/browse_rows.jpg)
- Similarly, create an article table with the following data model:
table: `article`
columns: `id`, `title`, `content`, `author_id` (foreign key to `author` table's `id`) and `created_at`
![Create foreign key for author_id column to author's id](./assets/author_fk.png)
- Now create a relationship from article table to author table by going to the Relationships tab.
- Clone this repo:
```bash
git clone https://github.com/hasura/graphql-engine
cd graphql-engine/community/sample-apps/svelte-apollo
```
## Setup App
Install the dependencies...
```bash
npm install
```
- Open `src/apollo.js` and configure Hasura's GraphQL Endpoint as follows:
```javascript
const wsLink = new WebSocketLink({
uri: "ws://localhost:8080/v1/graphql",
options: {
reconnect: true,
lazy: true
},
connectionParams: () => {
return { headers: getHeaders() };
},
});
const httpLink = new HttpLink({
uri: "http://localhost:8080/v1/graphql",
headers: getHeaders()
});
```
Replace the `uri` argument with your Hasura GraphQL Endpoint for both `wsLink` and `httpLink`
Start [Rollup](https://rollupjs.org):
```bash
npm run dev
```
Navigate to [localhost:5000](http://localhost:5000). You should see your app running. Edit a component file in `src`, save it, and reload the page to see your changes.
## Deploying to the web
### With [now](https://zeit.co/now)
Install `now` if you haven't already:
```bash
npm install -g now
```
Then, from within your project folder:
```bash
now
```
This will deploy the app on Now 2.0 Platform and you have the Svetle app running live :)

View File

@ -0,0 +1,6 @@
{
"version": 2,
"builds": [
{ "src": "package.json", "use": "@now/static-build", "config": { "distDir": "public" } }
]
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,35 @@
{
"name": "svelte-graphql-hasura",
"version": "1.0.0",
"author": "Praveen <praveen@hasura.io>",
"devDependencies": {
"npm-run-all": "^4.1.5",
"rollup": "^1.10.1",
"rollup-plugin-commonjs": "^9.3.4",
"rollup-plugin-livereload": "^1.0.0",
"rollup-plugin-node-resolve": "^4.2.3",
"rollup-plugin-replace": "^2.2.0",
"rollup-plugin-svelte": "^5.0.3",
"rollup-plugin-terser": "^4.0.4",
"sirv-cli": "^0.4.0",
"svelte": "^3.0.0"
},
"scripts": {
"build": "rollup -c",
"now-build": "rollup -c",
"autobuild": "rollup -c -w",
"dev": "run-p start:dev autobuild",
"start": "sirv public",
"start:dev": "sirv public --dev"
},
"dependencies": {
"apollo-cache-inmemory": "^1.6.0",
"apollo-client": "^2.6.0",
"apollo-link-http": "^1.5.14",
"apollo-link-ws": "^1.0.17",
"graphql": "^14.3.0",
"graphql-tag": "^2.10.1",
"subscriptions-transport-ws": "^0.9.16",
"svelte-apollo": "^0.3.0"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

@ -0,0 +1,61 @@
html, body {
position: relative;
width: 100%;
height: 100%;
}
body {
color: #333;
margin: 0;
padding: 8px;
box-sizing: border-box;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
}
a {
color: rgb(0,100,200);
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
a:visited {
color: rgb(0,80,160);
}
label {
display: block;
}
input, button, select, textarea {
font-family: inherit;
font-size: inherit;
padding: 0.4em;
margin: 0 0 0.5em 0;
box-sizing: border-box;
border: 1px solid #ccc;
border-radius: 2px;
}
input:disabled {
color: #ccc;
}
input[type="range"] {
height: 0;
}
button {
background-color: #f4f4f4;
outline: none;
}
button:active {
background-color: #ddd;
}
button:focus {
border-color: #666;
}

View File

@ -0,0 +1,17 @@
<!doctype html>
<html>
<head>
<meta charset='utf8'>
<meta name='viewport' content='width=device-width'>
<title>Svelte app</title>
<link rel='icon' type='image/png' href='favicon.png'>
<link rel='stylesheet' href='global.css'>
<link rel='stylesheet' href='bundle.css'>
</head>
<body>
<script src='bundle.js'></script>
</body>
</html>

View File

@ -0,0 +1,48 @@
import svelte from 'rollup-plugin-svelte';
import resolve from 'rollup-plugin-node-resolve';
import commonjs from 'rollup-plugin-commonjs';
import replace from 'rollup-plugin-replace';
import livereload from 'rollup-plugin-livereload';
import { terser } from 'rollup-plugin-terser';
const production = !process.env.ROLLUP_WATCH;
export default {
input: 'src/main.js',
output: {
sourcemap: true,
format: 'iife',
name: 'app',
file: 'public/bundle.js'
},
plugins: [
svelte({
// enable run-time checks when not in production
dev: !production,
// we'll extract any component CSS out into
// a separate file — better for performance
css: css => {
css.write('public/bundle.css');
}
}),
// If you have external dependencies installed from
// npm, you'll most likely need these plugins. In
// some cases you'll need additional configuration —
// consult the documentation for details:
// https://github.com/rollup/rollup-plugin-commonjs
resolve({browser: true}),
commonjs(),
replace({
'process.env.NODE_ENV': JSON.stringify('development'),
}),
// Watch the `public` directory and refresh the
// browser on changes when not in production
!production && livereload('public'),
// If we're building for production (npm run build
// instead of npm run dev), minify
production && terser()
]
};

View File

@ -0,0 +1,46 @@
<script>
import { restore, mutate } from 'svelte-apollo';
import { client } from './apollo';
import gql from 'graphql-tag';
const AUTHOR_LIST = gql`
query {
author(order_by: [{name: asc}]) {
name
}
}
`;
const ADD_AUTHOR = gql`
mutation($name: String!) {
insert_author(objects: [{name: $name}]) {
affected_rows
}
}
`;
let name = '';
export let authorCache;
async function addAuthor(e) {
e.preventDefault();
try {
await mutate(client, {
mutation: ADD_AUTHOR,
variables: { name }
});
alert("Added successfully");
const finalData = authorCache.data.author;
finalData.push({name, '__typename': 'author'});
restore(client, AUTHOR_LIST, {author: finalData});
// clear input
name = '';
} catch(error) {
console.error(error);
}
}
</script>
<form on:submit={addAuthor}>
<label for="author">Author</label>
<input type="text" id="author-name" bind:value={name} />
<button type="submit">Add Author</button>
</form>

View File

@ -0,0 +1,48 @@
<script>
import ApolloClient from 'apollo-client';
import { client } from './apollo';
import { setClient } from 'svelte-apollo';
import Articles, { preload as articlePreload } from './Articles.svelte';
import Authors, { preload as authorPreload } from './Authors.svelte';
import AddAuthor from './AddAuthor.svelte';
import AuthorsSubscription from './AuthorsSubscription.svelte';
// Approximate sapper preload
const articlePreloading = articlePreload();
const authorPreloading = authorPreload();
setClient(client);
</script>
<style>
h1 {
color: purple;
}
</style>
<section>
<h2>Articles (simple query)</h2>
{#await articlePreloading}
<p>Preloading articles....</p>
{:then preloaded}
<Articles {...preloaded} />
{:catch error}
<p>Error preloading articles: {error}</p>
{/await}
<h2>Authors (simple query with cache updates)</h2>
{#await authorPreloading}
<p>Preloading authors....</p>
{:then preloaded}
<Authors {...preloaded} />
<h2>Add Author (mutation)</h2>
<AddAuthor {...preloaded} />
{:catch error}
<p>Error preloading authors: {error}</p>
{/await}
<h2>Authors (subscription)</h2>
<AuthorsSubscription />
</section>

View File

@ -0,0 +1,44 @@
<script context="module">
import gql from 'graphql-tag';
import { client } from './apollo';
const ARTICLES = gql`
{
article {
id
title
author {
id
}
}
}
`;
export async function preload() {
return {
cache: await client.query({ query: ARTICLES })
};
}
</script>
<script>
import { restore, query } from 'svelte-apollo';
export let cache;
restore(client, ARTICLES, cache.data);
const articles = query(client, { query: ARTICLES });
</script>
<ul>
{#await $articles}
<li>Loading...</li>
{:then result}
{#each result.data.article as article (article.id)}
<li>{article.title}</li>
{:else}
<li>No articles found</li>
{/each}
{:catch error}
<li>Error loading articles: {error}</li>
{/await}
</ul>

View File

@ -0,0 +1,43 @@
<script context="module">
import gql from 'graphql-tag';
import { client } from './apollo';
const AUTHOR_LIST = gql`
query {
author(order_by: [{name: asc}]) {
name
}
}
`;
export async function preload() {
return {
authorCache: await client.query({ query: AUTHOR_LIST })
};
}
</script>
<script>
import { restore, query } from 'svelte-apollo';
export let authorCache;
restore(client, AUTHOR_LIST, authorCache.data);
const authors = query(client, { query: AUTHOR_LIST});
</script>
<ul>
{#await $authors}
<li>Loading...</li>
{:then result}
{#each result.data.author as author (author.id)}
<li>{author.name}</li>
{:else}
<li>No authors found</li>
{/each}
{:catch error}
<li>Error loading authors: {error}</li>
{/await}
</ul>

View File

@ -0,0 +1,30 @@
<script context="module">
import gql from 'graphql-tag';
import { client } from './apollo';
import { subscribe } from 'svelte-apollo';
const AUTHOR_LIST = gql`
subscription {
author(order_by: [{name: asc}]) {
name
}
}
`;
const authorsList = subscribe(client, { query: AUTHOR_LIST });
</script>
<ul>
{#await $authorsList}
<li>Loading...</li>
{:then result}
{#each result.data.author as author (author.id)}
<li>{author.name}</li>
{:else}
<li>No authors found</li>
{/each}
{:catch error}
<li>Error loading authors: {error}</li>
{/await}
</ul>

View File

@ -0,0 +1,44 @@
import ApolloClient from "apollo-client";
import { InMemoryCache } from "apollo-cache-inmemory";
import { WebSocketLink } from "apollo-link-ws";
import { split } from "apollo-link";
import { HttpLink } from "apollo-link-http";
import { getMainDefinition } from "apollo-utilities";
const headers = {'content-type': 'application/json'};
const getHeaders = () => {
return headers;
};
const cache = new InMemoryCache();
const wsLink = new WebSocketLink({
uri: "ws://localhost:8080/v1/graphql",
options: {
reconnect: true,
lazy: true
},
connectionParams: () => {
return { headers: getHeaders() };
},
});
const httpLink = new HttpLink({
uri: "http://localhost:8080/v1/graphql",
headers: getHeaders()
});
const link = split(
({ query }) => {
const { kind, operation } = getMainDefinition(query);
return kind === "OperationDefinition" && operation === "subscription";
},
wsLink,
httpLink
);
export const client = new ApolloClient({
link,
cache
});

View File

@ -0,0 +1,7 @@
import App from './App.svelte';
const app = new App({
target: document.body,
});
export default app;