-
Notifications
You must be signed in to change notification settings - Fork 61
[Package] PowerSync Nuxt Module #797
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
base: main
Are you sure you want to change the base?
Changes from all commits
db1ecce
e5c95ac
3521b82
c58db3c
5771c58
07a9c27
7c52649
a67886d
d67a0fe
6e3e768
e5219b9
d2bd1c3
e3b04e5
5883058
2bda6eb
49060a0
510a96f
6363f30
35490f8
30062cc
dd7181c
754581d
fb28c97
4d5ff6c
a65a509
18b4319
9c2fe9e
4d57259
30702fa
939eb89
02a3a1a
f304989
8e3e6f0
597666a
ee63d71
68bb624
b1d2fe1
5931a86
fccf045
e195ba3
9444525
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| --- | ||
| '@powersync/nuxt': minor | ||
| --- | ||
|
|
||
| Initial release of the PowerSync Nuxt module. Provides Nuxt Devtools integration, built-in diagnostics and data inspection, and composables. Supports Nuxt 4. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| # Self-hosted Environment Configuration | ||
| # Copy this template: `cp .env.template .env` | ||
| # Edit .env and enter your Supabase and PowerSync project details. | ||
|
|
||
| NUXT_PUBLIC_SUPABASE_URL=http://127.0.0.1:54321 | ||
| NUXT_PUBLIC_SUPABASE_ANON_KEY=<replace-with-your-anon-key-or-copy-publishable-key-from-supabase-start> | ||
| # PowerSync Configuration | ||
| NUXT_PUBLIC_POWERSYNC_URL=http://localhost:6000 | ||
|
|
||
| # Self-hosted PowerSync Configuration | ||
| PS_POSTGRESQL_URI=postgresql://postgres:postgres@supabase_db_nuxt-supabase-todolist:5432/postgres | ||
| # PS_SUPABASE_JWT_SECRET=super-secret-jwt-token-with-at-least-32-characters-long # Uncomment this if you want to use legacy Supabase JWT secret for auth | ||
| PS_JWKS_URI=http://kong:8000/auth/v1/.well-known/jwks.json | ||
| PS_API_TOKEN=super-secret | ||
| PS_PORT=6000 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| imports.autoImport=true |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,136 @@ | ||
| # PowerSync + Supabase Nuxt Demo: Todo List | ||
|
|
||
| This is a demo application showcasing PowerSync integration with Nuxt 4 and Supabase. It demonstrates real-time data synchronization for a simple todo list application using PowerSync's official Nuxt module. | ||
|
|
||
| ## Setup Instructions | ||
|
|
||
| Note that this setup guide has minor deviations from the [Supabase + PowerSync integration guide](https://docs.powersync.com/integration-guides/supabase-+-powersync). Below we refer to sections in this guide where relevant. | ||
|
|
||
| ### 1. Install dependencies | ||
|
|
||
| In the repo root directory, use [pnpm](https://pnpm.io/installation) to install dependencies: | ||
|
|
||
| ```bash | ||
| pnpm install | ||
| pnpm build:packages | ||
| ``` | ||
|
|
||
| ### Quick Start: Local Development | ||
|
|
||
| This demo can be started with local PowerSync and Supabase services. | ||
|
|
||
| 1. Install the [Supabase CLI](https://supabase.com/docs/guides/cli/getting-started) | ||
|
|
||
| 2. Copy the environment template: | ||
| ```bash | ||
| cp .env.template .env | ||
| ``` | ||
|
|
||
| 3. Start Supabase: | ||
| ```bash | ||
| supabase start | ||
| ``` | ||
|
|
||
| 4. Copy the values from the `supabase start` output into `.env`. Local Supabase uses JWKS for auth, so this demo configures PowerSync with `jwks_uri` and `audience: authenticated`: | ||
| - `NUXT_PUBLIC_SUPABASE_ANON_KEY`: Use the **Publishable** key value | ||
| - `PS_JWKS_URI`: Use `http://kong:8000/auth/v1/.well-known/jwks.json` when PowerSync runs in Docker on the Supabase network (default in step 5). This points PowerSync at local Supabase's JWKS so it can verify tokens. If Kong is not reachable from the container (e.g. custom network), try `http://host.docker.internal:54321/auth/v1/.well-known/jwks.json` on Docker Desktop for Mac/Windows. | ||
|
|
||
| 5. Start PowerSync: | ||
| ```bash | ||
| docker run \ | ||
| -p 6060:6060 \ | ||
| -e POWERSYNC_CONFIG_B64=$(base64 -i ./powersync.yaml) \ | ||
| -e POWERSYNC_SYNC_RULES_B64=$(base64 -i ./sync-rules.yaml) \ | ||
| --env-file ./.env \ | ||
| --network supabase_network_nuxt-supabase-todolist \ | ||
| --name powersync-nuxt journeyapps/powersync-service:latest | ||
| ``` | ||
|
|
||
| 6. Run the demo: | ||
| ```bash | ||
| pnpm dev | ||
| ``` | ||
|
|
||
| Open [http://localhost:3000](http://localhost:3000) to use the app. | ||
|
|
||
| ### 2. Create project on Supabase and set up Postgres | ||
|
|
||
| This demo app uses Supabase as its Postgres database and backend: | ||
|
|
||
| 1. [Create a new project on the Supabase dashboard](https://supabase.com/dashboard/projects). | ||
| 2. Go to the Supabase SQL Editor for your new project and execute the SQL statements in [`db/seed.sql`](db/seed.sql) to create the database schema, PowerSync replication role, and publication needed for PowerSync. | ||
|
|
||
| **Note:** Before executing the SQL, make sure to update the `powersync_role` password in `db/seed.sql` (currently set to `'postgres_12345'`) to a secure password of your choice. | ||
|
|
||
| **Important:** When connecting PowerSync to your Supabase database, you'll use the `powersync_role` credentials instead of the default Supabase connection string. This role has the necessary replication privileges and bypasses Row Level Security (RLS). | ||
|
|
||
| ### 3. Auth setup | ||
|
|
||
| This app uses Supabase's email/password authentication. | ||
|
|
||
| 1. Go to "Authentication" -> "Providers" in your Supabase dashboard | ||
| 2. Ensure "Email" provider is enabled | ||
| 3. You can disable email confirmation for development by going to "Authentication" -> "Email Auth" and disabling "Confirm email" | ||
|
|
||
| You'll need to create a user account when you first access the application. | ||
|
|
||
| ### 4. Set up PowerSync | ||
|
|
||
| You can use either PowerSync Cloud or self-host PowerSync: | ||
|
|
||
| - **PowerSync Cloud**: [Create a new project on the PowerSync dashboard](https://dashboard.powersync.com) and connect it to your Supabase database using the `powersync_role` credentials created in step 2. | ||
| - **Self-hosting**: Follow the [self-hosting guide](https://docs.powersync.com/self-hosting/getting-started) to deploy your own PowerSync instance. | ||
|
|
||
| The sync rules for this demo are provided in [`sync-rules.yaml`](sync-rules.yaml) in this directory. | ||
|
|
||
| ### 5. Set up local environment variables | ||
|
|
||
| Create a `.env` file in this directory with the following variables: | ||
|
|
||
| ```bash | ||
| NUXT_PUBLIC_SUPABASE_URL=your_supabase_url | ||
| NUXT_PUBLIC_SUPABASE_ANON_KEY=your_supabase_anon_key | ||
| NUXT_PUBLIC_POWERSYNC_URL=your_powersync_instance_url | ||
| ``` | ||
|
|
||
| Replace the values with your actual credentials: | ||
| - Get `NUXT_PUBLIC_SUPABASE_URL` and `NUXT_PUBLIC_SUPABASE_ANON_KEY` from your Supabase project settings under "Project Settings" -> "API" | ||
| - Get `NUXT_PUBLIC_POWERSYNC_URL` from your PowerSync instance (Cloud dashboard or your self-hosted instance URL) | ||
|
|
||
| ### 6. Run the demo app | ||
|
|
||
| In this directory, run the following to start the development server: | ||
|
|
||
| ```bash | ||
| pnpm dev | ||
| ``` | ||
|
|
||
| Open [http://localhost:3000](http://localhost:3000) with your browser to try out the demo. | ||
|
|
||
| ## Project Structure | ||
|
|
||
| ``` | ||
| ├── powersync/ | ||
| │ ├── AppSchema.ts # PowerSync schema definition | ||
| │ └── SuperbaseConnector.ts # Supabase connector implementation | ||
| ├── plugins/ | ||
| │ └── powersync.client.ts # PowerSync plugin setup | ||
| ├── pages/ | ||
| │ ├── index.vue # Main todo list page | ||
| │ ├── login.vue # Login page | ||
| │ └── confirm.vue # Auth confirmation page | ||
| ├── components/ | ||
| │ └── AppHeader.vue # Header component | ||
| ├── db/ | ||
| │ └── seed.sql # Database setup SQL | ||
| ├── powersync.yaml # PowerSync server configuration | ||
| ├── sync-rules.yaml # PowerSync sync rules | ||
| └── nuxt.config.ts # Nuxt configuration | ||
| ``` | ||
|
|
||
| ## Learn More | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It would be nice if this demo had a local Supabase config and quickstart for local development - which can be used to start the demo in only a few commands - like the YJS Demo has here.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have added all necessary files and instructions for this |
||
|
|
||
| - [PowerSync Documentation](https://docs.powersync.com/) | ||
| - [Supabase Documentation](https://supabase.com/docs) | ||
| - [Nuxt Documentation](https://nuxt.com/) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| export default defineAppConfig({ | ||
| ui: { | ||
| colors: { | ||
| primary: 'indigo', | ||
| neutral: 'stone', | ||
| }, | ||
| input: { | ||
| variants: { | ||
| variant: { | ||
| subtle: 'ring-default bg-elevated/50', | ||
| }, | ||
| }, | ||
| }, | ||
| header: { | ||
| slots: { | ||
| root: 'border-none', | ||
| }, | ||
| }, | ||
| }, | ||
| }) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,58 @@ | ||
| <template> | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd suggest that we keep a consistent orders for templates/script blocks across all our components in this demo.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good point. I have made things more consistent now. |
||
| <UApp> | ||
| <NuxtLayout> | ||
| <NuxtPage /> | ||
| </NuxtLayout> | ||
| </UApp> | ||
| </template> | ||
|
|
||
| <script setup lang="ts"> | ||
| useHead({ | ||
| meta: [{ name: 'viewport', content: 'width=device-width, initial-scale=1' }], | ||
| link: [{ rel: 'icon', href: '/favicon.ico' }], | ||
| htmlAttrs: { | ||
| lang: 'en', | ||
| }, | ||
| }) | ||
|
|
||
| const title = 'PowerSync Playground' | ||
| const description | ||
| = 'Demo of a simple todo list app using PowerSync and Supabase.' | ||
|
|
||
| useSeoMeta({ | ||
| title, | ||
| ogTitle: title, | ||
| description, | ||
| ogDescription: description, | ||
| }) | ||
|
|
||
| const appIsReady = ref(false) | ||
|
|
||
| provide('appIsReady', readonly(appIsReady)) | ||
|
|
||
| const powerSync = usePowerSync() | ||
| const syncStatus = usePowerSyncStatus() | ||
|
|
||
| const user = useSupabaseUser() | ||
| const { logger: powerSyncLogger } = useDiagnosticsLogger() | ||
|
|
||
| watch(user, () => { | ||
| if (user) { | ||
| if (syncStatus.value.hasSynced) { | ||
| powerSyncLogger.log('User is logged in and has synced...', { user: user, syncStatus: syncStatus.value }) | ||
| appIsReady.value = true | ||
| } | ||
| else { | ||
| powerSyncLogger.log('User is logged waiting for first sync...', { user: user, syncStatus: syncStatus.value }) | ||
| powerSync.value.waitForFirstSync().then(() => { | ||
| appIsReady.value = true | ||
| }) | ||
| } | ||
| } | ||
| else { | ||
| powerSyncLogger.log('User is not logged in disconnecting...', { user: user, syncStatus: syncStatus.value }) | ||
| powerSync.value.disconnect() | ||
| appIsReady.value = true | ||
| } | ||
| }, { immediate: true }) | ||
| </script> | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| @import "tailwindcss"; | ||
| @import "@nuxt/ui"; | ||
|
|
||
| :root { | ||
| --ui-header-height: 40px; | ||
|
|
||
| --ui-container: 100%; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| <template> | ||
| <UHeader :toggle="false"> | ||
| <template #left> | ||
| <UButton variant="link" @click="navigateTo('/')"> | ||
| <img src="~/assets/img/powersync-icon.svg" alt="Powersync" class="size-10 inline-flex"> | ||
| </UButton> | ||
| </template> | ||
|
|
||
| <template #right> | ||
| <UColorModeButton variant="link" /> | ||
|
|
||
| <UButton v-if="user" variant="link" class="cursor-pointer" color="neutral" @click="logout"> | ||
| Logout | ||
| </UButton> | ||
| </template> | ||
| </UHeader> | ||
| </template> | ||
|
|
||
| <script setup lang="ts"> | ||
| const client = useSupabaseClient() | ||
| const user = useSupabaseUser() | ||
| const powerSync = usePowerSync() | ||
|
|
||
| const logout = async () => { | ||
| await powerSync.value.disconnectAndClear() | ||
|
|
||
| await client.auth.signOut() | ||
| navigateTo('/login') | ||
| } | ||
| </script> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| -- Past this into your Superbase SQL Editor | ||
|
|
||
| -- TODO change this if changing the DB connection name | ||
| -- connect postgres; | ||
| -- Create tables | ||
|
|
||
| CREATE TABLE IF NOT EXISTS public.tasks( | ||
| id uuid NOT NULL DEFAULT gen_random_uuid(), | ||
| created_at timestamp with time zone NOT NULL DEFAULT now(), | ||
| completed_at timestamp with time zone NULL, | ||
| description text NOT NULL, | ||
| completed boolean NOT NULL DEFAULT FALSE, | ||
| user_id uuid NOT NULL, | ||
| CONSTRAINT tasks_pkey PRIMARY KEY (id) | ||
| ); | ||
|
|
||
| -- Create a role/user with replication privileges for PowerSync | ||
| CREATE ROLE powersync_role WITH REPLICATION BYPASSRLS LOGIN PASSWORD 'postgres_12345'; | ||
| -- Set up permissions for the newly created role | ||
| -- Read-only (SELECT) access is required | ||
| GRANT SELECT ON ALL TABLES IN SCHEMA public TO powersync_role; | ||
|
|
||
| -- Optionally, grant SELECT on all future tables (to cater for schema additions) | ||
| ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO powersync_role; | ||
|
|
||
|
|
||
| -- Create publication for PowerSync tables | ||
| CREATE PUBLICATION powersync FOR ALL TABLES; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| // @ts-check | ||
| import withNuxt from './.nuxt/eslint.config.mjs' | ||
|
|
||
| export default withNuxt({ | ||
| rules: { | ||
| '@typescript-eslint/no-explicit-any': 'off', | ||
| 'nuxt/nuxt-config-keys-order': 'off', | ||
| }, | ||
| }) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| <template> | ||
| <div> | ||
| <AppHeader /> | ||
|
|
||
| <UMain> | ||
| <slot /> | ||
| </UMain> | ||
| </div> | ||
| </template> |
Uh oh!
There was an error while loading. Please reload this page.