路由
安装路由
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.json
、vue-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