vue的两种服务器端渲染方案( 三 )


webpack.server.config
// webpack.server.configconst {merge} = require('webpack-merge')const nodeExternals = require('webpack-node-externals')// webpack的基础配置,比如sass,less预编译等const baseConfig = require('./webpack.base.config.js')const VueSSRServerPlugin = require('vue-server-renderer/server-plugin')module.exports = merge(baseConfig, {// 将 entry 指向应用程序的 server entry 文件entry: './src/entry-server.js',target: 'node',// 对 bundle renderer 提供 source map 支持devtool: 'source-map',// 此处告知 server bundle 使用 Node 风格导出模块(Node-style exports)output: {libraryTarget: 'commonjs2'},// https://webpack.js.org/configuration/externals/#function// https://github.com/liady/webpack-node-externals// 外置化应用程序依赖模块 。可以使服务器构建速度更快,// 并生成较小的 bundle 文件 。externals: nodeExternals({// 不要外置化 webpack 需要处理的依赖模块 。// 你可以在这里添加更多的文件类型 。例如,未处理 *.vue 原始文件,// 你还应该将修改 `global`(例如 polyfill)的依赖模块列入白名单allowlist: /.css$/}),// 这是将服务器的整个输出// 构建为单个 JSON 文件的插件 。// 默认文件名为 `vue-ssr-server-bundle.json`plugins: [new VueSSRServerPlugin()
setup-dev-server:封装createRenderer方法
const webpack = require('webpack')const fs = require('fs')const path = require('path')const chokidar = require('chokidar')const middleware = require("webpack-dev-middleware")const HMR = require("webpack-hot-middleware")const MFS = require('memory-fs')const clientConfig = require('./webpack.client.config')const serverConfig = require('./webpack.server.config')const readFile = (fs, file) => {try {return fs.readFileSync(path.join(clientConfig.output.path, file), 'utf8')} catch (error) {const setupServer = (app, templatePath, cb) => {let bundlelet clientManifestlet templatelet readyconst readyPromise = new Promise(r => ready = r)template = fs.readFileSync(templatePath, 'utf8')const update = () => {if (bundle && clientManifest) {// 通知 server 进行渲染// 执行 createRenderer -> RenderToStringready()cb(bundle, {template,clientManifest// webpack -> entry-server -> bundleconst mfs = new MFS();const serverCompiler = webpack(serverConfig);serverCompiler.outputFileSystem = mfs;serverCompiler.watch({}, (err, stats) => {if (err) throw err// 之后读取输出:stats = stats.toJson()stats.errors.forEach(err => console.error(err))stats.warnings.forEach(err => console.warn(err))if (stats.errors.length) returnbundle = JSON.parse(readFile(mfs, 'vue-ssr-server-bundle.json'))update()clientConfig.plugins.push(new webpack.HotModuleReplacementPlugin()clientConfig.entry.app = ['webpack-hot-middleware/client', clientConfig.entry.app]clientConfig.output.filename = '[name].js'const clientCompiler = webpack(clientConfig);const devMiddleware = middleware(clientCompiler, {noInfo: true, publicPath: clientConfig.output.publicPath, logLevel: 'silent'app.use(devMiddleware);app.use(HMR(clientCompiler));clientCompiler.hooks.done.tap('clientsBuild', stats => {stats = stats.toJson()stats.errors.forEach(err => console.error(err))stats.warnings.forEach(err => console.warn(err))if (stats.errors.length) returnclientManifest = JSON.parse(readFile(devMiddleware.fileSystem,'vue-ssr-client-manifest.json'update()// fs -> templatePath -> templatechokidar.watch(templatePath).on('change', () => {template = fs.readFileSync(templatePath, 'utf8')console.log('template is updated');update()return readyPromisemodule.exports = setupServer(5)配置搞完了接下来是代码渲染
在src目录下,新增index.template.html文件,将官网中的例子(地址:使用一个页面模板 )复制,并进行一些更改
{{ title }}{{{ meta }}}(6)再搞个store和api模拟一下数据请求
这里介绍一下一个很重要的东西asyncData 预取数据,预取数据是在vue挂载前,所以下文这里用了上下文来获取store而不是this
asyncData: ({ store }) => { return store.dispatch('getDataAction') },
在src下创建api文件夹,并在下面创建data.js文件
// data.jsconst getData = https://www.isolves.com/it/cxkf/qd/2023-02-28/() => new Promise((resolve) => {setTimeout(() => {resolve([id: 1,item: '测试1'},id: 2,item: '测试2'},}, 1000)export {getData
在src下创建store文件夹,并在下面创建index.js文件
// store.jsimport Vue from 'vue'import Vuex from 'vuex'Vue.use(Vuex)import { getData } from '../api/data'export function createStore () {return new Vuex.Store({state: {lists: []},actions: {getDataAction ({ commit }) {return getData().then((res) => {commit('setData', res)},mutations: {setData (state, data) {state.lists = data


推荐阅读