Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: move DB stuff over from sites repo #628

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Development

## Running

```
pnpm install
cd apps/svelte.dev
USE_GIT=true pnpm sync-docs
pnpm run dev
```

## Database setup

Login to [Supabase](https://supabase.com) and create a database. Once done, you should be on your database's dashboard. Duplicate the `.env.example` file and rename it to `.env.local`, and set these environment variables:

- `SUPABASE_URL`: The config URL
- `SUPABASE_KEY`: The public API key

Then, navigate to your database's "SQL Editor", click on "New query", and paste in [setup.sql](./apps/svelte.dev/setup.sql). Run this SQL to seed the database and you're good to go.

## Tutorial

The tutorial consists of two technically different parts: The Svelte tutorial and the SvelteKit tutorial. The SvelteKit tutorial uses [WebContainers](https://webcontainers.io/) under the hood in order to boot up a Node runtime in the browser. The Svelte tutorial uses Rollup in a web worker - it does not use WebContainers because a simple web worker is both faster and more reliable (there are known issues with iOS mobile).

WebContainers require [cross-origin isolation](https://webcontainers.io/guides/quickstart#cross-origin-isolation), which means the document needs to have these headers:

```
Cross-Origin-Embedder-Policy: require-corp
Cross-Origin-Opener-Policy: same-origin
```

The result of setting these headers is that the site can no longer embed URLs from other sites (like images from another domain) without those domains either having a `cross-origin-resource-policy: cross-origin` header (which most don't) or us adding the `crossorigin="anonymous"` attribute (or the experimental-only-working-in-chrome `credentialless` for iframes) to the elements that load those URLs. For this reason, navigations between the SvelteKit tutorial and other pages (and vice versa) are full page navigations so the headers don't interfere with the rest of the page.

When writing content for the tutorial, you need to be aware of the differences of loading content:

- When using root-relative paths, for a SvelteKit exercise the 'root' is the `static` directory inside the exercise itself, but for a Svelte exercise it is the root of the app so assets should do inside `apps/svelte.dev/static/tutorial`.
- When importing relative assets in a Svelte exercise, Rollup inlines them into the bundle as base64

## Dependencies

If you look in the site's package.json you'll notice several dependencies that don't appear to be used, such as `@testing-library/svelte`. These are present because they're referenced in the docs, and Twoslash needs to be able to find type definitions in order to typecheck snippets. Installing the dependencies was deemed preferable to faking it with `declare module`, since we're liable to end up with fictional types that way.

## Prerendering

Most of the site is prerendered. Since that involves some fairly expensive work, it can take a while. To build the site _without_ prerendering — for example, because you need to debug an issue that's affecting production builds — set the `PRERENDER` environment variable to `false`:

```bash
PRERENDER=false pnpm build
```
7 changes: 1 addition & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,4 @@ The tutorial, blog and examples are maintained within this repository.

## Setup

```
pnpm install
cd apps/svelte.dev
USE_GIT=true pnpm sync-docs
pnpm run dev
```
See [CONTRIBUTING.md](CONTRIBUTING.md)
30 changes: 1 addition & 29 deletions apps/svelte.dev/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,32 +14,4 @@ The tutorial, blog and examples are maintained within this repository.

## Development

### Tutorial

The tutorial consists of two technically different parts: The Svelte tutorial and the SvelteKit tutorial. The SvelteKit tutorial uses [WebContainers](https://webcontainers.io/) under the hood in order to boot up a Node runtime in the browser. The Svelte tutorial uses Rollup in a web worker - it does not use WebContainers because a simple web worker is both faster and more reliable (there are known issues with iOS mobile).

WebContainers require [cross-origin isolation](https://webcontainers.io/guides/quickstart#cross-origin-isolation), which means the document needs to have these headers:

```
Cross-Origin-Embedder-Policy: require-corp
Cross-Origin-Opener-Policy: same-origin
```

The result of setting these headers is that the site can no longer embed URLs from other sites (like images from another domain) without those domains either having a `cross-origin-resource-policy: cross-origin` header (which most don't) or us adding the `crossorigin="anonymous"` attribute (or the experimental-only-working-in-chrome `credentialless` for iframes) to the elements that load those URLs. For this reason, navigations between the SvelteKit tutorial and other pages (and vice versa) are full page navigations so the headers don't interfere with the rest of the page.

When writing content for the tutorial, you need to be aware of the differences of loading content:

- When using root-relative paths, for a SvelteKit exercise the 'root' is the `static` directory inside the exercise itself, but for a Svelte exercise it is the root of the app so assets should do inside `apps/svelte.dev/static/tutorial`.
- When importing relative assets in a Svelte exercise, Rollup inlines them into the bundle as base64

### Dependencies

If you look in the site's package.json you'll notice several dependencies that don't appear to be used, such as `@testing-library/svelte`. These are present because they're referenced in the docs, and Twoslash needs to be able to find type definitions in order to typecheck snippets. Installing the dependencies was deemed preferable to faking it with `declare module`, since we're liable to end up with fictional types that way.

### Prerendering

Most of the site is prerendered. Since that involves some fairly expensive work, it can take a while. To build the site _without_ prerendering — for example, because you need to debug an issue that's affecting production builds — set the `PRERENDER` environment variable to `false`:

```bash
PRERENDER=false pnpm build
```
See [../../CONTRIBUTING.md](CONTRIBUTING.md)
183 changes: 183 additions & 0 deletions apps/svelte.dev/db/setup.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
-- drop everything
alter table if exists public.gist drop constraint if exists gist_userid_fkey;
alter table if exists public.session drop constraint if exists session_userid_fkey;
drop index if exists gist_owner_idx;

drop table if exists public.user;
drop table if exists public.session;
drop table if exists public.gist;
drop table if exists public.todo;

drop function if exists public.get_user;
drop function if exists public.gist_create;
drop function if exists public.gist_update;
drop function if exists public.gist_destroy;
drop function if exists public.login;
drop function if exists public.logout;

create table public.user (
id bigserial primary key,
created_at timestamptz default now(),
updated_at timestamptz,
github_id int8 unique,
github_name text,
github_login text,
github_avatar_url text
);

create table public.session (
id uuid default extensions.uuid_generate_v4() not null primary key,
created_at timestamptz default now(),
userid int8,
expires timestamptz default now() + '1 year'
);

create table public.gist (
id uuid default extensions.uuid_generate_v4() not null primary key,
created_at timestamptz default now(),
name text,
files json,
userid int8,
updated_at timestamptz,
deleted_at timestamptz
);

create table public.todo (
uid uuid default extensions.uuid_generate_v4() not null primary key,
created_at timestamptz default now(),
guestid uuid not null,
text text,
done boolean
);

-- foreign key relations
alter table public.gist add constraint gist_userid_fkey foreign key (userid) references public.user (id);
alter table public.session add constraint session_userid_fkey foreign key (userid) references public.user (id);

-- indexes
create index gist_owner_idx on public.gist using btree (userid);
create index todo_owner_idx on public.todo using btree (guestid);

-- functions
create or replace function public.get_user (sessionid uuid)
returns record
language plpgsql volatile
as $$
declare
ret record;
_ record;
begin
select userid from session where session.id = sessionid into _;

select id, github_name, github_login, github_avatar_url from public.user into ret where public.user.id = _.userid;

return ret;
end;
$$;

create or replace function public.gist_list (
list_search text,
list_userid int8,
list_count int4,
list_start int4
)
returns table (
id uuid,
name text,
created_at timestamptz,
updated_at timestamptz
)
language plpgsql volatile
as $$
begin
return query
select gist.id, gist.name, gist.created_at, gist.updated_at
from gist
where gist.userid = list_userid and gist.deleted_at is null and gist.name ilike ('%' || list_search || '%')
order by coalesce(gist.updated_at, gist.created_at) desc
limit list_count + 1
offset list_start;
end;
$$;

create or replace function public.gist_create (name text, files json, userid int8)
returns record
language plpgsql volatile
as $$
declare
ret record;
begin
insert into gist (name, files, userid)
values (name, files, userid) returning gist.id, gist.name, gist.files, gist.userid into ret;

return ret;
end;
$$;

create or replace function public.gist_destroy (
gist_ids uuid[],
gist_userid int8
)
returns void
language plpgsql volatile
as $$
begin
update gist set deleted_at = now() where id = any(gist_ids) and userid = gist_userid;
end;
$$;

create or replace function public.gist_update (
gist_id uuid,
gist_name text,
gist_files json,
gist_userid int8
)
returns record
language plpgsql volatile
as $$
declare
ret record;
begin
update gist
set name = gist_name, files = gist_files, updated_at = now()
where id = gist_id and userid = gist_userid and deleted_at is null
returning id, name, files, userid into ret;

return ret;
end;
$$;

create or replace function public.login (
user_github_id int8,
user_github_name text,
user_github_login text,
user_github_avatar_url text
)
returns record
language plpgsql volatile
as $$
declare
_ record;
ret record;
begin
insert into "user" (github_id, github_name, github_login, github_avatar_url, updated_at)
values (user_github_id, user_github_name, user_github_login, user_github_avatar_url, now())
on conflict (github_id) do update set github_name = user_github_name, github_login = user_github_login, github_avatar_url = user_github_avatar_url, updated_at = now() where public."user".github_id = user_github_id
returning id into _;

insert into "session" (userid) values (_.id) returning session.id as sessionid, session.userid, session.expires into ret;

return ret;
end;
$$;

create or replace function public.logout (
sessionid uuid
)
returns void
language plpgsql volatile
as $$
begin
delete from session where id = sessionid;
end;
$$;