回忆杀,Nuxt.js
这两年,我主要从事部门周边业务,搭建了数个细碎的 web 应用。最近由于一些人事变动,我又回到了最初的产品线上。时光飞逝,欣赏着自己的遗(la)产(ji)代码,“青骢”岁月浮现眼前。今天就谈谈我第一个web技术栈——nuxt.js,一款server/client
同构渲染的 vue 框架。
安装
当年向领导层推荐 nuxt 的时候,我列了很多理由;虽然有些比较扯蛋,但当时最核心的考量是,nuxt 可以帮助我们零基础上手 web 应用。我这里先说说如何安装。nuxt 多年来一直使用的是 npm script 脚手架:操作就这么几步:
- 在命令行里敲下:
yarn create nuxt-app
- 按默认选项安装依赖
- 一句
yarn dev
,开工了!
也许,经历过那段时期的老员工依旧会对 nuxt 抱有微词,毕竟坑是不可抗拒的。但在前端开发方面,nuxt(相比于单纯的 vue 库)还是给我们带来了很多惊喜:它封装了上述所有配置,限制了代码风格和目录结构,提供了一个相对舒适的开发环境,我们因此得以在最短时间内投入到了生产实践中。
目录结构 作为一个通用框架,nuxt 给我们提供了什么?我最早是 1.4 版本开始的第一个 nuxt 项目,到今天是 2.11 版本,nuxt 的目录结构几乎没有变化:
├── .nuxt
├── pages
├── components
├── layouts
├── assets
├── static
├── store
├── plugins
├── middleware
├── nuxt.config.js
- .nuxt
nuxt 内置了 webpack,当运行nuxt build
后,它会将相关目录的文件打包压缩到.nuxt
目录下,方便进一步应用部署。
- pages
页面文件目录——vue 文件夹。该目录下的目录结构和 vue 文件名会在 build 时映射为vue-router
配置。我们来看看约定的路由规则:
├── pages │├── index.vue │├── login.vue │└── dashboard │└── about.vue
上述目录结构最终会被描述为:/
、/login
,以及/dashboard/about
三个路由。还可以设置动态路由;如下所示,该路由将被映射为/job/:id
,并可以通过this.$route.params.id
获取路由参数。
├── pages │└── job │└── _id.vue
此外,各个页面以及后续的引入模块,会以懒加载的形式在路由跳转后import
;相比于传统的 spa(单页面应用),ssr(服务端渲染)的 nuxt 单次加载的资源更少,这也成为了 nuxt 刚出来时的一个卖点——首页渲染快。
- 【回忆杀,Nuxt.js】components
组件目录,顾名思义,用于放置 vue 的功能组件。注意,该目录下的 vue 文件,不具有 nuxt 增强的生命周期钩子,即它不能使用 asyncData、fetch 这类钩子;这种限制我倒比较支持,组件和数据请求应当尽可能的正交化。
- layouts
第三个 vue 文件目录,放置 page 布局,通俗来说就是不同页面的通用模版。比如:我们自己写了一个叫/layouts/trophy.vue
的奖杯布局,
pages 目录下的页面通过 layout 字段指定该类型模版,之后 page 内容会填充到
标签里。
- asserts 和 static
asserts 和 static 就是所谓的资源目录,存放 css、less、图片等文件。Nuxt 集成了 css-loader、file-loader、url-loader 等 webpack 加载器,当你把这些文件放在 asserts 目录之下时,nuxt 内置的 webpack 会针对特定文件选择特定加载器,打包、压缩、拷贝到.nuxt 相应路径之下;而相对较大的资源文件,则可以放在 static 之下,webpack 将直接拷贝到.nuxt 之下
- store
store 对应的就是 vuex 状态树文件。nuxt 自带 vue 全家桶,自然也包含了 vuex。store 里的 js 文件最终会被 nuxt 构件为 vuex 相关功能配置。
- plugins & middlewar
插件和中间件,用于定制化拓展。比如使用 vuetify,element 这类 ui 库,我们就可以将相关配置放置在 plugins 里。又比如,你想对所有请求加权限控制,可以将配置放在 middlewar 里;所有资源的请求将先经过这里的中间件,并做相应的错误处理。
- nuxt.config.js
nuxt 框架本身的配置文件,可以定制框架功能。最常用的修改就是在这里调整默认的 webpack 配置了,而且最近几版新添的配置项,主要方向也是在暴露内置 webpack 的 api。
生命周期 上面提到过 nuxt 框架对 vue 生命周期的增强。我们刨去 vue 自带的生命周期(简化为 Render),看看增强部分。
文章图片
Nuxt Lifecycle
- nuxtServerInit
nuxtServerInit 只在首次请求到来时(第一次导航到站点,或是刷新页面时),在 server 端调用,与 client 端无关。设计的目的就是在 server 端异步请求数据,并初始化全局 vuex 状态树。
- middleware
第二步是请求通过各类中间件。上面提到过,我们会在 middlewar 目录下放置各类中间件作为请求的过滤器。中间件包括 nuxt.config.js 配置的全局中间件,和 layout、page 里指定的组件级中间件两种。
// middleware/authenticated.js export default function ({ store, redirect }) { if (!store.state.authenticated) { return redirect('/login') } }
- validate
validate 是 page 里的钩子方法,作用于动态路由对映的页面组件中。目的是配置一个校验方法,动态检验路由参数的有效性。
- asyncData / fetch
再之后是两种异步数据请求的钩子。asyncData
用于异步取数,并初始化data
(增强 vue 生命周期里的data
)。fetch
也是异步取数,但不返回数据,一般用作初始化局部使用的 vuex 状态数——可以与 nuxtServerInit 比较一下。
asyncData / fetch 触发的时机大家需要注意一下,client 和 server 都有可能触发。在页面初次加载时,由 server 触发数据请求;后续若有路由变化,会是在 client 触发。
Hooks | Server(1st page) | Client(1st page) | Client(next pages) |
---|---|---|---|
nuxtServerInit | ? | ? | ? |
middleware | ? | ? | ? |
beforeCreate | ? | ? | ? |
asyncData/fetch | ? | ? | ? |
Created | ? | ? | ? |
mounted | ? | ? | ? |
不过,框架之于库的劣势也很鲜明:缺乏灵活性,缺少配套插件,封装可能过深,项目侵入较大等等。我自己碰过最大的坑是,nuxt 对 serverless lambda 支持不友好;server 端的依赖不能打包部署,只能把所有 node_modules 一股脑扔到 lambda 上,结果超出了 lambda 上传 size 限制。所幸,有个小姑娘花了两礼拜时间,用 webpack 过滤掉了无用文件,从而大幅减少了 size。当然,依赖问题可能是各种技术栈都会碰到的难题。我就见过有些部门专门组织多人团队,花了一年时间才勉强解决依赖过大的问题,最后得到了领导层的高度赞扬。
总之,框架和库的选择目前来说还是极度依个人经验,很难找出一套可以量化优劣的评判机制;多写代码,积累经验,并在适当时机转型,可能是比较靠谱的应对之道。(我也经常在 nuxt 和 vue spa 之间摇摆,有时候还会被领导层喷“拍脑袋”,)
相关 文章同步发布于an-Onion 的 Github。码字不易,欢迎点赞
推荐阅读
- 猎杀IP
- 回忆曾经看过的小说
- 童年回忆
- 我的世界同人小说《暮色齿轮》第三回|我的世界同人小说《暮色齿轮》第三回 回忆
- 杀死一只知更鸟
- 吃可爱长大的易烊千玺,一害羞就会耸肩,花式耸肩杀
- 2018.07.07《刺杀骑士团长》村上春树
- 夏三两遗事·五
- (9)发现身边的“冷面杀手”铁缺乏
- 《陪孩子终身成长》读后感之(家暴是孩子健康的杀手)