Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Nuxt专题 - 原理的探究 #32

Open
kangschampagne opened this issue Apr 16, 2018 · 0 comments
Open

Nuxt专题 - 原理的探究 #32

kangschampagne opened this issue Apr 16, 2018 · 0 comments

Comments

@kangschampagne
Copy link
Owner

@kangschampagne kangschampagne commented Apr 16, 2018

最近笔者在使用 Nuxt.js 构建博客系统的前台,这个框架确实极大的方便了 vue 项目的开发。而原理笔者却不是特别的熟悉,因此开一篇文章逐步填补空缺的知识树分支。

这边简单提一下nuxt,Nuxt.js 是一个基于 Vue.js 的通用应用框架,Nuxt.js 预设了利用 Vue.js 开发服务端渲染的应用所需要的各种配置,并且可以一键生成静态站点。利于SEO,浏览器爬虫不会等待我们的ajax回调完成之后再去抓取我们的页面数据。利于首屏渲染,vue-ssr 会把拿到的数据渲染成html,不用等待全部的js资源都完成下载才显示我们的页面。

使用 nuxt-cli 构建完一个 nuxt.js 的应用,会运行 npm run dev,那么这个命令背后nuxt做了什么事情呢?
在 package.json 文件中查看 scripts

"scripts": {
  "dev": "nuxt",  // 启动一个热加载的Web服务器(开发模式) localhost:3000
  "build": "nuxt build", // 利用webpack编译应用,压缩JS和CSS资源(发布用)
  "start": "nuxt start",  // 以生成模式启动一个Web服务器 (nuxt build 会先被执行)
  "generate": "nuxt generate" // 编译应用,并依据路由配置生成对应的HTML文件 (用于静态站点的部署)
}

接下来,就围绕这几个命令,分析一下原理。从 nuxt 的源代码中,可以发现这四个命令基本对应着四个 bin 目录下的 js 文件,分别是 nuxt-dev, nuxt-build, nuxt-start, nuxt-generate

跟随笔者看 nuxt-dev 的部分,下面为删减代码, 完整代码地址

// 删减代码
// 提取 nuxt.config.js 内容
const nuxtConfig = loadNuxtConfig(argv)

function startDev(oldInstance) {
// ...  
// 创建 nuxt 和 builder 实例
  try {
    nuxt = new Nuxt(options)
    builder = new Builder(nuxt)
    instance = { nuxt, builder }
  } catch (err) {
    return onError(err, oldInstance)
  }
  return (
    Promise.resolve()
      // 运行 nuxt.build() 
      .then(() => builder.build())
      // 开启 node-server, 监听端口,和一些热重载的部分
      .then(() => {
        if (oldInstance) {
          return nuxt.listen(port, host)
        } else {
          return Promise.resolve()
        }
      })
  )
}

简言之, nuxt-dev 的运行步骤 (1)提取 nuxt.config.js 内容 (2)实例化 Nuxt() (3)运行build方法 (4)运行开发环境。
即我们可以直接使用 nuxt.js 进行编程,如下栗子:

const { Nuxt, Builder } = require('nuxt')

// Import and set nuxt.js options
let config = require('./nuxt.config.js')
config.dev = (process.env.NODE_ENV !== 'production')

let nuxt = new Nuxt(config)

// Start build process (only in development)
if (config.dev) {
  new Builder(nuxt).build()
}

// You can use nuxt.render(req, res) or nuxt.renderRoute(route, context)

那么其他的命令所执行的方法是什么呢?
nuxt-dev: 运行 build 方法,开启 node-server,监听3000端口,并使用热重载用于开发环境。
nuxt-build: 运行 build 方法,构建打包所有的 css 和 js 文件,用于生产环境。
nuxt-start: 直接开启 node-server,为 nuxt-build 完的文件开启生产环境服务器。
nuxt-generate: 运行 nuxt.generate() 方法,构建打包所有的 css 和 js 文件,按照路由指向的所有页面,都生成一个静态的 html 文件。

可以发现,基本上其区别都在 Nuxt() 实例化之后,执行各自具体的方法函数。

原本这个地方会细讲 nuxt 方法做了某些事情,但是发现 vue 官网对于 ssr 原理方面做了非常深刻的文档,地址。因此下面会简要解释 Vue SSR 的原理,并主要从 nuxt 架构和生产环境会遇到的一些问题进行探究。

Vue SSR 的原理

Nuxt.js 是一个 Node 程序,也就是将 Vue 跑在服务端,我们访问的页面路由,其实就是架在 Node http 服务器上的路由(按照 Nuxt 约定的 pages 文件夹生成),程序通过 vue 渲染返回首屏内容,并在客户端返回 spa 相应的脚本,而这些脚本都是延迟加载的,首屏渲染就不用使用到这些 js 脚本。

这里就需要 vue ssr 在服务端和客户端分别做了什么事情。先放一张
image

在 webpack 打包之前,有两者的入口文件,Server entry 和 Client entry。
Server entry:服务端 entry 主要是返回新创建的 vue 实例。为了避免在一个单例对象中的多次请求对状态的污染,所以每次渲染都会重复创建 vue 实例。在这个地方,也会进行组件状态数据的预获取,路由处理等。
Client entry:客户端 entry 就是将 Vue实例挂载到指定的 DOM 元素上。

在 webpack 打包之后,有两个 bundle 文件,Server bundle 和 Client bundle。
Server bundle:服务器按照请求通过 node 去生成预渲染的 HTML 字符串返回到请求的客户端,完成初始的渲染。
Client bundle:客户端拿到 HTML 之后,会使用这个 bundle 进行混合,使其变为由 Vue 管理的动态 DOM,为之后能够响应后续的数据变化。

nuxt 架构

关于 nuxt 的文件夹结构和功能,官方文档都有较为明确的叙述,这里也不再赘述。

@kangschampagne kangschampagne changed the title Nuxt Nuxt专题 - 原理的探究 Apr 16, 2018
@kangschampagne kangschampagne added help wanted and removed WRITING labels Sep 22, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
1 participant
You can’t perform that action at this time.