接觸了react很長一段時間,終于有時間給我接觸到實際的項目當(dāng)中,雖然只是個entry task,我希望能夠?qū)⒃趘ue所學(xué)到的優(yōu)化點都運用到react上。首先選型肯定是next.js,它是一個輕量級的服務(wù)端渲染框架。在現(xiàn)在node服務(wù)端橫行的年代,首屏直出的效果是非常重要的,除了seo的要求外,用戶體驗的提升是非常明顯的。
這里直出分為:
- 靜態(tài)直出(靜態(tài)化)
- 動態(tài)直出(服務(wù)端渲染)
- 預(yù)渲染(prerender-spa-plugin)
其中,靜態(tài)直出和動態(tài)直出是利用react的renderToNodeStream或者vue的renderToString的api實現(xiàn)了將dom監(jiān)控直出到node端,可以動態(tài)實時渲染數(shù)據(jù)(其中會有秒級cache)或者靜態(tài)化渲染。預(yù)渲染則是采用puppeteer在構(gòu)建時將首屏的dom結(jié)構(gòu)提前抓取下來構(gòu)造成為html。其中靜態(tài)化渲染效果應(yīng)該和預(yù)渲染效果是接近的,都是html的內(nèi)容是死的,而非數(shù)據(jù)真實動態(tài)數(shù)據(jù)。靜態(tài)化廣泛運用在vuepress和gatsby,這種技術(shù)更多是服務(wù)于博客或者網(wǎng)站官網(wǎng)。
相比之下,動態(tài)直出在列表渲染等因為用戶數(shù)據(jù)動態(tài)變化的頁面有著它天然的優(yōu)勢。
為什么說next.js是輕量級框架?它的出現(xià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
首先初始化項目,安裝三個依賴,配置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"
}
}
這時需要建個\pages的文件夾,里面新建文件index.js,寫入react組件,組件會自動注入到SPA當(dāng)中。其中pages是一個目錄,所有的頁面都會根據(jù)文件的存放格式自動生成路由,這也免去了react-router的干擾。
export default () => <div>Welcome to next.js!</div>
項目的從一到十
掘金有一篇文章Next.js踩坑入門系列。我讀完這個系列后,發(fā)現(xiàn)這些文章果然有坑。我在這里幫忙填坑。項目的頁面Layout配置,并非生成組件去完成,而是可以通過自定義重寫pages目錄當(dāng)中的_app.js和_document.js。這些都屬于next.js走向高階的必經(jīng)之路。例如,_app.js的重寫就由以下幾個優(yōu)點,額外next提供了getInitialProps的生命周期,完成服務(wù)端數(shù)據(jù)的獲取工作,這部分代碼是跑在服務(wù)端,而且每個頁面組件一樣存在getInitialProps的生命周期(這里不用擔(dān)心像vue一樣created的生命周期是走在服務(wù)端)。
- 保持頁面間跳轉(zhuǎn)的功能,不同頁面會走一樣的生命周期
- 頁面間跳轉(zhuǎn)時候保持state
- 全局錯誤處理
- 額外的插件處理(例如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;
這時候,有人會問,如果要內(nèi)聯(lián)一些腳本,自定義引用外部css或js,seo要加入meta標(biāo)簽要怎么辦?
這時_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;
有了這兩個自定義方案,很多場景都可以被自定義,項目也可以靈活起來。
項目的從十到百
需要各位同學(xué)的實戰(zhàn)和研究,next.js/examples有大量值得學(xué)習(xí)的栗子,可供借鑒模仿,我相信很多代碼模仿能力好的同學(xué)絕對不會錯過。
也可以通過執(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,非誠勿擾。