create-T3-app with extra tools/config out of the box
create-t3-app is one of the fastest and easiest way to scaffold fullstack app.
create-t3-extended make it even faster for my case (and maybe yours).
With these additional tools/ config:
Interesting Discussion
This documentation below show how I modify the original code base into what you'll find in this repo & also some useful tips & trick.
- If your case same with mine/ you agree with all my opinion, just use it & start.
- If your case is different than mine/ agree only some of my opinion, use create-t3-app & add the tools/ config you need.
If you find it helpful, feel free to use.
If you have opinion that you think better, feel free to discuss.
If you find bug, let's fix it.
I'm not consider myself an expert. Just learn & share.
Hopefully one day I will make a CLI for this. How smooth that will be?
🧹
Linting & Formatting better code 1 without the frustration of config.
Install prettier with the config & plugin for eslint & tailwind
npm i -D prettier eslint-config-prettier eslint-plugin-prettier prettier-plugin-tailwindcss
Confuse about plugin vs config? Read this and this.
Why don't we use stylelint also?
Tailwind is more than enough. Use arbitrary value & custom style.
Here is my experience:
I make component animation on css and realize that you can move it to tailwind custom style. I use scss on svg animation and realize css is not for this kind of job. You will screw up really fast (sarah drasner said). I move using animation library instead (more below).
prettier.config.cjs
Add prettier config file module.exports = {
trailingComma: 'es5',
useTabs: true,
tabWidth: 2,
semi: false,
singleQuote: true,
bracketSpacing: false,
jsxSingleQuote: true,
plugins: [require('prettier-plugin-tailwindcss')],
tailwindConfig: './tailwind.config.cjs',
}
.eslint.json
Extend eslint config {
- "plugins": ["@typescript-eslint"],
+ "plugins": ["@typescript-eslint", "prettier"],
"extends": [
"next/core-web-vitals",
"plugin:@typescript-eslint/recommended",
+ "prettier"
],
+ "rules": {
+ "prettier/prettier": "warn"
+ }
}
You can use prettier only on formatting or also give linting error/ warning. For my chase warn me.
Add more plugin if you need it
I personally love unicorn plugin.
Lint & format all of your file
npx prettier --write .
npx eslint .
⛓️
Git hooks better 1 and more exciting git experience
🧹
Pre-commit
Make sure everything is clean before commit it.
Add husky to the project
npx husky-init && npm i
Install lint-staged
npm i -D lint-staged
Add config file .lintstagedrc
{
"*.{js,jsx,cjs,ts,tsx}": "eslint --fix",
"*.{md,json}": "prettier --write"
}
Run lint-staged on pre-commit hook
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
- npm test
+ npx lint-staged
If the log message doesn't show correctly, see this issue
📨
Commit message
Give clear message by following the convention
Install commitlint
npm install -D @commitlint/cli @commitlint/config-conventional
Add config file
commitlint.config.cjs
module.exports = {
extends: ['@commitlint/config-conventional'],
}
Add to commit-message hook
npx husky add .husky/commit-msg "npx commitlint --edit \"\$1\""
Test by making a commit
git commit -m "foo: bar"
🤯
Commit emoji
Who don't like emoji??
Install gitmoji
npm i -g gitmoji-cli
Install gitmoji config for commitlint
npm i -D commitlint-config-gitmoji
Update commitlint config file
module.exports = {
- extends: ['@commitlint/config-conventional'],
+ extends: ['gitmoji'],
+ rules: {
+ 'header-max-length': [0, 'always', 100],
+ 'scope-case': [0, 'always', 'pascal-case']
+ }
}
Commit using gitmoji
gitmoji -c
🏗️
Pre-push
Clean doesn't mean it's not break
npx husky add .husky/pre-push "npm run build"
Hosting provider usually charge money if you exceed the build time limit. It can save you some time.
📈
Optimization Don't bring unnecessary thing in your baggage
📦
Bundle Analyzer
Consider package bundle size before add it to your arsenal.
Install bundle analyzer
npm -i -D @next/bundle-analyzer
Edit next.config.cjs
+ import bundleAnalyzer from '@next/bundle-analyzer'
+ const withBundleAnalyzer = bundleAnalyzer({
+ enabled: process.env.ANALYZE === 'true',
+ })
function defineNextConfig(config) {
- return config
+ return withBundleAnalyzer(config)
}
Add bundle analyzer build script
+ "build-stats": "ANALYZE=true npm run build"
Run build with bundle analyzer npm run build-stats
You can also check using bundle size using bundlephobia.
🧰
CSS
Optimize tailwind on production
Minify CSS using cssnano
npm -i -D cssnano
Edit postcss.config.cjs
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
+ ...(process.env.NODE_ENV === 'production' ? {cssnano: {}} : {}),
},
}
🚀
Going Live Why wait so long to go to the moon?
🪐
MySQL on PlanetScale
Sit with ease in case your app suddenly become a startup. Watch this interview
I use both local database & PlanetScale branch database for development. Depend on your need.
For local I use prisma migrate dev
For remote I use prima db push
Read this for the differences.
Local MySQL server
Go to prisma.schema and there will be instruction about what to do.
For MySQL installation follow guide.
Set database url on .env
DATABASE_URL=mysql://user:password@localhost:3306/database_name
Migrate local database (better wait after planet scale setup)
npx prisma migrate dev
PlanetScale setup
Ignore prisma migration file in .gitignore
/prisma/migrations/*
Follow this instruction and you are good to go.
Code mods:
prisma.schema
generator client {
provider = "prisma-client-js"
+ previewFeatures = ["referentialIntegrity"]
}
datasource db {
url = env("DATABASE_URL")
+ referentialIntegrity = "prisma"
}
Replace your DATABASE_URL on .env
with url that you get from PlanetScale
🔎
Google OAuth
Who doesn't have google account?
Setup credential at google console.
Create new project > configure consent screen
Go to "APIs & Services" > "Credentials" > "Create credentials" > "OAuth Client ID"
Add "Authorized JavaScript origins" with base url
http://localhost:3000
https://your-domain.vercel.app
Add "Authorized redirect URIs" with callback url
http://localhost:3000/api/auth/callback/google
https://your-domain.vercel.app/api/auth/callback/google
Add google credential to .env
+ GOOGLE_CLIENT_ID = 'Your Client ID'
+ GOOGLE_CLIENT_SECRET = 'Your Client Secret'
Add google env to schema.mjs
export const serverSchema = z.object({
...
+ GOOGLE_CLIENT_ID: z.string(),
+ GOOGLE_CLIENT_SECRET: z.string(),
})
Enable jwt callback (required)
callbacks: {
session({session, user}) {
...
},
+ async jwt({token}) {
+ return token
+ },
},
🔺
Vercel
Except you like to complicate things
Just add the env & deploy
Add your live url as next auth url on .env
+ NEXTAUTH_URL=https://your-domain.vercel.app
🪛
Other helpful things Trivially important
📄
NextJS custom Document
Create custom document _document.tsx
on pages directory
import {Html, Head, Main, NextScript} from 'next/document'
export default function Document() {
return (
<Html>
<Head />
<body>
<Main />
<NextScript />
</body>
</Html>
)
}
🅵 Fonts
There are a lot of curated font pairing ready to pick.
Pick font pairing from two of the most useful collection from heyreliable.com and pagecloud.com. You can also filter by the style that match your app.
Go to google font and search those fonts.
Select the specimen that you will use. Remember about performance! I recommend pick three font weight and the italic version of each weight.
Add the font link inside <Head>
component on _document.tsx
<Head>
+ <link rel='preconnect' href='https://fonts.googleapis.com' />
+ <link
+ rel='preconnect'
+ href='https://fonts.gstatic.com'
+ crossOrigin=''
+ />
+ <link
+ href='https://fonts.googleapis.com/css2?family=Hind:wght@400;600&family=Montserrat:ital,wght@0,400;0,600;0,800;1,400;1,600;1,800&display=swap'
+ rel='stylesheet'
+ />
...
<Head />
Extend tailwind config with the font family
theme: {
extend: {
fontFamily: {
+ heading: ['Montserrat', 'sans-serif'],
+ body: ['Hind', 'sans-serif'],
},
},
},
You can apply it directly to the tag if needed by changing styles/global.css
@layer base {
h1,
h2,
h3,
h4,
h5,
h6 {
@apply font-heading;
}
p {
@apply font-body;
}
}
⭐
Favicon
Just get it correctly.
Prepare your svg icon
Go to realfavicongenerator.net
Adjust & generate favicon
Download & put on public directory
Copy generated link to head on _document.tsx
<Head>
+ <link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
+ <link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
+ <link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
+ <link rel="manifest" href="/site.webmanifest">
+ <link rel="mask-icon" href="/safari-pinned-tab.svg" color="#5bbad5">
+ <meta name="msapplication-TileColor" content="#2d89ef">
+ <meta name="theme-color" content="#ffffff">
<Head/>
🌟
Animation
Steal user attention & help them navigate.
These css animation collection very useful to make your website stand out
Auto animate also really helpful for element transition.
For svg animation use GSAP. Sarah Drasner and other pro recommend it because it's the most mature and reliable library.
🗡️
Bleeding edge tech
Cool tech should not make you bleeding
These is only for exploration & discussion.
ORM Replacement
Kysely provide end-to-end type-safety but also edge-first approach to ORM replacement
Supercharge Database
I have been trying EdgeDB and it's SUPER COOL! But I think SurrealDB will be the real one.
Next to cover
- vscode extension
- nextjs
- svg