w3ctech

龙虎大战坐庄服务 端与客户端同构 —— Vue.js 应用框架 Nuxt.js

本文转载自:众成翻译 译者:净化 链接:http://www.zcfy.cc/article/4036 原文:http://www.sitepoint.com/nuxt-js-universal-vue-js

Web servers in a rack

通用(也称同构)的JavaScript已经成为JavaScript社区很常用的一个术语。通用的JavaScript用来形容可以在客户端执行,也可在龙虎大战坐庄服务 端执行的Javascript代码。

作者的其他文章

很多现代的JavaScript框架,比如Vue.js, 旨在构建单页应用(SPA)。单页应用的优势在于,改善用户体验,让网页速度更快,像APP一样流畅,即使更新。虽然单页应用优点很多,但是由于依赖多导致首屏渲染慢,无法做龙虎大战坐庄SEO 龙虎大战坐庄优化 也是让人头疼的问题。

龙虎大战坐庄服务 端渲染是指,提前将页面在龙虎大战坐庄服务 器端渲染好,当浏览器请求龙虎大战坐庄服务 器时,直接返回渲染好的html页面返回。

构建龙虎大战坐庄服务 端渲染的JavaScript程序多少有些无趣,在开始编码之前,需要大量的基础配置。因此,解决vue.js龙虎大战坐庄服务 端渲染问题的Nuxt.js产生了。

Nuxt.js 概要

简而言之,Nuxt.js是龙虎大战坐庄帮助 Vue.js轻松完成龙虎大战坐庄服务 端渲染工作的框架。Nuxt.js预设了龙虎大战坐庄服务 端渲染所需要的各种配置,如异步数据,中间件,路由。它好比是 Angular Universal 之于 AngularNext.js 之于 React

Nuxt.js文档所说,通过对客户端/龙虎大战坐庄服务 端基础架构的抽象,Nuxt.js 让开发者专注于页面的UI渲染。

静态文件生成器

Nuxt.js的一个重要功能是,通过 generate 命令,生成静态站点。类似于流行的静态生成龙虎大战坐庄工具 Jekyll

Nuxt.js 内部依赖

除了Vue.js 2.0之外,Nuxt.js集成了如下模块: Vue-Router, Vue-MetaVuex (仅在使用 Vuex 状态树配置项 时引入)。 这样的好处在于,不需要手工配置依赖,不需要同时在客户端和龙虎大战坐庄服务 端配置相同的库。 Nuxt.js在包含如上依赖的情况下,总大小仍然保持在 28kb min+gzip (如果使用了 Vuex 特性的话为 31kb)。

另外,Nuxt.js 使用 Webpackvue-loaderbabel-loader 来处理代码的自动化构建工作(如打包、代码分层、压缩等等)。

工作原理

当龙虎大战坐庄你 访问一个基于Nuxt.js构建的页面时,发生了的事情如下:

  1. 当用户访问应用程序, 如果store中定义了 nuxtServerInit action,Nuxt.js将调用它更新store。

  2. 接下来,将加载即将访问页面所依赖的任何中间件。Nuxt首先从nuxt.config.js这个文件中,加载全局依赖的中间件,之后检测每个相应页面对应的布局文件 ,最后,检测布局文件下子组件依赖的中间件。以上是中间件的加载顺序。

  3. 如果要访问的路由是一个动态路由, 且有一个相应的 validate() 龙虎大战坐庄方法 路由的validate 龙虎大战坐庄方法 ,讲进行路由校验。

  4. 之后, Nuxt.js 调用 asyncData()fetch() 龙虎大战坐庄方法 ,在渲染页面之前加载异步数据。asyncData() 龙虎大战坐庄方法 用于异步获取数据,并将fetch回来的数据,在龙虎大战坐庄服务 端渲染到页面。 用fetch() 龙虎大战坐庄方法 取回的将数据在渲染页面之前填入store。

  5. 最后一步, 将所有数据渲染到页面。

下图阐述了 Nuxt.js 应用一个完整的龙虎大战坐庄服务 器请求到渲染的流程,摘自官网:

Nuxt.js Schema

使用 Nuxt.js 创建一个静态网站

下面让龙虎大战坐庄龙虎大战坐庄我 们 动手创建一个基于Nuxt.js简单的静态博客。龙虎大战坐庄龙虎大战坐庄我 们 的发送的请求,返回 mock 的JSON数据。

完成下面例子,龙虎大战坐庄你 需要了解基础的 vue.js 知识。如果龙虎大战坐庄你 是个新手,龙虎大战坐庄你 可以通过Jack Franklin的getting started guide了解 Vue.js 2.0。同时,龙虎大战坐庄我 将使用ES6语法,龙虎大战坐庄你 可以参考http://www.sitepoint.com/tag/es6/ 重温ES6语法。

龙虎大战坐庄龙虎大战坐庄我 们 的 Demo 最终效果如下:

Nuxt SSR Blog

本文中代码可参照 GitHub, demo 龙虎大战坐庄地址 如下

基础配置

开始使用 Nuxt.js 最简单的方式是使用 Nuxt.js 团队自己开发的脚手架。龙虎大战坐庄龙虎大战坐庄我 们 可以使用 vue-cli 快速创建龙虎大战坐庄龙虎大战坐庄我 们 的项目 (ssr-blog):

`vue init nuxt/starter ssr-blog`

提示: 如果龙虎大战坐庄你 没有安装过vue-cli,请先通过npm install -g vue-cli 命令安装vue-cli。

之后,龙虎大战坐庄龙虎大战坐庄我 们 将安装项目的依赖:

cd ssr-blog
npm install

现在龙虎大战坐庄龙虎大战坐庄我 们 启动程序:

`npm run dev`

如果正确启动, 龙虎大战坐庄你 能访问 http://localhost:3000 ,展示的页面是 Nuxt.js 模板的初始页面。龙虎大战坐庄你 也可以通过查看页面源代码,验证页面所展示的一切内容,都是龙虎大战坐庄服务 端渲染好的。

下面,龙虎大战坐庄龙虎大战坐庄我 们 简单配置下 nuxt.config.js,包含以下选项:

// ./nuxt.config.js

module.exports = {
  /*
   * Headers of the page
   */
  head: {
    titleTemplate: '%s | Awesome JS SSR Blog',
    // ...
    link: [
      // ...
      { 
        rel: 'stylesheet', 
        href: 'http://cdnjs.cloudflare.com/ajax/libs/bulma/0.4.2/css/bulma.min.css' 
      }
    ]
  },
  // ...
}

在如上配置文件下,龙虎大战坐庄龙虎大战坐庄我 们 使用 titleTemplate 字段 title 变量指定文章题目,在渲染之前用title变量值替换掉%s这个占位,填充到titleTemplate

同时,龙虎大战坐庄我 也使用了 CSS 框架, Bulma, 预设一些样式。通过 link 配置项。

提示: Nuxt.js使用 vue-meta 更新龙虎大战坐庄龙虎大战坐庄我 们 的 html headers 信息。所以,龙虎大战坐庄龙虎大战坐庄我 们 可以看看 meta 具体的配置项,龙虎大战坐庄优化 页面 html 信息。

现在,龙虎大战坐庄龙虎大战坐庄我 们 可以通过几个步骤,完成博客的页面和功能。

使用 Layouts

首先,龙虎大战坐庄龙虎大战坐庄我 们 将为龙虎大战坐庄龙虎大战坐庄我 们 所有的页面定义一个通用的基本布局。龙虎大战坐庄龙虎大战坐庄我 们 通过修改 layouts/default.vue 文件,更新 main Nuxt.js layout:

<!-- ./layouts/default.vue -->

<template>
  <div>
    <!-- navigation -->
    <nav class="nav has-shadow">
      <div class="container">
        <div class="nav-left">
          <nuxt-link to="/" class="nav-item">
            Awesome JS SSR Blog!
          </nuxt-link>
          <nuxt-link active-class="is-active" to="/" class="nav-item is-tab" exact>Home</nuxt-link>
          <nuxt-link active-class="is-active" to="/about" class="nav-item is-tab" exact>About</nuxt-link>
        </div>
      </div>
    </nav>
    <!-- /navigation -->

    <!-- displays the page component -->
    <nuxt/>

  </div>
</template>

在龙虎大战坐庄龙虎大战坐庄我 们 通用的布局里,龙虎大战坐庄龙虎大战坐庄我 们 仅仅对页面添加导航栏,龙虎大战坐庄龙虎大战坐庄我 们 通过 component进一步完成具体页面模块的定制。龙虎大战坐庄你 可以查看components-nuxt-link 进一步了解。

在创建布局时component非常重要,它决定具体页面展示的元素。

当然,component也可以做龙虎大战坐庄更多 事情,比如定义通用组件和错误页面,但是龙虎大战坐庄龙虎大战坐庄我 们 的博客很简单,不需要这些功能。强烈建议阅读 Nuxt.js documentation on views ,龙虎大战坐庄你 可以通过这篇文章了解龙虎大战坐庄更多 Nuxt.js 特性。

简单的页面和路由

Nuxt.js 页面是以 单文件组件 形式龙虎大战坐庄组织 目录结构。 Nuxt.js 自动找到目录下每个 .vue 文件,并添加到页面中。

创建博客龙虎大战坐庄主页

龙虎大战坐庄龙虎大战坐庄我 们 可以通过修改 index.vue 文件修改龙虎大战坐庄主页 , 通过 Nuxt.js 创建的文件如下:

<!-- ./pages/index.vue -->
<template>
  <div>
    <section class="hero is-medium is-primary is-bold">
      <div class="hero-body">
        <div class="container">
          <h1 class="title">
            Welcome to the JavaScript SSR Blog.
          </h1>
          <h2 class="subtitle">
            Hope you find something you like.
          </h2>
        </div>
      </div>
    </section>
  </div>
</template>

<script>
  export default {
    head: {
      title: 'Home'
    }
  }
</script>

如前所述,在渲染之前,题目将自动填充至文件。

龙虎大战坐庄龙虎大战坐庄我 们 现在可以刷新页面,看看龙虎大战坐庄主页 的变化。

创建 About 页面

Nuxt.js 还有一个优秀的特性,监听文件夹下文件的更改,所以,在文件更改时,不需要重启应用更新。

来,龙虎大战坐庄龙虎大战坐庄我 们 添加一个简单的 about.vue 页面:

<!-- ./pages/about.vue -->
<template>
  <div class="main-content">
    <div class="container">
      <h2 class="title is-2">About this website.</h2>
      <p>Curabitur accumsan turpis pharetra <strong>augue tincidunt</strong> blandit. Quisque condimentum maximus mi, sit amet commodo arcu rutrum id. Proin pretium urna vel cursus venenatis. Suspendisse potenti. Etiam mattis sem rhoncus lacus dapibus facilisis. Donec at dignissim dui. Ut et neque nisl.</p>
      <br>
      <h4 class="title is-4">What we hope to achieve:</h4>
      <ul>
        <li>In fermentum leo eu lectus mollis, quis dictum mi aliquet.</li>
        <li>Morbi eu nulla lobortis, lobortis est in, fringilla felis.</li>
        <li>Aliquam nec felis in sapien venenatis viverra fermentum nec lectus.</li>
        <li>Ut non enim metus.</li>
      </ul>
    </div>
  </div>
</template>

<script>
export default {
  head: {
    title: 'About'
  }
}
</script>

现在龙虎大战坐庄龙虎大战坐庄我 们 访问 http://localhost:3000/about 看看about页面,无需重启,非常方便。

在龙虎大战坐庄主页 展示文章列表

龙虎大战坐庄龙虎大战坐庄我 们 的龙虎大战坐庄首页 在没有内容的时候展示如上, 所以下一步,龙虎大战坐庄龙虎大战坐庄我 们 要在 index.vue 上添加博客列表这个组件。

首先,龙虎大战坐庄龙虎大战坐庄我 们 需要把 JSON 格式的文章保存在龙虎大战坐庄服务 根目录下。文件可以从 这里龙虎大战坐庄下载 ,或者龙虎大战坐庄你 可以复制下面的 JSON 到根目录文件夹 posts.json 下:

[
    {
        "id": 4,
        "title": "Building universal JS apps with Nuxt.js",
        "summary": "Get introduced to Nuxt.js, and build great SSR Apps with Vue.js.",
        "content": "<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>",
        "author": "Jane Doe",
        "published": "08:00 - 07/06/2017"
    },
    {
        "id": 3,
        "title": "Great SSR Use cases",
        "summary": "See simple and rich server rendered JavaScript apps.",
        "content": "<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>",
        "author": "Jane Doe",
        "published": "17:00 - 06/06/2017"
    },
    {
        "id": 2,
        "title": "SSR in Vue.js",
        "summary": "Learn about SSR in Vue.js, and where Nuxt.js can make it all faster.",
        "content": "<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>",
        "author": "Jane Doe",
        "published": "13:00 - 06/06/2017"
    },
    {
        "id": 1,
        "title": "Introduction to SSR",
        "summary": "Learn about SSR in JavaScript and how it can be super cool.",
        "content": "<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>",
        "author": "John Doe",
        "published": "11:00 - 06/06/2017"
    }
]

提示: 理想情况下,龙虎大战坐庄龙虎大战坐庄我 们 应该从通过 API 获取文章数据。例如,Contentful是就是一个提供cms后台龙虎大战坐庄服务 的网站。

components 存放在 components 文件夹下,龙虎大战坐庄龙虎大战坐庄我 们 可以创建如下组件:

<!-- ./components/Posts.vue -->
<template>
  <section class="main-content">
    <div class="container">
      <h1 class="title has-text-centered">
        Recent Posts.
      </h1>
      <div class="columns is-multiline">
        <div class="column is-half" v-for="post in posts">
          <div class="card">
           <header class="card-header">
            <p class="card-header-title">
              {{ post.title }}
            </p>
          </header>
          <div class="card-content">
            <div class="content">
              {{ post.summary }}
              <br>
              <small>
                by <strong>{{ post.author}}</strong> 
                \\ {{ post.published }}
              </small>
            </div>
          </div>
          <footer class="card-footer">
            <nuxt-link :to="`/post/${post.id}`" 
              class="card-footer-item">
              Read More
            </nuxt-link>
          </footer>
        </div>
      </div>
    </div>
  </div>
</section>
</template>

<script>
  import posts from '~/posts.json'

  export default {
    name: 'posts',
    data () {
      return { posts }
    }
  }
</script>

龙虎大战坐庄龙虎大战坐庄我 们 引入 JSON 文件充当异步数据,通过 v-for 指令循环列表,取出龙虎大战坐庄龙虎大战坐庄我 们 需要的属性填充进组件模板展示。

提示: ~ 符号是 / 的别名。龙虎大战坐庄你 可以查看 这篇文档 了解更具体的用法。

下面,龙虎大战坐庄龙虎大战坐庄我 们 添加 component 到龙虎大战坐庄主页 :

<!-- ./pages/index.vue -->
<template>
<div>
    <!-- ... -->
    <posts />
</div>
</template>

<script>
import Posts from '~components/Posts.vue'

export default {
  components: {
    Posts
  },
  // ...
}
</script>

添加动态路由

现在,龙虎大战坐庄龙虎大战坐庄我 们 为文章页配置动态路由,龙虎大战坐庄龙虎大战坐庄我 们 以 /post/1 为例:

为此,龙虎大战坐庄龙虎大战坐庄我 们 添加 post 文件夹到 pages 目录下,如下:

pages
└── post
    └── _id
        └── index.vue

龙虎大战坐庄龙虎大战坐庄我 们 的程序生成相应的动态路由:

router: {
  routes: [
    // ...
    {
      name: 'post-id',
      path: '/post/:id',
      component: 'pages/post/_id/index.vue'
    }
  ]
}

更新单一发布文件:

<!-- ./pages/post/_id/index.vue -->
<template>
  <div class="main-content">
    <div class="container">
      <h2 class="title is-2">{{ post.title }}</h2>
      <div v-html="post.content"></div>
      <br>
      <h4 class="title is-5 is-marginless">by <strong>{{ post.author }}</strong> at <strong>{{ post.published }}</strong></h4>
    </div>
  </div>
</template>

<script>
  // import posts saved JSON data
  import posts from '~/posts.json'

  export default {
    validate ({ params }) {
      return /^\d+$/.test(params.id)
    },
    asyncData ({ params }, callback) {
      let post = posts.find(post => post.id === parseInt(params.id))
      if (post) {
        callback(null, { post })
      } else {
        callback({ statusCode: 404, message: 'Post not found' })
      }
    },
    head () {
      return {
        title: this.post.title,
        meta: [
          {
            hid: 'description',
            name: 'description',
            content: this.post.summary
          }
        ]
      }
    }
  }
</script>

Nuxt.js通过添加通用龙虎大战坐庄方法 ,简化开发流程。看看龙虎大战坐庄龙虎大战坐庄我 们 应该如何在单文件应用中使用它。

  • 路由校验可以通过路由校验龙虎大战坐庄方法 validate 校验路由。如果龙虎大战坐庄龙虎大战坐庄我 们 的验证路由参数验证数字,如果验证失败,将自动跳转到404页面。如果它返回“false”,Nuxt。js将自动加载404错误页面。想看龙虎大战坐庄更多 ,请查看这篇文档

  • asyncData 龙虎大战坐庄方法 用于 fetch 数据,并在龙虎大战坐庄服务 端渲染页面,返回给浏览器。它可以通过多种方式返回数据。龙虎大战坐庄龙虎大战坐庄我 们 可以通过多种方式返回数据。在本文中的例子里,龙虎大战坐庄龙虎大战坐庄我 们 使用回调函数返回页面。龙虎大战坐庄龙虎大战坐庄我 们 使用一个回调函数来返回相同的帖子“id”属性“id”参数的路线。龙虎大战坐庄你 可以看到不同的方式使用这个函数(这里)(http://nuxtjs.org/guide/async-data)。

  • 正如龙虎大战坐庄龙虎大战坐庄我 们 之前看到的,龙虎大战坐庄龙虎大战坐庄我 们 使用head 的龙虎大战坐庄方法 来设置页面 header 。这时,龙虎大战坐庄龙虎大战坐庄我 们 改变页面龙虎大战坐庄你 的 title ,添加页面信息到具体页面。

现在龙虎大战坐庄龙虎大战坐庄我 们 可以再次访问龙虎大战坐庄龙虎大战坐庄我 们 的博客看到所有路线和页面正常工作,并查看页面源代码生成的HTML。龙虎大战坐庄龙虎大战坐庄我 们 有一个龙虎大战坐庄服务 器端JavaScript应用程序呈现功能。

生成静态文件

接下来,龙虎大战坐庄龙虎大战坐庄我 们 要生成程序的 HTML 静态文件。

龙虎大战坐庄龙虎大战坐庄我 们 需要对 Nuxt.js 做一个小修改,Nuxt.js 默认忽略动态路由。为了生成动态路由文件,龙虎大战坐庄龙虎大战坐庄我 们 需要修改 ./nuxt.config.js

龙虎大战坐庄龙虎大战坐庄我 们 使用回调函数,返回以后包含动态路由的列表:

// ./nuxt.config.js

module.exports = {
  // ...
  generate: {
    routes(callback) {
      const posts = require('./posts.json')
      let routes = posts.map(post => `/post/${post.id}`)
      callback(null, routes)
    }
  }
}

如果龙虎大战坐庄你 想查看全部龙虎大战坐庄关于 generate 的配置, 可以参照 这篇文档

运行如下命令,生成全部页面:

`npm run generate`

Nuxt 将所有生成的页面放到 dist 文件夹下。

使用 Firebase Hosting 部署

最后一步,龙虎大战坐庄龙虎大战坐庄我 们 龙虎大战坐庄推荐 使用 Firebase Hosting 对项目进行部署,这样,网友在几秒内就能访问到龙虎大战坐庄龙虎大战坐庄我 们 的网站。

如果龙虎大战坐庄你 没使用过 Firebase,首先安装 Firebase CLI:

`npm install -g firebase-tools`

接下来,龙虎大战坐庄龙虎大战坐庄我 们 初始化网站,指定 dist 文件夹为公共目录,当提示:

`firebase init`

龙虎大战坐庄龙虎大战坐庄我 们 可以通过如下命令部署:

`firebase deploy`

这样,龙虎大战坐庄龙虎大战坐庄我 们 就可以访问 .firebaseapp.com 查看龙虎大战坐庄龙虎大战坐庄我 们 的网页了。查看官方 Demo 请访问http://nuxt-ssr-blog.firebaseapp.com/

Conclusion

结论

通过本文,龙虎大战坐庄龙虎大战坐庄我 们 学习了如何利用 Nuxt.js 搭配 Vue.js 构建龙虎大战坐庄服务 端渲染的 JavaScript 应用程序。龙虎大战坐庄龙虎大战坐庄我 们 还学习了如何使用其 generate 命令来生成龙虎大战坐庄龙虎大战坐庄我 们 页面的静态文件,并且,龙虎大战坐庄龙虎大战坐庄我 们 可以利用 Firebase Hosting 这样的静态托管龙虎大战坐庄工具 部署。

Nuxt.js 框架非常优秀,它已经成为了 Vue.js 官方龙虎大战坐庄推荐 的 SSR 框架 。龙虎大战坐庄我 期待 Nuxt.js 用于龙虎大战坐庄更多 的 SSR 项目,使用龙虎大战坐庄更多 Nuxt.js 的特性。

龙虎大战坐庄你 怎么看待 Vue.js SSR 框架 Nuxt.js ,龙虎大战坐庄你 怎么看待通用的 JavaScrpt 龙虎大战坐庄技术 ?请在评论区留言。

w3ctech微信

扫码关注w3ctech微信龙虎大战坐庄公众号

共收到0条回复