// entry-server.js import { createApp } from './src/app' export default context => { //这里用promise的原因有很多,其中有一个就是下面这个onReady方法是异步的。createBundleRenderer支持promise return new Promise((resolve, reject) => { const { app, router } = createApp() router.push(context.url) router.onReady(() => {//onReady方法还有getMatchedComponents方法还是需要了解一下 const matchedComponents = router.getMatchedComponents() if (!matchedComponents.length) { return reject({ code: 404 }) } resolve(app) }, reject) }) }
最后看一下router.js
//router.js import Vue from 'vue' import VueRouter from 'vue-router' //页面要先声明后使用,不要问为什么 import home from './pages/home' import store from './pages/store' Vue.use(VueRouter) export default new VueRouter({ mode: 'history', routes:[ {path:'https://www.jb51.net/',name:'home',component:home}, {path:'/store',name:'store',component:store}, ] })
再看一下两个页面的代码;
//store.vue <template> <div>this is store</div> </template> <script> export default {} </script>
改的差不多了,试一哈:
重新打个包webpack --config webpack.server.js
启动node server
>entry-client.js是干啥的
到目前为止还没用到entry-client.js叫客户端配置,不着急使用,先做个测试,写点逻辑试试:
修改下store.vue
//store.vue <template> <div @click='run'>{{msg}}</div> </template> <script> export default { data(){ msg:'this is store' }, created(){ this.msg = 'this is created' }, mounted(){ this.msg = 'this is mounted' }, methods: { run(){ alert('this is methods') } } } </script>
看这个样子页面最终展示的结果应该是this is mounted,然而结果是这样的:
很好解释,服务端对于钩子函数的理解也是很正确的,created会在页面返回之前执行,而mounted是在vue实例成型之后执行,就是页面渲染后,这个是要在客户端才会执行,可是为什么页面出来了没有执行mounted,而且run的点击事件没有生效;
看看页面:
一个js文件都没加载,怎么执行逻辑,就是个静态页面0.0;
这时候entry-client.js就出场了
新增两个文件
//entry-client.js import { createApp } from './src/app.js'; const { app } = createApp(); app.$mount('#app');
基本配置;
//webpack.client.config.js const merge = require('webpack-merge') const baseConfig = require('./webpack.base.config.js') const VueSSRClientPlugin = require('vue-server-renderer/client-plugin') module.exports = merge(baseConfig, { entry: './entry-client.js', optimization:{ runtimeChunk:true }, plugins: [ // 此插件在输出目录中 // 生成 `vue-ssr-client-manifest.json`。 new VueSSRClientPlugin(), ] })
这个地方重点除了VueSSRClientPlugin生成vue-ssr-client-manifest.json外,optimization是webpack4产物,用来分离生成共公chunk,配置还算复杂,可以看下这里webpack4 optimization总结
修改下server.js
//server.js const express = require('express'); const chalk = require('chalk'); const server = express(); const serverBundle = require('./dist/vue-ssr-server-bundle.json') const clientManifest = require('./dist/vue-ssr-client-manifest.json')//新增 const renderer = require('vue-server-renderer').createBundleRenderer(serverBundle,{ runInNewContext: false, // 推荐 template: require('fs').readFileSync('./index.html', 'utf-8'), clientManifest // //新增 }) server.get('*', (req, res) => { res.set('content-type', "text/html"); const context = { url:req.url } renderer.renderToString(context, (err, html) => { if (err) { res.status(500).end('Internal Server Error') return } else { res.end(html) } }) }) server.listen(8080,function(){ let ip = getIPAdress(); console.log(`服务器开在:${chalk.green(ip)}:${chalk.yellow(8080)}`) }) function getIPAdress(){//node下的os模块可以拿到启动该文件的服务端的部分信息,细节自己去node上面查 var interfaces = require('os').networkInterfaces(); for (var devName in interfaces) { var iface = interfaces[devName]; for (var i = 0; i < iface.length; i++) { var alias = iface[i]; if (alias.family === 'IPv4' && alias.address !== '127.0.0.1' && !alias.internal) { return alias.address; } } } }
打包下:webpack --config webpack.client.config.js
node server 一下,看看页面
js有了,可是为什么还不行,不能点0.0;
看看。奥报错了
读取不到静态文件;
修改server.js加个静态文件托管:
再看看
事件也有了,页面没变化,console一下,发现值其实已经变了,只是失去了响应式;这就是为什么要用vuex的缘故;
>加入vuex
开始想在页面中用this.$set方法,然而行不通,而且不可能给每个值都重新写一个这个方法;
加个sotre.js