先說說先要搭建這個工具的原由吧!最近這段時間分別了學習Typescript和react服務端渲染,可是苦於沒有沒有實際使用端場景,我就忽然想起了將Typescript與Next結合起來搭建一個服務端渲染端工具,一是這樣便可以起到練手的做用,二是若是之後有相應業務需求能夠直接拿來用。話很少說,咱們開始吧!javascript
next.js做爲一款輕量級的應用框架,主要用於構建靜態網站和後端渲染網站,爲何選Next呢?,只因Next有以下幾個優勢:前端
這裏就很少說了,相信你們都很熟練了java
mkdir TAN
cd TAN
npm init -y
複製代碼
npm install react react-dom express next --save
npm install @types/{react,react-dom} --save-dev
複製代碼
export default () => <div>Welcome to next.js!</div>
複製代碼
{
...
"scripts": {
"dev": "next"
}
...
}
複製代碼
運行npm run dev命令打開 http://localhost:3000便可查看初始頁面。node
npm install typescript --save
複製代碼
@zeit/next-typescript 再也不須要,由於Next.js已內置支持Typescriptreact
{
"presets": [
"next/babel"
]
}
複製代碼
{
"compileOnSave": false,
"compilerOptions": {
"strict": true,
"target": "esnext",
"module": "esnext",
"jsx": "preserve",
"allowJs": true,
"moduleResolution": "node",
"allowSyntheticDefaultImports": true,
"experimentalDecorators": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"removeComments": false,
"preserveConstEnums": true,
"sourceMap": true,
"skipLibCheck": true,
"baseUrl": ".",
"typeRoots": [
"./node_modules/@types/",
],
"lib": [
"dom",
"es2015",
"es2016"
]
},
"exclude": ["node_modules"]
}
複製代碼
在上面的配置中,請注意: 使用「jsx」:「preserve」而不是react-native,由於Next.js在5.0.0以後支持.jsx文件擴展名,以前它只識別.js文件。webpack
{
"extends": ["tslint:latest"],
"rules": {
"arrow-parens": false,
"interface-name": [true, "never-prefix"],
"no-object-literal-type-assertion": false,
"no-submodule-imports": false,
"semicolon": [true, "never"],
"trailing-comma": [true, {"multiline": "nerver", "singleline": "never"}]
}
}
複製代碼
將page/index.js修改成index.tsx,並作以下修改git
interface Person {
name: String;
}
const Rashomon: Person = {
name: 'rashomon',
}
export default () => <div>{Rashomon.name}!</div>
複製代碼
const next = require('next');
const { createServer } = require('http');
const { parse } = require('url')
const dev = process.env.NODE_ENV !== 'production';
const port = parseInt(process.env.PORT, 10) || 3000;
const app = next({dev})
const handle = app.getRequestHandler()
app.prepare().then(() => {
createServer((req, res) => {
const parsedUrl = parse(req.url, true)
handle(req, res, parsedUrl)
}).listen(port, err => {
console.log(err, port)
if (err) throw err
console.log(`> Ready on http://localhost:${port}`)
})
})
複製代碼
更改package.json啓動命令 "dev": "node server.js", 運行npm run dev,你會發現提示一行錯誤:It looks like you're trying to use TypeScript but do not have the required package(s) installed.意思是試圖使用TypeScript,但沒有安裝所需的包。咱們只需運行下列命令便可github
npm install --save-dev @types/node
複製代碼
再次運行命令打開http://localhost:3000便可看到咱們的頁面。web
npm install antd --save
npm install babel-plugin-import --save-dev
複製代碼
{
"presets": [
"next/babel"
],
"plugins": [
["import", { "libraryName": "antd", "style": false }]
]
}
複製代碼
npm install less @zeit/next-less null-loader --save
複製代碼
const withLess = require('@zeit/next-less');
module.exports = withLess({
lessLoaderOptions: {
javascriptEnabled: true,
},
webpack: (config, { isServer }) => {
if (isServer) {
const antStyles = /antd\/.*?\/style.*?/
const origExternals = [...config.externals]
config.externals = [
(context, request, callback) => {
if (request.match(antStyles)) return callback()
if (typeof origExternals[0] === 'function') {
origExternals[0](context, request, callback)
} else {
callback()
}
},
...(typeof origExternals[0] === 'function' ? [] : origExternals),
]
config.module.rules.unshift({
test: antStyles,
use: 'null-loader',
})
}
return config
},
})
複製代碼
3.引入antd樣式
在page文件夾下新建index.less文件,引入antd樣式,並在index.tsx中引入,typescript
@import '~antd/dist/antd.less';
複製代碼
並在index.tsx中作以下修改
import {Button} from 'antd';
import './index.less'
interface Person {
name: String;
}
const Rashomon: Person = {
name: 'rashomon',
}
export default () => <Button type='primary'>{Rashomon.name}!</Button>
複製代碼
npm install less-vars-to-js --save
複製代碼
根目錄下新建assets文件並新建antd-custom.less
@primary-color: #08979c;
複製代碼
在next.config.js中讀取該樣式文件,通過less-vars-to-js將less文件的內容做爲字符串接收,並返回一個包含全部變量的對象。
next.config.js添加以下內容:
... // 添加內容
const lessToJS = require('less-vars-to-js');
const fs = require('fs');
const path = require('path');
// Where your antd-custom.less file lives
const themeVariables = lessToJS(
fs.readFileSync(path.resolve(__dirname, './assets/antd-custom.less'), 'utf8')
)
...
lessLoaderOptions: {
javascriptEnabled: true,
modifyVars: themeVariables,
},
···
複製代碼
運行啓動命令,頁面以下圖:
npm install redux react-redux next-redux-wrapper @types/react-redux --save
npm install redux-saga next-redux-saga @types/next-redux-saga --save
複製代碼
因爲篇幅關係建立store、reducers、saga、action的過程咱們就再也不這裏綴述,感興趣的同窗能夠查看github上的代碼。咱們在這裏着重講一下如何引入store,爲了在頁面初始化時引入store,須要自定義,在pages文件夾下新建_app.tsx.
_app.tsx幫咱們作以下幾件事:
所以,在pages文件下新建_app.tsx,引入store,代碼以下
import React from 'react'
import App from 'next/app';
import { Provider } from 'react-redux';
import Head from 'next/head'
import withRedux from 'next-redux-wrapper'
import withReduxSaga from 'next-redux-saga'
import Layout from '../components/Layout' // 頁面基礎佈局
import initStore from '../redux/store' // store
import '../static/style/index.less' // antd樣式
class MyApp extends App {
// next.js提供了一個標準的獲取遠程數據的接口:getInitialProps,經過getInitialProps咱們能夠獲取到遠程數據並賦值給頁面的props。
// getInitialProps便可以用在服務端也能夠用在前端
static async getInitialProps({ Component, ctx }: any) {
let pageProps = {};
if (Component.getInitialProps) {
pageProps = await Component.getInitialProps({ ctx });
}
return { pageProps };
}
render() {
const { Component, pageProps, store }: any = this.props
return (
<Provider store={store}> <Head> <title>Tarn</title> </Head> <Layout> <Component {...pageProps} /> </Layout> </Provider> ) } } export default withRedux(initStore)(withReduxSaga(MyApp)) 複製代碼
最終實現一個計數器與列表,以下圖:
404和500錯誤客戶端和服務端都會經過error.js組件處理。若是你想改寫它,則在pages文件下新建_error.js,當用戶訪問錯誤路由時會訪問_error頁面
import React from 'react'
export default class Error extends React.Component {
static getInitialProps({ res, err }) {
const statusCode = res ? res.statusCode : err ? err.statusCode : null;
return { statusCode }
}
render() {
return (
<p>
{this.props.statusCode
? `An error ${this.props.statusCode} occurred on server`
: 'An error occurred on client'}
</p>
)
}
}
複製代碼
到此爲止,咱們已經基本實現了一個基於Typescript+Ant-Design + Redux+Next.js的服務端渲染框架,也熟悉了一部分next的用法,想要了解更多能夠前往官網地址爲next.js。但願你們能夠有所收穫,想要了解更多不一樣技術實現的服務端渲染框架的同窗能夠看這裏github.com/zeit/next.j…
原文在這裏:gitHub 若有遺漏,還請指正!!
若是以爲對您有幫助!請別忘記點個贊或者關注哦!您的關注將是我前進的動力!!衝鴨!!!
「無畏前端」不定時更新社區優秀技術文章!