Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save LazyClutch/98b6d1071b9544c672617c37c34e7f07 to your computer and use it in GitHub Desktop.
Save LazyClutch/98b6d1071b9544c672617c37c34e7f07 to your computer and use it in GitHub Desktop.

基于 Nuxt.js 的 Vue.js 服务端渲染介绍

Vue.js 是目前最火热的前端框架之一,而 Nuxt.js 是针对 Vue.js 推出的服务端渲染框架,通过高度定制化的配置以及简洁的 API,开发者可以快速进行服务端渲染项目的开发,本文将对 Nuxt.js 框架做一个简要介绍。

题图

服务端渲染

服务端渲染(Server Side Render)并不是一个新的概念,在单页应用(SPA)还没有流行起来的时候,页面就是通过服务端渲染好,并传递给浏览器的。当用户需要访问新的页面时,需要再次请求服务器,返回新的页面。

为了优化体验,开发者们开始选择采用 JavaScript 在前端完成渲染过程,用前后端分离的手段,使后端更专注于数据,而前端注重于处理展示,通过设计良好的 API 以及 Ajax 技术完成前后端的交互,jQuery, React.js, Vue.js, Angular.js 等框架应运而生。

这些框架给开发者带来了巨大的便利,但是对于一些论坛、资讯网站、或是企业的官方网站来说,他们对**搜索引擎优化(SEO)**有强烈的要求,而前端渲染技术是无法满足他们的需求的。如果无法通过搜索引擎的搜索输出自身的内容,那么网站的价值就会大大受影响,要解决这类问题,还是要靠服务端渲染。

本文会介绍 Vue.js 的服务端渲染解决方案 Nuxt.js。Vue.js 推出后,其数据驱动和组件化思想,以及简洁易上手的特性给开发者带来了巨大的便利,Vue.js 官方提供的vue-server-renderer可以用来进行服务端渲染的工作,但是需要增加额外的工作量,开发体验仍有待提高,而 Nuxt.js 推出后,这个问题被很好的解决了。

Nuxt.js简介

Nuxt.js 是一个基于 Vue.js 的同构渲染框架,Nuxt.js 预设了利用Vue.js 开发服务端渲染的应用所需要的各种配置,并且可以一键生成静态站点。同时,Nuxt.js 的热加载机制可以使开发者非常便捷的进行网站的开发。

Nuxt.js 于 2016 年 10 月 25 号发布,上线还不足一年,但是已经受到了广泛的好评,最新的稳定版本是 0.10.7,目前仍在进行 1.0 版本的内测,Nuxt.js 社区也在逐步完善中,官网已经支持了中文文档。

简单上手

Vue.js 的vue-cli工具可以很方便的让我们使用现成的模板初始化 Vue.js 项目,而 Nuxt.js 团队已经为我们提供了初始化 Nuxt.js 项目的模板,安装vue-cli后,只需在命令行中输入

vue init nuxt/starter <projectName>

即可完成项目的创建工作,然后进入项目目录中执行以下命令:

npm install
npm run dev

Nuxt.js 会使用 3000 端口运行服务,在浏览器中输入http://localhost:3000就可以看到一个带有 Nuxt.js 的 logo 的原始的页面了。

初始页面

项目目录

完成了一个简单的 Hello World 项目后,我们来进一步研究 Nuxt.js,进入 Nuxt.js 项目后,项目目录如下:

目录

下面简要介绍一下各个目录的作用:

  • .nuxt: 用于存放 Nuxt.js 的核心库文件。例如,你可以在这个目录下找到server.js文件,描述了 Nuxt.js 进行服务端渲染的逻辑(见' Nuxt.js 的渲染流程'),router.js文件包含一张自动生成的路由表。
  • assets: 用于存放静态资源,该目录下的资源使用webpack构建。
  • components: 存放项目中的各种组件,注意,只有在这个目录下的文件才能被称为组件
  • layouts: 创建自定义的页面布局,可以在这个目录下创建全局页面的统一布局,或是错误页布局。如果需要在布局中渲染pages目录中的路由页面,需要在布局文件中加上<nuxt />标签。
  • middleware: 放置自定义的中间件,会在加载组件之前调用。
  • pages: 在这个目录下,Nuxt.js 会根据目录的结构生成vue-router路由,详见下文
  • plugins: 可以在这个目录中放置自定义插件,在根Vue对象实例化之前运行。例如,可以将项目中的埋点逻辑封装成一个插件,放置在这个目录中,并在nuxt.config.js中加载。
  • static: 不使用webpack构建的静态资源,会映射到根路径下,如robots.txt
  • store: 存放 Vuex 状态树。
  • nuxt.config.js: Nuxt.js 的配置文件,详见下文。

Nuxt.js的渲染流程

Nuxt.js 通过一系列构建于 Vue.js 之上的方法进行服务端渲染,具体流程如下:

  1. 调用nuxtServerInit方法

    当请求打入时,最先调用的即是nuxtServerInit方法,可以通过这个方法预先将服务器的数据保存,如已登录的用户信息等。另外,这个方法中也可以执行异步操作,并等待数据解析后返回。

  2. Middleware

    经过第一步后,请求会进入Middleware层,在该层中有三步操作:

    • 读取nuxt.config.js中全局middleware字段的配置,并调用相应的中间件方法
    • 匹配并加载与请求相对应的layout
    • 调用layoutpage的中间件方法
  3. 调用validate方法

    在这一步可以对请求参数进行校验,或是对第一步中服务器下发的数据进行校验,如果校验失败,将抛出404页面。

  4. 调用fetchasyncData方法

    这两个方法都会在组件加载之前被调用,它们的职责各有不同,asyncData用来异步的进行组件数据的初始化工作,而fetch方法偏重于异步获取数据后修改 Vuex 中的状态。 我们在 Nuxt.js 的源码util.js中可以看到以下方法:

    export function applyAsyncData (Component, asyncData = {}) {
      const ComponentData = Component.options.data || noopData
      Component.options.data = function () {
        const data =  ComponentData.call(this)
        return { ...data, ...asyncData }
      }
      if (Component._Ctor && Component._Ctor.options) {
        Component._Ctor.options.data = Component.options.data
      }
    }

这个方法会在asyncData方法调用完毕后进行调用,可以看到,组件从asyncData方法中获取的数据会和组件原生的data方法获取的数据做一次合并,最终仍然会在data方法中返回,所以得出,asyncData方法其实是原生data方法的扩展。

经过以上四步后,接下来就是渲染组件的工作了,整个过程可以用下图表示(注【1】):

渲染过程

如上文所述,在.nuxt目录下,你可以找到server.js文件,这个文件封装了 Nuxt.js 在服务端渲染的逻辑,包括一个完整的Promise对象的链式调用,从而完成上面描述的整个服务端渲染的步骤。

Nuxt.js 的一些使用技巧

nuxt.config.js 的配置

nuxt.config.js是 Nuxt.js 的配置文件,可以通过针对一系列参数的设置来完成 Nuxt.js 项目的配置,可以在 Nuxt.js 官网( https://zh.nuxtjs.org/guide/configuration )找到针对这个文件的说明,下面举例一些常用的配置:

  • head: 可以在这个配置项中配置全局的head,如定义网站的标题,meta,引入第三方的 CSS,JavaScript 文件等:

      head: {
          title: '百姓店铺',
          meta: [
            	{ charset: 'utf-8' },
            	{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
            	{ name: 'applicable-device', content: 'pc,mobile' },
          ],
          link: [
            	{ rel: 'stylesheet', type: 'text/css', href: 'https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css'}
          ],
          script: [
            	{src: 'https://code.jquery.com/jquery-3.1.1.min.js'},
            	{src: 'https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js'}
          ]
      },
    
  • build: 这个配置项用来配置 Nuxt.js 项目的构建规则,即webpack的构建配置,如通过 vendor 字段引入第三方模块,通过 plugin 字段配置webpack插件,通过 loaders 字段自定义webpack加载器等。 通常我们会在 build 的 vendor 字段中引入axios模块,从而在项目中进行 HTTP 请求(axios也是 Vue.js 官方推荐的 HTTP 请求框架)。

      build: {
      	vendor: ['core-js', 'axios', '~plugins/Tracker.js'],
      	loaders: [
      		{
      			test: /\.(scss|sass)$/,
      			use: [{
      				loader: "style-loader"
      			}, {
      				loader: "css-loader"
      			}, {
      				loader: "sass-loader"
      			}]
      		},
      		{
      			test: /\.(png|jpe?g|gif|svg)$/,
      			loader: 'url-loader',
      			query: {
      				limit: 1000,
      				name: 'img/[name].[hash:7].[ext]'
      			}
      		},
      		{
      			test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
      			loader: 'url-loader',
      			query: {
      				limit: 1000,
      				name: 'fonts/[name].[hash:7].[ext]'
      			}
      		}
      	]
      }
    
  • css: 在这个配置项中,引入全局的 CSS 文件,之后每个页面都会被引入。

  • router: 可以在此配置路由的基本规则,以及进行中间件的配置。例如,你可以创建一个用来获取User-Agent的中间件,并在此加载。

  • loading: Nuxt.js 提供了一套页面内加载进度指示组件,可以在此配置颜色,禁用,或是配置自定义的加载组件。

  • env: 可以在此配置用来在服务端和客户端共享的全局变量。

目录即路由

Nuxt.js 在vue-router之上定义了一套自动化的生成规则,即依据 pages 的目录结构生成。例如,我们有以下目录结构:

router

这个目录下含有一个基础路由(无参数)以及两个动态路由(带参数),Nuxt.js 会生成如下的路由配置表(可以在.nuxt目录下的router.js文件中找到):

routes: [
	{
		path: "/",
		component: _abe13a78,
		name: "index"
	},
	{
		path: "/article/:id?",
		component: _48f202f2,
		name: "article-id"
	},
	{
		path: "/:page",
		component: _5ccbb43a,
		name: "page"
	}
]

对于article-id这个路由,路径中带有:id?参数,表明这是一个可选的路由,如果要将其设为必选,则必须在article的目录下添加index.vue文件。 再看下面一个例子:

route2

由于有同名文件和文件夹的存在,Nuxt.js 会为我们生成嵌套路由,生成的路由结构如下,在使用时,需要增加<nuxt-child />标签来显示子视图的内容。

routes: [
	{
		path: "/article",
		component: _f930b330,
		children: [
			{
				path: "",
				component: _1430822a,
				name: "article"
			},
			{
				path: ":id",
				component: _339e8013,
				name: "article-id"
			}
		]
	}
]

此外,Nuxt.js 还可以设置动态嵌套路由,具体可参见 Nuxt.js 的官方文档( https://zh.nuxtjs.org/guide/routing

总结

Nuxt.js 尽管是一个非常年轻的框架,目前也有很多待改进的问题,但它的出现为 Vue.js 开发者搭建服务端渲染项目提供了巨大的便利,期待 Nuxt.js 1.0 版本发布后,能给我们带来更多实用的新功能。

【1】: 图片来源: Nuxt.js 官网 ( https://nuxtjs.org/guide/#schema )

@zpbx
Copy link

zpbx commented Aug 11, 2017

谢谢交稿!我先说几条字面上的修改建议:

  • 素材不完整。请参考 写作规范

  • 代码尽可能使用文本,不要用图片。

  • 块级代码最好加上语言类型,以便渲染出语法高亮。

  • 中西文之间加空格,比如 “Nuxt.js 于2016年10月25号发布” → “Nuxt.js 于 2016 年 10 月 25 号发布”。具体参见 写作规范

  • 行内代码与中文之间需加空格。具体参见 写作规范

  • 非原创图片需要注明来源。具体参见 写作规范

@LazyClutch
Copy link
Author

  • 作者署名: 李韧
  • 作者头像:

头像

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment