从0到1打造Vue服务端渲染-二

路由

安装路由

npm i vue-router -S

router目录index.js

import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'

Vue.use(VueRouter)

const routes = [
  {
    path: '/',
    name: 'home',
    component: Home
  },
  {
    path: '/about',
    name: 'about',
    component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
  }
]

//为什么不导出一个router实例?
//每次用户请求都需要创建一个router实例 
export default function createRouter(){
	return  new VueRouter({
		mode:'history',
		routes
	})
}

入口

在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}
}

服务端入口

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)
	})
}

客户端入口

entry-client.js


//挂载,激活app

import createApp from './app'

const { app,router} = createApp();
router.onReady( () => {
	app.$mount("#app")
})

webpack

安装依赖

npm i webpack-node-externals  lodash.merge -D

打包脚本

npm i cross-env -D

package.json

"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"

完整vue.config.js文件

//webpack 服务端、客户端插件
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: ()=>({
        // 将entry指向应用程序的 server/client 文件
        entry: `./src/entry-${target}.js`,
        // 对 bundle renderer 提供 source map支持
        devtool: 'source-map',
        // 这运行 webpack 以 Node 适用方式处理动态导入(dynamic import)
        // 并且还会在编译 Vue 组件时告知 'vue-loader' 输出面向服务器代码(server-oriented code)
        target: TARGET_NODE? 'node' : 'web',
        node: TARGET_NODE? undefined : false,
        output: {
            // 此处告知 server bundle 使用Node风格导出模块
            libraryTarget: TARGET_NODE ? "commonjs2" : undefined
        },
        //外置化应用程序依赖模块。可以使服务器构建速度更快,并生成较小的bundle文件
        externals: TARGET_NODE
            ? nodeExternals({
                // 不要外置化webpack  需要处理的依赖模块
                // 可以在这里添加更多的文件类型。例如,未处理 *.vue 原始文件
                // 你还应该将修改 `global` (例如 polyfill)的依赖模块列入白名单
                whitelist: [/\.css$/]
            })
            : undefined,
        optimization: {
            splitChunks: TARGET_NODE ? false : undefined 
        },
        // 这是将服务器的整个输出构建为单个JSON文件的插件
        // 服务端默认文件名为 `vue-ssr-server-bundle.json`
        plugins: [TARGET_NODE? new VueSSRServerPlugin(): new VueSSRClientPlugin()]
    }),

    chainWebpack: config => {
        config.module
            .rule('vue')
            .use('vue-loader')
            .tap(options => {
                merge(options, {
                    optimizeSSR: false
                })
            })
    }
}

打包命令

npm run build

打包了两次生成client,server目录,其中生成了两个文件vue-ssr-client-manifest.jsonvue-ssr-server-bundle.json客户端包和服务端包

├── client
│   ├── favicon.ico
│   ├── img
│   │   └── logo.82b9c7a5.png
│   ├── index.html
│   ├── js
│   │   ├── about.3f29108f.js
│   │   ├── about.3f29108f.js.map
│   │   ├── chunk-vendors.3857e89d.js
│   │   ├── chunk-vendors.3857e89d.js.map
│   │   ├── main.2275f1d5.js
│   │   └── main.2275f1d5.js.map
│   └── vue-ssr-client-manifest.json
└── server
│    └── vue-ssr-server-bundle.json

项目目录

....
│	
├── src
│   ├── App.vue
│   ├── app.js
│   ├── assets
│   │   └── logo.png
│   ├── components
│   │   └── HelloWorld.vue
│   ├── entry-client.js
│   ├── entry-server.js
│   ├── main.js
│   ├── router
│   │   └── index.js
│   ├── store
│   │   └── index.js
│   └── views
│       ├── About.vue
│       └── Home.vue
└── vue.config.js

 上一篇
web前端知识梳理-javascript web前端知识梳理-javascript
javascript基本数据类型 基本数据类型:Undefined、Null、Boolean、Number、String。 引用类型:Object、Array、Function JavaScript检测一个变量是一个String类型
2019-12-23
下一篇 
从0到1打造Vue服务端渲染-三 从0到1打造Vue服务端渲染-三
改造上节课node服务index.js,通过用户传进来的url来渲染页面内容,我从新建了一个server.js //nodejs 服务器 const express = require('express') const Vue = req
2019-12-10
  目录