• 使用next.js完成从开发到部署


    next.js 是一个非常棒的轻量级的react同构框架,使用它可以快速的开发出基于服务端渲染的react应用。在next.js 官网推荐的是使用now来部署应用,但是对于国内用户或者说是有特殊需求的用户来说,部署到自定义服务器也许是大多数人希望的。借着近期公司官网改版,顺便分享下自己从开发到部署过程中所经历的点点滴滴。

    依稀还记得第一次使用next.js 是在去年(2017年),那个时候使用的是next.js 2.x版本,react还是15版本,一年过去,现在react已经发展到16版本,而next.js 已经发展到6.0版本了,迭代速度瞠目结舌,在使用新版本的过程中也是遇到不少的坑。

    用到的技术

    先说下这次用到了哪些技术,下面列举了项目中主要用到的技术或工具库。

    由express原班人马开发的下一代web框架,用来提供web服务。

    是一个高性能的HTTP和反向代理服务器,也是一个IMAP/POP3/SMTP服务器(摘自百度百科),由俄罗斯人开发。用来提供静态文件服务、https证书、代理服务。

    一个javascript ui库

    一个轻量级的react同构应用框架

    由蚂蚁金服开发的基于react的一套中后台产品组件库

    基于react的动画解决方案

    判断组件是否在当前可视区的react 组件

    一个带有负载均衡功能的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,这里就随便从我真实项目中抽取部分代码来作师范。

    1.  
      export default class HomePage extends React.Component {
    2.  
      static async getInitialProps({ req, pathname }) {
    3.  
      const data = await fetch(`${ctx}/api/projects/common/list`).then(res => res.json())
    4.  
      .then(dt => dt)
    5.  
      .catch(err => {
    6.  
      return {
    7.  
      success: false,
    8.  
      message: err.message
    9.  
      }
    10.  
      })
    11.  
      return { pathname,data };
    12.  
      }
    13.  
       
    14.  
      render() {
    15.  
      const { pathname, data } = this.props;
    16.  
      return (
    17.  
      <div>
    18.  
      <Head>
    19.  
      <title>首页-易科捷(武汉)生态科技有限公司</title>
    20.  
      </Head>
    21.  
      <div>Welcome to next.js!</div>
    22.  
      {/*这里省略代码*/}
    23.  
      </div>
    24.  
      );
    25.  
      }
    26.  
      }
    27.  
       
    28.  
      复制代码

    如果你的package.json中没有配置next启动脚本,请访问setup进行配置,下面我们在控制台运行npm run dev,如果一切顺利,打开浏览器,你将会看到Welcome to next.js!

    next.js中开发体验和react几乎没有什么区别,但是在webpack配置这块可能需要下点功夫。一些常用的插件像sasscss等, next.js都已经给你提供了,你也可以使用社区开源的插件来完成你的开发之旅。详情请查看next.js官网

    部署

    在经历了开发阶段、测试等等一系列流程,现在终于等到了部署阶段。在next.js中生产阶段打包只需要运行npm run build即可,官方推荐不修改打包的文件夹名字(原名称为.next),这里个人推荐修改成build或者dist这些名称。在打包完成之后,需要编写nodejs启动入口文件,下面贴出实例代码:

    1.  
      const Koa = require('koa')
    2.  
      const next = require('next')
    3.  
      const Router = require('koa-router')
    4.  
       
    5.  
      const port = parseInt(process.env.PORT, 10) || 3000
    6.  
      const dev = process.env.NODE_ENV !== 'production'
    7.  
      const app = next({ dev })
    8.  
      const handle = app.getRequestHandler()
    9.  
       
    10.  
      app.prepare()
    11.  
      .then(() => {
    12.  
      const server = new Koa()
    13.  
      const router = new Router()
    14.  
      // 首页
    15.  
      router.get('/', async ctx => {
    16.  
      await app.render(ctx.req, ctx.res, '/', ctx.query)
    17.  
      ctx.respond = false
    18.  
      })
    19.  
      // 关于
    20.  
      router.get('/about', async ctx => {
    21.  
      await app.render(ctx.req, ctx.res, '/about', ctx.query)
    22.  
      ctx.respond = false
    23.  
      })
    24.  
      // 产品
    25.  
      router.get('/products/:id', async ctx => {
    26.  
      const {id} = ctx.params
    27.  
      await app.render(ctx.req, ctx.res, `/products/${id}`, ctx.query)
    28.  
      ctx.respond = false
    29.  
      })
    30.  
      // 案例
    31.  
      router.get('/case', async ctx => {
    32.  
      await app.render(ctx.req, ctx.res, '/case', ctx.query)
    33.  
      ctx.respond = false
    34.  
      })
    35.  
      // 联系我们
    36.  
      router.get('/contact', async ctx => {
    37.  
      await app.render(ctx.req, ctx.res, '/contact', ctx.query)
    38.  
      ctx.respond = false
    39.  
      })
    40.  
      // 详情
    41.  
      router.get('/view/:type/:id', async ctx => {
    42.  
      const {id, type} = ctx.params
    43.  
      await app.render(ctx.req, ctx.res, `/view`, {id, type})
    44.  
      ctx.respond = false
    45.  
      })
    46.  
      // 如果没有配置nginx做静态文件服务,下面代码请务必开启
    47.  
      /* router.get('*', async ctx => {
    48.  
      await handle(ctx.req, ctx.res)
    49.  
      ctx.respond = false
    50.  
      })*/
    51.  
      // 防止出现控制台报404错误
    52.  
      server.use(async (ctx, next) => {
    53.  
      ctx.res.statusCode = 200
    54.  
      await next()
    55.  
      })
    56.  
      server.use(router.routes())
    57.  
      server.listen(port, () => {
    58.  
      console.log(`> Ready on http://localhost:${port}`)
    59.  
      })
    60.  
      })
    61.  
       
    62.  
      复制代码

    一般的静态文件、gzip压缩无需交给nodejs来做,个人一直认为专业的事交给专业的人。这里将该项任务转移给nginx,特别注意上面实例代码中我注释的部分代码,若果你没有使用nginx来做静态文件服务,请务必开启,否则像next.js打包出来的jscss、图片文件等,都将报404

    next.js生产打包阶段打包出来的js文件请求路径中带有版本号,而真实打包出来的文件夹却没有实际对应的目录,也就是打包出来的是虚拟目录,这里如果使用nginx就需要特别注意。好在next.js提供配置项来修改build id,以下是我的真实代码:

    1.  
      // next.config.js
    2.  
      module.exports = {
    3.  
      generateBuildId: async () => {
    4.  
      // For example get the latest git commit hash here
    5.  
      return 'v1'
    6.  
      }
    7.  
      }
    8.  
      复制代码

    这样打包出来的虚拟路径大概是_next/v1/page/xxx.js,如果你使用cdn前缀,这里有一点区别,但是版本号依然存在。

    还有一个坑就是next.js打包出来的有三个文件夹:bundlesdiststatic,对于不知道源码的人来说,根本不知道实际请求文件在哪一个文件夹。于是我就看next.js源码,发现其实找的是bundle文件下的page,源码位置:L214

    所以在配置nginx就需要使用别名。下面给出一段我的nginx真实配置代码:

    1.  
      # 网站根目录文件
    2.  
      location ~ ^/(robots.txt|humans.txt|favicon.ico|sw.js|baidu_verify_7Kj6tQjI3v.html) {
    3.  
      root /home/website/eco_website_pc/static/;
    4.  
      if ($request_filename ~* sw.js){
    5.  
      expires -1s;
    6.  
      }
    7.  
      expires 10m;
    8.  
       
    9.  
      }
    10.  
      # static下的文件
    11.  
      location ^~ /static/ {
    12.  
      alias /home/website/eco_website_pc/static/;
    13.  
      if ($request_filename ~* sw.js){
    14.  
      expires -1s;
    15.  
      }
    16.  
      expires 10m;
    17.  
       
    18.  
      }
    19.  
      # next pages页面下的脚本
    20.  
      location ~ ^/(/_next/v1/) {
    21.  
      alias /home/website/eco_website_pc/build/bundles/;
    22.  
      if ($request_filename ~* sw.js){
    23.  
      expires -1s;
    24.  
      }
    25.  
      expires 10m;
    26.  
       
    27.  
      }
    28.  
      # next static下的静态文件
    29.  
      location ~ ^/(/_next/static/) {
    30.  
      root /home/website/eco_website_pc/build;
    31.  
      if ($request_filename ~* sw.js){
    32.  
      expires -1s;
    33.  
      }
    34.  
      expires 10m;
    35.  
       
    36.  
      }
    37.  
      复制代码

    静态文件配置好了就需要配置https证书了,因为我们这次项目是公司官网,证书我就自己去免费弄了一个,这里我使用的freessl上面提供的亚洲诚信的证书。在申请完ssl证书之后需要去域名提供商那里去配置TXT记录,我这里使用的是阿里云,在完成验证后,freessl将会下载证书,拿到该证书之后需要去配置nginx ssl证书,下面贴出我的完整配置:

    1.  
      server {
    2.  
      listen 80;
    3.  
      listen 443 ssl;
    4.  
      server_name wh-eco.com;
    5.  
      charset utf-8;
    6.  
      ssl_certificate /home/website/ssl/www/full_chain.pem;
    7.  
      ssl_certificate_key /home/website/ssl/www/private.key;
    8.  
      fastcgi_param HTTPS on;
    9.  
      fastcgi_param HTTP_SCHEME https;
    10.  
       
    11.  
      if ($scheme = http ) {
    12.  
      return 301 https://$host$request_uri;
    13.  
      }
    14.  
      access_log /var/log/nginx/www.wh-eco.com.access.log;
    15.  
      error_log /var/log/nginx/www.wh-eco.com.error.log;
    16.  
      location / {
    17.  
      proxy_pass http://127.0.0.1:xxxx; #保密 0.0
    18.  
      proxy_set_header Host $host;
    19.  
      #proxy_redirect off;
    20.  
      proxy_set_header REMOTE-HOST $remote_addr;
    21.  
      # 网站可能后期会使用websocket 特次升级请求协议
    22.  
      proxy_http_version 1.1;
    23.  
      proxy_set_header Upgrade $http_upgrade;
    24.  
      proxy_set_header Connection "upgrade";
    25.  
      proxy_set_header X-Real-IP $remote_addr;
    26.  
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    27.  
      proxy_connect_timeout 60;
    28.  
      proxy_read_timeout 600;
    29.  
      proxy_send_timeout 600;
    30.  
      }
    31.  
      # 网站根目录文件
    32.  
      location ~ ^/(robots.txt|humans.txt|favicon.ico|sw.js|baidu_verify_7Kj6tQjI3v.html) {
    33.  
      root /home/website/eco_website_pc/static/;
    34.  
      if ($request_filename ~* sw.js){
    35.  
      expires -1s;
    36.  
      }
    37.  
      expires 10m;
    38.  
       
    39.  
      }
    40.  
      # static下的文件
    41.  
      location ^~ /static/ {
    42.  
      alias /home/website/eco_website_pc/static/;
    43.  
      if ($request_filename ~* sw.js){
    44.  
      expires -1s;
    45.  
      }
    46.  
      expires 10m;
    47.  
       
    48.  
      }
    49.  
      # next pages页面下的脚本
    50.  
      location ~ ^/(/_next/v1/) {
    51.  
      alias /home/website/eco_website_pc/build/bundles/;
    52.  
      if ($request_filename ~* sw.js){
    53.  
      expires -1s;
    54.  
      }
    55.  
      expires 10m;
    56.  
       
    57.  
      }
    58.  
      # next static下的静态文件
    59.  
      location ~ ^/(/_next/static/) {
    60.  
      root /home/website/eco_website_pc/build;
    61.  
      if ($request_filename ~* sw.js){
    62.  
      expires -1s;
    63.  
      }
    64.  
      expires 10m;
    65.  
       
    66.  
      }
    67.  
      error_page 500 502 503 504 = /error.html;
    68.  
      error_page 404 = /notfound.html;
    69.  
      location = /error.html {
    70.  
      root /home;
    71.  
      }
    72.  
      location = /notfound.html{
    73.  
      root /home;
    74.  
      }
    75.  
      }
    76.  
      复制代码

    至于gzip你可以根据你要求来做配置,贴一个我的示例配置:

    1.  
      gzip on;
    2.  
      gzip_comp_level 6;
    3.  
      gzip_vary on;
    4.  
      gzip_types
    5.  
      application/atom+xml
    6.  
      application/javascript
    7.  
      application/json
    8.  
      application/rss+xml
    9.  
      application/vnd.ms-fontobject
    10.  
      application/x-font-ttf
    11.  
      application/x-web-app-manifest+json
    12.  
      application/xhtml+xml
    13.  
      application/xml
    14.  
      font/opentype
    15.  
      image/svg+xml
    16.  
      image/x-icon
    17.  
      image/jpeg
    18.  
      image/gif
    19.  
      image/png
    20.  
      text/css
    21.  
      text/plain
    22.  
      text/x-component;
    23.  
      复制代码

    在完成nginx配置之后需要做的是以pm2方式启动整个应用

    1.  
      pm2 start ecosystem.config.js
    2.  
      复制代码

    在运行完上述命令后,如果一切顺利,你就可以输入域名来访问你的应用了(假设你已经完成了域名解析工作)。

    总结

    一入前端深似海

    漫思
  • 相关阅读:
    ChukWa入门1
    asp.net常用代码集锦
    泛型讲解
    深入宠物店PetShopSQLServerDAL数据访问与SampleDuwamish比较
    写有效率的SQL查询(转载)
    VisualStudio2005技巧集合
    iptables总结【转载】
    vmware workstation 如何注册
    4.继承
    Linux系统下源代码包方式 安装前准备[1]
  • 原文地址:https://www.cnblogs.com/sexintercourse/p/14421789.html
Copyright © 2020-2023  润新知