Nuxt.js(Vue SSR)创建项目到服务器(Nginx+PM2)部署详细流程

7,573 阅读7分钟

一、什么是 SSR ?

  • SSR 就是 服务器渲染,什么是 服务器渲染?由 服务器 组装好 DOM 元素,生成 HTML 字符串给到浏览器,也就是在浏览器里面是可以看到整个页面的 DOM 源码的。

  • SSR 解决的问题:

    SEO:搜索引擎的优先爬取级别是页面的 HTML 结构,当我们使用 SSR 的时候,服务端已经生成了与业务相关联的 HTML,这样的信息对于 SEO 是很友好的。

    内容呈现:客户端无需等待所有的 JS 文件加载完成即可看见渲染的业务相关视图(压力来到了服务端这边,这也是需要做权衡的地方,需要区分哪些由服务端渲染,哪些可以交给客户端)。

  • SSR 相关的弊端:

    代码兼容:对于开发人员来讲,需要去兼容代码在不同环境的运行 Vue SSR 所需要的服务端环境是 Node,有一些客户端的对象,比如 dom、windows 之类的则无法使用。

    服务器负载:相对于前后端分离模式下服务器只需要提供静态资源来说,SSR 需要的服务器负载更大,所以在项目中使用 SSR 模式要慎重,比如一整套图表页面,相对于服务端渲染,可能用户不会在乎初始加载的前几秒,可以交由客户端使用类似于骨架屏,或者懒加载之类的提升用户体验。

  • Vue 与 Vue SSR 与 原生HTML 页面源码区别对比,在网页上右键查看源码:

    Vue SSR 与 原生HTML 是可以看到源码标签的

    Vue 默认是看不到源码标签的,因为它是 JS 组装的。


二、什么是 Nuxt.js ?

  • 目前做 SSR 的方式有几种,大概列举一下:

    1、前端编写 原生静态页面,给到服务器,通过服务器框架进行组合数据,例如 php 的 Web 开发。

    2、使用 prerender-spa-plugin 插件,作者是 Vue 核心团队的成员,这种实现方式并不叫 SSR,而是 预渲染。不过效果上是一样的,甚至某种程度上来说可能要比 SSR 更好。相比官方提供的 SSR 繁琐配置,prerender 配置更简单快捷。

    3、Vue 官方提供的轮子在 Node 端做 SSR, 相对于 prerender 插件来说,SSR上手真的超级复杂,有兴趣可以自行查看 Vue SSR 指南。这种方法可以做到真实数据实时渲染,完全可供 SEO 小蜘蛛尽情的爬来爬去,完全前后端同构,路由配置共享,不再影响服务器 404 请求,但是配置比较麻烦、处理流程比较复杂 (比对预渲染插件,复杂太多)约束较多,对服务器会造成较大的压力,服务器成本太高了。

    4、Nuxt.js 是使用 Webpack 和 Node.js 进行封装的基于 Vue 的 SSR 框架,不需要自己搭建一套 SSR 程序,而是通过其约定好的文件结构和 API 就可以实现一个首屏渲染的 Web 应用。

    我这里选择使用 Nuxt.js 来做 SSR。


三、通过 Nuxt.js 创建项目

  • Nuxt.js 官方安装流程,项目需要依赖 Node 环境,我这里用的包管理工具是 NPM,Nuxt.js 版本是 2.14.5。

  • 创建项目,确保安装了 npx(npx 在 NPM 版本 5.2.0 默认安装了):

    $ npx create-nuxt-app <项目名>
    
    $ npm create nuxt-app <项目名>
    
    $ yarn create nuxt-app <项目名>
    

    或者用 yarn :

    $ yarn create nuxt-app <项目名>
    

    我这里用 npx 创建一个测试项目,例如:

    $ npx create-nuxt-app nuxt-test
    
    // 进入到文件夹,执行创建项目命令
    dengzemiaodeMacBook-Pro:test dengzemiao$ npx create-nuxt-app nuxt-test
    create-nuxt-app v3.5.2
    ✨  Generating Nuxt.js project in nuxt-test
    
    // 项目初始配置,自己看着选,用什么选什么 不懂就选 None,后面也可以装的。
    ? Project name: nuxt-test
    ? Programming language: JavaScript
    ? Package manager: Npm
    ? UI framework: None
    ? Nuxt.js modules: Axios - Promise based HTTP client
    ? Linting tools: (Press <space> to select, <a> to toggle all, <i> to invert sele
    ction)
    ? Testing framework: None
    ? Rendering mode: Universal (SSR / SSG)
    ? Deployment target: Server (Node.js hosting)
    ? Development tools: jsconfig.json (Recommended for VS Code if you're not using 
    typescript)
    ? What is your GitHub username? dengzemiao
    ? Version control system: None
    
    .....等待一段时间,就会提示创建项目成功
      
    🎉  Successfully created project nuxt-test
    
    // 如果是开发中,运行 npm run dev 就可以,开发者模式
    To get started:
    
      cd nuxt-test
      npm run dev
    
    // 如果是需要发布到线上了,需要先 build 在 start 才能正式发布
    To build & start for production:
    
      cd nuxt-test
      npm run build
      npm run start
    

四、Nuxt.js 本地运行

  • 这篇文章只讲 创建项目 到 发布服务器,以及服务器怎么部署才能通过服务器访问,其他项目细节配置放在其他文章中去写。

  • 创建完成项目之后,可以先运行项目一下,用上面 To get started 或 To build & start for production 中的方式运行起来项目,只是前者是 development 模式,后者是 production 模式。

    dengzemiaodeMacBook-Pro:test dengzemiao$ cd nuxt-test
    dengzemiaodeMacBook-Pro:nuxt-test dengzemiao$ npm run dev
    
    > nuxt-test@1.0.0 dev /Users/dengzemiao/Desktop/Project/web/test/nuxt-test
    > nuxt
    
    
       ╭───────────────────────────────────────╮
       │                                       │
       │   Nuxt @ v2.14.12                     │
       │                                       │
       │   ▸ Environment: development          │
       │   ▸ Rendering:   server-side          │
       │   ▸ Target:      server               │
       │                                       │
       │   Listening: http://localhost:3000/   │
       │                                       │
       ╰───────────────────────────────────────╯
    

    然后通过上面的 http://localhost:3000/ 打开浏览器进行访问,但是这个是开发环境。

  • 在 pages 里面的 .vue 文件都会被自动转成路由,文件夹也是一样。

  • 例如:项目 pages 文件夹里面有个 index.vue 文件,它会被编译成 index.html,在路由中也就是 /index,可以尝试修改 index.vue 里面的内容,或者新建一个 .vue 文件进行测试内容。

  • 例如:我在 pages 里面创建一个测试文件 dzm.vue,运行起来项目,访问的路径就是 http://localhost:3000/dzm

    <template>
      <div>
        dzm 测试页面 {{ env }}
      </div>
    </template>
    
    <script>
    export default {
      data () {
        return {
          // 当前启动的环境 development: 开发环境 production: 生产环境
          env: process.env.NODE_ENV
        }
      }
    }
    </script>
    

五、Nuxt.js 直接 ip 访问项目(生产和开发都适用)

  • 运行开发环境 $ npm run dev

       ╭───────────────────────────────────────╮
       │                                       │
       │   Nuxt @ v2.14.12                     │
       │                                       │
       │   ▸ Environment: development          │
       │   ▸ Rendering:   server-side          │
       │   ▸ Target:      server               │
       │                                       │
       │   Listening: http://localhost:3000/   │
       │                                       │
       ╰───────────────────────────────────────╯
    
  • 运行生产环境 $ npm run build + $ npm run start

       ╭──────────────────────────────────────────╮
       │                                          │
       │   Nuxt @ v2.14.12                        │
       │                                          │
       │   ▸ Environment: production              │
       │   ▸ Rendering:   server-side             │
       │   ▸ Target:      server                  │
       │                                          │
       │   Memory usage: 29.1 MB (RSS: 73.1 MB)   │
       │                                          │
       │   Listening: http://localhost:3000/      │
       │                                          │
       ╰──────────────────────────────────────────╯
    
  • 通过上面的两个运行的结果,得到的地址都是 http://localhost:3000/,这个是固定本地 localhost:3000 才可以进访问,需要改成支持本地 ip 也能访问,也就是你拿到本机电脑的 ip 加上端口也能进行访问到,例如: http://10.0.93.169:3000

  • 找到 nuxt.config.js,添加下面代码:

    export default {
      head: {...},
      css: [...],
      
      // 配置服务器(主要是这个配置)
      server: {
        // port: 8000, // default: 3000
        host: '0.0.0.0', // default: localhost (推荐)
        // host: '0', // 等于 host: '0.0.0.0' 这样配置,在mac上这么配置没问题,但是在window上这么配置有报错。
        timing: false
      },
    

    再次运行项目,生产或测试都行,访问地址就会变成本机的 ip 地址加端口:

     ╭─────────────────────────────────────────╮
     │                                         │
     │   Nuxt @ v2.14.12                       │
     │                                         │
     │   ▸ Environment: development             │
     │   ▸ Rendering:   server-side            │
     │   ▸ Target:      server                 │
     │                                         │
     │   Memory usage: 29.4 MB (RSS: 74 MB)    │
     │                                         │
     │   Listening: http://10.0.93.169:3000   │
     │                                         │
     ╰─────────────────────────────────────────╯
    

    本地运行项目就到这里结束了,下面需要将项目发布到服务器运行起来。

四、Nuxt.js 上传服务器(Nginx + Node + PM2)

  • 下面的这些操作如果需要测试,可以放在本地机器上进行搭建,把本地电脑当服务器使使。

  • 服务器 安装 Nginx + Node + PM2。

  • Nuxt.js 是依赖 Node,所以 服务器 需要安装 Node,装了 Node 就会自带 NPM,然后通过 NPM 安装 PM2:

    $ npm install -g pm2
    
    // 可以通过 -h 查询使用方式
    $ pm2 -h
    

    PM2 是 Node 的进程管理工具。为啥用这个?举个例子:运行项目之后,命令行窗口是不能关闭的,如果关闭了就无法访问这个项目地址了,所以需要支持关闭命令行窗口,运行的项目依然能够访问,也就是后台挂起进程,PM2 就可以做到这个事情。

  • 安装好上面环境,在 Nginx 根目录里面通过 Git 拉下来 Nuxt.js 源码,可以新开文件夹存放也是可以的,随你自己

    $ git clone xxxxx.git
    
    // 如果存在代码就拉一下代码 保持最新
    $ git pull
    

    这里说一下,在网上搜一下会搜到很多只需要导入几个文件就可以运行项目的文章,但是这种方式有时候会出现 编译函数找不到、资源文件找不到 之类的问题,所以如果不是特别熟悉 Nuxt.js 的话,直接将整个项目拉下来使用,不需要去单独导入某些文件,这样也完美的避开一些细节上的坑,网上的文章一般都是推荐导入下面几个文件:

    .nuxt
    static
    nuxt.config.js
    package.json
    package-lock.json
    
  • 将代码拉到服务器后,需要先走一遍 npm 安装,安装一下依赖包

    $ npm install
    
  • 然后编译项目

    $ npm run build
    
  • PM2 运行项目,后台挂起,你的项目名称,可以随意填个,但是推荐跟项目 package.json 文件里面的 name 字段值一样,这样好区分。。

    // 之前是通过 $ npm run dev 或者 $ npm run start,但是命令行窗口不能关闭
    
    // 启动开发环境后台挂起,列举了常用的几种方式,任意选一种
    $ pm2 start npm -- run dev
    $ pm2 start npm --name "你的项目名称" -- run dev
    $ pm2 start ./node_modules/nuxt/bin/nuxt.js 
    ....
    
    // 启动生产环境后台挂起,列举了常用的几种方式,任意选一种
    $ pm2 start npm -- run start
    $ pm2 start npm --name "你的项目名称" -- run start
    ....
    
    // 例如:服务器启动开发环境,开发环境只需要一行命令
    $ pm2 start ./node_modules/nuxt/bin/nuxt.js 
    
    // 例如:服务器启动生产环境,生产环境需要先 build 在 start
    $ npm run build
    $ pm2 start npm --name "nuxt-test" -- run start
    
    // window 电脑注意:上面命令在 MAC 跟 服务器都可以生效,但是在 window 上如果做测试,
    // 有部分命令无法生效,我用window 用的少,所以也没去深入折腾,这里给一下建议:
    // window 电脑本地测试PM2挂开发环境,生产环境目前上面几种启动方式都无法挂载成功,直接上服务器挂就行了,本地只是用于测试,开发环境也不影响测试。
    // 只能通过这行命令启动开发环境,生产环境的命令挂起无效,暂时没解决
    $ pm2 start ./node_modules/nuxt/bin/nuxt.js 
    
  • 然后可以通过 $ pm2 list 查看是否挂起成功,这样显示了就是挂起成功了

    ┌─────┬──────────────┬─────────────┬─────────┬─────────┬──────────┬────────┬──────┬───────────┬──────────┬──────────┬──────────┬──────────┐
    │ id  │ name         │ namespace   │ version │ mode    │ pid      │ uptime │ ↺    │ status    │ cpu      │ mem      │ user     │ watching │
    ├─────┼──────────────┼─────────────┼─────────┼─────────┼──────────┼────────┼──────┼───────────┼──────────┼──────────┼──────────┼──────────┤
    │ 0   │ nuxt-test    │ default     │ N/A     │ fork    │ 1190     │ 0s     │ 0    │ online    │ 0%       │ 7.8mb    │ den… │ disabled │
    └─────┴──────────────┴─────────────┴─────────┴─────────┴──────────┴────────┴──────┴───────────┴──────────┴──────────┴──────────┴──────────┘
    

    现在就可以通过你这台电脑或者服务器的 ip 地址加端口号进行访问了,例如:http://10.0.90.164:3000/。

  • 如果需要停掉后台挂起,执行删除命令即可,id 就是 $ pm2 list 列表中的 id 值:

    // 删除单个挂起进程
    $ pm2 delete id
    // 删除全面挂起进程
    $ pm2 delete all
    
    例如:
    $ pm2 delete 0
    
  • 如果项目修改调整了,上传了新的东西,只需要拉下代码编译后,重启 PM2 对应环境进程即可:

    开发环境 - 初始化:$ git pull + $ npm install + $ pm2 start npm --name "你的项目名称" -- run dev

    生产环境 - 初始化:$ git pull + $ npm install + $ npm run build + $ pm2 start npm --name "你的项目名称" -- run start

    注意:$ pm2 start .... 命令,每次启动都会在 $ pm2 list 列表中新增一个管理进程,所以只需要初始化创建了就行了,后面如果不是通过 $ pm2 delete id 手动删除了,就不需要每次 $ pm2 start ....,只需要重启即可:

    开发环境 - 后续版本更新:$ git pull + $ npm install + $ pm2 restart id

    生产环境 - 后续版本更新:$ git pull + $ npm install + $ npm run build + $ pm2 restart id

  • 额外说一句:如果 PM2 启动项目之后,不知道访问那个地址,那可以先 $ pm2 delete id 删除进程,执行自带的运行方式 $ npm run dev 或 $ npm run start,需要哪个环境就运行哪个命令,运行之后可以拿到访问地址,拿到之后关掉,在通过 PM2 运行访问同意一个地址,注意端口号别变化了,如果端口被占用,会分配一个新的端口:

     ╭──────────────────────────────────────────╮
     │                                          │
     │   Nuxt @ v2.14.12                        │
     │                                          │
     │   ▸ Environment: production              │
     │   ▸ Rendering:   server-side             │
     │   ▸ Target:      server                  │
     │                                          │
     │   Memory usage: 29.4 MB (RSS: 74.6 MB)   │
     │                                          │
     │   Listening: http://10.0.90.164:3000/    │
     │                                          │
     ╰──────────────────────────────────────────╯
    
  • 最终通过 PM2 启动挂起之后,现在需要配置一下 Nginx,之前启动是 Node 服务,访问是没问题的,但是现在需要通过 Nginx 反代理到 Node,也就是通过 Nginx 去访问到 Node 的资源地址。

  • 找到 Nginx 的 nginx.conf 文件,在里面添加一个新的服务,以及一个反代理服务

    http {
    
      # 新建一个 nuxt server 服务
      upstream nuxt {
        # 这里就是上面配置的 Node ip + 端口号,之前默认是 localhost:3000
        server 0.0.0.0:3000;
        keepalive 64;
      }
    
      server {
        listen 8083; #服务器端口
        server_name www.nuxt.com;  #这里对应你服务器的域名
        location / {
            proxy_pass http://nuxt;  #这里对应上面 upstream 中新建的服务名
            index index.html index.htm;
        }
      }
    }
    

  • 配置好这个之后,通过 $ nginx 启动 Nginx 或者 $ nginx -s reload 刷新 Nginx 配置文件生效。

  • 配置好之后,启动 Node,启动 Nginx,这样就可以直接通过 Node 的 ip + :3000端口 直接访问,也可以通过 Nginx 的 ip或域名 + :8083端口 访问了,对外当然是走 Nginx 了,配置一下域名。

  • 到这就完事了,其他就是项目内部的细节配置跟使用了,会写到另外的文章里面去!

  • Nuxt.js(Vue SSR)项目配置以及开发细节

  • 附带 PM2 配置文件的使用,作用就是将生产或开发环境设置到配置文件里面,只需要执行配置文件即可达到效果,当然也可以不用走配置文件,走上面命令行区分生产或开发环境也一样,看自己喜好。