准备项目结构与拆分路由
定义登录页面组件 在项目中创建并配置登录页面组件,例如将其放在 src/views/Login.vue 文件中。
路由配置 在路由配置文件中,为登录页面设置一个带有特殊meta属性的路由,表示该路由需要进行服务器端渲染(SSR):
// router.js 或相关路由配置文件
import Login from '@/views/Login.vue';
import { createRouter, createWebHashHistory } from 'vue-router';
const router = createRouter({
history: createWebHashHistory(),
routes: [
// 其他非SSR路由...
{ path: '/', component: () => import('@/views/Home.vue') },
// 登录页SSR路由
{ path: '/login', component: Login, meta: { ssr: true } },
],
});
编写服务端渲染入口
创建一个服务端渲染入口文件(如 server-entry.js),实现SSR逻辑:
// 导入相关模块
import Login from '@/views/Login.vue';
import { createApp } from './app';
import { createServerRenderer } from '@vue/server-renderer';
import { router } from '../router'; // 引入路由配置
// 判断是否为SSR路由的方法
function isSSRRoute(routeMeta) {
return routeMeta && routeMeta.ssr;
}
// 创建服务器渲染器
export default createServerRenderer(async context => {
// 创建应用实例和路由实例
const { app, router: _router } = createApp();
// 根据请求路径决定是否进行SSR渲染
const matchedComponent = router.getMatchedComponents({ path: context.url })[0];
if (isSSRRoute(matchedComponent.meta)) {
// 设置当前路由并等待数据加载完成
_router.push(context.url);
await _router.isReady();
}
// 执行服务器端渲染并将结果转换为HTML字符串
return renderToString(app);
});
数据预取与服务端环境配置
数据预取 如果登录页面在渲染时需要从服务器获取数据,可以在组件中使用 asyncData 或 fetch 钩子方法,确保在服务器端渲染前获取所需数据。
在登录页面组件中使用asyncData钩子:
在Login.vue组件的标签内添加asyncData方法,该方法会在服务器端渲染时被调用,并在组件实例化前同步数据。
export default {
data() {
return {
// 初始化数据
};
},
async asyncData({ store, params, query }) {
// 使用Vuex Store、路由参数或查询参数来获取数据(如果有)
// 根据实际情况替换以下示例API请求
const response = await this.$axios.get('/api/login-preload-data');
// 返回一个对象,其属性将合并到组件的data对象中
return {
initialFormData: response.data, // 假设这是登录页面需要的初始数据
};
},
methods: {
// 登录逻辑等其他方法
},
};
在非Nuxt.js项目中处理SSR时的数据预取:
如果不是在Nuxt.js环境下,需要在自定义的服务器端渲染逻辑中手动触发asyncData的执行。在调用renderToString方法前,先执行asyncData并等待其返回结果。
// server-entry.js
import { createApp } from './app';
import { createServerRenderer } from '@vue/server-renderer';
import { router } from '../router';
import Login from '@/views/Login.vue';
// 创建一个通用的处理函数,用于执行asyncData
async function executeAsyncData(component, context) {
if (component.options.asyncData) {
const asyncDataResult = await component.options.asyncData(context);
return Object.assign({}, context, asyncDataResult);
}
return context;
}
export default createServerRenderer(async context => {
const { app, router: _router } = createApp();
// 获取匹配的组件
const matchedComponent = router.getMatchedComponents({ path: context.url })[0];
// 如果是登录页面并且需要SSR
if (matchedComponent === Login && matchedComponent.options.meta.ssr) {
// 执行asyncData
context = await executeAsyncData(matchedComponent, context);
}
_router.push(context.url);
await _router.isReady();
return renderToString(app);
});
服务端环境
安装依赖 安装 @vue/server-renderer 包,用于在服务器端渲染Vue应用。
配置Webpack 调整Webpack配置,分别构建用于客户端和服务器端的bundle文件。
npm install --save @vue/server-renderer
用yarn:
yarn add @vue/server-renderer
Webpack配置调整
分别构建客户端和服务器端bundle
webpack.client.config.js:
const { VueLoaderPlugin } = require('vue-loader');
const path = require('path');
module.exports = {
target: 'web',
entry: './src/client-entry.js',
output: {
filename: 'client-bundle.js',
path: path.resolve(__dirname, 'dist'),
},
resolve: {
alias: {
'vue$': 'vue/dist/vue.esm-bundler.js', // or vue.runtime.esm-bundler.js for runtime-only build
},
},
module: {
rules: [
{
test: /\.vue$/,
use: 'vue-loader',
},
// other loaders for CSS, images, etc.
],
},
plugins: [
new VueLoaderPlugin(),
],
};
webpack.server.config.js:
const { VueSSRServerPlugin } = require('vue-server-renderer');
const path = require('path');
module.exports = {
target: 'node',
entry: './src/server-entry.js',
output: {
libraryTarget: 'commonjs2',
filename: 'server-bundle.js',
path: path.resolve(__dirname, 'dist'),
},
resolve: {
alias: {
'vue$': 'vue/dist/vue.runtime.common.prod.js', // use the production version of Vue with server rendering capabilities
},
},
module: {
rules: [
{
test: /\.vue$/,
use: 'vue-loader',
},
// other loaders for CSS (usually extract-text-webpack-plugin for SSR), images, etc.
],
},
externals: nodeExternals(), // 忽略node_modules目录,只打包应用程序依赖
plugins: [
new VueSSRServerPlugin({
filename: 'vue-ssr-server-bundle.json', // 输出Vue SSR编译后的JSON文件
}),
],
};
// Node.js外部模块解析器,通常需要安装对应的包:npm install --save-dev nodeExternals
function nodeExternals() {
return ({ context, request }, callback) => {
if (request.match(/\.(css|scss|sass|jpg|png|gif)$/i)) {
return callback(null, 'empty-module');
}
if (/^vue/.test(request)) {
return callback();
}
callback();
};
}
上面只是示例,可以参考,然后还需要在项目中创建相应的client-entry.js和server-entry.js文件,分别作为客户端和服务器端的入口点。在服务器端入口文件中,通常会包含服务端渲染的相关逻辑,包括引入Vue组件、创建应用、处理请求并调用@vue/server-renderer进行渲染。
构建Node.js服务器
创建Node.js服务器 使用Express或其他框架创建一个HTTP服务器,监听客户端请求。
// server.js
import express from 'express';
import serverRenderer from './server-entry.js';
const app = express();
// 处理请求并返回SSR渲染的HTML
app.use(async (req, res) => {
const html = await serverRenderer(req, res);
res.send(html);
});
// 启动服务器
app.listen(3000, () => {
console.log('Server is listening on port 3000');
});
整合客户端逻辑
客户端接管
确保在HTML模板中注入客户端脚本,当脚本加载并执行时,Vue应用将识别并接管已经存在于DOM中的服务器端渲染内容,从而实现无缝切换至客户端渲染模式。
综上所述,差不多就ok了。。。。。。通过对登录页面进行特别标记、编写服务端渲染逻辑、预取数据、配置服务端环境并启动服务器,以及在客户端进行正确的接管,Vue项目中的登录页面就可以成功实现服务器端渲染。这样不仅提高了SEO效果,还能让用户更快地看到登录页面的初始内容。