next.js 是一個很是棒的輕量級的react
同構框架,使用它能夠快速的開發出基於服務端渲染的react
應用。在next.js 官網推薦的是使用now
來部署應用,可是對於國內用戶或者說是有特殊需求的用戶來講,部署到自定義服務器也許是大多數人但願的。藉着近期公司官網改版,順便分享下本身從開發到部署過程當中所經歷的點點滴滴。javascript
依稀還記得第一次使用next.js 是在去年(2017年),那個時候使用的是next.js 2.x版本,react
仍是15版本,一年過去,如今react
已經發展到16版本,而next.js 已經發展到6.0版本了,迭代速度瞠目結舌,在使用新版本的過程當中也是遇到很多的坑。css
先說下此次用到了哪些技術,下面列舉了項目中主要用到的技術或工具庫。html
由express原班人馬開發的下一代web框架,用來提供web服務。前端
是一個高性能的HTTP和反向代理服務器,也是一個IMAP/POP3/SMTP服務器(摘自百度百科),由俄羅斯人開發。用來提供靜態文件服務、https證書、代理服務。java
一個javascript ui庫node
一個輕量級的react同構應用框架react
由螞蟻金服開發的基於
react的
一套中後臺產品組件庫webpack
基於
react
的動畫解決方案nginx
判斷組件是否在當前可視區的
react
組件git
一個帶有負載均衡功能的Node應用的進程管理器
同構WHATWG Fetch API
講了這麼多,讓咱們進入開發階段,第一步構建項目架構,這裏分享下本身的項目結構:
📁 .vscode
vscode
配置文件
📁 component
react組件
📁 common
公共部分,我放置的是導航欄信息、全局變量和全局樣式等等
📁 pages
項目全部頁面入口,也是next.js 各頁面入口文件
📁 static
靜態文件
📁 styles
各頁面樣式表
🗄 index.js
node啓動文件
🗄 .babelrc
babel配置文件
🗄 .gitignore
git 配置文件
🗄 ecosystem.config.js
pm2配置文件
🗄 next.config.js
next.js 配置文件
🗄 postcss.config.js
postcss 配置文件
🗄 nginx.conf
nginx配置文件
🗄 package.json
npm配置文件
在完成了項目結構配置以後,假設你已經在package.json
中保存了咱們所須要的全部依賴,讓咱們嘗試着輸入yarn
來安裝依賴。這裏假設安裝一切順利,下面繼續咱們的開發之旅。
首先,在pages
文件下新建一個index.js
,這裏就隨便從我真實項目中抽取部分代碼來做師範。
export default class HomePage extends React.Component {
static async getInitialProps({ req, pathname }) {
const data = await fetch(`${ctx}/api/projects/common/list`).then(res => res.json())
.then(dt => dt)
.catch(err => {
return {
success: false,
message: err.message
}
})
return { pathname,data };
}
render() {
const { pathname, data } = this.props;
return (
<div> <Head> <title>首頁-易科捷(武漢)生態科技有限公司</title> </Head> <div>Welcome to next.js!</div> {/*這裏省略代碼*/} </div>
);
}
}
複製代碼
若是你的package.json
中沒有配置next
啓動腳本,請訪問setup進行配置,下面咱們在控制檯運行npm run dev
,若是一切順利,打開瀏覽器,你將會看到Welcome to next.js!
在next.js
中開發體驗和react
幾乎沒有什麼區別,可是在webpack
配置這塊可能須要下點功夫。一些經常使用的插件像sass
、css
等, next.js
都已經給你提供了,你也可使用社區開源的插件來完成你的開發之旅。詳情請查看next.js官網。
在經歷了開發階段、測試等等一系列流程,如今終於等到了部署階段。在next.js
中生產階段打包只須要運行npm run build
便可,官方推薦不修改打包的文件夾名字(原名稱爲.next
),這裏我的推薦修改爲build
或者dist
這些名稱。在打包完成以後,須要編寫nodejs
啓動入口文件,下面貼出實例代碼:
const Koa = require('koa')
const next = require('next')
const Router = require('koa-router')
const port = parseInt(process.env.PORT, 10) || 3000
const dev = process.env.NODE_ENV !== 'production'
const app = next({ dev })
const handle = app.getRequestHandler()
app.prepare()
.then(() => {
const server = new Koa()
const router = new Router()
// 首頁
router.get('/', async ctx => {
await app.render(ctx.req, ctx.res, '/', ctx.query)
ctx.respond = false
})
// 關於
router.get('/about', async ctx => {
await app.render(ctx.req, ctx.res, '/about', ctx.query)
ctx.respond = false
})
// 產品
router.get('/products/:id', async ctx => {
const {id} = ctx.params
await app.render(ctx.req, ctx.res, `/products/${id}`, ctx.query)
ctx.respond = false
})
// 案例
router.get('/case', async ctx => {
await app.render(ctx.req, ctx.res, '/case', ctx.query)
ctx.respond = false
})
// 聯繫咱們
router.get('/contact', async ctx => {
await app.render(ctx.req, ctx.res, '/contact', ctx.query)
ctx.respond = false
})
// 詳情
router.get('/view/:type/:id', async ctx => {
const {id, type} = ctx.params
await app.render(ctx.req, ctx.res, `/view`, {id, type})
ctx.respond = false
})
// 若是沒有配置nginx作靜態文件服務,下面代碼請務必開啓
/* router.get('*', async ctx => { await handle(ctx.req, ctx.res) ctx.respond = false })*/
// 防止出現控制檯報404錯誤
server.use(async (ctx, next) => {
ctx.res.statusCode = 200
await next()
})
server.use(router.routes())
server.listen(port, () => {
console.log(`> Ready on http://localhost:${port}`)
})
})
複製代碼
通常的靜態文件、gzip壓縮無需交給nodejs
來作,我的一直認爲專業的事交給專業的人。這裏將該項任務轉移給nginx
,特別注意上面實例代碼中我註釋的部分代碼,若果你沒有使用nginx
來作靜態文件服務,請務必開啓,不然像next.js
打包出來的js
、css
、圖片文件等,都將報404
。
在next.js
生產打包階段打包出來的js
文件請求路徑中帶有版本號,而真實打包出來的文件夾卻沒有實際對應的目錄,也就是打包出來的是虛擬目錄,這裏若是使用nginx
就須要特別注意。好在next.js
提供配置項來修改build id
,如下是個人真實代碼:
// next.config.js
module.exports = {
generateBuildId: async () => {
// For example get the latest git commit hash here
return 'v1'
}
}
複製代碼
這樣打包出來的虛擬路徑大概是_next/v1/page/xxx.js
,若是你使用cdn
前綴,這裏有一點區別,可是版本號依然存在。
還有一個坑就是next.js
打包出來的有三個文件夾:bundles
、dist
、static
,對於不知道源碼的人來講,根本不知道實際請求文件在哪個文件夾。因而我就看next.js
源碼,發現其實找的是bundle
文件下的page
,源碼位置:L214
因此在配置nginx
就須要使用別名。下面給出一段個人nginx
真實配置代碼:
# 網站根目錄文件
location ~ ^/(robots.txt|humans.txt|favicon.ico|sw.js|baidu_verify_7Kj6tQjI3v.html) {
root /home/website/eco_website_pc/static/;
if ($request_filename ~* sw.js){
expires -1s;
}
expires 10m;
}
# static下的文件
location ^~ /static/ {
alias /home/website/eco_website_pc/static/;
if ($request_filename ~* sw.js){
expires -1s;
}
expires 10m;
}
# next pages頁面下的腳本
location ~ ^/(/_next/v1/) {
alias /home/website/eco_website_pc/build/bundles/;
if ($request_filename ~* sw.js){
expires -1s;
}
expires 10m;
}
# next static下的靜態文件
location ~ ^/(/_next/static/) {
root /home/website/eco_website_pc/build;
if ($request_filename ~* sw.js){
expires -1s;
}
expires 10m;
}
複製代碼
靜態文件配置好了就須要配置https
證書了,由於咱們此次項目是公司官網,證書我就本身去免費弄了一個,這裏我使用的freessl上面提供的亞洲誠信的證書。在申請完ssl
證書以後須要去域名提供商那裏去配置TXT
記錄,我這裏使用的是阿里雲,在完成驗證後,freessl將會下載證書,拿到該證書以後須要去配置nginx
ssl
證書,下面貼出個人完整配置:
server {
listen 80;
listen 443 ssl;
server_name wh-eco.com;
charset utf-8;
ssl_certificate /home/website/ssl/www/full_chain.pem;
ssl_certificate_key /home/website/ssl/www/private.key;
fastcgi_param HTTPS on;
fastcgi_param HTTP_SCHEME https;
if ($scheme = http ) {
return 301 https://$host$request_uri;
}
access_log /var/log/nginx/www.wh-eco.com.access.log;
error_log /var/log/nginx/www.wh-eco.com.error.log;
location / {
proxy_pass http://127.0.0.1:xxxx; #保密 0.0
proxy_set_header Host $host;
#proxy_redirect off;
proxy_set_header REMOTE-HOST $remote_addr;
# 網站可能後期會使用websocket 特次升級請求協議
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_connect_timeout 60;
proxy_read_timeout 600;
proxy_send_timeout 600;
}
# 網站根目錄文件
location ~ ^/(robots.txt|humans.txt|favicon.ico|sw.js|baidu_verify_7Kj6tQjI3v.html) {
root /home/website/eco_website_pc/static/;
if ($request_filename ~* sw.js){
expires -1s;
}
expires 10m;
}
# static下的文件
location ^~ /static/ {
alias /home/website/eco_website_pc/static/;
if ($request_filename ~* sw.js){
expires -1s;
}
expires 10m;
}
# next pages頁面下的腳本
location ~ ^/(/_next/v1/) {
alias /home/website/eco_website_pc/build/bundles/;
if ($request_filename ~* sw.js){
expires -1s;
}
expires 10m;
}
# next static下的靜態文件
location ~ ^/(/_next/static/) {
root /home/website/eco_website_pc/build;
if ($request_filename ~* sw.js){
expires -1s;
}
expires 10m;
}
error_page 500 502 503 504 = /error.html;
error_page 404 = /notfound.html;
location = /error.html {
root /home;
}
location = /notfound.html{
root /home;
}
}
複製代碼
至於gzip
你能夠根據你要求來作配置,貼一個個人示例配置:
gzip on;
gzip_comp_level 6;
gzip_vary on;
gzip_types
application/atom+xml
application/javascript
application/json
application/rss+xml
application/vnd.ms-fontobject
application/x-font-ttf
application/x-web-app-manifest+json
application/xhtml+xml
application/xml
font/opentype
image/svg+xml
image/x-icon
image/jpeg
image/gif
image/png
text/css
text/plain
text/x-component;
複製代碼
在完成nginx
配置以後須要作的是以pm2
方式啓動整個應用
pm2 start ecosystem.config.js
複製代碼
在運行完上述命令後,若是一切順利,你就能夠輸入域名來訪問你的應用了(假設你已經完成了域名解析工做)。
一入前端深似海