## 本文整理學習 Nextjs 相關的知識與文件<br/>來源來自於網路及自我整理 ###### 路由使用 app router 方式 ###### 部分內容可能跟 page router 不同 # node js 版本 使用 v20.11.1 最新版本可能造成編譯錯誤 # vs code debug build launch.json ```json=! { // 如需詳細資訊,請瀏覽: https://nextjs.org/docs/pages/building-your-application/configuring/debugging "version": "0.2.0", "configurations": [ { "name": "Next.js: debug server-side", "type": "node-terminal", "request": "launch", "command": "npm run dev" }, { "name": "Next.js: debug client-side", "type": "chrome", "request": "launch", "url": "http://localhost:3000" }, { "name": "Next.js: debug full stack", "type": "node-terminal", "request": "launch", "command": "npm run dev", "serverReadyAction": { "pattern": "- Local:.+(https?://.+)", "uriFormat": "%s", "action": "debugWithChrome" } } ] } ``` # 編譯腳本 內容寫在 package.json example: ```json=! { "name": "qpp-web-next", "version": "0.1.0", "private": true, "scripts": { "dev": "next dev", "build": "next build", "start": "next start", "lint": "next lint", "static_github": "next build && touch ./out/.nojekyll" }, "dependencies": { "react": "^18", "react-dom": "^18", "next": "14.1.3" }, "devDependencies": { "typescript": "^5", "@types/node": "^20", "@types/react": "^18", "@types/react-dom": "^18", "autoprefixer": "^10.0.1", "postcss": "^8", "tailwindcss": "^3.3.0", "eslint": "^8", "eslint-config-next": "14.1.3" } } ``` script 裡面可以寫自己需要的腳本 如 static_github 內容是編譯 github pages 靜態網頁用 除了會跑原本的 build 以外還會額外產出 nojekyll 檔案 讓 github pages 不會略過帶有底線的資料夾 呼叫使用 ```shell=! npm run <command> ``` ex: ```shell=! npm run build ``` # next.config next.config.mjs 和 next.config.js 是用於配置 Next.js 應用程式的配置檔案,兩者的主要區別在於檔案格式和支援的特性。 檔案格式: next.config.mjs 使用 ECMAScript 模組 (ESM) 格式,因此您可以在檔案中使用 import 和 export 語法。 next.config.js 使用 CommonJS 格式,因此您應該使用 require() 和 module.exports 來匯入和匯出模組。 特性支援: next.config.mjs 支援更先進的 JavaScript 功能,如 ES 模組、動態 import() 等。 next.config.js 在功能上相對保守,不支援一些 ES 模組特性。 > 因此,如果您的專案使用了較新的 JavaScript 特性或者想要使用 import 和 export 語法,建議選擇使用 next.config.mjs。否則,可以繼續使用傳統的 next.config.js。在選擇檔案格式時,您應該根據您的專案需求和團隊技術棧來決定。 [JavaScript 模塊 MDN Web Doc](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Modules) # CSR & SSR ![截圖 2024-03-12 下午2.40.33](https://hackmd.io/_uploads/BkSetdp6T.png) 我們用上面這張圖來瞭解兩者的差異,如果是 CSR 瀏覽器請求 HTML 後,必須等待請求 JS 檔案,然後再等待 React 把元件 mount 到 DOM上,以及請求 API 還會花費額外的時間。 此外,有些網站很注重搜尋引擎優化 (SEO),搜尋引擎的原理即是爬蟲,而爬蟲通常不包含請求 HTML 後再請求 JS 檔案,所以如果是一般透過前端請求 API 後才載入資料,搜尋引擎便看不到網頁實際上的內容,不利於 SEO。 如果是 SSR,網頁的內容都會在伺服器端處理,爬蟲看到的即是包含完整內容的 HTML,便有利於進行 SEO。同時也有助於減少使用者從請求網頁到看見網頁內容時間,提升使用者體驗 (UX)。 ![截圖 2024-03-12 下午2.42.21](https://hackmd.io/_uploads/r1VDF_TTT.png) CSR 與 SSR 主要不一樣的點在於多了一個渲染伺服器,渲染伺服器會用於第一次使用者請求 HTML 時,會將內容都事先放到 HTML 中,所以使用者看到的就是一個已經包含完整內容的網頁。 以下包含 React SSR 幾個重點: 擁有一個獨立的伺服器 (後端),提供 API 可以請求資料。 渲染伺服器與瀏覽器端都可以請求 API。 渲染伺服器會在使用者請求 HTML 時,會請求 API 的資料,並將內容都事先放到 HTML 中。 在第一次請求 HTML 後,之後的元件 routing、請求 API 都是在瀏覽器端執行。 > 以上自 [React SSR | 從零開始實作 SSR — 基礎篇](https://medium.com/手寫筆記/server-side-rendering-ssr-in-reactjs-part1-d2a11890abfc) 轉載 # 靜態資源 Next.js 可以在頂層 `public` 目錄 下運行靜態資源,例如圖片。就像 pages 一樣,`public` 目錄中的檔案可以在根目錄下被引用。 `public` 目錄對於 robots.txt、Google Site Verification 或任何靜態資源都很有用。 # apple-touch-icon 用來設定蘋果 (Apple) iOS Safari 將網頁 - 通常是一個 Progressive Web Apps (PWAs) 網頁 - 新增到桌面時的圖示: ```xml=! <link rel="apple-touch-icon" sizes="180x180" href="/favicon/apple-touch-icon.png" /> ``` 如果沒設定 apple-touch-icon Apple 會自己幫你用 screenshot 建立一個圖示。 常見的 touch icon 尺寸可以是 180x180 pixels 或 192x192 pixels! # favicon, icon... ```typescript=! import Footer from "@/app/_components/footer"; import { CMS_NAME, HOME_OG_IMAGE_URL } from "@/lib/constants"; import type { Metadata } from "next"; import { Inter } from "next/font/google"; import "./globals.css"; const inter = Inter({ subsets: ["latin"] }); export const metadata: Metadata = { title: `Next.js Blog Example with ${CMS_NAME}`, description: `A statically generated blog example using Next.js and ${CMS_NAME}.`, openGraph: { images: [HOME_OG_IMAGE_URL], }, }; export default function RootLayout({ children, }: Readonly<{ children: React.ReactNode; }>) { return ( <html lang="en"> <head> <link rel="apple-touch-icon" sizes="180x180" href="/favicon/apple-touch-icon.png" /> <link rel="icon" type="image/png" sizes="32x32" href="/favicon/favicon-32x32.png" /> <link rel="icon" type="image/png" sizes="16x16" href="/favicon/favicon-16x16.png" /> <link rel="manifest" href="/favicon/site.webmanifest" /> <link rel="mask-icon" href="/favicon/safari-pinned-tab.svg" color="#000000" /> <link rel="shortcut icon" href="/favicon/favicon.ico" /> <meta name="msapplication-TileColor" content="#000000" /> <meta name="msapplication-config" content="/favicon/browserconfig.xml" /> <meta name="theme-color" content="#000" /> <link rel="alternate" type="application/rss+xml" href="/feed.xml" /> </head> <body className={inter.className}> <div className="min-h-screen">{children}</div> <Footer /> </body> </html> ); } ``` # css 模組 CSS 模組可以匯入到 `app` 目錄中的任何檔案中: ###### `app/dashboard/layout.tsx` ```ts=! import styles from './styles.module.css' export default function DashboardLayout({ children, }: { children: React.ReactNode }) { return <section className={styles.dashboard}>{children}</section> } ``` CSS 模組是一個可選功能,僅對副檔名為 `.module.css` 的檔案啟用。 仍然支援常規 `<Link>` 樣式表和全域性CSS檔案。 在 production 中,所有 CSS 模組檔案將自動連接成許多縮小和程式拆分的 `.css` 檔案。 這些 `.css` 檔案代表應用程式中的熱執行路徑,確保為應用程式繪製最少的 CSS 載入量。 ###### `app/dashboard/styles.module.css` ```css=! .dashboard { padding: 24px; } ``` # 全域性樣式 全域性樣式可以匯入到 `app` 目錄中的任何佈局、頁面或元件中。 例如,創建一個 `app/global.css` 寫入以下內容: ```css=! body { padding: 20px 20px 60px; max-width: 680px; margin: 0 auto; } ``` 在 root layout 裡(`app/layout.tsx`) 匯入 `globa.css` 此樣式將應用到所有頁面 ```ts=! export default function RootLayout({ children, }: { children: React.ReactNode }) { return ( <html lang="en"> <body>{children}</body> </html> ) } ``` 外部樣式可以從 `app` 資料夾的任何地方被引入: ```ts=! import 'bootstrap/dist/css/bootstrap.css' export default function RootLayout({ children, }: { children: React.ReactNode }) { return ( <html lang="en"> <body className="container">{children}</body> </html> ) } ``` > 外部樣式必須直接從 npm package 匯入或下載 > 並與您的程式庫一起放置 > 不能使用`<link rel="stylesheet" />`。 # Next.js 元件 ## Link ```typescript=! import Link from "next/link"; ``` Link 元件可以允許在同一個 Next.js 應用程式中的兩個頁面之間進行客戶端的頁面跳轉 客戶端導航意味著頁面轉換時使用 JavaScript,這比瀏覽器內建的預設跳轉方法更快。 ```xml=! <Link href="/">Back to home</Link> ``` ```xml=! <Link href="/posts">this page!</Link> ``` Next.js 會自動進行程式碼拆分,所以每個頁面只載入該頁面所需的內容。 這意味著在渲染首頁時,初始化的過程不會載入其他頁面的程式碼。 在 Next.js 的生產版本中,每當 Link 元件出現在瀏覽器的顯示裝置中時,Next.js 都會在後台自動提前載入連結頁面的程式碼。當您單擊連結時,目標頁面的代碼已經在背景執行加載,所以頁面轉換幾乎是即時的! > Note: 如果您需要鏈接到 Next.js 應用之外的 外部連結 頁面,只需使用不帶 `<Link>` 的 `<a>` 標籤 > 如果您需要添加屬性,例如,`<className>`,請將其添加到 `<a>` 標籤,而非添加到 `<Link>` 標籤。這是一個範例. ## Image ```typescript=! import Image from "next/image"; ``` `next/image` 是為了現代網頁的需求,而在 HTML `<img>` 基礎之上建立的擴展元件。 在預設情況下 Next.js 支援圖片優化。包括了支援現代 web 格式,且進行大小調整、優化和運行圖片 (就像 WebP 一樣),這避免了在較小的可見區域加載大型圖片。同時,Next.js 還可以自動適應未來的圖片格式,並將其提供給支援這些格式的瀏覽器。 自動圖片優化可與任何圖片一起使用。即使圖片由外部數據源(例如 CMS)托管,它仍然可以進行優化。 Next.js 在使用者發出請求時,會動態優化圖片,而非在建置時進行優化。這與靜態網站產生器以及僅支援靜態內容的解決方案不同,不論是上傳 10 張還是 1 千萬張圖片,都不會增加建置時間。 圖片默認採用「懶加載」方式,這意味著圖片不在可見區域時不會影響頁面速度。當圖片被滾動到可見區域時才會加載。 圖片總是以避免累積版面位移的方式呈現,這是 Google 會在搜尋排名中使用的核心網頁指標。 ```typescript=! <Image src="/vercel.svg" alt="Vercel Logo" className="dark:invert" width={100} height={24} priority /> ``` ## Head ```typescript=! import Head from "next/head"; ``` 可以設置 詮釋資料(Metadata) ```xml=! <Head> <title>Create Next App</title> <link rel="icon" href="/favicon.ico" /> </Head> ``` > 若想了解更多有關 Head 元件的資訊,請參閱 `next/head` 的 API 參考。 > > 若想自訂 `<html>` 標籤,像是加入 `lang` 屬性,你可以透過建立 `pages/_document.js` 檔案來達成,詳細資訊請參閱 [自訂 Document 文件](https://nextjs.tw/docs/advanced-features/custom-document)。 > ps.目前版本需再確認 ## Script ```typescript=! import Script from "next/script"; ``` `next/script` 是基於 HTML`<script>` 元素的擴充功能,可優化提取和執行其他腳本的時機。 ```xml=! <> <Head> <title>First Post</title> </Head> <script src="https://connect.facebook.net/en_US/sdk.js" defer /> <h1 className="title"> Read <Link href="/posts/first-post">this page!</Link> </h1> </> ``` 在 Next.js 中,`<script>` 標籤有一個屬性叫做 `async`,這個屬性告訴瀏覽器在加載該腳本時不需要等待,可以同時加載其他資源。 使用 `async` 屬性的 `<script>` 標籤會異步加載腳本,在腳本下載完成後立即執行。這意味著該腳本的執行可能在頁面的其他資源加載完成之前開始。 這個屬性對於需要立即執行但對頁面內容不是必需的腳本非常有用,例如分析程式碼、社交分享按鈕等。 需要注意的是,使用 `async` 屬性的腳本不保證按照它們在頁面上出現的順序執行。如果您需要確保腳本按照指定順序執行,可以考慮使用 `defer` 屬性代替 `async` 屬性。 # TypeScript 參考 * [[掘竅] 了解這些,更快掌握 TypeScript 在 React 中的使用(Using TypeScript in React)](https://pjchender.blogspot.com/2020/07/typescript-react-using-typescript-in.html) * [讓 TypeScript 成為你全端開發的 ACE!](https://ithelp.ithome.com.tw/users/20120614/ironman/2685) * [ 學了 React 後的下一步?準備好兩把刷子!](https://pjchender.dev/ironman-2021/ironman-2021-day01/) * [TypeScript Omit 的用法](https://blog.marsen.me/2022/09/12/2022/TypeScript_Omit/) * [TypeScript 新手指南](https://willh.gitbook.io/typescript-tutorial/basics/declaration-files) # 相關網站 * [前端框架簡介](https://developer.mozilla.org/zh-TW/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Introduction) * [為什麼你需要 Next.js](https://ithelp.ithome.com.tw/articles/10265138) * [快速上手 NextJS v13 - 基礎觀念 AppRouter 篇](https://johnnywang1994.github.io/book/articles/js/next13-intro-approuter.html) * [來做 Facebook 貼文串的前端吧!中(設計參考)](https://medium.com/@qaz7821819/五分鐘學前端系統設計面試-五-來做-facebook-貼文串的前端吧-中-fd2fb34bde19) * [Next.js 官方文件](https://nextjs.org/docs) * [Next.js 中文官方文件(已無更新)](https://nextjs.tw/docs/getting-started) * [Next.js sample on github](https://github.com/vercel/next.js/tree/canary/examples) * [該怎麼知道網站是 CSR 還是 Pre-Rendering](https://ithelp.ithome.com.tw/articles/10314924) * [SSR 與 CSR 深度解析:從渲染方式到效能優化](https://www.shubo.io/rendering-patterns/) * [不用寫程式也能產生 API — strapi](https://medium.com/黑洞創造-blackhole-creative/不用寫程式就能產生-api-strapi-工具介紹-f40d01570322) * [tailwind css](https://tailwindcss.com/docs/min-height) * [tailwindcss - 從零開始學](https://ithelp.ithome.com.tw/users/20162607/ironman/6658) # Trouble [Next.js not fully functional on Safari for iOS 12 #48627](https://github.com/vercel/next.js/issues/48627)