#关于Vue SSR的一点看法
栏目: JavaScript · 发布时间: 7年前
内容简介:SSR,意为 Server Side Rendering(服务端渲染),目的是为了解决单页面应用的 SEO 和首屏渲染速度慢的问题,对于一般网站影响不大,但是对于需要做SEO的网站是致命的,搜索引擎无法抓取页面相关内容,也就是用户搜不到此网站的相关信息。客户端渲染需要:加载html=>解析html=>加载js=>解析js=>生成dom节点=>插入html文档,所以很慢; 服务端渲染就是将首屏的html结构构建好直接返回,客户端只需要:加载html=>解析html。所以首屏打开速度大大提高,但同时对服务器的压
SSR,意为 Server Side Rendering(服务端渲染),目的是为了解决单页面应用的 SEO 和首屏渲染速度慢的问题,对于一般网站影响不大,但是对于需要做SEO的网站是致命的,搜索引擎无法抓取页面相关内容,也就是用户搜不到此网站的相关信息。
2.为什么要用SSR?
客户端渲染需要:加载html=>解析html=>加载js=>解析js=>生成dom节点=>插入html文档,所以很慢; 服务端渲染就是将首屏的html结构构建好直接返回,客户端只需要:加载html=>解析html。所以首屏打开速度大大提高,但同时对服务器的压力也比客户端渲染要大。
3.关于实现SSR的几种方式
目前Vue SSR的实现有两种实现,一种是基于官方Vue SSR指南文档的官方方案,一种是vue.js通用应用框架--NUXT。 官方方案具有更直接的控制应用程序的结构,更深入底层,更加灵活,同时在使用官方方案的过程中,也会对Vue SSR有更加深入的了解。 而NUXT提供了平滑的开箱即用的体验,它建立在同等的Vue技术栈之上,但抽象出很多模板,并提供了一些额外的功能,例如静态站点生成。通过NUXT可以根据约定的规则,快速的实现Vue SSR。
(1)nuxt
官方是这么介绍自己的: Nuxt.js 是一个基于 Vue 的通用应用框架。 通过对客户端/服务端基础架构的抽象组织,Nuxt.js 主要关注的是应用的 UI渲染。
我们的目标是创建一个灵活的应用框架,你可以基于它初始化新项目的基础结构代码,或者在已有 Node.js 项目中使用 Nuxt.js。 Nuxt.js 预设了利用 Vue 开发服务端渲染的应用所需要的各种配置。
除此之外,我们还提供了一种命令叫:nuxt generate,为基于 Vue 的应用提供生成对应的静态站点的功能。
我们相信这个命令所提供的功能,是向开发集成各种微服务(miscroservices)的 Web 应用迈开的新一步。 作为框架,Nuxt.js 为 客户端/服务端 这种典型的应用架构模式提供了许多有用的特性,例如异步数据加载、中间件支持、布局支持等。
Nuxt.js是使用 Webpack 和 Node.js 进行封装的基于Vue的SSR框架,使用它,你可以不需要自己搭建一套 SSR 程序,而是通过其约定好的文件结构和API就可以实现一个首屏渲染的 Web 应用。
之所以叫 Nuxt.js 也是因为受到了 Next.js 的启发。 Nuxt.js 是一个 Node 程序,就像上面说的,我们是要把 Vue 跑在服务端,所以必须使用 Node 环境。
我们对 Nuxt.js 应用的访问,实际上是在访问这个 Node.js 程序的路由,程序输出首屏渲染内容 + 用以重新渲染的 SPA 的脚本代码,而路由是由 Nuxt.js 约定好的 pages 文件夹生成的。
所以,整体上,Nuxt.js 通过各个文件夹和配置文件的约束来管理我们的程序,而又不失扩展性,其有自己的插件机制。
- .nuxt : Nuxt自动生成,临时的用于编辑的文件,build
- assets:Webpack 编译的各类资源,// 用于组织未编译的静态资源入LESS、SASS 或 JavaScript
- components:各组件,用于你自己管理公共组件或非公共组件 ,比如滚动组件,日历组件,分页组件
- layouts:宿主布局页面模板组件,用于你可以把不同的页面指定使用不同的布局,不可更改。
- middleware:中间件,首屏渲染和路由跳转前均执行对应中间件,可以返回promise或直接next(很实用!)
- pages:各页面组件,用于生成对应路由,支持嵌套,支持动态路由,存放写的页面,我们主要的工作区域
- plugins:插件,SPA中用的各类第三方组件和一些node模块,JavaScript插件放的地方
- static :/ 用于存放静态资源文件,比如图片
- store:内置了vuex,可以直接返回数据模块或返回一个自建vuex根对象,具体要翻文档,用于组织应用的Vuex 状态管理
- .editorconfig : // 开发 工具 格式配置
- .eslintrc.js : // ESLint的配置文件,用于检查代码格式
- .gitignore : // 配置git不上传的文件
- nuxt.config.json : // 用于组织Nuxt.js应用的个性化配置,已覆盖默认配置
- package-lock.json : // npm自动生成,用于帮助package的统一性设置的,yarn也有相同的操作
- package-lock.json : // npm自动生成,用于帮助package的统一性设置的,yarn也有相同的操作
- package.json : // npm包管理配置文件
- 其他:你可以自定义文件夹和别名映射,文档都有提及,这里有配置代码
nuxt.config.js对程序的扩展管理可大概分为以下类:
- build:主要对应 Webpack 中的各配置项,可以对默认的 Webpack 配置进行扩展,如这里代码
- cache:主要对应内置的组件缓存模块lru-cache的配置对象,有默认值,可选关闭
- css:对应我们在SPA随处引用样式文件的require语句
- dev:用于自定义配置环境变量,对应之前webpack.config.js相关文件中的变量语句
- env:同上息息相关
- generate:对generate命令执行时的行为做一些定制
- head:对应vue-meta插件的全局配置,vue-meta用于VUE/SSR程序的文档元信息的管理
- loading:用于定制化Nuxt.js内置的进度条组件
- performance:用于配置Node.js服务器性能上的配置
- plugins:用于管理和应用对应plugins文件夹中的插件
- rootdir:用于设置 Nuxt.js 应用的根目录(这俩api有很大合并的意义)
- srcdir:用于设置 Nuxt.js 应用的源码目录(这俩api有很大合并的意义)
- router:用于对vue-router的扩展和定制,其中还包括了中间件的配置,但并不完美
- transition:用于定制Nuxt.js内置的页面切换过渡效果的默认属性值
- watchers:用于定制Nuxt.js内置的文件监听模块chokidar和 -Webpack 的相关配置项
同时,Nuxt.js 支持以generate命令将程序直接构建为静态 html ,就像上面说的,可以作为静态资源直接输出。 打包 npm run generate
开发中遇到的坑点
一开始用generate打包上线,发现首屏打开速度超慢,在测服上面大概需要10s+才能打开首页,但打开其他页面都是秒开,然后开始找原先,压缩vendor.js和app.js之后速度大约块一两s,此时首屏打开任很慢,仍然需要8s+才能打开页面,慢点的情况下可能需要30s+,实在不能忍,打开浏览器debug模式,发现首次加载的时候加载了所有的页面的js,这样首页打开速度慢.其他页面秒开就解释的通了,如下图,
原因找到了,接下来就是怎么解决了,于是我翻看官方文档,尝试了以下方法:
在 nuxt.config.js 里面设置:
module.exports = {
render: {
resourceHints: false,
},
......
......
}
复制代码
nuxt官方文档上是这样说明的
nuxt的坑还有很多,但是还是值得尝试的
(2)vue-server-renderer
让我们先创建一个项目并安装一些依赖项:
1. mkdir vue-ssr 2. cd vue-ssr 3. npm init 4 .npm i vue@next vue-server-renderer --save 复制代码
package.json:
{
"name": "vue-ssr",
"version": "1.0.0",
"dependencies": {
"vue": "^2.5.17",
"vue-server-renderer": "^2.5.17"
}
}
复制代码
注意:vue版本号要和vue-server-renderer版本号保持一致
webpack.base.config.js
module.exports = {
module: {
rules: [{
test: /\.vue$/,
loader: 'vue-loader',
},
{
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/
}
]
},
plugins: [],
resolve: {
alias: {
'vue$': 'vue/dist/vue.esm.js'
}
}
}
复制代码
webpack.server.conf.js
const merge = require('webpack-merge')
const nodeExternals = require('webpack-node-externals')
const baseConfig = require('./webpack.base.config.js')
const VueSSRServerPlugin = require('vue-server-renderer/server-plugin')
const path = require('path');
const root= path.resolve(__dirname, '..');
module.exports = merge(baseConfig, {
// 将 entry 指向应用程序的 server entry 文件
entry: path.join(root, 'entry/entry-server.js'),
// 这允许 webpack 以 Node 适用方式(Node-appropriate fashion)处理动态导入(dynamic import),
// 并且还会在编译 Vue 组件时,
// 告知 `vue-loader` 输送面向服务器代码(server-oriented code)。
target: 'node',
// 对 bundle renderer 提供 source map 支持
devtool: 'source-map',
// 此处告知 server bundle 使用 Node 风格导出模块(Node-style exports)
output: {
libraryTarget: 'commonjs2',
path: path.join(root, 'dist'),
filename: 'bundle.server.js'
},
// https://webpack.js.org/configuration/externals/#function
// https://github.com/liady/webpack-node-externals
// 外置化应用程序依赖模块。可以使服务器构建速度更快,
// 并生成较小的 bundle 文件。
externals: nodeExternals({
// 不要外置化 webpack 需要处理的依赖模块。
// 你可以在这里添加更多的文件类型。例如,未处理 *.vue 原始文件,
// 你还应该将修改 `global`(例如 polyfill)的依赖模块列入白名单
whitelist: /\.css$/
}),
// 这是将服务器的整个输出
// 构建为单个 JSON 文件的插件。
// 默认文件名为 `vue-ssr-server-bundle.json`
plugins: [
new VueSSRServerPlugin()
]
})
复制代码
webpack.client.conf.js
const webpack = require('webpack')
const merge = require('webpack-merge')
const baseConfig = require('./webpack.base.config.js')
const VueSSRClientPlugin = require('vue-server-renderer/client-plugin')
const path = require('path');
const root= path.resolve(__dirname, '..');
module.exports = merge(baseConfig, {
entry: path.join(root, 'entry/entry-client.js'),
output: {
path: path.join(root, 'dist'),
filename: 'bundle.client.js'
},
plugins: [
// 重要信息:这将 webpack 运行时分离到一个引导 chunk 中,
// 以便可以在之后正确注入异步 chunk。
// 这也为你的 应用程序/vendor 代码提供了更好的缓存。
new webpack.optimize.CommonsChunkPlugin({
name: 'manifest',
filename: 'manifest.js',
minChunks: Infinity
}),
// 此插件在输出目录中
// 生成 `vue-ssr-client-manifest.json`。
new VueSSRClientPlugin()
]
})
复制代码
entry-server.js
/* entry-server.js */
import { createApp } from '../src/app'
export default context => {
return new Promise((resolve, reject) => {
const {app, router} = createApp()
// 更改路由
router.push(context.url)
// 等到 router 将可能的异步组件和钩子函数解析完
router.onReady(() => {
const matchedComponents = app.$router.getMatchedComponents()
// 匹配不到的路由,执行 reject 函数,并返回 404
if (!matchedComponents.length) { return reject({code: 404}) }
// Promise 应该 resolve 应用程序实例,以便它可以渲染
resolve(app)
}, reject)
})
}
复制代码
entry-client.js
import { createApp } from '../src/app'
// 客户端特定引导逻辑……
const {app} = createApp()
// 这里假定 App.vue 模板中根元素具有 `id="app"`
app.$mount('#app')
复制代码
server.js
const path = require('path')
const express = require('express')
const app = express()
const { createBundleRenderer } = require('vue-server-renderer')
// 创建renderer
const template = require('fs').readFileSync('./index.ssr.html', 'utf-8')
const serverBundle = require('./dist/vue-ssr-server-bundle.json')
const clientManifest = require('./dist/vue-ssr-client-manifest.json') // 这个可以动态将生成的js文件渲染到html模版中
const renderer = createBundleRenderer(serverBundle, {
runInNewContext: false, // 推荐
template: template,
clientManifest: clientManifest
})
app.use(express.static(path.join(__dirname, 'dist')))
// 响应路由请求
app.get('*', (req, res) => {
const context = { url: req.url }
// 创建vue实例,传入请求路由信息
renderer.renderToString(context, (err, html) => {
if (err) {
return res.state(500).end('运行时错误')
}
res.send(html)
})
})
// 服务器监听地址
app.listen(8099, () => {
console.log('服务器已启动!')
})
复制代码
基本上到这个地方关键性构建以及服务模块代码补充完成后,一个简单的基于vue-server-renderer例子就可以运行起来了。
以上所述就是小编给大家介绍的《#关于Vue SSR的一点看法》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Programming in Haskell
Graham Hutton / Cambridge University Press / 2007-1-18 / GBP 34.99
Haskell is one of the leading languages for teaching functional programming, enabling students to write simpler and cleaner code, and to learn how to structure and reason about programs. This introduc......一起来看看 《Programming in Haskell》 这本书的介绍吧!