接觸了react很長一段時(shí)間,終于有時(shí)間給我接觸到實(shí)際的項(xiàng)目當(dāng)中,雖然只是個(gè)entry task
癣籽,我希望能夠?qū)⒃趘ue所學(xué)到的優(yōu)化點(diǎn)都運(yùn)用到react上方灾。首先選型肯定是next.js,它是一個(gè)輕量級的服務(wù)端渲染框架讼渊。在現(xiàn)在node服務(wù)端橫行的年代动看,首屏直出的效果是非常重要的,除了seo的要求外爪幻,用戶體驗(yàn)的提升是非常明顯的菱皆。
這里直出分為:
- 靜態(tài)直出(靜態(tài)化)
- 動態(tài)直出(服務(wù)端渲染)
- 預(yù)渲染(prerender-spa-plugin)
其中,靜態(tài)直出和動態(tài)直出是利用react的renderToNodeStream或者vue的renderToString的api實(shí)現(xiàn)了將dom監(jiān)控直出到node端挨稿,可以動態(tài)實(shí)時(shí)渲染數(shù)據(jù)(其中會有秒級cache)或者靜態(tài)化渲染仇轻。預(yù)渲染則是采用puppeteer在構(gòu)建時(shí)將首屏的dom結(jié)構(gòu)提前抓取下來構(gòu)造成為html。其中靜態(tài)化渲染效果應(yīng)該和預(yù)渲染效果是接近的奶甘,都是html的內(nèi)容是死的篷店,而非數(shù)據(jù)真實(shí)動態(tài)數(shù)據(jù)。靜態(tài)化廣泛運(yùn)用在vuepress和gatsby臭家,這種技術(shù)更多是服務(wù)于博客或者網(wǎng)站官網(wǎng)疲陕。
相比之下方淤,動態(tài)直出在列表渲染等因?yàn)橛脩魯?shù)據(jù)動態(tài)變化的頁面有著它天然的優(yōu)勢。
為什么說next.js是輕量級框架蹄殃?它的出現(xiàn)有著漸進(jìn)式的感覺携茂。阿里出了umijs企業(yè)級插件化前端框架,但是太過于繁瑣窃爷,不適合新手上手邑蒋。next.js的插件化目的性更加明確。以下是next.js的官方插件按厘,可以很輕易的接入css modules
医吊、typescript
等。在ssr的框架里面算是非常友善逮京,可以有非常豐富的examples卿堂。
- @zeit/next-mdx
- @zeit/next-css
- @zeit/next-sass
- @zeit/next-less
- @zeit/next-stylus
- @zeit/next-preact
- @zeit/next-typescript
- @zeit/next-bundle-analyzer
- @zeit/next-source-maps
- @zeit/next-workers
如何快速從零構(gòu)建構(gòu)建next.js
首先初始化項(xiàng)目,安裝三個(gè)依賴懒棉,配置npm script
草描,框架已經(jīng)搭建完成。其中策严,next
用于開發(fā)環(huán)境的調(diào)試穗慕。next build
用于構(gòu)建服務(wù)端資源。將資源移交到服務(wù)器后妻导,next start
命令啟動node服務(wù)逛绵。next export
是用于靜態(tài)化資源,靜態(tài)化的資源可以用于降級倔韭。
yarn add next react react-dom
{
"scripts": {
"dev": "next",
"build": "next build",
"start": "next start",
"export": "next export"
}
}
這時(shí)需要建個(gè)\pages
的文件夾术浪,里面新建文件index.js
,寫入react組件寿酌,組件會自動注入到SPA當(dāng)中胰苏。其中pages是一個(gè)目錄,所有的頁面都會根據(jù)文件的存放格式自動生成路由醇疼,這也免去了react-router的干擾硕并。
export default () => <div>Welcome to next.js!</div>
項(xiàng)目的從一到十
掘金有一篇文章Next.js踩坑入門系列。我讀完這個(gè)系列后秧荆,發(fā)現(xiàn)這些文章果然有坑鲤孵。我在這里幫忙填坑。項(xiàng)目的頁面Layout配置辰如,并非生成組件去完成,而是可以通過自定義重寫pages目錄當(dāng)中的_app.js
和_document.js
贵试。這些都屬于next.js走向高階的必經(jīng)之路琉兜。例如凯正,_app.js的重寫就由以下幾個(gè)優(yōu)點(diǎn),額外next提供了getInitialProps
的生命周期豌蟋,完成服務(wù)端數(shù)據(jù)的獲取工作廊散,這部分代碼是跑在服務(wù)端,而且每個(gè)頁面組件一樣存在getInitialProps
的生命周期(這里不用擔(dān)心像vue一樣created的生命周期是走在服務(wù)端)梧疲。
- 保持頁面間跳轉(zhuǎn)的功能允睹,不同頁面會走一樣的生命周期
- 頁面間跳轉(zhuǎn)時(shí)候保持state
- 全局錯(cuò)誤處理
- 額外的插件處理(例如mobx的引入)
//_app.js
import React from 'react';
import App, { Container } from 'next/app';
class MyApp extends App {
static async getInitialProps({ Component, ctx }) {
let pageProps = {};
if (Component.getInitialProps) {
pageProps = await Component.getInitialProps(ctx);
}
return { pageProps };
}
render() {
const { Component, pageProps } = this.props;
return (
<Container>
<Component {...pageProps} />
</Container>
);
}
}
export default MyApp;
這時(shí)候,有人會問幌氮,如果要內(nèi)聯(lián)一些腳本缭受,自定義引用外部css或js,seo要加入meta標(biāo)簽要怎么辦该互?
這時(shí)_document.js
需要被重寫米者,next
還提供了Head
組件方便你自定義<head>,并且可以把<html>, <body>等重寫宇智。
// ./pages/_document.js
import Document, { Html, Head, Main, NextScript } from 'next/document';
class MyDocument extends Document {
static async getInitialProps(ctx) {
const initialProps = await Document.getInitialProps(ctx);
return { ...initialProps };
}
render() {
return (
<Html>
<Head>
<style>{`body { margin: 0 } /* custom! */`}</style>
</Head>
<body className="custom_class">
<Main />
<NextScript />
</body>
</Html>
);
}
}
export default MyDocument;
有了這兩個(gè)自定義方案蔓搞,很多場景都可以被自定義,項(xiàng)目也可以靈活起來随橘。
項(xiàng)目的從十到百
需要各位同學(xué)的實(shí)戰(zhàn)和研究喂分,next.js/examples有大量值得學(xué)習(xí)的栗子,可供借鑒模仿机蔗,我相信很多代碼模仿能力好的同學(xué)絕對不會錯(cuò)過蒲祈。
也可以通過執(zhí)行create-next-app
的命令來了解例子。
npx create-next-app --example with-typescript with-typescript-app
# or
yarn create next-app --example with-typescript with-typescript-app
題外話
shopee蜒车,又稱蝦皮讳嘱,是一家騰訊投資的跨境電商平臺。這里加班少酿愧,技術(shù)氛圍好沥潭。如果想和我并肩作戰(zhàn)一起學(xué)習(xí),可以找我內(nèi)推嬉挡。郵箱weiping.xiang@shopee.com钝鸽,非誠勿擾。