Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537
當今快速發展的網站開發領域,Next.js以其獨特的優勢和便捷的功能,成為了前端開發者的新寵。Next.js是一個開源的JavaScript框架,它建立在流行的JavaScript庫React之上,專為構建用戶界面而設計。作為一個專門用于構建網絡應用程序的框架,Next.js被廣泛描述為一個用于服務端渲染或靜態生成應用程序的React框架。通過提供一系列工具和約定,Next.js極大地簡化了基于React的網絡應用程序的開發過程,使得構建快速、高性能且可擴展的網站變得更加容易。
Next.js提供的附加功能能夠讓你構建生產就緒的應用程序,這些功能包括路由、優化渲染、數據獲取、打包、編譯等等。最吸引人的一點是,使用Next.js時,你不需要安裝額外的包,因為Next.js提供了你所需的一切。要實現這些功能,只需遵循Next.js的觀點和約定即可。
通過這些特性,Next.js為開發者提供了一個功能豐富、靈活且高效的平臺,用于構建各種規模和復雜度的Web應用。無論是企業級應用、電商網站還是個人博客,Next.js都能夠提供強大的支持,使得Web開發更加簡單、快捷,并且能夠達到高性能的要求。學習和掌握Next.js,無疑會讓你在現代Web開發的道路上更加得心應手。
打開你的命令行工具(如終端、命令提示符或PowerShell),并執行以下命令,記得將<app-name>替換為你的項目名稱:
npx create-next-app@latest <app-name>
這個命令會自動從npm下載并執行create-next-app腳本,創建一個使用最新版本的Next.js的新項目。在這個過程中,腳本可能會詢問你是否想要配置TypeScript、ESLint或Tailwind CSS等選項。根據你的項目需求,跟隨提示進行選擇。
項目創建完成后,通過以下命令切換到項目目錄:
cd <app-name>
然后,啟動開發服務器:
npm run dev
執行此命令后,Next.js會啟動一個本地開發服務器,并且通常會自動打開你的默認網頁瀏覽器顯示你的新Next.js應用。如果沒有自動打開,你可以手動訪問http://localhost:3000來查看你的應用。
在Next.js中,路由是構建Web應用程序的基礎之一,其獨特的基于文件系統的路由機制為開發者提供了高效且直觀的頁面管理方式。通過簡單地在代碼庫中添加文件和文件夾,你可以定義用戶可以在瀏覽器中訪問的URL路徑。下面是幾個關于Next.js路由的學習場景,讓我們更深入地了解如何在Next.js應用中實現和管理路由。
場景1:訪問根目錄
當用戶訪問根目錄(即localhost:3000)時,顯示主頁。你可以通過在src/app目錄下創建page.tsx文件來實現這一點。
// src/app/page.tsx
export default function Home() {
return <h1>Home Page</h1>;
}
這段代碼定義了一個簡單的React組件,當用戶訪問應用的根目錄時,將展示“Home Page”。
場景2:訪問/about頁面
當用戶訪問localhost:3000/about時,顯示關于頁面。在src/app/about目錄下創建page.tsx文件來實現。
// src/app/about/page.tsx
export default function About() {
return <h1>About Page</h1>;
}
場景3:嵌套路由
Next.js允許通過在文件夾內創建文件夾來創建路由層次結構。
// src/app/blog/page.tsx
export default function Blog() {
return <h1>Blog Page</h1>;
}
// src/app/blog/first/page.tsx
export default function FirstBlog() {
return <h1>First Blog Page</h1>;
}
這種方式適用于簡單的應用程序結構,但對于復雜的應用程序可能不是最佳選擇。
場景4:動態路由
動態路由允許基于URL中提供的參數動態生成頁面。這意味著,你無需為每個可能的路由創建單獨的靜態頁面,而是可以使用動態路由來處理URL中的模式或參數。
// src/app/products/[productId]/page.tsx
export default function ProductDetails({ params }: { params: { productId: string }; }) {
return (
<>
<h1>Details about product {params.productId}</h1>
</>
);
}
在Next.js中,"Catch all"路由是一種強大的路由特性,它允許你匹配包括零個、一個或多個路徑段的路由。這種方式非常適用于當你需要構建像文檔頁面這樣的復雜和靈活的路由結構時。通過使用雙括號[[...slug]]語法,你可以創建一個能夠捕獲所有傳入請求的動態路由,并且根據URL的不同部分呈現不同的內容。
示例解讀
在提供的示例中,我們創建了一個Docs組件,它利用"catch all"路由來展示文檔頁面。這個組件能夠根據URL中slug參數的不同,渲染出不同的文檔內容。這里的slug是一個數組,它包含了URL中捕獲的所有動態段。
// src/app/docs/[[...slug]]/page.tsx
export default function Docs({params}: {
params: {
slug: string[];
};
}) {
// 檢查slug參數的長度,以決定渲染哪種內容
if (params.slug?.length===2) {
return <h1>Viewing docs for feature {params.slug[0]} and concept {params.slug[1]}</h1>;
} else if (params.slug?.length===1) {
return <h1>Viewing docs for feature {params.slug[0]}</h1>;
}
// 如果沒有提供slug參數,渲染默認的文檔頁面
return <h1>Docs Page</h1>;
}
優勢
使用"catch all"路由的優勢在于,它為構建具有靈活路由需求的應用程序(如文檔網站、博客平臺等)提供了簡單而強大的解決方案。開發者可以輕松地管理和展示變化多端的內容,而無需為每個可能的URL變體單獨設置路由規則。這不僅提高了開發效率,也使得應用架構更加清晰和易于維護。
在Next.js中處理404錯誤頁面是一個簡單而直接的過程,通過定義一個特定的組件,你可以為用戶提供一個更友好的錯誤提示頁面,而不是默認的瀏覽器錯誤頁面。這對于改善用戶體驗和維持網站的專業形象非常重要。
通過在src/app目錄下創建一個not-found.tsx文件,你可以定義一個NotFound組件,當用戶嘗試訪問一個不存在的頁面時,將顯示該組件。
// src/app/not-found.tsx
export default function NotFound() {
return (
<>
<h2>Page not found</h2>
<p>Could not find requested resource</p>
</>
);
}
在Next.js中,當用戶嘗試訪問一個不存在的路由時,Next.js會自動查找并渲染pages/404.js或src/pages/404.js文件(取決于你的項目結構)。如果你在這些位置定義了自定義404頁面,Next.js將渲染你定義的頁面而不是默認的404頁面。
在Next.js中使用私有文件夾是管理項目文件結構的一個高效方式,尤其適合于那些想要將UI邏輯與路由邏輯分離、維護項目內部文件組織一致性、在代碼編輯器中排序和分組文件、以及避免未來Next.js文件命名規范可能帶來的命名沖突的開發者。通過簡單地在文件夾名稱前加上下劃線_,你可以輕松地創建私有文件夾,這些文件夾及其所有子文件夾都會被Next.js的路由系統自動忽略。
假設你有一些庫文件或者一些只供內部使用的組件,你不希望這些文件或組件被當作頁面對外提供服務。你可以將這些文件放在一個前綴為下劃線的文件夾中,比如_lib。
// src/app/_lib/page.tsx
export default function PrivateRoute() {
return <h1>You can't view this in the browser</h1>;
}
在上面的例子中,盡管我們創建了page.tsx文件,由于它位于_lib文件夾下,訪問localhost:3000/_lib將會顯示404錯誤,因為Next.js自動將_lib及其子文件夾從路由系統中排除了。
在Next.js中組織和管理路由時,有時候我們需要邏輯上對路由進行分組,而又不希望這種分組影響到URL路徑結構。這種需求在實際開發中非常常見,例如,你可能想要將所有與身份驗證相關的頁面(如登錄、注冊、忘記密碼等)放在同一個文件夾下以提高開發體驗,但又不想在URL中體現這種文件結構。
使用路由分組解決問題
Next.js提供了一種簡便的方法來實現這一點:路由分組。通過在文件夾名周圍添加括號,你可以告訴Next.js這個文件夾是用于邏輯分組的,并且不應該影響到URL的結構。
例如,如果不使用路由分組,你可能會將登錄頁面放在/pages/auth/login.tsx,這將導致頁面的URL為localhost:3000/auth/login。但是,如果你想要保持login頁面的URL為localhost:3000/login,同時又想在項目文件中將這個頁面放在auth分組下,你可以通過路由分組來實現。
實現路由分組
要實現路由分組,只需要將相關的文件夾用括號括起來。以下是具體操作步驟:
通過這種方式,login頁面的物理路徑可能是/pages/(auth)/login.tsx,但是在瀏覽器中訪問這個頁面的URL將會是localhost:3000/login,而不是localhost:3000/auth/login。
路由分組的好處
通過利用Next.js的路由分組功能,你可以在確保URL路徑簡潔的同時,對項目中的文件和路由進行有效的邏輯分組,這對于大型項目的開發和維護來說尤為重要。
在構建Web應用時,常常需要某些UI元素(如頭部導航和底部信息)在多個頁面間共享。這種需求通過使用布局(Layouts)來實現最為高效。布局允許開發者定義一個組件作為頁面的共享結構,然后將特定的頁面內容注入到這個結構中。Next.js通過支持布局,使得管理和重用頁面結構變得簡單。
根布局(Root Layout)
根布局是應用于所有路由的布局。你可以創建一個layout.js或layout.tsx文件來定義根布局,然后在其中包括所有頁面共享的元素,如頭部和底部。根布局組件應該接受一個children屬性,這個屬性在渲染時會被填充為子頁面。
// 示例:定義根布局
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en">
<body>
<header>
<p>Header</p>
</header>
{children}
<footer>
<p>Footer</p>
</footer>
</body>
</html>
);
}
嵌套布局(Nested Layout)
嵌套布局用于特定的路由段,只有當這些路由段處于活動狀態時,定義在內部的布局才會被渲染。通過在特定文件夾下定義layout.js(例如app/dashboard/layout.js),你可以為那個路由段及其子路由提供專用的布局。
// 示例:定義特定路由段的嵌套布局
export default function DashboardLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<div>
<nav>
<p>Dashboard Navigation</p>
</nav>
{children}
</div>
);
}
這種方式允許你為應用中的不同部分定義不同的布局結構,如儀表板、博客部分等,每個部分都可以有自己的頭部導航、側邊欄或其他共享元素。
使用布局的好處
使用根布局和嵌套布局,你可以靈活地定義應用的頁面結構,同時保持代碼的清晰和組織性。這是構建大型應用時管理頁面布局的一種高效方法。
在今天的文章中,我們一起探索了Next.js這個強大的JavaScript框架,從基本概念到路由、布局以及私有文件夾的高級特性,每一點都旨在幫助你更好地理解如何利用Next.js構建高性能、易于維護的現代Web應用。無論你是剛開始接觸Web開發的新手,還是希望提升項目質量的資深開發者,Next.js都提供了豐富的功能和靈活性,以滿足不同的開發需求。
我們的探索之旅還遠沒有結束。在下篇文章中,我將繼續深入分享Next.js的更多精彩內容,每一篇文章都旨在為你揭開Next.js高效開發的更多秘密,助你在Web開發的道路上更加得心應手。
別忘了關注「前端達人」,這里不僅有深入淺出的技術文章,還有最新的前端趨勢解讀,幫助你保持技術的前瞻性和競爭力。你的關注、點贊和轉發是對我最大的支持,也是我持續分享高質量內容的動力。
著現代Web應用的發展,用戶界面變得越來越復雜,同時用戶對應用的響應速度和互動性有著更高的期待。在這樣的背景下,Next.js 作為一個前沿的React框架,提供了一系列高級功能來滿足開發者的需求,今天我們來介紹 Next.js 14 的第二部分。
Next.js 14 初學者指南 (一)
在當今這個信息爆炸的時代,擁有一個高可見度的網站已成為許多企業和個人的追求。搜索引擎優化(SEO)是實現這一目標的重要手段。為了讓你的Next.js應用更好地被搜索引擎發現,Next.js引入了一個非常實用的功能——元數據API。通過這個API,你可以為每個頁面定義元數據,確保當你的頁面被分享或索引時顯示準確、相關的信息。
1. 靜態元數據的配置
靜態元數據是指在構建時確定的有關頁面的信息,并且在運行時不會改變。這些元數據與特定頁面相關聯,可以包括標題和描述等數據。例如,如果你有一個關于頁面,你可以這樣配置它的靜態元數據:
//src/app/about/page.tsx
export const metadata={
title: "關于我",
};
export default function About() {
return <h1>關于我</h1>;
}
通過這種方式,當你的“關于我”頁面被搜索引擎索引或被分享到社交媒體時,其標題會正確地顯示為“關于我”。
2. 動態生成的元數據
與靜態元數據不同,動態元數據允許你根據運行時的動態數據或條件生成頁面的元數據。這對于那些內容經常變化或依賴于用戶輸入的頁面非常有用。比如,你有一個展示產品詳情的頁面,可以這樣配置其元數據:
import { Metadata } from "next";
type Props={
params: {
productId: string;
};
};
export const generateMetadata=({ params }: Props ): Metadata=> {
return {
title: `產品 ${params.productId} 的詳情`,
};
};
export default function ProductDetails({ params }: Props) {
return <h1>產品 {params.productId} 的詳情</h1>;
}
甚至,你可以使用異步函數來生成元數據,這在你需要從數據庫或API獲取數據時特別有用:
export const generateMetadata=async ({ params }: Props): Promise<Metadata>=> {
const title=await new Promise((resolve)=> {
setTimeout(()=> {
resolve(`產品 ${params.productId}`);
}, 100);
});
return { title: `產品 ${title} 的詳情`, };
};
3、元數據規則
4、title metadata
關于元數據中的title屬性,這是一個非常關鍵的部分,它直接影響到你的頁面在搜索引擎中的顯示標題以及用戶在瀏覽器標簽頁中看到的內容。title可以是一個字符串或者是一個對象,這取決于你想如何控制標題的顯示。
當你在layout.tsx文件中定義元數據時,title字段提供了幾個有趣的選項來增加靈活性:
//layout.tsx
export const metadata: Metadata={
title: {
absolute: "",
default: "",
template: "%s | 網站名稱",
},
description: "",
};
這個功能特別適合那些頁面結構復雜、需要精細控制每個頁面標題的網站。通過在不同級別(全局布局、頁面布局、單獨頁面)精心設計title的設置,可以確保無論用戶進入網站的哪個部分,都能通過標題快速了解內容,并通過模板確保網站的整體品牌一致性得到維護。
舉個例子,如果你的一個頁面沒有指定特定的標題,那么它就會使用default中的值。而當頁面指定了自己的標題時,template中定義的模式就會發揮作用,自動將頁面的標題和網站名稱進行組合,形成一個既清晰又具有品牌特色的標題展示。
這種靈活性和自動化的結合,不僅使得SEO優化變得簡單,而且還能在提升用戶體驗的同時,加強網站品牌的影響力。
通過精心設計每個頁面的元數據,不僅可以提高網站的搜索引擎排名,還能提升用戶體驗,增加點擊率。在社交媒體時代,一個吸引人的頁面標題和描述可以大大增加內容的分享率。而Next.js提供的元數據API,讓這一切變得簡單而直接。
在構建一個動態且互動性強的網站時,頁面間的導航是不可或缺的一環。Next.js 為此提供了非常便利的解決方案——Link 組件和 useRouter 鉤子,讓客戶端導航變得既簡單又高效。
Link 組件是 Next.js 中用于實現路由跳轉的主要方式,它基于 HTML 的 <a> 元素進行了擴展,使得在 Next.js 應用中的路由之間進行導航變得非常簡便。使用 Link 組件時,你只需要導入它并指定 href 屬性為目標路徑即可:
import Link from "next/link";
<Link href="/blog">博客</Link>
有時候,我們需要在代碼中根據某些條件或邏輯來動態導航到不同的頁面,這時就可以使用 Next.js 提供的 useRouter 鉤子。useRouter 允許你訪問路由對象,通過這個對象,你可以控制應用的路由行為,例如進行頁面跳轉。
以下是一個使用 useRouter 進行程序化導航的示例:
import { useRouter } from "next/router";
const MyComponent=()=> {
const router=useRouter();
const handleClick=()=> {
console.log("下單");
router.push("/"); // 使用 router.push 方法跳轉到首頁
};
return (
<button onClick={handleClick}>下單</button>
);
}
在這個例子中,當用戶點擊“下單”按鈕時,handleClick 函數會被觸發,然后應用會使用 router.push("/") 代碼來跳轉到首頁。這種方式非常適合在用戶完成某些操作后需要自動跳轉頁面的場景。
無論是通過 Link 組件還是 useRouter 鉤子進行導航,Next.js 都為開發者提供了極大的便利和靈活性。通過這些工具,你可以輕松地在你的應用中實現復雜的導航邏輯,為用戶提供流暢且富有互動性的網頁體驗。
在構建現代Web應用時,開發者常常需要在多個頁面之間共享某些布局或樣式。Next.js的模板(Templates)功能就是為此而生。模板類似于布局(Layouts),它們都可以包裹每個子布局或頁面。但模板和布局在功能上有一定的差異,特別是在處理頁面導航時。
模板的特性
當用戶在共享同一模板的不同路由之間導航時,模板會呈現一些獨特的行為:
定義模板
定義模板非常簡單,你只需要創建一個默認導出的React組件,這個組件可以從template.js或template.tsx文件中導出。這個組件通常會接受children作為其屬性,并在其內部渲染這些子元素:
export default function Template({ children }: { children: React.ReactNode }) {
return <div>{children}</div>
}
模板使用場景
模板特別適合于那些需要在多個頁面之間共享相同布局,但又希望在每次頁面跳轉時能夠完全重置狀態和DOM的場景。這可以確保用戶在不同頁面間導航時,能夠獲得一致且干凈的體驗,而不必擔心前一個頁面的狀態影響到當前頁面。
通過明智地使用模板,你可以在保持代碼組織和復用性的同時,為用戶提供流暢且一致的瀏覽體驗。
loading.tsx 文件在 Next.js 應用中扮演著特別的角色,它允許開發者為特定路由段創建加載狀態,這些加載狀態在內容加載時展示給用戶。使用 loading.tsx 可以有效地提升用戶體驗,特別是在網絡環境較差或內容較多需要較長時間加載的場景下。
創建加載狀態
在 loading.tsx 文件中,你可以定義一個或多個加載狀態的 React 組件。這些組件可以是簡單的動畫,如旋轉的加載指示器,或者更復雜的占位符布局,如骨架屏。
// loading.tsx
export default function Loading() {
return (
<div className="loading-container">
<p>內容加載中,請稍候...</p>
{/* 這里可以添加加載動畫或圖標 */}
</div>
);
}
使用加載狀態
當用戶導航到一個新的路由段,而這個路由段的內容還在加載時,你定義的加載狀態會立即顯示給用戶。這提供了一個視覺反饋,讓用戶知道應用正在響應其操作,并且內容正在積極加載中。這樣可以避免用戶在看到空白頁面時感到困惑或者認為應用出現了問題。
提升用戶體驗
利用 loading.tsx 實現的加載狀態可以大大提升應用的用戶體驗:
在設計加載狀態時,重要的是要保持它的簡潔和與應用整體風格的一致性。加載狀態不僅是一種功能性需求,也是提升品牌體驗和應用專業度的機會。
在構建現代web應用時,有效地管理和響應錯誤是至關重要的。Next.js 通過文件系統層次結構中的 error.tsx 文件,為開發者提供了一種靈活而強大的方式來創建和管理錯誤UI,以及處理特定路由段的錯誤。
創建針對性的錯誤UI
通過在應用的不同路由級別添加 error.tsx 文件,你可以為這些路由定制特定的錯誤處理UI。這種方法使得在用戶遇到錯誤時,能夠展示更具體、更友好的錯誤消息和恢復選項,而不是一個通用的錯誤頁面。
// 使用 'use client' 來指明這些錯誤組件必須是客戶端組件
'use client';
import { useEffect } from 'react';
export default function Error({
error,
reset,
}: {
error: Error & { digest?: string };
reset: ()=> void;
}) {
useEffect(()=> {
// 將錯誤記錄到錯誤報告服務中
console.error(error);
}, [error]);
return (
<div>
<h2>出錯了!</h2>
<button onClick={()=> reset()}>
重試
</button>
</div>
);
}
隔離錯誤影響
將 error.tsx 文件放置于應用的不同級別,能夠幫助你更精確地控制錯誤的影響范圍。例如,在特定的路由段出現錯誤時,只有那部分內容會展示錯誤信息,應用的其他部分仍然可以正常工作。這樣既提高了應用的魯棒性,也優化了用戶體驗。
錯誤恢復功能
在 error.tsx 中,你可以提供恢復功能,如重試按鈕,允許用戶嘗試從錯誤中恢復,而無需重新加載整個頁面。這種快速響應錯誤并嘗試恢復的能力,對于保持應用的交互性和用戶滿意度至關重要。
嵌套路由中的錯誤處理
通過在嵌套的文件夾結構中不同級別放置 error.tsx 文件,你可以實現更細粒度的錯誤處理。這意味著,你可以為應用中的不同部分定制不同的錯誤處理策略和UI,使錯誤處理更加靈活和用戶友好。
這種方法利用了Next.js的文件系統路由和組件模型,提供了一種既簡潔又強大的錯誤處理機制,幫助開發者構建更加可靠和用戶友好的應用。
Next.js 的并行路由是一種高級路由機制,允許在同一布局中同時渲染多個頁面,極大地增強了頁面布局和內容管理的靈活性。通過使用名為“插槽(slots)”的功能,開發者可以以模塊化的方式組織內容。
定義插槽
要定義一個插槽,我們使用 @folder 命名約定。然后,每個插槽作為屬性傳遞給其對應的 layout.tsx 文件。
以儀表盤為例,你可以使用并行路由同時渲染用戶、收入和通知頁面:
// dashboard/layout.tsx
export default function DashboardLayout({
children,
users,
revenue,
notifications
}: {
children: React.ReactNode;
users: React.ReactNode;
revenue: React.ReactNode;
notifications: React.ReactNode;
}) {
return (
<>
<div>{children}</div>
<div>{users}</div>
<div>{revenue}</div>
<div>{notifications}</div>
</>
);
}
并行路由的一個優勢是它們能夠將單個布局劃分為各種插槽,使代碼更易于管理。
獨立的路由處理
布局的每個插槽,例如用戶分析或收入指標,都可以有自己的加載和錯誤狀態。在不同頁面部分以不同速度加載或遇到獨特錯誤的場景中,這種細粒度的控制尤其有益。
路由內的子導航
你的儀表盤的每個插槽都可以實質上作為一個小應用程序運行,完備自己的導航和狀態管理。這在諸如儀表盤這樣的復雜應用中特別有用,不同部分服務于不同的目的。
//dashboard/@notifications/page.tsx
export default function Notifications() {
return (
<div>通知</div>
<Link href="/dashboard/">歸檔</Link>
);
};
//dashboard/@notifications/archieved/page.tsx
export default function ArchivedNotifications() {
return (
<div>歸檔通知</div>
<Link href="/dashboard/">默認</Link>
);
};
這種結構不僅提升了代碼的模塊化和可讀性,而且還增強了用戶界面的交互性,使用戶能夠在儀表盤的不同部分之間流暢地導航,同時各部分能夠獨立地加載和處理數據。這樣的設計思想,為構建復雜且高效的Web應用提供了新的可能性。
通過今天的分享,我們了解了Next.js并行路由的強大之處,以及它如何使我們能夠構建更加動態和響應式的Web應用。這項技術不僅提高了應用的性能和用戶體驗,還讓代碼的組織和維護變得更加高效。
在這信息爆炸的時代,我始終致力于探索前端技術的最新動態,為你帶來更多的技術干貨。如果你對今天的內容感興趣,不妨點贊、關注、轉發,并在評論區留下你的看法和問題。我非常期待你的反饋和互動!
此外,不要忘了關注「前端達人」,我將不定期分享更多關于前端開發的技術文章、教程和最佳實踐。讓我們一起在前端的道路上不斷進步,探索更多可能性!
者|Next.js 團隊
譯者|無明
出處丨前端之巔
在經過 26 次金絲雀發布和 340 萬次下載之后,近日,我們正式發布了 Next.js 7.0,新功能包括:
Next.js 的主要目標之一是提供最佳的性能和開發者體驗。最新版本為構建和調試管道帶來了很多重大改進。
得益于 Webpack 4 和 Babel 7,以及我們對代碼庫做出的很多改進和優化,Next.js 現在在開發過程中的啟動速度提高了 57%。
我們新增了增量編譯緩存,讓變更代碼的構建速度快了 40%。
以下是我們收集的一些示例數據:
因為使用了 webpackbar,在開發和構建的同時可以看到更好的實時反饋:
使用 react-error-overlay 更好地報告錯誤
準確地渲染錯誤對于良好的開發和調試體驗來說是至關重要的。到目前為止,我們可以渲染錯誤消息和堆棧跟蹤信息。我們在此基礎上更進一步,我們使用 react-error-overlay 來豐富堆棧跟蹤信息:
這是之前和之后的錯誤顯示比較:
另外,借助 react-error-overlay,你只需單擊特定代碼塊就可以輕松打開文本編輯器。
從發布第一個版本以來,Next.js 一直使用 Webpack 來打包代碼和重用豐富的插件。Next.js 現在使用了最新的 Webpack 4,其中包含很多改進和 bug 修復。
另一個新功能是支持 WebAssembly,Next.js 甚至可以進行 WebAssembly 服務器渲染。
這里有一個例子:
https://github.com/zeit/next.js/tree/canary/examples/with-webassembly
因為使用了 Webpack 4,我們引入了一種從捆綁包中提取 CSS 的新方法,這個插件叫作 mini-extract-css-plugin(https://github.com/webpack-contrib/mini-css-extract-plugin)。
mini-extract-css-plugin 提供了 @zeit/next-css、@zeit/next-less、@zeit/next-sass 和 @zeit/next-stylus。
這些 Next.js 插件的新版本解決了與 CSS 導入相關的 20 個問題,例如,現在支持 import() 動態導入 CSS:
// components/my-dynamic-component.js import './my-dynamic-component.css' export default ()=> <h1>My dynamic component</h1> // pages/index.js import dynamic from 'next/dynamic' const MyDynamicComponent=dynamic(import('../components/my-dynamic-component')) export default ()=> <div> <MyDynamicComponent/> </div>
一個重大改進是現在不再需要在 pages/_document.js 中添加一下內容:
<link rel="stylesheet" href="/_next/static/style.css" />
Next.js 會自動注入這個 CSS 文件。在生產環境中,Next.js 還會自動向 CSS URL 中添加內容哈希,當文件發生變更時,最終用戶就不會得到舊文件,并且能夠獲得不可變的永久緩存。
簡而言之,要在 Next.js 項目中支持導入.css 文件,只需要在 next.config.js 中注冊 withCSS 插件:
const withCSS=require('@zeit/next-css') module.exports=withCSS({/* my next config */})
從版本 3 開始,Next.js 就通過 next/dynamic 來支持動態導入。
作為這項技術的早期采用者,我們必須自己編寫解決方案來處理 import()。
因此,Next.js 逐漸缺失 Webpack 后來引入的一些功能,包括 import()。
例如,無法手動命名和捆綁某些文件:
import(/* webpackChunkName: 'my-chunk' */ '../lib/my-library')
另一個例子是在 next/dyanmic 模塊之外使用 import()。
從 Next.js 7 開始,我們不再直接使用默認的 import(),Next.js 為我們提供了開箱即用的 import() 支持。
這個變更也是完全向后兼容的。使用動態組件非常簡單:
import dynamic from 'next/dynamic' const MyComponent=dynamic(import('../components/my-component')) export default ()=> { return <div> <MyComponent /> </div> }
這段代碼的作用是為 my-component 創建一個新的 JavaScript 文件,并只在渲染< MyComponent/>時加載它。
最重要的是,如果沒有進行渲染,< script>標記就不會出現在初始 HTML 文檔中。
為了進一步簡化我們的代碼庫并利用優秀的 React 生態系統,在 Next.js 7 中,我們使用 react-loadable 重寫了 next/dynamic 模塊。這為動態組件引入了兩個很棒的新特性:
Next.js 6 中就已經引入了 Babel 7 測試版。后來 Babel 7 穩定版本發布,現在,Next.js 7 正在使用這個新發布的穩定版 Babel 7。
一些主要特性:
如果你的 Next.js 項目中沒有自定義 Babel 配置,那么就不存在重大變更。
但如果你具有自定義 Babel 配置,則必須將相應的自定義插件 / 預設升級到最新版本。
如果你從 Next.js 6 以下的版本升級,可以使用 babel-upgrade 工具。
除了升級到 Babel 7 之外,當 NODE_ENV 被設置為 test 時,Next.js Babel 預設(next/babel)現在默認將 modules 選項設置為 commonjs。
這個配置選項通常是在 Next.js 項目中創建自定義.babelrc 的唯一理由:
{ "env": { "development": { "presets": ["next/babel"] }, "production": { "presets": ["next/babel"] }, "test": { "presets": [["next/babel", { "preset-env": { "modules": "commonjs" } }]] } } }
使用 Next.js 7,這將變成:
{ "presets": ["next/babel"] }
現在可以刪除.babelrc,因為在沒有 Babel 配置時,Next.js 將自動使用 next/babel。
Next.js 在預渲染 HTML 時會將頁面內容放在< html>、< head>、< body>結構中,并包含頁面所需的 JavaScript 文件。
這個初始載荷之前約為 1.62kB。在 Next.js 7 中,我們優化了初始 HTML 載荷,現在為 1.5kB,減少了 7.4%,讓頁面變得更加精簡。
我們主要通過以下幾種方式來縮小文件:
在 Next.js 5 中,我們引入了 assetPrefix 支持,讓 Next.js 可以自動從某個位置(通常是 CDN)加載資源。如果你的 CDN 支持代理,可以使用這種辦法。你可以像這樣請求資源:
https://cdn.example.com/_next/static/<buildid>/pages/index.js
通常,CDN 先檢查緩存中是否包含這個文件,否則直接從源中請求文件。
不過,某些解決方案需要將目錄直接預先上傳到 CDN 中。這樣做的問題在于 Next.js 的 URL 結構與.next 文件夾中的文件夾結構不匹配。例如我們之前的例子:
https://cdn.example.com/_next/static/<buildid>/pages/index.js // 映射到: .next/page/index.js
在 Next.js 7 中,我們改變了.next 的目錄結構,讓它與 URL 結構相匹配:
https://cdn.example.com/_next/static/<buildid>/pages/index.js // 映射到: .next/static/<buildid>/pages/index.js
盡管我們建議使用代理類型的 CDN,但新結構也允許不同類型 CDN 的用戶將.next 目錄上傳到 CDN。
我們也引入了 styled-jsx 3,Next.js 的默認 CSS-in-JS 解決方案,現在已經為 React Suspense 做好了準備。
如果一個組件不屬于當前組件作用域的一部分,那么該如何設置這個子組件的樣式呢?例如,如果你將一個組件包含在父組件中,并只有當它被用在父組件中時才需要特定的樣式:
const ChildComponent=()=> <div> <p>some text</p> </div> export default ()=> <div> <ChildComponent /> <style jsx>{` p { color: black } `}</style> </div>
上面的代碼試圖選擇 p 標簽,但其實不起作用,因為 styled-jsx 樣式被限定在當前組件,并沒有泄漏到子組件中。解決這個問題的一種方法是使用:global 方法,將 p 標記的前綴移除。但這樣又引入了一個新問題,即樣式泄露到了整個頁面中。
在 styled-jsx 3 中,通過引入一個新的 API css.resolve 解決了這個問題,它將為給定的 syled-jsx 字符串生成 className 和< style>標簽(styles 屬性):
import css from 'styled-jsx/css' const ChildComponent=({className})=> <div> <p className={className}>some text</p> </div> const { className, styles }=css.resolve`p { color: black }` export default ()=> <div> <ChildComponent className={className} /> {styles} </div>
這個新 API 可以將自定義樣式傳給子組件。
由于這是 styled-jsx 的主要版本,如果你使用了 styles-jsx/css,那么在捆綁包大小方面有一個重大變化。在 styled-jsx 2 中,我們將生成外部樣式的“scoped”和“global”版本,即使只使用“scoped”版本,我們也會將“global”版本包含在內。
使用 styled-jsx 3 時,全局樣式必須使用 css.global 而不是 css,這樣 styled-jsx 才能對包大小進行優化。
App 和 Page 之間的 React Context(服務器端渲染)
從 Next.js 7 開始,我們支持 pages/_app.js 和頁面組件之間的 React Context API。
以前,我們無法在服務器端的頁面之間使用 React 上下文。原因是 Webpack 保留了內部緩存模塊而不是使用 require.cache,我們開發了一個自定義 Webpack 插件來改變這種行為,以便在頁面之間共享模塊實例。
這樣我們不僅可以使用新的 React 上下文,在頁面之間共享代碼時還能減少 Next.js 的內存占用。
從 Next.js 首次發布以來,就已獲得相當多的用戶,從財富 500 強公司到個人博客。我們非常高興看到 Next.js 的采用量一直在增長。
目前,超過 12,500 個被公開索引的域名在使用 Next.js。我們有超過 500 名貢獻者,他們至少提交過一次代碼。在 GitHub 上,這個項目已經有 29,000 個 star。自首次發布以來,已提交了大約 2200 個拉取請求。
Next.js 社區在 spectrum.chat/next-js 上擁有近 2000 名成員。
英文原文
https://nextjs.org/blog/next-7
*請認真填寫需求信息,我們會在24小時內與您取得聯系。