mirror of
https://github.com/supabase/supabase.git
synced 2026-07-05 03:24:19 +08:00
328 lines
14 KiB
Plaintext
328 lines
14 KiB
Plaintext
---
|
||
id: plasmic
|
||
title: 'Plasmic'
|
||
description: 'Get started with Supabase and Plasmic, an open-source framework for building internal tools.'
|
||
---
|
||
|
||
In this guide, we will show you how to build a crowd-sourced Pokemon Pokedex, by connecting **Supabase**, an open source Firebase backend alternative, with **Plasmic**, a visual builder for the web. While many users leverage Plasmic to quickly launch and iterate on landing pages, in this tutorial we’ll show just how powerful Plasmic can be as a general-purpose visual builder for React, which can be used to design and implement fully featured read-write applications.
|
||
|
||
You can play with the live demo here:
|
||
[https://plasmic-supabase-demo.vercel.app/](https://plasmic-supabase-demo.vercel.app/)
|
||
|
||
You can also take a look at the Plasmic project here:
|
||
[https://studio.plasmic.app/projects/66RKaSPCwKxYjCfXWHCxn6](https://studio.plasmic.app/projects/66RKaSPCwKxYjCfXWHCxn6)
|
||
|
||
> You’ll need to enable 3rd-party cookies in your browser for the project to properly load.
|
||
|
||

|
||
|
||
At a high level,
|
||
|
||
- **Supabase** is used to store the database of Pokemon (backed by Postgres) and provides an authentication backend. Our code base includes React components for querying the database, displaying this data, and supporting user sessions.
|
||
- **Plasmic** is used to create the pages and visual design of the application. We import our Supabase components into the Studio, which can be visually assembled and configured there (e.g. for displaying data).
|
||
- Plasmic designed pages are rendered back into the Next.js application.
|
||
|
||
## Step 1: Set up your Backend on Supabase
|
||
|
||
- On the [Supabase dashboard](https://app.supabase.com/), click `New project` and set the name of the project.
|
||
By default, Supabase will already be set up for user signups with email, with users being stored in a `users` table.
|
||
|
||

|
||
|
||
- Navigate to the `Table Editor` on the left side navigation bar. Here we can create a `New table` to store our Pokemon entries. Make sure you are in the `schema public` view. Create a new table called `entries`, with 6 columns:
|
||
- `id`: is a unique ID for the entry. This column should be generated automatically as the primary column.
|
||
- `user_id`: Create a relation to the `user` table by clicking on the link icon next to the column name. Here, you can select the `id` column of the `user` table.
|
||
- `name`, `description`, `imageUrl`: This will store the name, description, and imageUrl for each Pokemon.
|
||
- `inserted_at` : This will be an automatically populated column, set to when the row was first inserted.
|
||
|
||
> Note: In this tutorial we’ve turned off “[Row Level Security (RLS)](https://supabase.com/docs/guides/auth/row-level-security)”. In practice, you will want to create policies that restrict who gets to create, edit, and delete posts. By turning this off, any user can modify the database without restrictions.
|
||
|
||

|
||
|
||
For your convenience, feel free to import the following CSV into Supabase to pre-populate your database. In order to import, you must select `Import data via spreadsheet`, in the new table dialog box. (It does not work on existing tables.)
|
||
|
||
[pokedex-export.csv](/img/guides/integrations/plasmic/pokedex-export.csv)
|
||
|
||
## Step 2: Set up your codebase
|
||
|
||
We have a working code example for you [here](https://github.com/plasmicapp/plasmic/tree/master/examples/supabase-demo). This starter comes with all of the code components you need to get started querying Supabase through Plasmic Studio.
|
||
|
||
> Code components are React components defined in your code base that we import into Plasmic Studio for use. Your project will be configured to look for these at `http://localhost:3000/plasmic-host` You can use these components in your design, as well as style them. Check out `supabase-demo/plasmic-init.ts` to see how they are registered with Plasmic.
|
||
|
||
First, clone the repo to your development machine and install the dependencies.
|
||
|
||
```bash
|
||
git clone git@github.com:plasmicapp/plasmic.git
|
||
cd plasmic/examples/supabase-demo/
|
||
yarn install
|
||
```
|
||
|
||
Copy `.env.example` to `.env.local`, which will store the environment variables when running a local development server. Add your Supabase project’s URL and public key, which you can find in the `API` tab on the left pane of your Supabase dashboard.
|
||
|
||
Now run the dev server, which listens at `http://localhost:3000`
|
||
|
||
```bash
|
||
yarn dev
|
||
```
|
||
|
||
## Step 3: Explore the existing application
|
||
|
||
Navigate to [http://localhost:3000](http://localhost:3000) in your web browser. The project will already be set up for user signups, logins, and an admin interface for adding and editing Pokemon to the database. Feel free to sign up with your email address for an account and add Pokemon to the database. Supabase will require that you verify your email address before you can log in.
|
||
|
||
If you pre-populated the database in Step 1. you should see the following homepage after logging in. Otherwise, feel free to add Pokemon manually via the UI.
|
||
|
||

|
||
|
||
## Step 4: Clone the Plasmic project
|
||
|
||
Now let’s try to make some additions! The code base is currently configured to a read-only copy of the Plasmic project. Let’s make an editable copy first.
|
||
|
||
Open the default starter Plasmic project here:
|
||
[https://studio.plasmic.app/projects/66RKaSPCwKxYjCfXWHCxn6](https://studio.plasmic.app/projects/66RKaSPCwKxYjCfXWHCxn6)
|
||
|
||

|
||
|
||
To make an editable copy, click on the `Copy Project` button in the blue bar. This will clone the project and redirect you to your copy.
|
||
|
||
### Step 4a: Configure your code base to use the new Plasmic project
|
||
|
||
Take note of the `project ID` and `API token`. You can find the project ID in the URL:
|
||
`https://studio.plasmic.app/projects/PROJECTID`.
|
||
|
||
The API token can be found by clicking the `Code` button in the top bar.
|
||
|
||

|
||
|
||
Now go back to `.env.local` and update the corresponding project ID and token fields.
|
||
|
||
### Step 4b: Configure your Plasmic project app host
|
||
|
||
To tell Plasmic to look for your code components on your dev server, you’ll need to update your project’s app host to `http://localhost:3000/plasmic-host`.
|
||
|
||
> Note: At this point, you’ll need to keep your dev server running at `http://localhost:3000`for the project to load.
|
||
|
||
<video width="99%" autoPlay="autoplay" muted playsInline controls={true}>
|
||
<source
|
||
src="/docs/videos/guides/integrations/plasmic/configure-app-host-plasmic-05.mp4"
|
||
type="video/mp4"
|
||
muted
|
||
playsInline
|
||
/>
|
||
</video>
|
||
|
||
After restarting the dev server and Plasmic Studio, you should now be able to make edits across Plasmic Studio and your codebase.
|
||
|
||
## Step 5: Create a new page for our Pokedex gallery
|
||
|
||
Let’s make a visual gallery for our Pokemon by using the code components from the code base.
|
||
|
||
Create a new page called `Gallery`, and set a path for this page (`/gallery`).
|
||
|
||
<video width="99%" autoPlay="autoplay" muted playsInline controls={true}>
|
||
<source
|
||
src="/docs/videos/guides/integrations/plasmic/create-gallery-page-plasmic-06.mp4"
|
||
type="video/mp4"
|
||
muted
|
||
playsInline
|
||
/>
|
||
</video>
|
||
|
||
Insert a `SupabaseGrid` by searching the AddDrawer (by clicking the blue + button)
|
||
|
||
> For source see `components/CodeComponents/DatabaseComponents.tsx`
|
||
|
||

|
||
|
||
Then in the right-hand panel, configure the props on `SupabaseGrid`.
|
||
|
||
- `tableName` should match the table you created in Supabase
|
||
- `tableColumns` are a comma-delimited list of columns you want to select from the table
|
||
- We also set the number of columns and spacing shown in the grid
|
||
|
||

|
||
|
||
The `SupabaseGrid` will loop over the rows from the query.
|
||
|
||
Now customize the repeated content by inserting instances of `SupabaseField`. Select the type of content and a selector string to fetch a single value. In the example below, we use `{{row.imageUrl}}` to retrieve the `imageUrl` column of the row. Apply any styling and layout you want on these elements.
|
||
|
||

|
||
|
||
### Putting it all together (video)
|
||
|
||
For your convenience, the following video shows you how to create the page end-to-end.
|
||
|
||
<video width="99%" autoPlay="autoplay" muted playsInline controls={true}>
|
||
<source
|
||
src="/docs/videos/guides/integrations/plasmic/end-to-end-plasmic-10.mp4"
|
||
type="video/mp4"
|
||
muted
|
||
playsInline
|
||
/>
|
||
</video>
|
||
|
||
## Step 6: Check your dev server
|
||
|
||
If you have been running your development server this whole time, you’ll see that we have been automatically fetching and rebuilding your site as you make changes in Plasmic Studio. If you need to restart your dev server, just run:
|
||
|
||
```bash
|
||
yarn dev
|
||
```
|
||
|
||
See the results at `http://localhost:3000/gallery`.
|
||
|
||
## How does this all work under the hood?
|
||
|
||
### SupabaseGrid
|
||
|
||
`SupabaseGrid` is a code component that was registered in `plasmic-init.ts`. The `props` field is used to tell the Plasmic Studio the component prop interface, which allows us to expose these props in the right pane as shown in the screenshots earlier. See the docs for details on [component registration](https://docs.plasmic.app/learn/registering-code-components/).
|
||
|
||
```tsx
|
||
// plasmic-init.ts
|
||
...
|
||
|
||
PLASMIC.registerComponent(SupabaseGrid, {
|
||
name: "SupabaseGrid",
|
||
props: {
|
||
tableName: "string",
|
||
tableColumns: "string",
|
||
queryFilters: "object",
|
||
children: {
|
||
type: "slot",
|
||
defaultValue: {
|
||
type: "text",
|
||
value: "Placeholder",
|
||
},
|
||
},
|
||
numColumns: {
|
||
type: "number",
|
||
defaultValue: 4,
|
||
},
|
||
columnGap: {
|
||
type: "number",
|
||
defaultValue: 16,
|
||
},
|
||
rowGap: {
|
||
type: "number",
|
||
defaultValue: 16,
|
||
},
|
||
count: "number",
|
||
loading: {
|
||
type: "slot",
|
||
defaultValue: {
|
||
type: "text",
|
||
value: "Loading...",
|
||
},
|
||
},
|
||
},
|
||
importPath: "./components/CodeComponents/DisplayCollections",
|
||
});
|
||
```
|
||
|
||
### SupabaseQuery
|
||
|
||
`SupabaseGrid` wraps a `SupabaseQuery` component, where we perform the query based on the provided props and store the result in a `SupabaseQueryContext`. This will be used in downstream components to display the data.
|
||
|
||
```tsx
|
||
// supabase-demo/components/CodeComponents/DatabaseComponents.tsx
|
||
export function SupabaseQuery(props: SupabaseQueryProps) {
|
||
// These props are set in the Plasmic Studio
|
||
const { children, tableName, columns, className, filters, single } = props;
|
||
const [result, setResult] = React.useState<any[] | undefined>(undefined);
|
||
|
||
...
|
||
|
||
// Performs the Supabase query
|
||
let query = supabase.from(tableName!).select(columns + ",id");
|
||
query = applyFilter(query, validFilters, contexts);
|
||
const { data, error, status } = await (single ? query.single() : query.order('id', { ascending: false }));
|
||
|
||
if (error && status !== 406) {
|
||
throw error;
|
||
} else if (data) {
|
||
setResult(data);
|
||
}
|
||
|
||
...
|
||
|
||
// Save the result in a `SupabaseQueryContext for use with downstream components
|
||
return (
|
||
<div className={className}>
|
||
<SupabaseQueryContext.Provider value={result}>
|
||
{children}
|
||
</SupabaseQueryContext.Provider>
|
||
</div>
|
||
);
|
||
}
|
||
```
|
||
|
||
Note that this code component is defined in your codebase. Feel free to augment it to expose more powerful querying capabilities to the Plasmic Studio.
|
||
|
||
### SupabaseGridCollection
|
||
|
||
`SupabaseGrid` also nests a `SupabaseGridCollection` under the `SupabaseQuery`. This code component is a simple CSS grid, where we retrieve the Supabase query results from `SupabaseQueryContext`, and iterate over the results. For each row, we populate a `RowContext`, which will be used by the children to read the results of a single row. Note the use of `repeatedElement`, a special convenience function that enables the component’s children to be repeated. In this case, this represents a single card to be shown in the gallery.
|
||
|
||
```tsx
|
||
// supabase-demo/components/CodeComponents/DisplayCollections.tsx
|
||
|
||
export function SupabaseGridCollection(props: SupabaseGridCollectionProps) {
|
||
const supabaseQuery = React.useContext(SupabaseQueryContext)
|
||
const {
|
||
children,
|
||
columns,
|
||
columnGap,
|
||
rowGap,
|
||
count,
|
||
className,
|
||
loading,
|
||
testLoading,
|
||
} = props
|
||
|
||
const result = supabaseQuery
|
||
if (!result || testLoading) {
|
||
return loading
|
||
}
|
||
|
||
return (
|
||
<div
|
||
style={{
|
||
display: 'grid',
|
||
gridTemplateColumns: `repeat(${columns}, 1fr)`,
|
||
columnGap: `${columnGap}px`,
|
||
rowGap: `${rowGap}px`,
|
||
}}
|
||
className={className}
|
||
>
|
||
{result.slice(0, count).map((row: any, i: any) => (
|
||
<RowContext.Provider value={row} key={row.id}>
|
||
<div key={row.id}>{repeatedElement(i === 0, children)}</div>
|
||
</RowContext.Provider>
|
||
))}
|
||
</div>
|
||
)
|
||
}
|
||
```
|
||
|
||
### SupabaseField
|
||
|
||
`SupabaseField` will either render a `SupabaseTextField` or `SupabaseImgField` depending on the type. These code components simply read a single value from the contexts and display the data.
|
||
|
||
```tsx
|
||
// supabase-demo/components/CodeComponents/DisplayCollections.tsx
|
||
|
||
export function SupabaseTextField({
|
||
name,
|
||
className,
|
||
}: {
|
||
name?: string
|
||
className?: string
|
||
}) {
|
||
const contexts = useAllContexts()
|
||
if (!name) {
|
||
return <p>You need to set the name prop</p>
|
||
}
|
||
return <div className={className}>{getPropValue(name, contexts)}</div>
|
||
}
|
||
```
|
||
|
||
In summary, by populating state into React contexts, we can store and retrieve data for use in other code components, which can be used for arbitrarily powerful interactions in Plasmic Studio.
|