关于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做我的项目的一点小小的总结,欢送大家批评指正

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理