├── .eslintrc.json ├── .gitignore ├── README.md ├── next.config.js ├── package-lock.json ├── package.json ├── postcss.config.js ├── public ├── coffee.jpg ├── next.svg └── vercel.svg ├── src ├── app │ ├── coffee.jpg │ ├── dynamic │ │ └── page.tsx │ ├── favicon.ico │ ├── globals.css │ ├── layout.tsx │ ├── page.tsx │ └── static │ │ └── page.tsx └── lib │ └── getLocalBase64.ts ├── tailwind.config.js └── tsconfig.json /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # next.js 12 | /.next/ 13 | /out/ 14 | 15 | # production 16 | /build 17 | 18 | # misc 19 | .DS_Store 20 | *.pem 21 | 22 | # debug 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | 27 | # local env files 28 | .env*.local 29 | 30 | # vercel 31 | .vercel 32 | 33 | # typescript 34 | *.tsbuildinfo 35 | next-env.d.ts 36 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # "Next.js blurDataUrl Images with Plaiceholder" 2 | 3 | --- 4 | 5 | ### Author Links 6 | 7 | 👋 Hello, I'm Dave Gray. 8 | 9 | 👉 [My Courses](https://courses.davegray.codes/) 10 | 11 | ✅ [Check out my YouTube Channel with hundreds of tutorials](https://www.youtube.com/DaveGrayTeachesCode). 12 | 13 | 🚩 [Subscribe to my channel](https://bit.ly/3nGHmNn) 14 | 15 | ☕ [Buy Me A Coffee](https://buymeacoffee.com/DaveGray) 16 | 17 | 🚀 Follow Me: 18 | 19 | - [Twitter](https://twitter.com/yesdavidgray) 20 | - [LinkedIn](https://www.linkedin.com/in/davidagray/) 21 | - [Blog](https://yesdavidgray.com) 22 | - [Reddit](https://www.reddit.com/user/DaveOnEleven) 23 | 24 | --- 25 | 26 | ### Description 27 | 28 | 📺 [YouTube Video](https://youtu.be/Bz3No1RFXWY) for this repository. 29 | 30 | 31 | ### 📚 Recommended Prerequisites 32 | - 🔗 [Next.js 13 for Beginners](https://youtu.be/843nec-IvW0) 33 | 34 | ### 📚 References 35 | - 🔗 [Next.js Official Site](https://nextjs.org/) 36 | - 🔗 [Plaiceholder Docs](https://plaiceholder.co/docs) 37 | 38 | --- 39 | 40 | ### ⚙ Free Web Dev Tools 41 | - 🔗 [Google Chrome Web Browser](https://google.com/chrome/) 42 | - 🔗 [Visual Studio Code (aka VS Code)](https://code.visualstudio.com/) 43 | - 🔗 [ES7 React Snippets](https://marketplace.visualstudio.com/items?itemName=dsznajder.es7-react-js-snippets) 44 | 45 | --- 46 | 47 | ### 🎓 Academic Honesty 48 | 49 | **DO NOT COPY FOR AN ASSIGNMENT** - Avoid plagiarism and adhere to the spirit of this [Academic Honesty Policy](https://www.freecodecamp.org/news/academic-honesty-policy/). 50 | -------------------------------------------------------------------------------- /next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = {} 3 | 4 | module.exports = nextConfig 5 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "blurdataurl-example", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start", 9 | "lint": "next lint" 10 | }, 11 | "dependencies": { 12 | "@types/node": "20.4.6", 13 | "@types/react": "18.2.18", 14 | "@types/react-dom": "18.2.7", 15 | "autoprefixer": "10.4.14", 16 | "eslint": "8.46.0", 17 | "eslint-config-next": "13.4.12", 18 | "next": "13.4.12", 19 | "plaiceholder": "^3.0.0", 20 | "postcss": "8.4.27", 21 | "react": "18.2.0", 22 | "react-dom": "18.2.0", 23 | "tailwindcss": "3.3.3", 24 | "typescript": "5.1.6" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /public/coffee.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gitdagray/blurdataurl-nextjs/bc512a7f51d34c90e6ba74fa306285c83521bccb/public/coffee.jpg -------------------------------------------------------------------------------- /public/next.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/vercel.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/coffee.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gitdagray/blurdataurl-nextjs/bc512a7f51d34c90e6ba74fa306285c83521bccb/src/app/coffee.jpg -------------------------------------------------------------------------------- /src/app/dynamic/page.tsx: -------------------------------------------------------------------------------- 1 | import Image from 'next/image' 2 | import getBase64 from '@/lib/getLocalBase64' 3 | 4 | export default async function DynamicPage() { 5 | 6 | const myBlurDataUrl = await getBase64('http://localhost:3000/coffee.jpg') 7 | 8 | return ( 9 |
10 | 11 |
12 | Coffee 22 |
23 | 24 |
25 | ) 26 | } 27 | -------------------------------------------------------------------------------- /src/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gitdagray/blurdataurl-nextjs/bc512a7f51d34c90e6ba74fa306285c83521bccb/src/app/favicon.ico -------------------------------------------------------------------------------- /src/app/globals.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | -------------------------------------------------------------------------------- /src/app/layout.tsx: -------------------------------------------------------------------------------- 1 | import './globals.css' 2 | import type { Metadata } from 'next' 3 | import { Inter } from 'next/font/google' 4 | 5 | const inter = Inter({ subsets: ['latin'] }) 6 | 7 | export const metadata: Metadata = { 8 | title: 'Create Next App', 9 | description: 'Generated by create next app', 10 | } 11 | 12 | export default function RootLayout({ 13 | children, 14 | }: { 15 | children: React.ReactNode 16 | }) { 17 | return ( 18 | 19 | {children} 20 | 21 | ) 22 | } 23 | -------------------------------------------------------------------------------- /src/app/page.tsx: -------------------------------------------------------------------------------- 1 | import Link from "next/link" 2 | 3 | export default function Home() { 4 | 5 | return ( 6 |
7 | 8 |

blurDataURL Examples

9 | 10 | Static 11 | 12 | Dynamic 13 | 14 |
15 | ) 16 | } 17 | -------------------------------------------------------------------------------- /src/app/static/page.tsx: -------------------------------------------------------------------------------- 1 | import Image from 'next/image' 2 | import coffeePic from '../coffee.jpg' 3 | 4 | export default async function StaticPage() { 5 | 6 | return ( 7 |
8 | 9 |
10 | Coffee 19 |
20 | 21 |
22 | ) 23 | } 24 | -------------------------------------------------------------------------------- /src/lib/getLocalBase64.ts: -------------------------------------------------------------------------------- 1 | import { getPlaiceholder } from "plaiceholder" 2 | 3 | export default async function getBase64(imageUrl: string) { 4 | try { 5 | const res = await fetch(imageUrl) 6 | 7 | if (!res.ok) { 8 | throw new Error(`Failed to fetch image: ${res.status} ${res.statusText}`) 9 | } 10 | 11 | const buffer = await res.arrayBuffer() 12 | 13 | const { base64 } = await getPlaiceholder(Buffer.from(buffer)) 14 | 15 | //console.log(`base64: ${base64}`) 16 | 17 | return base64 18 | 19 | } catch (e) { 20 | if (e instanceof Error) console.log(e.stack) 21 | } 22 | } -------------------------------------------------------------------------------- /tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | module.exports = { 3 | content: [ 4 | './src/pages/**/*.{js,ts,jsx,tsx,mdx}', 5 | './src/components/**/*.{js,ts,jsx,tsx,mdx}', 6 | './src/app/**/*.{js,ts,jsx,tsx,mdx}', 7 | ], 8 | theme: { 9 | extend: { 10 | backgroundImage: { 11 | 'gradient-radial': 'radial-gradient(var(--tw-gradient-stops))', 12 | 'gradient-conic': 13 | 'conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))', 14 | }, 15 | }, 16 | }, 17 | plugins: [], 18 | } 19 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "strict": true, 8 | "forceConsistentCasingInFileNames": true, 9 | "noEmit": true, 10 | "esModuleInterop": true, 11 | "module": "esnext", 12 | "moduleResolution": "bundler", 13 | "resolveJsonModule": true, 14 | "isolatedModules": true, 15 | "jsx": "preserve", 16 | "incremental": true, 17 | "plugins": [ 18 | { 19 | "name": "next" 20 | } 21 | ], 22 | "paths": { 23 | "@/*": ["./src/*"] 24 | } 25 | }, 26 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], 27 | "exclude": ["node_modules"] 28 | } 29 | --------------------------------------------------------------------------------