From fe312ed4bd3b75588e6d3746135c13329b38c64c Mon Sep 17 00:00:00 2001 From: Lee Robinson Date: Thu, 24 Feb 2022 20:41:41 -0700 Subject: [PATCH] Update MySQL example. (#34784) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Changes from https://github.com/planetscale/nextjs-starter. Realized the current example was not only out of date, but the demo was broken. Will update the demo site post-merge here 👍 --- examples/with-mysql/.env.example | 1 + examples/with-mysql/.env.local.example | 7 -- examples/with-mysql/README.md | 110 +++++++++++------- examples/with-mysql/components/Product.js | 30 +++++ .../components/button-link/index.tsx | 27 ----- .../with-mysql/components/button/index.tsx | 33 ------ .../with-mysql/components/container/index.tsx | 5 - .../components/edit-entry-form/index.tsx | 78 ------------- .../components/entries/entry/index.tsx | 46 -------- .../with-mysql/components/entries/index.tsx | 19 --- .../components/entry-form/index.tsx | 66 ----------- .../with-mysql/components/footer/index.tsx | 13 --- examples/with-mysql/components/nav/index.tsx | 18 --- .../components/powered-by-vercel/index.tsx | 15 --- examples/with-mysql/lib/db.ts | 24 ---- examples/with-mysql/lib/prisma.js | 14 +++ examples/with-mysql/lib/swr-hooks.ts | 19 --- examples/with-mysql/next-env.d.ts | 5 - examples/with-mysql/next.config.js | 3 + examples/with-mysql/package.json | 25 ++-- examples/with-mysql/pages/_app.js | 5 + examples/with-mysql/pages/_app.tsx | 13 --- examples/with-mysql/pages/api/create-entry.ts | 30 ----- examples/with-mysql/pages/api/delete-entry.ts | 26 ----- examples/with-mysql/pages/api/edit-entry.ts | 31 ----- examples/with-mysql/pages/api/get-entries.ts | 18 --- examples/with-mysql/pages/api/get-entry.ts | 28 ----- examples/with-mysql/pages/api/products.js | 16 +++ examples/with-mysql/pages/entry/[id].tsx | 33 ------ examples/with-mysql/pages/entry/edit/[id].tsx | 14 --- examples/with-mysql/pages/index.js | 46 ++++++++ examples/with-mysql/pages/index.tsx | 38 ------ examples/with-mysql/pages/new.tsx | 14 --- examples/with-mysql/postcss.config.js | 20 +--- examples/with-mysql/prisma/data.js | 52 +++++++++ examples/with-mysql/prisma/schema.prisma | 29 +++++ examples/with-mysql/prisma/seed.js | 36 ++++++ examples/with-mysql/public/favicon.ico | Bin 0 -> 25931 bytes .../public/images/astronaut-suit.jpg | Bin 0 -> 56988 bytes examples/with-mysql/public/images/helmet.jpg | Bin 0 -> 68385 bytes .../with-mysql/public/images/placeholder.jpg | Bin 0 -> 38919 bytes examples/with-mysql/public/images/shirt.jpg | Bin 0 -> 82991 bytes examples/with-mysql/public/images/socks.jpg | Bin 0 -> 22356 bytes .../with-mysql/public/images/sweatshirt.jpg | Bin 0 -> 70930 bytes examples/with-mysql/public/vercel.svg | 4 + examples/with-mysql/scripts/migrate-db.js | 53 --------- examples/with-mysql/styles/globals.css | 3 + examples/with-mysql/styles/index.css | 18 --- examples/with-mysql/tailwind.config.js | 16 +-- examples/with-mysql/tsconfig.json | 24 ---- 50 files changed, 322 insertions(+), 803 deletions(-) create mode 100644 examples/with-mysql/.env.example delete mode 100644 examples/with-mysql/.env.local.example create mode 100644 examples/with-mysql/components/Product.js delete mode 100644 examples/with-mysql/components/button-link/index.tsx delete mode 100644 examples/with-mysql/components/button/index.tsx delete mode 100644 examples/with-mysql/components/container/index.tsx delete mode 100644 examples/with-mysql/components/edit-entry-form/index.tsx delete mode 100644 examples/with-mysql/components/entries/entry/index.tsx delete mode 100644 examples/with-mysql/components/entries/index.tsx delete mode 100644 examples/with-mysql/components/entry-form/index.tsx delete mode 100644 examples/with-mysql/components/footer/index.tsx delete mode 100644 examples/with-mysql/components/nav/index.tsx delete mode 100644 examples/with-mysql/components/powered-by-vercel/index.tsx delete mode 100644 examples/with-mysql/lib/db.ts create mode 100644 examples/with-mysql/lib/prisma.js delete mode 100644 examples/with-mysql/lib/swr-hooks.ts delete mode 100644 examples/with-mysql/next-env.d.ts create mode 100644 examples/with-mysql/next.config.js create mode 100644 examples/with-mysql/pages/_app.js delete mode 100644 examples/with-mysql/pages/_app.tsx delete mode 100644 examples/with-mysql/pages/api/create-entry.ts delete mode 100644 examples/with-mysql/pages/api/delete-entry.ts delete mode 100644 examples/with-mysql/pages/api/edit-entry.ts delete mode 100644 examples/with-mysql/pages/api/get-entries.ts delete mode 100644 examples/with-mysql/pages/api/get-entry.ts create mode 100644 examples/with-mysql/pages/api/products.js delete mode 100644 examples/with-mysql/pages/entry/[id].tsx delete mode 100644 examples/with-mysql/pages/entry/edit/[id].tsx create mode 100644 examples/with-mysql/pages/index.js delete mode 100644 examples/with-mysql/pages/index.tsx delete mode 100644 examples/with-mysql/pages/new.tsx create mode 100644 examples/with-mysql/prisma/data.js create mode 100644 examples/with-mysql/prisma/schema.prisma create mode 100644 examples/with-mysql/prisma/seed.js create mode 100644 examples/with-mysql/public/favicon.ico create mode 100644 examples/with-mysql/public/images/astronaut-suit.jpg create mode 100644 examples/with-mysql/public/images/helmet.jpg create mode 100644 examples/with-mysql/public/images/placeholder.jpg create mode 100644 examples/with-mysql/public/images/shirt.jpg create mode 100644 examples/with-mysql/public/images/socks.jpg create mode 100644 examples/with-mysql/public/images/sweatshirt.jpg create mode 100644 examples/with-mysql/public/vercel.svg delete mode 100644 examples/with-mysql/scripts/migrate-db.js create mode 100644 examples/with-mysql/styles/globals.css delete mode 100644 examples/with-mysql/styles/index.css delete mode 100644 examples/with-mysql/tsconfig.json diff --git a/examples/with-mysql/.env.example b/examples/with-mysql/.env.example new file mode 100644 index 000000000000..9205e1aeee0b --- /dev/null +++ b/examples/with-mysql/.env.example @@ -0,0 +1 @@ +DATABASE_URL=mysql://:@/?sslaccept=strict diff --git a/examples/with-mysql/.env.local.example b/examples/with-mysql/.env.local.example deleted file mode 100644 index 2062d45cde42..000000000000 --- a/examples/with-mysql/.env.local.example +++ /dev/null @@ -1,7 +0,0 @@ -# Example .env.local file for MySQL Database credentials - -MYSQL_HOST= -MYSQL_DATABASE= -MYSQL_USERNAME= -MYSQL_PASSWORD= -MYSQL_PORT= diff --git a/examples/with-mysql/README.md b/examples/with-mysql/README.md index d8d75d5e4578..b9b095d02c56 100644 --- a/examples/with-mysql/README.md +++ b/examples/with-mysql/README.md @@ -1,82 +1,102 @@ -# MySQL Example +# Next.js + MySQL -This is an example of using [MySQL](https://www.mysql.com/) in a Next.js project. +This is a [Next.js](https://nextjs.org/) project that uses [Prisma](https://www.prisma.io/) to connect to a [PlanetScale](https://planetscale.com/) MySQL database and [Tailwind CSS](https://tailwindcss.com/) for styling. ## Demo -### [https://next-mysql.vercel.app](https://next-mysql.vercel.app/) +https://next-mysql.vercel.app -## Deploy your own +## Prerequisites + +- [Node.js](https://nodejs.org/en/download/) +- [PlanetScale CLI](https://github.com/planetscale/cli) +- Authenticate the CLI with the following command: + +```sh +pscale auth login +``` + +## Set up the database + +Create a new database with the following command: -Once you have access to [the environment variables you'll need](#step-5-set-up-environment-variables), deploy the example using [Vercel](https://vercel.com?utm_source=github&utm_medium=readme&utm_campaign=next-example): +```sh +pscale database create +``` -[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/git/external?repository-url=https://github.com/vercel/next.js/tree/canary/examples/with-mysql&project-name=nextjs-mysql&repository-name=nextjs-mysql&env=MYSQL_HOST,MYSQL_DATABASE,MYSQL_USERNAME,MYSQL_PASSWORD&envDescription=Required%20to%20connect%20the%20app%20with%20MySQL&envLink=https%3A%2F%2Fgithub.com%2Fvercel%2Fnext.js%2Ftree%2Fcanary%2Fexamples%2Fwith-mysql%23step-2-set-up-environment-variables&demo-title=Next.js%20%2B%20MySQL%20Demo&demo-description=A%20simple%20app%20demonstrating%20Next.js%20and%20MySQL%20&demo-url=https%3A%2F%2Fnext-mysql.vercel.app%2F) +> A branch, `main`, was automatically created when you created your database, so you can use that for `BRANCH_NAME` in the steps below. -## How to use +## Set up the starter Next.js app Execute [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app) with [npm](https://docs.npmjs.com/cli/init) or [Yarn](https://yarnpkg.com/lang/en/docs/cli/create/) to bootstrap the example: ```bash -npx create-next-app --example with-mysql next-mysql-app +npx create-next-app --example with-mysql nextjs-mysql # or -yarn create next-app --example with-mysql next-mysql-app +yarn create next-app --example with-mysql nextjs-mysql ``` -## Configuration - -### Step 1. Set up a MySQL database +Next, you'll need to create a database username and password through the CLI to connect to your application. If you'd prefer to use the dashboard for this step, you can find those instructions in the [Connection Strings documentation](https://docs.planetscale.com/concepts/connection-strings#creating-a-password) and then come back here to finish setup. -Set up a MySQL server either locally or any cloud provider. +First, create your `.env` file by renaming the `.env.example` file to `.env`: -### Step 2. Set up environment variables +```sh +mv .env.example .env +``` -Copy the `env.local.example` file in this directory to `.env.local` (which will be ignored by Git): +Next, using the PlanetScale CLI, create a new username and password for the branch of your database: -```bash -cp .env.local.example .env.local +```sh +pscale password create ``` -Set each variable on `.env.local`: - -- `MYSQL_HOST` - Your MySQL host URL. -- `MYSQL_DATABASE` - The name of the MySQL database you want to use. -- `MYSQL_USERNAME` - The name of the MySQL user with access to database. -- `MYSQL_PASSWORD` - The passowrd of the MySQL user. +> The `PASSWORD_NAME` value represents the name of the username and password being generated. You can have multiple credentials for a branch, so this gives you a way to categorize them. To manage your passwords in the dashboard, go to your database overview page, click "Settings", and then click "Passwords". -### Step 3. Run migration script +Take note of the values returned to you, as you won't be able to see this password again. -You'll need to run a migration to create the necessary table for the example. +```text +Password production-password was successfully created. +Please save the values below as they will not be shown again -```bash -npm run migrate -# or -yarn migrate + NAME USERNAME ACCESS HOST URL ROLE PLAIN TEXT + --------------------- -------------- ----------------------------------- ------------------ ------------------------------------------------------- + production-password xxxxxxxxxxxxx xxxxxx.us-east-2.psdb.cloud Can Read & Write pscale_pw_xxxxxxx ``` -### Step 4. Run Next.js in development mode +You'll use these properties to construct your connection string, which will be the value for `DATABASE_URL` in your `.env` file. Update the `DATABASE_URL` property with your connection string in the following format: -```bash -npm install -npm run dev -# or -yarn install -yarn dev +```text +mysql://:@/?sslaccept=strict ``` -Your app should be up and running on [http://localhost:3000](http://localhost:3000)! If it doesn't work, post on [GitHub discussions](https://github.com/vercel/next.js/discussions). +Push the database schema to your PlanetScale database using Prisma. + +`npx prisma db push` + +Run the seed script to populate your database with `Product` and `Category` data. + +`npx run seed` -## Deploy on Vercel +## Run the App -You can deploy this app to the cloud with [Vercel](https://vercel.com?utm_source=github&utm_medium=readme&utm_campaign=next-example) ([Documentation](https://nextjs.org/docs/deployment)). +Run the app with following command: -#### Deploy Your Local Project +`npm run dev` -To deploy your local project to Vercel, push it to GitHub/GitLab/Bitbucket and [import to Vercel](https://vercel.com/new?utm_source=github&utm_medium=readme&utm_campaign=next-example). +Open your browser at [localhost:3000](localhost:3000) to see the running application. + +## Deploy your own + +After you've got your application running locally, it's time to deploy it. To do so, you'll need to promote your database branch (`main` by default) to be the production branch ([read the branching documentation for more information](https://docs.planetscale.com/concepts/branching)). + +```sh +pscale branch promote +``` -**Important**: When you import your project on Vercel, make sure to click on **Environment Variables** and set them to match your `.env.local` file. +Now that your branch has been promoted to production, you can either use the existing password you generated earlier for running locally or create a new password. Regardless, you'll need a password in the deployment steps below. -#### Deploy from Our Template +Deploy the example using [Vercel](https://vercel.com?utm_source=github&utm_medium=readme&utm_campaign=next-example): -Alternatively, you can deploy using our template by clicking on the Deploy button below. +[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/git/external?repository-url=https://github.com/vercel/next.js/tree/canary/examples/with-mysql&project-name=with-mysql&repository-name=with-mysql&env=DATABASE_URL) -[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/git/external?repository-url=https://github.com/vercel/next.js/tree/canary/examples/with-mysql&project-name=nextjs-mysql&repository-name=nextjs-mysql&env=MYSQL_HOST,MYSQL_DATABASE,MYSQL_USERNAME,MYSQL_PASSWORD&envDescription=Required%20to%20connect%20the%20app%20with%20MySQL&envLink=https%3A%2F%2Fgithub.com%2Fvercel%2Fnext.js%2Ftree%2Fcanary%2Fexamples%2Fwith-mysql%23step-2-set-up-environment-variables&demo-title=Next.js%20%2B%20MySQL%20Demo&demo-description=A%20simple%20app%20demonstrating%20Next.js%20and%20MySQL%20&demo-url=https%3A%2F%2Fnext-mysql.vercel.app%2F) +> Make sure to update the `DATABASE_URL` variable during this setup process. diff --git a/examples/with-mysql/components/Product.js b/examples/with-mysql/components/Product.js new file mode 100644 index 000000000000..bea16c88a91b --- /dev/null +++ b/examples/with-mysql/components/Product.js @@ -0,0 +1,30 @@ +import Image from 'next/image' + +export default function Product({ product }) { + const { name, description, price, image, category } = product + + return ( +
+ {name} +
+
{name}
+

{description}

+

${price}

+
+
+ + {category.name} + +
+
+ ) +} diff --git a/examples/with-mysql/components/button-link/index.tsx b/examples/with-mysql/components/button-link/index.tsx deleted file mode 100644 index 88e46586e476..000000000000 --- a/examples/with-mysql/components/button-link/index.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import Link from 'next/link' -import cn from 'clsx' - -function ButtonLink({ href = '/', className = '', children }) { - return ( - - - {children} - - - ) -} - -export default ButtonLink diff --git a/examples/with-mysql/components/button/index.tsx b/examples/with-mysql/components/button/index.tsx deleted file mode 100644 index ca8714a1b961..000000000000 --- a/examples/with-mysql/components/button/index.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import cn from 'clsx' - -function Button({ - onClick = console.log, - className = '', - children = null, - type = null, - disabled = false, -}) { - return ( - - ) -} - -export default Button diff --git a/examples/with-mysql/components/container/index.tsx b/examples/with-mysql/components/container/index.tsx deleted file mode 100644 index 4c5b421a04c0..000000000000 --- a/examples/with-mysql/components/container/index.tsx +++ /dev/null @@ -1,5 +0,0 @@ -function Container({ className = '', children }) { - return
{children}
-} - -export default Container diff --git a/examples/with-mysql/components/edit-entry-form/index.tsx b/examples/with-mysql/components/edit-entry-form/index.tsx deleted file mode 100644 index f84307d00fea..000000000000 --- a/examples/with-mysql/components/edit-entry-form/index.tsx +++ /dev/null @@ -1,78 +0,0 @@ -import { useState, useEffect } from 'react' -import Router, { useRouter } from 'next/router' - -import Button from '../button' - -export default function EntryForm() { - const [_title, setTitle] = useState('') - const [_content, setContent] = useState('') - const [submitting, setSubmitting] = useState(false) - const router = useRouter() - const { id, title, content } = router.query - - useEffect(() => { - if (typeof title === 'string') { - setTitle(title) - } - if (typeof content === 'string') { - setContent(content) - } - }, [title, content]) - - async function submitHandler(e) { - e.preventDefault() - setSubmitting(true) - try { - const res = await fetch('/api/edit-entry', { - method: 'PATCH', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - id, - title: _title, - content: _content, - }), - }) - const json = await res.json() - setSubmitting(false) - if (!res.ok) throw Error(json.message) - Router.push('/') - } catch (e) { - throw Error(e.message) - } - } - - return ( -
-
- - setTitle(e.target.value)} - /> -
-
- -