前言

在Java Web时代,由于前后端在一个服务,客户端向服务端发送请求,web服务器解析HTTP格式的数据,转发到指定的servlet,servlet根据参数从数据库拿到数据,放进域对象并返回指定的JSP页面,JSP跟域对象数据一起渲染成HTML,最后通过HTTP响应体返回给客户端,整个过程发生在服务器。

而随着前后端分离后,前端用前端框架开发,开发完成后把项目打包成静态文件(HTML,CSS,JS)放在静态Web服务器(Nginx),此时客户端向服务器发出请求,服务器就会返回这些静态文件,到达客户端后,客户端在模板上执行JS后,把整个项目构建成完整的单页面应用,并通过AJAX向服务端请求数据,再渲染在单页面应用上,整个过程都发生在客户端。

正文

配置基于vue3.0

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 env = process.env;

const isServer = env.RUN_ENV === "server";

const resolve = dir => require('path').join(__dirname, dir)

module.exports = {

lintOnSave: false,

publicPath: "/",

outputDir: `dist/${env.RUN_ENV}`,

devServer: {

port: 3001,

publicPath: "/"

},

configureWebpack: {

// 将 entry 指向应用程序的 server / client 文件,不写默认是main.js

entry: `./src/entry-${env.RUN_ENV}.js`,

devtool: "eval",

// 这允许 webpack 以 Node 适用方式(Node-appropriate fashion)处理动态导入(dynamic import),

// 并且还会在编译 Vue 组件时,

// 告知 `vue-loader` 输送面向服务器代码(server-oriented code)。

target: isServer ? "node" : "web",

output: {

libraryTarget: isServer ? "commonjs2" : undefined,

},

// https://webpack.js.org/configuration/externals/#function

// https://github.com/liady/webpack-node-externals

// 外置化应用程序依赖模块。可以使服务器构建速度更快,

// 并生成较小的 bundle 文件。

externals: isServer

? nodeExternals({

// 不要外置化 webpack 需要处理的依赖模块。

// 你可以在这里添加更多的文件类型。例如,未处理 *.vue 原始文件,

// 你还应该将修改 `global`(例如 polyfill)的依赖模块列入白名单

whitelist: /\.css$/,

})

: undefined,

optimization: { splitChunks: isServer ? false : undefined },

// 这是将服务器的整个输出

// 构建为单个 JSON 文件的插件。

// 服务端默认文件名为 `vue-ssr-server-bundle.json`

// 客户端默认文件名为 `vue-ssr-client-manifest.json`

plugins: [isServer ? new VueSSRServerPlugin() : new VueSSRClientPlugin()],

},

chainWebpack: config => {

config.resolve.alias

.set('@', resolve('src'))

},

css: {

loaderOptions: {

// 设置 scss 公用变量文件

stylus: {

}

}

},

}

entry-client.js

import Vue from 'vue'

import 'es6-promise/auto'

import { createApp } from './app'

import ProgressBar from './components/ProgressBar.vue'

// global progress bar

const bar = Vue.prototype.$bar = new Vue(ProgressBar).$mount()

document.body.appendChild(bar.$el)

// a global mixin that calls `asyncData` when a route component's params change

Vue.mixin({

beforeRouteUpdate(to, from, next) {

const { asyncData } = this.$options

if (asyncData) {

asyncData({

store: this.$store,

route: to

}).then(next).catch(next)

} else {

next()

}

}

})

Vue.mixin({

beforeMount () {

const { asyncData } = this.$options

if (asyncData) {

// 将获取数据操作分配给 promise

// 以便在组件中,我们可以在数据准备就绪后

// 通过运行 `this.dataPromise.then(...)` 来执行其他任务

this.dataPromise = asyncData({

store: this.$store,

route: this.$route

})

}

}

})

const { app, router, store } = createApp()

// prime the store with server-initialized state.

// the state is determined during SSR and inlined in the page markup.

if (window.__INITIAL_STATE__) {

store.replaceState(window.__INITIAL_STATE__)

}

// wait until router has resolved all async before hooks

// and async components...

router.onReady(() => {

// Add router hook for handling asyncData.

// Doing it after initial route is resolved so that we don't double-fetch

// the data that we already have. Using router.beforeResolve() so that all

// async components are resolved.

router.beforeResolve((to, from, next) => {

const matched = router.getMatchedComponents(to)

const prevMatched = router.getMatchedComponents(from)

let diffed = false

const activated = matched.filter((c, i) => {

return diffed || (diffed = (prevMatched[i] !== c))

})

const asyncDataHooks = activated.map(c => c.asyncData).filter(_ => _)

if (!asyncDataHooks.length) {

return next()

}

bar.start()

Promise.all(asyncDataHooks.map(hook => hook({ store, route: to })))

.then(() => {

bar.finish()

next()

})

.catch(next)

})

// actually mount to DOM

app.$mount('#app')

})

// service worker

// if ('https:' === location.protocol && navigator.serviceWorker) {

// navigator.serviceWorker.register('/service-worker.js')

// }

entry-server.js

import { createApp } from './app'

const isDev = process.env.NODE_ENV !== 'production'

// This exported function will be called by `bundleRenderer`.

// This is where we perform data-prefetching to determine the

// state of our application before actually rendering it.

// Since data fetching is async, this function is expected to

// return a Promise that resolves to the app instance.

export default context => {

return new Promise((resolve, reject) => {

const s = isDev && Date.now()

const { app, router, store } = createApp()

const { url } = context

const { fullPath } = router.resolve(url).route

if (fullPath !== url) {

return reject({ url: fullPath })

}

// set router's location

router.push(url)

// wait until router has resolved possible async hooks

router.onReady(() => {

const matchedComponents = router.getMatchedComponents()

// no matched routes

if (!matchedComponents.length) {

return reject({ code: 404 })

}

// Call fetchData hooks on components matched by the route.

// A preFetch hook dispatches a store action and returns a Promise,

// which is resolved when the action is complete and store state has been

// updated.

Promise.all(matchedComponents.map(({ asyncData }) => asyncData && asyncData({

store,

route: router.currentRoute

}))).then(() => {

isDev && console.log(`data pre-fetch: ${Date.now() - s}ms`)

// After all preFetch hooks are resolved, our store is now

// filled with the state needed to render the app.

// Expose the state on the render context, and let the request handler

// inline the state in the HTML response. This allows the client-side

// store to pick-up the server-side state without having to duplicate

// the initial data fetching on the client.

context.state = store.state

resolve(app)

}).catch(reject)

}, reject)

})

}

app.js

import Vue from 'vue'

import App from './App.vue'

import { createStore } from './store'

import { createRouter } from './router'

import { sync } from 'vuex-router-sync'

// import titleMixin from './util/title'

// import * as filters from './util/filters'

// mixin for handling title

// Vue.mixin(titleMixin)

// register global utility filters.

// Object.keys(filters).forEach(key => {

// Vue.filter(key, filters[key])

// })

// Expose a factory function that creates a fresh set of store, router,

// app instances on each call (which is called for each SSR request)

export function createApp () {

// create store and router instances

const store = createStore()

const router = createRouter()

// sync the router with the vuex store.

// this registers `store.state.route`

sync(store, router)

// create the app instance.

// here we inject the router, store and ssr context to all child components,

// making them available everywhere as `this.$router` and `this.$store`.

const app = new Vue({

router,

store,

render: h => h(App)

})

// expose the app, the router and the store.

// note we are not mounting the app here, since bootstrapping will be

// different depending on whether we are in a browser or on the server.

return { app, router, store }

}

server.js

const fs = require("fs");

const path = require("path");

const express = require('express')

const app = express()

// 第 2 步:获得一个createBundleRenderer

// const { createBundleRenderer } = require("vue-server-renderer");

// const serverBundle = require("./dist/server/vue-ssr-server-bundle.json");

// const clientManifest = require("./dist/client/vue-ssr-client-manifest.json");

// const renderer = createBundleRenderer(serverBundle, {

// runInNewContext: false,

// template: fs.readFileSync(path.resolve(__dirname, "./src/index.template.html"), "utf-8"),

// clientManifest,

// });

function renderToString(context) {

return new Promise((resolve, reject) => {

renderer.renderToString(context, (err, html) => {

err ? reject(err) : resolve(html);

});

});

}

app.use('/js', express.static('./dist/client/js'));

app.use('/css', express.static('./dist/client/css'));

app.get('/api/:id', (req, res) => {

res.header('Access-Control-Allow-Origin', '*');

res.header('Access-Control-Allow-Headers', 'Content-Type, Content-Length, Authorization, Accept, X-Requested-With , yourHeaderFeild');

res.header('Access-Control-Allow-Methods', 'PUT, POST, GET, DELETE, OPTIONS');

const { id } = req.params

const result = {

code: 200,

data: id,

msg: '请求成功'

}

res.setHeader("Content-Type", "application/json;charset=utf-8")

res.setHeader("Server", "Sli97")

res.json(result);

res.end()

})

app.get('/test', (req, res) => {

console.log(req.query)

const { id } = req.query

console.log(id)

res.setHeader("Content-Type", "application/json;charset=utf-8")

res.setHeader("Server", "Sli97")

res.send("test :" + id)

})

// app.get('*', async (req, res) => {

// const context = { url: req.url, title: "Hello SSR", }

// // 将 context 数据渲染为 HTML

// const html = await renderToString(context).catch(err => {

// if (err.url) {

// res.redirect(err.url)

// } else if (err.code === 404) {

// res.status(404).send('404 | Page Not Found')

// } else {

// // Render Error Page or Redirect

// res.status(500).send('500 | Internal Server Error')

// console.error(`error during render : ${req.url}`)

// console.error(err.stack)

// }

// });

// res.send(html)

// })

/*服务启动*/

const port = 3000;

app.listen(port, () => {

console.log(`server started at localhost:${port}`);

});

package.json脚本命令

"scripts": {

"serve": "cross-env RUN_ENV=client vue-cli-service serve ",

"start": "npm run build:server && npm run build:client && npm run server",

"build:client": "cross-env RUN_ENV=client vue-cli-service build",

"build:server": "cross-env RUN_ENV=server vue-cli-service build",

"server": "node server",

"test": "echo \"Error: no test specified\" && exit 1"

},

ssr服务器 .json文件,服务端渲染 SSR相关推荐

  1. ssr服务器 .json文件,vuessr 服务器端渲染

    安装 npm install vue vue-server-renderer --save 构建配置 服务端 webpack配置 onst merge = require('webpack-merge ...

  2. React + Koa 实现服务端渲染(SSR)

    ⚛️React是目前前端社区最流行的UI库之一,它的基于组件化的开发方式极大地提升了前端开发体验,React通过拆分一个大的应用至一个个小的组件,来使得我们的代码更加的可被重用,以及获得更好的可维护性 ...

  3. 服务端渲染(SSR) 通用技术解决方案

    项目背景 服务端渲染(SSR) 通用技术解决方案的诞生来源于对 360搜索百科移动端项目的一次重构实践.而当时决定重构该项目的主要原因有以下几点: 1.  技术栈陈旧,熟悉.开发以及维护成本都较高 项 ...

  4. vue服务端渲染ssr

    vue服务端渲染ssr 一.SSR概念 传统web渲染技术 SPA SSR 二.webpack+vue2的实现方式 1.创建工程 2.安装依赖 3.编写一个简单的SSR 4.完整的ssr 5.代码链接 ...

  5. 服务端渲染(SSR)和Nuxt.js

    服务端渲染(SSR) 客户端渲染和传统服务端渲染的问题 SPA应用有两个非常明显的问题: 首屏渲染慢 不利于 SEO 传统的服务端渲染又存在: 应用的前后端部分完全耦合在一起,在前后端协同开发方面会有 ...

  6. 服务端渲染SSR的理解

    服务端渲染SSR的理解 SSR服务端渲染Server Side Render就是当进行请求时,页面上的内容是通过服务端渲染生成的,浏览器直接显示服务端返回的HTML即可. 客户端渲染CSR 通常在构建 ...

  7. vue服务端渲染(ssr)与普通vue的区别,ssr的基本使用

    ssr是vue的服务端渲染技术,nuxt是一个可以用来做ssr服务端渲染开发的框架. ssr是技术基础,nuxt是封装 一.什么是SSR? Vue.js 是构建客户端应用程序的框架.默认情况下,可以在 ...

  8. node+ejs实现服务端渲染SSR

    一.服务端渲染SSR 1.什么是客户端渲染和服务端渲染? 客户端渲染:客户端向服务端请求HTML页面,后端不返回完整的 HTML页面,浏览器解析HTML页面过程中如果遇到ajax数据请求,会向服务端请 ...

  9. 服务端渲染SSR与客户端渲染

    文章目录 一.服务端渲染和客户端渲染的区别 服务端渲染(SSR -- server side render) 客户端渲染 二.使用服务端渲染(SSR)的利弊 优势 局限 三.实际应用 应用原则 举例 ...

  10. vue服务端转html,普通vue-cli初始项目转为服务端渲染SSR

    1.第一步没啥好说的,利用vue-cli脚手架创建一个demo项目: vue init webpack vue-ssr-demo cd vue-ssr-demo npm install 2.安装SSR ...

最新文章

  1. java利用递归画杨辉三角_用java程序编写杨辉三角形,初学者适用
  2. Redis缓存使用技巧和设计方案
  3. 关于如何换肤、子类化的解决方案
  4. 流畅的验证组件:FluentValidation
  5. (九)2005年我的第一次软件行业创业,烧掉30万、2年时间打水漂的惨痛教训
  6. DCMTK:创建和验证DICOM数字签名
  7. php软件开发--nodejs
  8. MySQL 慌了!这个分库分表方法论,要火了?
  9. 谁说前端工程师不能成为全栈?
  10. 090925 H 广联达之道 培训笔记
  11. 强烈推荐SQL Prompt 3.8,并发布SQL Prompt 3.8 ,SQL Refator 的xxx
  12. [蛋蛋插画日记]喂喂,看“表演”请砸钱币喔!
  13. u深度重装系统详细教程_u深度u盘启动盘装win10教程
  14. KDD2020|字节联合密歇根州立大学提出推荐广告联合训练框架RAM(已开源)
  15. 麒麟v10安装达梦数据库
  16. from .onnxruntime_pybind11_state import * # noqa ddddocr运行报错
  17. Android 音乐播放器的开发教程(六)service的运用及音乐列表点击播放 ----- 小达
  18. 只要8元,就能体验美国第一夫人的乐趣
  19. 苹果电脑MACbookAir快捷键大全
  20. uni-app 本地图片引入问题

热门文章

  1. 问的书写规则是什么意思_汉字书写规则
  2. mysql 创建数据库 utf8 命令_mysql创建数据库 utf8
  3. 如何更电计算机共享名称,电脑网络共享设置
  4. 奥地利邮政服务推出加密收藏邮票
  5. JavaFX的webview下载文件的一种实现思路
  6. 单片机实验(十一)单片机独立按键控制LED
  7. isupper函数用法
  8. Differential Geometry之第二章曲线的局部理论
  9. 测试用例目的和测试用例方法
  10. 论文复现——PFLD——人脸关键点检测