乐趣区

关于javascript:分享一个Nuxtjs项目实战经历

1.  为什么应用 Nuxt.js?2.  nuxt 我的项目搭建
3.  异步数据加载
4.  token 的解决逻辑
5.  mysql 接入
6.  session 的长久化解决

1. 为什么应用 Nuxt.js?

    在理解 Nuxt.js 之前,咱们先来理解一下前端页面倒退过程。Web 网站从诞生至今的二十多年工夫你,前端资源分配比例顺次经验了  大量 HTML + 大量 CSS、大量 HTML + 大量 CSS + 大量 JavaScript、大量 HTML + 大量 CSS + 大量 JavaScript、大量 HTML + 大量 CSS + 大量 JavaScript。并且 all-in-js 的趋势越来越显著。在 React\Vue\Angular 等开发框架的反对下,HTML 和 CSS 都能够有 js 编写,经编译后产生 CSS 代码和用于浏览器环境下渲染的 HTML 的 JavaScript 代码。因为 JavaScript 的起步晚于 HTML 和 CSS,最后的 Web 页面都是动态的 HTML,起初才逐渐退出 CSS 和 JavaScript。SEO 爬虫软件通过剖析网站的 HTML 文档抓取信息,但并不能反对抓取 JavaScript 脚本,即使是在 React 和 Vue 等浏览器端渲染计划 CSR 大行其道的明天,也仅有 google 爬虫能初步简略反对 SPA,这还须要在编写代码时做非凡解决。传统的服务器端渲染 SSR 计划是借助服务端编程语言或者框架搭配的 HTML 模板引擎将数据编译为 HTML 文档,比方实用于 Java 的 FreeMaker 和实用于 Node.js 的 Pug 等。模板引擎能够被了解为一个功能强大的字符串解决工厂。

  Nuxt.js 是当下罕用的的服务器端渲染计划 SSR。SSR 绝对于 CSR 最次要的劣势在于其反对 SEO(搜索引擎优化)和首屏工夫短,能够在服务端把次要内容获取实现并生成 HTML 发送到浏览器端,这个过程中能够提供更加具体的信息供 SEO 抓取。而罕用是 SPA 计划则通常是返回一个仅有及时行代码的 html 文档和一大堆 JavaScript 文件到浏览器端,HTML 文档中简直不蕴含页面重要信息,页面内容次要由 JavaScript 文件中的逻辑产生并增加到 dom 中。在首屏渲染方面,当初的很多大中型我的项目在首页就会申请大量数据,SSR 我的项目中能够把首屏须要的要害数据申请放在服务端实现,大多数状况下服务端网络设施是显著强于 C 端浏览器的,这样能节俭不少申请工夫,用户看到的页面,是一个曾经带有要害数据的可用页面。而 SPA 页面往往是在页面加载实现之后再去发送网络申请,白屏工夫会更长,用户体验不佳。

   然而并不是所有的前端我的项目都举荐应用 SSR,因为 Nuxt.js 和 Next.js 等框架的反对能力目前还有余,SSR 我的项目中开发前端还是有很多中央会有掣肘,比方生命周期和罕用钩子不如 CSR SPA 我的项目那样丰盛。然而在对 SEO 和首屏渲染工夫具备强需要的我的项目中,如企业官网、产品列表等我的项目,咱们心愿页面能尽量被搜索引擎抓取到并且能尽可能减少用户的白屏等待时间,就能够采纳 SSR 框架进行开发。

  Nuxt.js 是一个基于 Vue.js 的轻量级利用框架,可用来创立服务端渲染 利用,也可充当动态站点引擎生成动态站点利用,具备优雅的代码构造分层和热加载等个性。Nuxt.js 实现了开箱即用的劝勉反对,利用 SSR,Node.js 服务器将基于 Vue 的组件渲染成 HTML 并传输到客户端,而不是纯 javascript。与传统的 Vue SPA 相比,应用 SSR 将带来微小的 SEO 晋升、更好的用户体验和更多的机会。

2. Nuxt.js 我的项目搭建

   Nuxt.js 团队创立了脚手架工具 create-nuxt-app 来搭建 Nuxt.js 我的项目,可采纳如下命令创立:

`px create-nuxt-app < 我的项目名 >`

或者

`yarn create nuxt-app < 我的项目名 >`
创立中会让人抉择集成的服务器框架(如 Express\Koa\Hapi)等,还能够抉择须要的 UI 框架、测试框架、开发模式等等。咱们也能够抉择应用 Express-template 创立我的项目
`vue init nuxt-community/express-template nuxt-express`
当然也能够本人手动创立 nuxt 我的项目,从 package.json 装置 nuxt 依赖开始本人入手。如果咱们采纳 express-template 创立我的项目,失去的我的项目目录如下:|—— server        Node.js 后盾代码寄存目录
    |—— routes                api 接口代码文件目录
      |—— users.js    api 接口代码文件
    |—— index.js              外围文件,接口层通用配置
|—— assets                     用于搁置未编译的动态资源如 LESS、SASS
    |—— css                        
    |—— img
|—— components          一般组件目录
    |—— Footer.vue
|—— layouts                   布局文件目录
    |—— default.vue        默认布局(必须),也能够本人编写布局,在 page 中指定应用该布局文件,没有指定时,默认应用 default 布局
    |—— error.vue            页面出错时会默认展现的布局
|—— middleware           用于寄存利用的中间件
|—— pages                      路由组件目录,每一个文件都将作为一个独自的页面出现
   |—— _id.vue                路由组件文件(编译后会主动生成路由 /:id)|—— index.vue            路由组件文件(对应路由 /)|—— plugins                    公共函数目录
    |—— axios.js
|—— static                       动态文件目录,该目录不会被 webpack 编译
|—— store                       用于组织利用的 vuex 状态树
|—— .eslintrc.js       
|—— .gitignore
|—— nuxt.config.js         用于自定义配置,能够笼罩默认配置
|—— package.json
|—— README.md
    

这里至关重要的就是 nuxt.config.js 文件,能够在该文件中个性化配置 nuxt 我的项目的部署形式、生成 html 的配置项(如 title\head\css\plugins)、打包配置选项、路由配置、环境变量配置等等丰盛的选项。

3. 异步数据加载

nuxt.js 封装了 $http$axios组件,能够让咱们在前端页面中,像一般的 SPA 利用一样不便地应用这些网络申请模块在浏览器中向后盾申请数据。

后面咱们提到 nuxt.js 能够利用于 SEO,它的特别之处就在于扩大了 Vue.js,减少了一个叫asyncData 的办法,使得咱们能够在设置组件的数据之前能异步获取或解决数据。asyncData 办法会在组件(限于页面组件)每次加载之前被调用。它能够在服务端或路由更新之前被调用。在这个办法被调用的时候,办法参数中默认提供了 $http 和 $axios 组件,能够利用 asyncData 办法来获取数据,Nuxt.js 会将 asyncData 返回的数据交融组件 data 办法返回的数据一并返回给以后组件。这也就决定了咱们能够在服务端实现首屏数据申请,并将数据填充到 html 中,再返回给浏览器。

nuxt 我的项目能够仅仅作为一个中间层提供接口转发和服务器端渲染,也能够涵盖一个残缺的后盾提供服务。在官网我的项目中,咱们的后盾服务和 nuxt 利用是在同一个我的项目中的,首先咱们在 nuxt.config.js 文件中指明了后盾接口的申请地址,所有 /api 结尾的接口都将向根目录下 server 目录中申请:

/*
** Server Middleware
*/
serverMiddleware: {'/api': '~/server'},

咱们革新了上述 server 目录,使其能够成为一个独立的利用提供对内和对外的服务,整个服务就是一个 express 利用,革新后的 server 目录构造也更加清晰简略:

|—— server        Node.js 后盾代码寄存目录
    |—— controllers         控制器目录,接口的逻辑解决等
      |—— users.js    user 相干的控制器,与数据库表相干的解决时,会援用相应的 models
   |—— middleware       接口中间件,能够做一些权限、cookie 等方面的通用解决
      |—— check.js    
   |—— models                数据层目录
      |—— user.js      user 无关的表的读取解决等逻辑,援用 db.js
   |—— mysql                  数据库操作目录
      |—— db.js        数据库连贯通用配置
       |—— sql.js        sql 语句表,咱们把所有的 sql 语句都放到这里,不便咱们对立审核
    |—— routes                 api 接口路由目录
        |—— index.js    路由调配的中间件
      |—— users.js    user 相干的路由治理,援用 user 控制器和接口中间件
    |—— index.js              外围文件,接口层通用配置

4. token 的解决逻辑

在零碎中有注册登录等功能模块时,就须要用到 token 的治理。在 nuxt 我的项目后盾中,同 express 利用一样,咱们能够应用 express-jwt 来实现。

express-jwt 有多种加密计划,咱们这里采纳 rsa 计划,学生成公钥和私钥保留在根目录。咱们个别在用户登录胜利之后生成 token,并在返回报文中返回给浏览器,由浏览器保留并在下一个接口增加到 headers 中,express-jwt 提供了现成的接口生成 token:

// 留神默认状况 Token 必须以 Bearer+ 空格 结尾
const privateKey = fs.readFileSync('rsa_private_key.pem')
const token = 'Bearer' + jwt.sign(
  {
    user_id: user.id,
    isLogin: true
  },
  privateKey,
  {algorithm: 'RS256'}
)
return res.send({
  code: constants.SUCCESS,
  token,
  user,
  msg: '登录胜利'
})

token 的校验则是在接口通用逻辑 server/index.js 中解决,在接口申请中间件中应用 express-jwt,会自行采纳公钥校验 token,咱们能够设置不通过 Token 解析的接口门路。如果 token 校验通过,则接口进入下一环节,如果没有通过,则会返回 UnauthorizedError 的谬误并被捕获解决。

import fs from 'fs'
import express from 'express'
import expressJwt from 'express-jwt'
const createError = require('http-errors')

// Create express instance
const app = express()
const publicKey = fs.readFileSync('rsa_public_key.pem')
app.use(expressJwt({
  secret: publicKey, // 签名的密钥
  algorithms: ['RS256'] // 设置算法(官网文档上没有写这个,然而不配置的话会报错)}).unless({path: ['/api/users/login', '/api/users/getcaptcha', '/api/test', /\/api\/portal/i] // 不通过 Token 解析的门路
}))
// error handler
app.use(function (err, req, res, next) {if (err.name === 'UnauthorizedError') {
    //  能够依据本人的业务逻辑来解决
    return res.send({
      code: '401',
      msg: '您还未登录,请先登录'
    })
  }
  // set locals, only providing error in development
  res.locals.message = err.message
  res.locals.error = req.app.get('env') === 'development' ? err : {}
  // render the error page
  res.status(err.status || 500)
  res.render('error')
})
module.exports = app

5. mysql 的接入

无妨先理解一下 config-lite 这款小工具。它默认读取根目录下 config 文件夹下的文件,依据以后的零碎环境 development\production 一次降级查找对应名称的 js\json\node\yml\yaml 等文件配置,并和 default 配置合并,产生以后环境下最终配置文件。咱们能够通过它读取以后配置,而不必在切换环境变量时更改咱们应用的配置。

咱们能够应用罕用的各种类型的数据库,express 应用服务框架均由良好的接入能力。在研究院门户网站中咱们采纳罕用的 mysql 数据库,这里须要应用到 express 接入 mysql 的连贯工具 mysql npm 包。首先在 config\development.js 中咱们定义数据库连贯相干配置

module.exports = {
  mysql: {
    // 测试服务器
    host: '127.0.0.1',
    port: '3306',
    user: 'your-database-username',
    password: 'your-password',
    database: 'your-database-name',
    waitForConnections: true,
    connectionLimit: 50,
    queueLimit: 0
  }
}

在 server\mysql\db.js 中,咱们定义数据库的接入形式。数据库的连贯能够采纳单个申请连贯 connection,也能够采纳连接池 pool,还有 poolcluster 等计划,具体的 api 能够在 github 中 mysql 包中查看。咱们这里示例采纳一般连接池,mysql npm 工具会在连贯实现之后主动敞开连接池。

import mysql from 'mysql'
const config = require('config-lite')({
  filename: process.env.NODE_ENV,
  config_basedir: __dirname,
  config_dir: 'config'
})
const pool = mysql.createPool(config.mysql)
export default pool

在 models 中咱们就能够援用 pool 来进行数据库相干操作,如 userModels,pool.query 提供了数据库连接池的操作方法,办法第一个参数是一条 sql 语句

import pool from '../mysql/db'
import {UserSql} from '../mysql/sql'

findOne (param) {return new Promise(function (resolve, reject) {pool.query(UserSql.findOne, [param.username], function (error, results, fields) {if (error) {console.error(error)
          reject(error)
        }
        resolve(results[0])
      })
    })
}

6. session 的长久化解决

会话咱们同样须要用到 express 的小工具 express-session,在 config\default.js 中咱们须要配置 session 的参数:

module.exports = {port: parseInt(process.env.PORT, 10) || 8001,
  session: {
    name: 'aaa',
    secret: 'bbb',
    id: '',
    captcha: '',
    cookie: {
      httpOnly: true,
      secure: false,
      maxAge: 365 * 24 * 60 * 60 * 1000
    }
  }
}

配置参数中申明了 cookie 的相干参数、token 的生成密钥等相干参数。在 server\index.js 文件中,咱们引入 session 中间件

import session from 'express-session'
app.use(session({
  name: config.session.name,
  secret: config.session.secret,
  resave: false,
  captcha: config.session.captcha,
  saveUninitialized: false,
  cookie: config.session.cookie
}))

然而这样并没有实现 session 长久化存储,在开发过程中重启我的项目后产生 session 失落。express 有针对 session 在 mysql 数据库中长久化存储的小工具,咱们须要在在 server\mysql\db.js 中初始化 sessionStore:

import mysql from 'mysql'
const config = require('config-lite')({
  filename: process.env.NODE_ENV,
  config_basedir: __dirname,
  config_dir: 'config'
})
const session = require('express-session')
const MySQLStore = require('express-mysql-session')(session)
const pool = mysql.createPool(config.mysql)
export const sessionStore = new MySQLStore({}/* session store options */, pool)
export default pool

在 server\index.js 文件中,判断接口 session 时,退出长久化配置,这样会主动在 mysql 数据库中增加一张 sessions 表,存储 session_id、expires、data 等信息。咱们能够在必要的时候对长久化的 session 做 destroy clear 等操作,也能够将长久化的 session reload 到内存中。

import {sessionStore} from './mysql/db'
import session from 'express-session'
app.use(session({
  name: config.session.name,
  secret: config.session.secret,
  resave: false,
  captcha: config.session.captcha,
  saveUninitialized: false,
  cookie: config.session.cookie,
  store: sessionStore
}))

以上就是第一次用 nuxt.js 做我的项目的一点小小的总结,欢送大家批评指正

退出移动版