2023年6月21日发(作者:)
实现⼀个SSR的前端博客的⽰例代码为什么要⽤公司现有的项⽬只有落地页是通过前端本⾝server读取pug⽂件进⾏服务端渲染的,当然是为了⾸屏加载速度以及SEO。 是⼀个基于的通⽤应⽤框架,预设了利⽤开发服务端渲染的应⽤所需要的各种配置,只需要安装官⽅⽂档的要求进⾏开发,就可以很好的解决SSR的问题。我们以⼀个简单的博客为例,来实践⼀下。项⽬介绍当前基于的简化版博客,包括注册、登录、⽂章列表页⾯、⽂章详情页、以及⽤户列表页等⼏个页⾯,⽤户信息使⽤了Vux进⾏存储,异步数据使⽤了asyncData进⾏获取,配合了nuxtServerInit、cookie来处理刷新页⾯后Vux数据丢失的问题,同时使⽤了error模板页⾯处理常规错误,使⽤了中间件进⾏了简单的权限校验。该项⽬不⾜点,统⼀封装了axios的⽅法,但是没有考虑到服务端请求接⼝,token的处理。⽬录结构 assets: 资源⽂件。⽤于组织未编译的静态资源如 LESS、SASS或 JavaScript。components: 组件。layouts: page: 模板页⾯,默认为 可以在这个⽬录下创建全局页⾯的统⼀布局,或是错误处理页⾯页,需要提供⼀个nuxt 标签,类似于router-viewmiddleware: 中间件,放置⾃定义的中间件,会在加载组件之前调⽤。可以在页⾯中调⽤: middleware: '中间件名称'。pages: 页⾯, 为根页⾯, 框架读取该⽬录下所有的 .vue⽂件并⾃动⽣成对应的路由配置,如需要动态参数id,则可以添加_id的⽂件,必须是下划线加参数名。plugin: 插件,⽤于组织那些需要在 根应⽤实例化之前需要运⾏的 Javascript 插件。static: 静态⽂件,静态⽂件⽬录 static⽤于存放应⽤的静态⽂件,此类⽂件不会被 调⽤ Webpack 进⾏构建编译处理。store: ⽤于组织vuex状态管理。具体使⽤请移步⾄ 官⽹。: ⽂件⽤于组织 应⽤的个性化配置,配置head,loading,css,plugins等。⽣命周期1. incoming Request 浏览器发出的请求)2. nuxtServerInit 服务端接受请求后,要检查当前有没有 nuxtServerInit配置项,如果有就执⾏这个函数3. store action ⽤来操作vuex4. middleware 可以做jWT等⼀些操作。5. validate() 检验参数,参数检验失败,可以在layout⾥的error⾥⾯进⾏捕捉。6. asyncData()& fetch() asyncData⽤来渲染组件,fetch⽤来渲染vuex7. RenderNuxt扩展以后的⽣命周期和⽅法以下:beforeCreate: ƒ beforeCreate()components: {NuxtLoading: {…}}computed: {isOffline: ƒ}context: {isStatic: false, isDev: true, isHMR: true, app: {…}, payload: undefined, …}created: ƒ created()data: ƒ data()head: {title: "nuxt-meituan-ssr", meta: Array(3), link: Array(1), style: Array(0), script: Array(0)}methods: {refreshOnlineStatus: ƒ, refresh: ƒ, errorChanged: ƒ, setLayout: ƒ, loadLayout: ƒ}mounted: ƒ mounted()nuxt: {…}render: ƒ render(h, props)router: VueRouter {app: Vue, apps: Array(1), options: {…}, beforeHooks: Array(2), resolveHooks: Array(0), …}watch: {: "errorChanged"}注意:⽣命周期的钩⼦只有beforeCreate和created会在服务端和客户端渲染。以上⽣命周期⾥都获取不到window对象。asyncData和fetch我们可以拿到数据,不要尝试挂载数据到data上,此时获取不到this对象。开发总结如何修改默认启动端⼝?可以在下⾯修改配置,如下。"config":{ "nuxt":{ "host":"127.0.0.1", "port":"3304" }}如何添加全局的样式?可以在assets⾥添加全局Css⽂件,如在assets下的Css⽂件夹⽬录下添加了⼀个⽂件,然后在⾥配置该css⽂件路径即可。 css:['~assers/css/']通过别名访问图⽚在template⾥是正确的,为何在Css设置背景图却报错?在css配置的是,需要将'~/'后⾯的'/'去除掉。
backround-image:url('~static/');如何添加路由动画?同样,我们在Css⽂件⾥添加⼀些动画代码,⼀般样式会在其后⾯添加-active和-leave-active,其实和Vue动画形式⼀致。其中以page开头的动画,默认会作⽤于全部页⾯,如果想给特定的页⾯加动画,可以在对应的页⾯script⾥引⽤,如 transitions:'bounce'即可。.page-enter-active, .page-leave-active { transition: opacity .3s } .page-enter, .page-leave-active { opacity: 0 } .bounce-enter-active { animation: bounce-in .8s; } .bounce-leave-active { animation: bounce-out .5s; } @keyframes bounce-in { 0% { transform: scale(1) } 50% { transform: scale(1.01) } 100% { transform: scale(1) } } @keyframes bounce-out { 0% { transform: scale(1) } 50% { transform: scale(1.01) } 100% { transform: scale(1) } }路由参数如何传递?同Vue-router,有声明式和编程式两种⽅式,⽆⾮是标签变成了 (...) nuxt-link :to="{name:'article',params:{id:1234}}" >声明式 // 编程式 this.$({ name:'article', params:{ id:1234 } })动态路由如何进⾏参数检验?提供了⼀个validate的⽣命周期钩⼦,可以在此进⾏参数的校验。以⽂章详情校验id为例,我们需要判断传⼊的id是否是数字,可以像下⾯这样处理。 validate({ params }) { return /^d+$/.test() }如何添加404等错误页⾯?可以在layout下新建⼀个页⾯,内容如下,当访问⼀个不存在的页⾯的时候,或者参数检验失败的时候,或者我们在middleware中间件处理抛出异常的时候,都会跳转到该页⾯。 页⾯不存在
应⽤发⽣错误异常
Stars: {{ $ }}
如何动态修改title的内容?如果是写死的,可以直接修改head的配置。 head() { return { // title: '',这⾥⼀旦声明,在asyncdata⾥修改也不起作⽤,直接以这个为准 meta: [ { hid: 'description', // 替换唯⼀标识 hid { hid: 'description', name: 'description', content: ' project' } name: 'content', content: '⽂章详情' } ] } },如果是动态数据从数据源⾥获取,然后通过asynData⾥的app对象,动态修改head的title。 asyncData({ app, params }) { const id = ; return getArticleDetail({ id }) .then(result => { = ; }) .catch(err => {}) }如何进⾏权限JWT验证?登录成功以后,我们会在cookie和Vuex中缓存token信息,当界⾯刷新的时候,会⾛store⾥的nuxtServerInit 函数,该函数仅在每个服务器端渲染中运,可以使⽤获取浏览器的cookie,再次更新store⾥的值,接着会⾛到中间件,中间件进⾏验证,如果有token信息则继续,没有则跳转到登录页。1. 为什么要在nuxtServerInit更新store的值?需要在middleware⾥使⽤,否则刷新后store⾥的值为空了。2. 客户端调⽤接⼝可以拿到token,服务器端如何拿到?可以通过nuxtServerInit⾥的req拿到请求信息的cookie,然后请求接⼝。3. 前后端分离,刷新的时候如何保证⽤户名、token等信息依然存在?可以像上⾯⼀样,每次取cookie的值再次更新store,但这样有⼀个问题,cookie可能会被篡改,后端代码需要做验证。也可以每次刷新重新通过token请求接⼝,更新⽤户信息。store代码import Vue from 'vue';import Vuex from 'vuex';import user from './modules/user';import { COOKIE_KEY } from '~/assets/js/';(Vuex);const store = () => new ({ modules: { user }, actions: { async nuxtServerInit({ commit, dispatch }, { req, app }) { if () { let parsedResult = {}; (';').forEach(cookie => { const currentCookie = ('='); parsedResult[currentCookie[0].trim()] = (currentCookie[1] || '').trim(); }); const userInfo = { name: parsedResult[COOKIE_], token: parsedResult[COOKIE_] }; commit('user/setUserInfo',userInfo); } } } });export default store;中间件代码export default function({ store, error, redirect }) { if (! || !) { // error({ // message: 'You are not connected', // statusCode: 403 // }) redirect('/'); }}nginx部署 npm run build选择build以后的四个⽂件: .nuxt, static, , 上传到服务器。pm2 pm2 start npm --name '' -- run startnginx配置查看⽹页源代码可以看到: server{ listen 3000; server_name ;
gzip on; gzip_buffers 32 4K; gzip_comp_level 6; gzip_min_length 100; gzip_types application/javascript text/css text/xml; gzip_disable "MSIE [1-6].";
gzip_vary on; proxy_buffer_size 64k; proxy_buffers 32 32k; proxy_busy_buffers_size 128k; location / { root /data/ww/nuxt; proxy_pass 127.0.0.1:3002; proxy_set_header X-Real-IP $remote_addr; } }这样,使⽤实现了⼀个服务端渲染的简易博客。以上就是本⽂的全部内容,希望对⼤家的学习有所帮助,也希望⼤家多多⽀持。
2023年6月21日发(作者:)
实现⼀个SSR的前端博客的⽰例代码为什么要⽤公司现有的项⽬只有落地页是通过前端本⾝server读取pug⽂件进⾏服务端渲染的,当然是为了⾸屏加载速度以及SEO。 是⼀个基于的通⽤应⽤框架,预设了利⽤开发服务端渲染的应⽤所需要的各种配置,只需要安装官⽅⽂档的要求进⾏开发,就可以很好的解决SSR的问题。我们以⼀个简单的博客为例,来实践⼀下。项⽬介绍当前基于的简化版博客,包括注册、登录、⽂章列表页⾯、⽂章详情页、以及⽤户列表页等⼏个页⾯,⽤户信息使⽤了Vux进⾏存储,异步数据使⽤了asyncData进⾏获取,配合了nuxtServerInit、cookie来处理刷新页⾯后Vux数据丢失的问题,同时使⽤了error模板页⾯处理常规错误,使⽤了中间件进⾏了简单的权限校验。该项⽬不⾜点,统⼀封装了axios的⽅法,但是没有考虑到服务端请求接⼝,token的处理。⽬录结构 assets: 资源⽂件。⽤于组织未编译的静态资源如 LESS、SASS或 JavaScript。components: 组件。layouts: page: 模板页⾯,默认为 可以在这个⽬录下创建全局页⾯的统⼀布局,或是错误处理页⾯页,需要提供⼀个nuxt 标签,类似于router-viewmiddleware: 中间件,放置⾃定义的中间件,会在加载组件之前调⽤。可以在页⾯中调⽤: middleware: '中间件名称'。pages: 页⾯, 为根页⾯, 框架读取该⽬录下所有的 .vue⽂件并⾃动⽣成对应的路由配置,如需要动态参数id,则可以添加_id的⽂件,必须是下划线加参数名。plugin: 插件,⽤于组织那些需要在 根应⽤实例化之前需要运⾏的 Javascript 插件。static: 静态⽂件,静态⽂件⽬录 static⽤于存放应⽤的静态⽂件,此类⽂件不会被 调⽤ Webpack 进⾏构建编译处理。store: ⽤于组织vuex状态管理。具体使⽤请移步⾄ 官⽹。: ⽂件⽤于组织 应⽤的个性化配置,配置head,loading,css,plugins等。⽣命周期1. incoming Request 浏览器发出的请求)2. nuxtServerInit 服务端接受请求后,要检查当前有没有 nuxtServerInit配置项,如果有就执⾏这个函数3. store action ⽤来操作vuex4. middleware 可以做jWT等⼀些操作。5. validate() 检验参数,参数检验失败,可以在layout⾥的error⾥⾯进⾏捕捉。6. asyncData()& fetch() asyncData⽤来渲染组件,fetch⽤来渲染vuex7. RenderNuxt扩展以后的⽣命周期和⽅法以下:beforeCreate: ƒ beforeCreate()components: {NuxtLoading: {…}}computed: {isOffline: ƒ}context: {isStatic: false, isDev: true, isHMR: true, app: {…}, payload: undefined, …}created: ƒ created()data: ƒ data()head: {title: "nuxt-meituan-ssr", meta: Array(3), link: Array(1), style: Array(0), script: Array(0)}methods: {refreshOnlineStatus: ƒ, refresh: ƒ, errorChanged: ƒ, setLayout: ƒ, loadLayout: ƒ}mounted: ƒ mounted()nuxt: {…}render: ƒ render(h, props)router: VueRouter {app: Vue, apps: Array(1), options: {…}, beforeHooks: Array(2), resolveHooks: Array(0), …}watch: {: "errorChanged"}注意:⽣命周期的钩⼦只有beforeCreate和created会在服务端和客户端渲染。以上⽣命周期⾥都获取不到window对象。asyncData和fetch我们可以拿到数据,不要尝试挂载数据到data上,此时获取不到this对象。开发总结如何修改默认启动端⼝?可以在下⾯修改配置,如下。"config":{ "nuxt":{ "host":"127.0.0.1", "port":"3304" }}如何添加全局的样式?可以在assets⾥添加全局Css⽂件,如在assets下的Css⽂件夹⽬录下添加了⼀个⽂件,然后在⾥配置该css⽂件路径即可。 css:['~assers/css/']通过别名访问图⽚在template⾥是正确的,为何在Css设置背景图却报错?在css配置的是,需要将'~/'后⾯的'/'去除掉。
backround-image:url('~static/');如何添加路由动画?同样,我们在Css⽂件⾥添加⼀些动画代码,⼀般样式会在其后⾯添加-active和-leave-active,其实和Vue动画形式⼀致。其中以page开头的动画,默认会作⽤于全部页⾯,如果想给特定的页⾯加动画,可以在对应的页⾯script⾥引⽤,如 transitions:'bounce'即可。.page-enter-active, .page-leave-active { transition: opacity .3s } .page-enter, .page-leave-active { opacity: 0 } .bounce-enter-active { animation: bounce-in .8s; } .bounce-leave-active { animation: bounce-out .5s; } @keyframes bounce-in { 0% { transform: scale(1) } 50% { transform: scale(1.01) } 100% { transform: scale(1) } } @keyframes bounce-out { 0% { transform: scale(1) } 50% { transform: scale(1.01) } 100% { transform: scale(1) } }路由参数如何传递?同Vue-router,有声明式和编程式两种⽅式,⽆⾮是标签变成了 (...) nuxt-link :to="{name:'article',params:{id:1234}}" >声明式 // 编程式 this.$({ name:'article', params:{ id:1234 } })动态路由如何进⾏参数检验?提供了⼀个validate的⽣命周期钩⼦,可以在此进⾏参数的校验。以⽂章详情校验id为例,我们需要判断传⼊的id是否是数字,可以像下⾯这样处理。 validate({ params }) { return /^d+$/.test() }如何添加404等错误页⾯?可以在layout下新建⼀个页⾯,内容如下,当访问⼀个不存在的页⾯的时候,或者参数检验失败的时候,或者我们在middleware中间件处理抛出异常的时候,都会跳转到该页⾯。 页⾯不存在
应⽤发⽣错误异常
Stars: {{ $ }}
如何动态修改title的内容?如果是写死的,可以直接修改head的配置。 head() { return { // title: '',这⾥⼀旦声明,在asyncdata⾥修改也不起作⽤,直接以这个为准 meta: [ { hid: 'description', // 替换唯⼀标识 hid { hid: 'description', name: 'description', content: ' project' } name: 'content', content: '⽂章详情' } ] } },如果是动态数据从数据源⾥获取,然后通过asynData⾥的app对象,动态修改head的title。 asyncData({ app, params }) { const id = ; return getArticleDetail({ id }) .then(result => { = ; }) .catch(err => {}) }如何进⾏权限JWT验证?登录成功以后,我们会在cookie和Vuex中缓存token信息,当界⾯刷新的时候,会⾛store⾥的nuxtServerInit 函数,该函数仅在每个服务器端渲染中运,可以使⽤获取浏览器的cookie,再次更新store⾥的值,接着会⾛到中间件,中间件进⾏验证,如果有token信息则继续,没有则跳转到登录页。1. 为什么要在nuxtServerInit更新store的值?需要在middleware⾥使⽤,否则刷新后store⾥的值为空了。2. 客户端调⽤接⼝可以拿到token,服务器端如何拿到?可以通过nuxtServerInit⾥的req拿到请求信息的cookie,然后请求接⼝。3. 前后端分离,刷新的时候如何保证⽤户名、token等信息依然存在?可以像上⾯⼀样,每次取cookie的值再次更新store,但这样有⼀个问题,cookie可能会被篡改,后端代码需要做验证。也可以每次刷新重新通过token请求接⼝,更新⽤户信息。store代码import Vue from 'vue';import Vuex from 'vuex';import user from './modules/user';import { COOKIE_KEY } from '~/assets/js/';(Vuex);const store = () => new ({ modules: { user }, actions: { async nuxtServerInit({ commit, dispatch }, { req, app }) { if () { let parsedResult = {}; (';').forEach(cookie => { const currentCookie = ('='); parsedResult[currentCookie[0].trim()] = (currentCookie[1] || '').trim(); }); const userInfo = { name: parsedResult[COOKIE_], token: parsedResult[COOKIE_] }; commit('user/setUserInfo',userInfo); } } } });export default store;中间件代码export default function({ store, error, redirect }) { if (! || !) { // error({ // message: 'You are not connected', // statusCode: 403 // }) redirect('/'); }}nginx部署 npm run build选择build以后的四个⽂件: .nuxt, static, , 上传到服务器。pm2 pm2 start npm --name '' -- run startnginx配置查看⽹页源代码可以看到: server{ listen 3000; server_name ;
gzip on; gzip_buffers 32 4K; gzip_comp_level 6; gzip_min_length 100; gzip_types application/javascript text/css text/xml; gzip_disable "MSIE [1-6].";
gzip_vary on; proxy_buffer_size 64k; proxy_buffers 32 32k; proxy_busy_buffers_size 128k; location / { root /data/ww/nuxt; proxy_pass 127.0.0.1:3002; proxy_set_header X-Real-IP $remote_addr; } }这样,使⽤实现了⼀个服务端渲染的简易博客。以上就是本⽂的全部内容,希望对⼤家的学习有所帮助,也希望⼤家多多⽀持。
发布评论