# 前言
Vue
的 SEO
大家都不陌生,一般有两种,一种是预渲染插件 prerender-spa-plugin,主要用于只需要部分页面的情形。另一种是后端渲染 Vue SSR,比较彻底的一种方案,比较受欢迎。
# 举个例子
SSR
也并没有大家想的那么深奥,上代码。。。
第一步:安装插件 vue-server-renderer、webpack-node-externals、lodash.merge、cross-env
npm i --save-dev vue-server-renderer webpack-node-externals lodash.merge cross-env
第二步:更改路由
导出
const router = new Router({
mode: 'history',
routes,
});
// ssr 输出
export default function createRouter() {
return new Router({
mode: 'history',
routes,
});
}
// 普通输出
// export default router;
第三步:在 src
根目录下创建 app.js
// 创建 vue 实例
import Vue from 'vue'
import App from './App.vue'
import createRouter from './router'
export default function createApp() {
const router = createRouter();
const app = new Vue({
router,
render: h => h(App)
});
return { app, router }
}
第四步:在 src
目录下分别创建 entry-client.js、 entry-server.js
// entry-client.js ==> 挂载、激活app
import createApp from './app'
const { app, router } = createApp();
router.onReady(() => {
app.$mount('#app');
})
// entry-server.js ==> 将来渲染首屏
import createApp from './app'
export default context => {
return new Promise((resolve, reject) => {
const { app, router } = createApp();
// 进入到首屏
router.push(context.url)
router.onReady(() => {
resolve(app);
}, reject)
});
}
第五步:配置 vue.config.js
const VueSSRServerPlugin = require("vue-server-renderer/server-plugin");
const VueSSRClientPlugin = require("vue-server-renderer/client-plugin");
const nodeExternals = require("webpack-node-externals");
const merge = require("lodash.merge");
const TARGET_NODE = process.env.WEBPACK_TARGET === "node";
const target = TARGET_NODE ? "server" : "client";
module.exports = {
css: {
extract: false,
},
outputDir: "./dist/" + target,
configureWebpack: () => {
if (process.env.WEBPACK_TARGET !== "node") return
return ({
entry: `/src/entry-${target}.js`,
devtool: "source-map",
target: TARGET_NODE ? "node" : "web",
node: TARGET_NODE ? undefined : false,
output: {
libraryTarget: TARGET_NODE ? "commonjs2" : undefined
},
externals: TARGET_NODE ?
nodeExternals({
// whitelist
allowlist: [/\.css$/]
}) : undefined,
optimization: {
splitChunks: undefined
},
plugins: [TARGET_NODE ? new VueSSRServerPlugin() : new VueSSRClientPlugin()]
})
},
chainWebpack: config => {
config.module.rule("vue").use("vue-loader").tap(options => {
merge(options, { optimizeSSR: false })
})
}
};
第六步:与 src
平级,创建 server
文件夹并创建 index.js
文件
const clientManifest = require("../dist/client/vue-ssr-client-manifest.json");
const renderer = createBundleRenderer(serverBundle, {
runInNewContext: false,
template: fs.readFileSync("../public/index.temp.html", "utf-8"), // 宿主文件
clientManifest
});
app.use(express.static('../dist/client', { index: false }));
app.get("*", async(req, res) => {
try {
const context = {
url: req.url,
title: 'test title'
}
const html = await renderer.renderToString(context);
res.send(html)
} catch (error) {
console.log(error)
}
})
app.listen(3000, () => {
console.log(123456)
})
第七步:修改 packsge.json
文件
"scripts": {
"serve": "cross-env WEBPACK_TARGET=dev vue-cli-service serve",
"build:client": "vue-cli-service build",
"build:server": "cross-env WEBPACK_TARGET=node vue-cli-service build --mode server",
"build": "npm run build:server && npm run build:client",
"lint": "vue-cli-service lint"
},
第八步:在 public
文件夹下创建 index.temp.html
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>ssr</title>
</head>
<body>
<!--vue-ssr-outlet-->
</body>
</html>
注意:body 里必须这么写
第九步:运行打包
npm run build
注意: 这里打包会执行两次:客户端 和 服务端
打包后的结果:
目录总览:
到这里 SSR
就创建完成了,最后启动服务 node index.js
看下下结果吧