回忆杀,Nuxt.js
这两年,我主要从事部门周边业务,搭建了数个细碎的 web 应用。最近因为少量人事变动,我又回到了最初的产品线上。时光飞逝,欣赏着自己的遗(la)产(ji)代码,“青骢”岁月浮现眼前。今天就谈谈我第一个web技术栈——nuxt.js,一款server/client
同构渲染的 vue 框架。
安装
当年向领导层推荐 nuxt 的时候,我列了很多理由;尽管有些比较扯蛋,但当时最核心的考量是,nuxt 可以帮助我们零基础上手 web 应用。我这里先说说如何安装。nuxt 多年来一直使用的是 npm script 脚手架:操作就这么几步:
- 在命令行里敲下:
yarn create nuxt-app <my-project>
- 按默认选项安装依赖
- 一句
yarn dev
,开工了!
在 vue-cli 满天飞的今天,npm 脚手架自然算不上什么惊奇的事情了,但几年前能做到零基础启动 vue 是很不容易的。我记得那时候市面上的资料还是基于 html 挂载 vue.js——把 vue 当作一个相似于 Jquery 的 lib 使用。作为练习项目而言,以上足够了;但是,放到一个企业级项目里,你要考虑其余问题,比方浏览器兼容、开发体验、代码风格……这就意味着你要配齐 vue 全家桶,各色 webpack、eslint、babel 配置,集成三方的 UI 库,布置后台服务等等等等。在一个几乎没有任何现代开发经验的项目组里,该怎样上手?从零开始学所有配置,或者是在 github 的某个角落找到大体接近你需求的 demo,而后开始修改自己也不懂的各色文件?
也许,经历过那段时期的老员工仍旧会对 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 刚出来时的一个卖点——首页渲染快。components
组件目录,顾名思义,用于放置 vue 的功能组件。注意,该目录下的 vue 文件,不具备 nuxt 加强的生命周期钩子,即它不能使用 asyncData、fetch 这类钩子;这种限制我倒比较支持,组件和数据请求应当尽可能的正交化。
layouts
第三个 vue 文件目录,放置 page 布局,浅显来说就是不同页面的通用模版。比方:我们自己写了一个叫
/layouts/trophy.vue
的奖杯布局,<!-- layouts/trophy.vue --><template> <div id="app"> <header/> <main> <nuxt /> </main> </rooter> </div></template>
pages 目录下的页面通过 layout 字段指定该类型模版,之后 page 内容会填充到
<nuxt />
标签里。<!-- pages/index.vue --><script>export default { layout: "trophy"};</script>
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-cli 推荐结构的普及;目录结构看似正当,但是与主流风格稍有不同,还是略显美中不足的。在项目开始前,最好先确定这类代码规范;这样,当切换项目、新手入门,或者是多团队合作时,能尽最大可能减少“解码成本”——了解项目逻辑所需的成本。我参加的项目因为历史惯性,之后都沿用了 nuxt 风格。
生命周期
上面提到过 nuxt 框架对 vue 生命周期的加强。我们刨去 vue 自带的生命周期(简化为 Render),看看加强部分。
Nuxt Lifecycle
nuxtServerInit
nuxtServerInit 只在初次请求到来时(第一次导航到站点,或者是刷新页面时),在 server 端调用,与 client 端无关。设计的目的就是在 server 端异步请求数据,并初始化全局 vuex 状态树。
middleware
第二步是请求通过各类中间件。上面提到过,我们会在 middlewar 目录下放置各类中间件作为请求的过滤器。中间件包括 nuxt.config.js 配置的全局中间件,和 layout、page 里指定的组件级中间件两种。
// middleware/authenticated.jsexport default function ({ store, redirect }) { if (!store.state.authenticated) { return redirect('/login') }}
<!-- /pages/index.vue --><script>export default { middleware: 'authenticated'}</script>
validate
validate 是 page 里的钩子方法,作用于动态路由对映的页面组件中。目的是配置一个校验方法,动态检验路由参数的有效性。
<!-- /pages/job/_id.vue --><script>export default { validate({ params, query, store }) { return true // if the params are valid return false // will stop Nuxt.js to render the route and display the error page }}</script>
asyncData / fetch
再之后是两种异步数据请求的钩子。
asyncData
用于异步取数,并初始化data
(加强 vue 生命周期里的data
)。fetch
也是异步取数,但不返回数据,一般用作初始化局部使用的 vuex 状态数——可以与 nuxtServerInit 比较一下。<script>export default { asyncData() { return axios.get("/api/data"); }, async fetch ({ store, params }) { let { stars } = await axios.get('http://api/stars'); store.commit('setStars', stars); },};</script>
asyncData / fetch 触发的时机大家需要注意一下,client 和 server 都有可能触发。在页面首次加载时,由 server 触发数据请求;后续若有路由变化,会是在 client 触发。
nuxt 加强的生命钩子主要就是上面几种,分工很明确。不过因为 SSR 的特性,server 和 client 端都有可能触发这些钩子,所以 debug 的时候,还是很容易搞混的。我这里列一下最常见的钩子触发时机,大家注意一下:
Hooks | Server(1st page) | Client(1st page) | Client(next pages) |
---|---|---|---|
nuxtServerInit | ? | ? | ? |
middleware | ? | ? | ? |
beforeCreate | ? | ? | ? |
asyncData/fetch | ? | ? | ? |
Created | ? | ? | ? |
mounted | ? | ? | ? |
小结
这期详情了一款基于 vue 的 SSR 框架——nuxt。nuxt 框架比照 vue 库的好处是:它提供了一套完整的处理方案,帮助团队统一命令、规范代码、集成配套工具、封装配置文件,以及提供生产和开发环境。这是对缺少文档、缺乏经验,或者是流动性很大的团队来说,不可或者缺的优异功能。
不过,框架之于库的劣势也很鲜明:缺乏灵活性,缺少配套插件,封装可能过深,项目侵入较大等等。我自己碰过最大的坑是,nuxt 对 serverless lambda 支持不友好;server 端的依赖不能打包部署,只能把所有 node_modules 一股脑扔到 lambda 上,结果超出了 lambda 上传 size 限制。所幸,有个小姑娘花了两礼拜时间,用 webpack 过滤掉了无用文件,从而大幅减少了 size。当然,依赖问题可能是各种技术栈都会碰到的难题。我就见过有些部门专门组织多人团队,花了一年时间才勉强处理依赖过大的问题,最后得到了领导层的高度赞扬。
总之,框架和库的选择目前来说还是极度依个人经验,很难找出一套可以量化优劣的评判机制;多写代码,积累经验,并在适当时机转型,可能是比较靠谱的应对之道。(我也经常在 nuxt 和 vue spa 之间摇摆,有时候还会被领导层喷“拍脑袋”,)
相关
文章同步发布于an-Onion 的 Github。码字不易,欢迎点赞
1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是摆设,本站源码仅提供给会员学习使用!
7. 如遇到加密压缩包,请使用360解压,如遇到无法解压的请联系管理员
开心源码网 » 回忆杀,Nuxt.js