<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Next.js + TypeScript 搭建一個簡易的博客系統(tǒng)

          共 11174字,需瀏覽 23分鐘

           ·

          2020-10-16 02:07


          最近想攻關(guān)一個 node.js 框架。希望找到一個能夠幫我們把大部分事情都做好的框架,可以直接上手快速開發(fā)。不像傳統(tǒng)的 Express、Koa 需要配置大量中間件。按照這個想法,谷歌了一下就是 —— Next.js 了。最后完成了一個簡易的博客系統(tǒng),

          代碼地址: https://github.com/Maricaya/nextjs-blog

          預覽地址:http://121.36.50.175/

          不得不說 SSR 真香,幾乎沒有白屏時間,加載非常快。

          來記錄下學習(踩坑)的過程,這篇文章的代碼都在https://github.com/Maricaya/nextjs-blog-1啦。

          先來看看 Next.js 是什么吧。

          Next.js 是一個全棧框架

          Next.js 是一個輕量級的 React 服務(wù)端渲染應(yīng)用框架。

          它支持多種渲染方式:客戶端渲染、靜態(tài)頁面生成、服務(wù)端渲染。

          使用Next.js 實現(xiàn) SSR 是一件很簡單的事,我們完全可以不用自己去寫webpack等配置,Next.js 都幫我們做好了。

          弱項

          上面討論了 Next.js 的很多優(yōu)點,但每個框架都有不完美的地方,尤其是在 Node.js 社區(qū)。

          作為一個后端框架,Next.js 完全沒有提供操作數(shù)據(jù)庫的相關(guān)功能,只能自行搭配其他框架。(比如 Sequelize 或者 TypeORM)。

          也沒有提供測試相關(guān)功能,也需要自行搭配,可以選擇 Jest 或者 Cypress。

          現(xiàn)在我們基本了解了 Next.js,接下來跟著官網(wǎng)做一個簡單的項目吧。

          創(chuàng)建項目

          #?nextjs-blog-1?是我們的項目名稱
          npm?init?next-app?nextjs-blog-1

          選擇 Default starter app。

          進入 nextjs-blog-1,用命令行啟動項目 yarn dev

          看到下面這個頁面?,就說明你的項目啟動成功啦。

          下面我們?yōu)轫椖考由?TypeScript!

          啟動 TypeScrip!

          第一步就是安裝 TypeScript。

          yarn?global?add?typescript

          創(chuàng)建 tsconfig.json

          然后我們運行 tsc \--init,得到 tsconfig.json,這是 TypeScript 的配置文件。

          接下來安裝類型聲明文件,然后重啟項目。

          yarn?add?--dev?typescript?@types/react?@types/node
          yarn?dev

          然后我們將文件名 index.js 改為 index.tsx。

          創(chuàng)建第一篇文章

          根目錄下創(chuàng)建 posts 文件夾,我們的文章放在這個路徑下。

          創(chuàng)建 posts/first-post.tsx 文件,寫入代碼:

          //?第一篇文章
          import?React?from?"react"
          import?{NextPage}?from?'next';

          const?FirstPost:?NextPage?=?()?=>?{
          ??return?(
          ????
          First?Post</div>
          ??)
          }
          export?default?FirstPost;

          這個時候訪問 http://localhost:3000/hosts/first-post 就能看見頁面了。

          Link 快速導航

          官網(wǎng)中介紹了 Link 快速導航。

          稍微了解前端同學們可能會有這樣的問題,不是有 a 標簽可以導航嗎,Next.js 為什么要多此一舉。

          據(jù)官網(wǎng)介紹,Link 可以實現(xiàn)快速導航。我們來做個實驗,看看它和 a 標簽有什么不同。

          先在項目分別中使用 a 標簽、Link 標簽導航,實現(xiàn)首頁和第一篇文章互相跳轉(zhuǎn)。

          index.tsx

          <h1?className="title">
          ??第一篇文章
          ????<a?href="/posts/first-post">a?點擊這里a>
          ????<Link?href="/posts/first-post"><a?>link?點擊這里a>Link>
          h1>

          /posts/first-post.tsx

          //?回到首頁
          <hr/>
          <a?href="/">a?點擊這里a>
          <Link><a?href="/">link?點擊這里a>Link>

          點擊 a 標簽,每次進入 first-post、index 頁面,瀏覽器都會重新請求所有的 html、css、js。

          接下來使用 Link 標簽導航,神奇的事情發(fā)生了,瀏覽器只發(fā)送了 2 個請求。

          第二個請求是 webpack,所以真實的請求只有 1 個,就是 first-post.js。

          反復在兩個頁面中跳轉(zhuǎn),除了 webpack,瀏覽器沒有發(fā)出任何請求。

          Next.js 到底做了什么?快速導航和傳統(tǒng)導航有什么區(qū)別?

          傳統(tǒng)導航

          我們先來看看從 page1 到 page2,傳統(tǒng)導航是怎么實現(xiàn)的?

          訪問第一個頁面 page1 時,瀏覽器請求 html,然后依次加載 css、js。

          當用戶點擊 a 標簽,就重定向到 page2,瀏覽器請求 html,然后再次加載 css、js。

          Link 快速導航

          再看相同的過程,Next.js 中的快速導航是怎么實現(xiàn)的。

          首先訪問 page1,瀏覽器下載 html,然后依次加載 css、js。這些和傳統(tǒng)導航一樣。

          但是當用戶點擊 Link 標簽時, page1 會執(zhí)行一個 js,這個js 會對 Link 標簽進行解析,點擊 Link 之后請求 page2 的 page2.js,這個 page2.js 就是 page2 的 html+css+js。

          請求完 page2.js 之后,會回到 page1 的頁面,把 page2 的 html、css、js 更新到 page1 上。也就是把 page1 更新為 page2。

          所以,瀏覽器沒有親自訪問過 page2,而是 page1 通過 ajax 來獲取 page2 的內(nèi)容。

          優(yōu)點

          所以,Link 快速導航(客戶端導航)有這么多優(yōu)點:

          • 頁面不會刷新,用 AJAX 請求新頁面內(nèi)容。
          • 不會請求重復的 HTML、CSS、JS。
          • 自動在頁面插入新內(nèi)容,刪除舊內(nèi)容。
          • 因為省了一些請求和解析過程,所以速度極快。

          同構(gòu)代碼

          什么是同構(gòu)?

          同構(gòu)是指同開發(fā)一個可以跑在不同的平臺上的程序, 這里指 js 代碼可以同時運行在 node.js 的 web server 和瀏覽器中。

          也就是代碼運行在兩端。

          做個試驗,我們在組件里寫一句 console.log('aaa')

          結(jié)果 Node 控制臺、Chrome 控制臺都會打印出 aaa

          注意差異

          但并不是所有的代碼都會運行在兩端。

          比如需要用戶觸發(fā)的代碼,只會運行在瀏覽器端。

          我們的代碼也不能隨意編寫,必須保證在兩端都能運行。比如 window,在 Node.js 中沒有這個對象,就會報錯。

          優(yōu)點

          減少代碼開發(fā)量, 提高代碼復用量。

          • 一份代碼能同時跑在瀏覽器和服務(wù)器,因此代碼量減少了。
          • 業(yè)務(wù)邏輯也不需要在瀏覽器和服務(wù)端同時維護,減小了程序出錯的可能。

          全局配置 Head, Metadata, CSS

          Head

          title

          我們想讓頁面的 title 不同,應(yīng)該怎么配置?

          在 Head 中配置 title,Head 會幫我們寫入 title。


          我的博客

          Metadata

          meta 也是一樣

          <Head>
          ????<meta?name="viewport"?content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no,viewport-fit=cover"/>
          Head>

          但是目前 index.tsx 和 first-post.tsx 是兩個文件,難道要寫入兩遍嗎?有沒有統(tǒng)一寫入的方法?

          全局配置

          創(chuàng)建 pages/_app.js,從官網(wǎng)上抄下代碼,寫入我們的 tie然后重啟 yarn dev。

          export?default?function?App({?Component,?pageProps?})?{
          ??//?Component
          ??return?<div>
          <Component?{...pageProps}?/>
          div>

          }

          其中 Component 就是我們定義的 index 和 first-post;pageProps 是頁面的選項,目前是空對象。

          export default function App 是每個頁面的根組件。頁面切換時 App 不會銷毀,App 里面的組件會銷毀。我們可以用 App 保存全局狀態(tài)。

          CSS

          也是一樣,全局的 CSS 放在 _app.js 中。因為切頁面的時候 App 不會被銷毀,其他地方只能寫局部 CSS。

          imprort?'../styles/global.css'

          絕對引用

          寫相對路徑有點麻煩,能不能指定根目錄寫絕對路徑呢?翻了翻官網(wǎng),發(fā)現(xiàn) Next.js 提供了類似的功能。

          配置 tsconfig.json,定義根目錄。

          {
          ??"compilerOptions":?{
          ????"baseUrl":?"."
          ??}
          }

          重啟項目,就可以絕對引入 css 啦:

          imprort?'styles/global.css'

          靜態(tài)資源

          next 推薦放在 public/ 里,但是我并不推薦這種做法,因為不支持改文件名。

          有前端基礎(chǔ)的同學就知道,不支持改文件名,會影響我們的緩存策略。

          如果 public 中的靜態(tài)資源沒有加緩存,這樣每次請求資源都會去請求服務(wù)器,造成資源浪費。

          但是如果加了緩存,我們每次更新靜態(tài)資源就必須更新資源名稱,否則瀏覽器還是會加載舊資源。

          所以,我們在根目錄新建 /assets 來放置靜態(tài)資源,并且需要在 next.js 中配置 webpack。

          根據(jù)官網(wǎng),在根目錄創(chuàng)建 next.config.js,自定義 webpack 配置。

          圖片

          配置 image-loader

          配置 file-loader

          安裝 yarn add \--dev file-loader

          next.config.js

          module.exports?=?{
          ??webpack:?(config,?options)?=>?{
          ????config.module.rules.push({
          ??????test:?/\.(png|jpg|jpeg|gif|svg)$/,
          ??????use:?[
          ????????{
          ??????????loader:?'file-loader',
          ??????????options:?{
          ????????????//?img?路徑名稱.hash.ext
          ????????????//?比如?1.png?路徑名稱為
          ????????????//?_next/static/1.29fef1d3301a37127e326ea4c1543df5.png
          ????????????name:?'[name].[contenthash].[ext]',
          ????????????//?硬盤路徑
          ????????????outputPath:?'static',
          ????????????//?網(wǎng)站路徑是
          ????????????publicPath:?'_next/static'
          ??????????}
          ????????}
          ??????]
          ????})
          ????return?config
          ??}
          }

          直接使用 next-images

          如果不想自己配置,也可以直接使用 next-images。

          yarn?add?--dev?next-images

          next.config.js

          const?withImages?=?require('next-images')

          module.exports?=?withImages({
          ??webpack(config,?options)?{
          ????return?config
          ??}
          })

          使用方法


          TypeScript

          現(xiàn)在導入圖像的文件還是會報錯,因為我們使用了 TypeScript,而 Typescript 不知道如何解釋導入的圖像。

          next-images 很貼心地準備了圖像模塊的定義文件。

          所以,我們只需要在 next-env.d.ts 文件中添加 next-images 類型的引用就好啦。

          ///?

          更多的其他文件

          自己找到 loader,然后配置 next.config.js,或者看看有沒有封裝成 next 插件。

          這些屬于 webpack 的范圍,大家可以自己探索。這篇文章就不啰嗦了。

          Next.js API

          到現(xiàn)在為止,我們的 index 和 posts/first-post 都是 HTML 頁面。

          但實際開發(fā)中我們需要請求 /user、 /shops 等 API,它們返回的內(nèi)容是 JSON 格式的字符串。在 Next.js 中怎么實現(xiàn)呢?

          使用 Next.js 的 API 模式。

          使用 Next.js API

          demo

          API 的默認路徑為 /api/v1/xxx,我們新建一個測試接口 demo.ts 。

          在 api 目錄下的代碼只運行在 Node.js 里,不會運行在瀏覽器中。

          demo.tsx

          //?ts?就是加上了類型
          import?{NextApiHandler}?from?'next';

          const?Demo:NextApiHandler?=?(req,?res)?=>?{
          ????//?其他的操作和?js?一樣
          ??res.statusCode?=?200;
          ??res.setHeader('Content-Type',?'application/json');
          ??res.write(JSON.stringify({name:?'狗子'}));
          ??res.end();
          };

          export?default?Demo;

          訪問 http://localhost:3000/api/demo,得到數(shù)據(jù)。

          posts

          接下來我們完成一個正式博客 API,posts 接口。

          首先準備博客文件,根目錄下創(chuàng)建 markdown 文檔,寫入幾篇 md 格式的博客。

          然后我們借助 gray-matter 從 md 文件中解析數(shù)據(jù)。

          lib/posts.tsx 這個文件導出 JSON 數(shù)據(jù)。

          import?path?from?"path";
          import?fs,?{promises?as?fsPromise}?from?"fs";
          import?matter?from?"gray-matter";

          export?const?getPosts?=?async?()?=>?{
          ??const?markdownDir?=?path.join(process.cwd(),?'markdown');

          ??const?fileNames?=?await?fsPromise.readdir(markdownDir);

          ??const?x?=?fileNames.map(fileName?=>?{
          ????const?fullPath?=?path.join(markdownDir,?fileName);
          ????const?id?=?fileName.replace(fullPath,?'');
          ????const?text?=?fs.readFileSync(fullPath,?'utf8');
          ????const?{data:?{title,?date},?content}?=?matter(text);
          ????return?{
          ??????id,?title,?date
          ????}
          ??});
          ??console.log('x');
          ??console.log(x);
          ??return?x;
          };

          搞定了數(shù)據(jù),下面就簡單多了,posts API 接口直接從上面的代碼中獲取數(shù)據(jù),然后返回給前端即可。pages/api/posts.tsx

          import?{NextApiHandler}?from?'next';
          import?{getPosts}?from?'lib/posts';


          const?Posts:?NextApiHandler?=?async?(req,?res)?=>?{
          ??const?posts?=?await?getPosts();
          ??res.statusCode?=?200;
          ??res.setHeader('Content-Type',?'application/json');
          ??res.write(JSON.stringify(posts));
          ??res.end();
          };
          export?default?Posts;

          ps:Next.js 基于 Express,所以支持 Express 的中間件。如果有復雜的操作,可以借助 Express 中間件。

          Next.js 三種渲染方式

          下面我們來做前端部分,用三種渲染方式實現(xiàn)。

          客戶端渲染

          只在瀏覽器上執(zhí)行的渲染。

          也就是最原始的前端渲染方式,頁面在瀏覽器獲取到 JavaScript 和 CSS 等文件后開始渲染。路由是客戶端路由,也就是目前最常見的 SPA 單頁應(yīng)用。

          缺點

          但這種方式會造成兩個問題。一是白屏,目前解決方法是在 AJAX 得到相應(yīng)之前,頁面中先加入 Loading。二是 SEO 不友好,因為搜索引擎訪問頁面時,默認不會執(zhí)行 JS,只能看到 HTML,看不到 AJAX 請求的數(shù)據(jù)。

          代碼

          pages/posts/BSR.tsx

          import?{NextPage}?from?'next';
          import?axios?from?'axios';
          import?{useEffect,?useState}?from?"react";
          import?*?as?React?from?"react";

          type?Post?=?{
          ????id:?string,
          ????id:?string,
          ????title:?string
          }
          const?PostsIndex:?NextPage?=?()?=>?{
          ????//?[]?表示只在第一次渲染的時候請求
          ????const?[posts,?setPosts]?=?useState([]);
          ????const?[isLoading,?setIsLoading]?=?useState(false);
          ????useEffect(()?=>?{
          ????????setIsLoading(true);
          ????????axios.get('/api/posts').then(response?=>?{
          ??????????setPosts(response.data);
          ??????????setIsLoading(false);
          ????????},?()?=>?{
          ????????????setIsLoading(true);
          ????????})
          ????},?[]);
          ????return?(
          ????????

          ????????????

          文章列表</h1>
          ????????????{isLoading???
          加載中div>?:
          ????????????????posts.map(p?=>?
          ????????????????{p.id}
          ????????????</div>)}
          ????????div>
          ????)
          };

          export?default?PostsIndex;

          訪問 http://localhost:3000/posts/BSR,如果網(wǎng)絡(luò)不好,白屏時間很長。

          因為數(shù)據(jù)本來不在頁面上,通過 ajax 請求后渲染到頁面上。

          文章列表都是前端渲染的,我們稱之為客戶端渲染。

          靜態(tài)頁面生成(SSG) Static Site Generation

          我們做的博客網(wǎng)站,其實每個人看到的文章列表都是一樣的。

          那為什么還需要在每個人的瀏覽器上渲染一次呢?

          能不能直接在后端渲染好,瀏覽器直接請求呢?

          這樣的話,N 次渲染就變成了 1 次渲染,N 次客戶端渲染變成了 1 次靜態(tài)頁面生成。

          這個過程就叫做動態(tài)內(nèi)容靜態(tài)化

          優(yōu)缺點

          這種方式可以解決白屏問題、SEO 問題。

          但這種方式所有用戶請求的內(nèi)容都一樣,無法生成用戶相關(guān)內(nèi)容。

          代碼:getStaticProps 獲取 posts

          顯然,后端最好不要通過 AJAX 來獲取 posts。

          我們的數(shù)據(jù)就在文件夾里面,直接讀取數(shù)據(jù)就可以,沒必要發(fā)送 AJAX。

          那么,應(yīng)該如何獲取獲取 posts 呢?

          使用 Next.js 提供的方法 getStaticProps 導出數(shù)據(jù),NextPage 的 props 參數(shù)會自動獲取導出的數(shù)據(jù)。

          具體來看看代碼吧:

          SSG.tsx

          import?{GetStaticProps,?NextPage}?from?'next';
          import?{getPosts}?from?'../../lib/posts';
          import?Link?from?'next/link';
          import?*?as?React?from?'react';

          type?Post?=?{
          ??id:?string,
          ??title:?string
          }

          type?Props?=?{
          ??posts:?Post[];
          }
          //?props?中有下面導出的數(shù)據(jù)?posts
          const?PostsIndex:?NextPage?=?(props)?=>?{
          ??const?{posts}?=?props;
          ????//?前后端控制臺都能打印?->?同構(gòu)
          ??console.log(posts);
          ??return?(
          ????

          ??????

          文章列表</h1>
          ??????{posts.map(p?=>?
          ????????posts/${p.id}`}>
          ??????????
          ????????????{p.id}
          ??????????

          ????????
          ??????

          )}
          ????

          ??);
          };

          export?default?PostsIndex;
          //?實現(xiàn)SSG
          export?const?getStaticProps:?GetStaticProps?=?async?()?=>?{
          ??const?posts?=?await?getPosts();
          ??return?{
          ????props:?{
          ??????posts:?JSON.parse(JSON.stringify(posts))
          ????}
          ??};
          };

          訪問 http://localhost:3000/posts/SSG,頁面訪問成功。

          前端怎么不通過 AJAX 獲取數(shù)據(jù)?

          posts 數(shù)據(jù)我們只傳遞給了服務(wù)器,為什么在前端也能打印出來?

          我們來看看此時的頁面:

          現(xiàn)在前端不用 AJAX 也能拿到 posts 了,直接通過 __NEXT_DATA__ 獲取數(shù)據(jù)。這就是同構(gòu) SSR 的好處:后端數(shù)據(jù)可以直接傳給前端,前端 JSON.parse 一下子就能得到 posts。

          getStaticProps 靜態(tài)化的時機

          開發(fā)環(huán)境,每次請求都會運行一次 getStaticProps,這是為了方便我們修改代碼重新運行。

          而在生產(chǎn)環(huán)境,getStaticProps 只在 build 時運行,這樣可以提供一份 HTML 給所有用戶下載。

          來體驗下生產(chǎn)環(huán)境吧,打包我們的項目。

          yarn?build
          yarn?start

          打包之后,我們得到三種類型的文件:

          • λ (Server) SSR 不能自動創(chuàng)建 HTML(等會再說)

          • ○ (Static) 自動創(chuàng)建 HTML (發(fā)現(xiàn)你沒用到 props)

          • ● (SSG) 自動創(chuàng)建 HTML + JSON (等你用到 props)

          創(chuàng)建出了這三種文件:posts.html = posts.js + posts.json

          • posts.html 含有靜態(tài)內(nèi)容,用于用戶直接訪問
          • post.js 也含有靜態(tài)內(nèi)容,用于快速導航(與 HTML 對應(yīng))
          • posts.json 含有數(shù)據(jù),跟 posts.js 結(jié)合得到頁面

          那為什么不直接把數(shù)據(jù)放入 posts.js 呢?顯然,是為了讓 posts.js 接受不同的數(shù)據(jù)。

          當我們展示每篇博客的時候,他們的樣式相同,內(nèi)容不同,就會用到這個功能了。

          小結(jié)

          • 如果動態(tài)內(nèi)容與用戶無關(guān),那么可以提前靜態(tài)化。
          • 通過 getStaticProps 可以獲取數(shù)據(jù),靜態(tài)內(nèi)容 + 數(shù)據(jù)(本地獲取)就得到了完整頁面。代替了之前的 靜態(tài)內(nèi)容+動態(tài)數(shù)據(jù)(AJAX獲取)。
          • 靜態(tài)化是在 yarn build 的時候?qū)崿F(xiàn)的
          • 優(yōu)點
            • 生產(chǎn)環(huán)境直接給出完整頁面
            • 首屏不會白屏
            • 搜索引擎能看到頁面內(nèi)容(方便 SEO)

          服務(wù)端渲染(SSR)

          如果頁面跟用戶相關(guān)呢?這種情況較難提前靜態(tài)化。

          那怎么辦呢?

          • 要么客戶端渲染,下拉更新
          • 要么服務(wù)的渲染,下拉 AJAX 更新(沒有白屏

          優(yōu)點

          這種方式可以解決白屏問題、SEO 問題。可以生成用戶相關(guān)內(nèi)容(不同用戶結(jié)果不同)。

          代碼

          和 SSG 代碼基本一致,不過使用的函數(shù)換成 getServerSideProps。

          寫一段代碼,顯示當前用戶瀏覽器是什么。

          import?{GetServerSideProps,?NextPage}?from?'next';
          import?*?as?React?from?'react';
          import?{IncomingHttpHeaders}?from?'http';

          type?Props?=?{
          ??browser:?string
          }
          const?index:?NextPage?=?(props)?=>?{
          ??return?(
          ????

          ??????

          你的瀏覽器是?{props.browser}</h1>
          ????div>
          ??);
          };
          export?default?index;

          export?const?getServerSideProps:?GetServerSideProps?=?async?(context)?=>?{
          ??const?headers:IncomingHttpHeaders?=?context.req.headers;
          ??const?browser?=?headers['user-agent'];
          ??return?{
          ????props:?{
          ??????browser
          ????}
          ??};
          };

          getServerSideProps

          無論是開發(fā)環(huán)境還是生產(chǎn)環(huán)境,都是在請求到來之后運行 getServerSideProps。

          回顧一下 getStaticProps,看看他們的區(qū)別。

          • 開發(fā)環(huán)境,每次請求到來后運行,方便開發(fā)
          • 生產(chǎn)環(huán)境,build 時運行

          參數(shù)

          • context,類型為 NextPageContext
          • context.req/context.res 可以獲取請求和響應(yīng)
          • 一般只需要用到 context.req

          SSR 原理

          最后我們來看看 SSR 到底是怎么實現(xiàn)的。

          我們都知道 SSR 是提前渲染好靜態(tài)內(nèi)容,這些靜態(tài)內(nèi)容是在服務(wù)端渲染,還是在客戶端渲染的?

          具體渲染幾次呢?一次還是兩次?

          參考 React SSR 的官方文檔

          推薦 在后端調(diào)用 renderToString() 的方法,把整個頁面渲染成字符串。

          然后前端調(diào)用 hydrate() 方法,把后端傳遞的字符串和自己的實例混合起來,保留 HTML 并附上事件監(jiān)聽。

          以上就是 Next.js 實現(xiàn) SSR 的主要方法,也就是后端會渲染 HTML, 前端添加監(jiān)聽。

          前端也會渲染一次,以確保前后端渲染結(jié)果一致。如果結(jié)果不一致,控制臺會報錯提醒我們。

          總結(jié)

          • 創(chuàng)建項目 npm init next-app 項目名
          • 快速導航
          • 同構(gòu)代碼:一份代碼,兩端運行
          • 全局組件:pages/_app.js
            • 全局 CSS:在 _app.js 里 import
          • 自定義 head:使用 組件
          • Next.js API:都放在 /pages/api 目錄中
          • 三種渲染的方式:BSR、SSG、SSR
            • 動態(tài)內(nèi)容 術(shù)語:客戶端渲染,通過 AJAX 請求,渲染成 HTML。
            • 動態(tài)內(nèi)容靜態(tài)化 術(shù)語:SSG,通過 getStaticProps 獲取用戶無關(guān)內(nèi)容
            • 用戶相關(guān)動態(tài)內(nèi)容靜態(tài)化 術(shù)語:SSR,通過 getServerSideProps 獲取請求 缺點:無法獲取客戶端信息,如瀏覽器窗口大小
            • 靜態(tài)內(nèi)容 直接輸出 HTML,沒有術(shù)語。

          篇幅有限,更多可前往 https://github.com/Maricaya/nextjs-blog-1


          “在看和轉(zhuǎn)發(fā)”就是最大的支持
          瀏覽 45
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  免费黄色欧美 | 美女性爱网| 91精品国产福利在线观看 | 麻豆出品必是精品(3) | 少妇激情五月天 |