前面我们已经对vue
的服务端渲染有了一定的认识,并且对vue-ssr
的构建配置有了一个基本的思路。前置知识参见:从0-1学习vue-srr, 深入学习vue-ssr
接下来我们根据前面讲述的基本思路开始学习如何进行一系列的操作,将页面赋予动态交互的能力,并且具备完成企业级项目开发的能力。
PS:本案例源代码仅供参考: 源码地址
一、项目源码结构
一个项目,肯定要有自己的目录,即源码存放的结构,这一点在官网中也已经介绍的很清楚了,这里不再赘述,官网介绍参见:源码结构
src
├── components
│ ├── Foo.vue
│ ├── Bar.vue
│ └── Baz.vue
├── App.vue
├── app.js # 通用 entry(universal entry)
├── entry-client.js # 仅运行于浏览器
└── entry-server.js # 仅运行于服务器
我们根据官网介绍,依次创建 App.vue
app.js
entry-client.js
entry-server.js
另外我们还需要创建 index.template.html
模板文件和 server.js
文件
App.vue
中:
<template>
<div id="app">
<h1>{
{ message }}</h1>
<input type="text" v-model="message">
<button @click="myClick">按钮</button>
</div>
</template>
<script>
export default {
name: 'App',
data() {
return {
message: 'hello vue-ssr'
}
},
methods: {
myClick() {
console.log('hello vue-ssr')
}
}
}
</script>
index.template.html
中:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>spades-vue-ssr</title>
</head>
<body>
<!-- 下面这行注释,就是动态数据替换的地方 -->
<!--vue-ssr-outlet-->
</body>
</html>
其他文件中的代码参见官网
二、安装依赖及配置打包
这里需要安装的依赖比较多,没必要死记硬背,需要的时候过来查看文档或者去官网查资料。但这里的介绍一定要搞清楚,头脑中有个印象,不然到时候查资料都不知道如何去查~
PS: 请考虑下你的webpack
版本,支持去踩 webpack5
的坑,不过这里使用的是 webpack4
和 webpack-cli3
1、安装生产依赖
npm i vue vue-server-renderer express cross-env
包 | 说明 |
---|---|
vue | vue.js 核心库 |
vue-server-rendere | Vue 服务端渲染工具 |
express | 基于 Node 的 Web 服务框架 |
cross-env | 通过 npm scripts 设置跨平台环境变量 |
2、安装开发依赖
npm i -D webpack webpack-cli webpack-merge webpack-node-externals @babel/core @babel/plugin-transform-runtime @babel/preset-env babel-loader css-loader url-loader file-loader rimraf vue-loader vue-template-compiler friendly-errors-webpack-plugin
包 | 说明 |
---|---|
webpack | webpack 核心包 |
webpack-cli | webpack 的命令行工具 |
webpack-merge | webpack 配置信息合并工具 |
webpack-node-externals | 排除 webpack 中的 Node 模块 |
rimraf | 基于 Node 封装的一个跨平台 rm -rf 工具 |
friendly-errors-webpack-plugin | 友好的 webpack 错误提示 |
@babel/core @babel/plugin-transform-runtime @babel/preset-env babel-loader |
Babel 相关工具 |
vue-loader vue-template-compiler |
处理 .vue 资源 |
file-loader | 处理字体资源 |
css-loader | 处理 CSS 资源 |
url-loader | 处理图片资源 |
3、配置文件
初始化 webpack 打包配置文件
build
├── webpack.base.config.js # 公共配置
├── webpack.client.config.js # 客户端打包配置文件
└── webpack.server.config.js # 服务端打包配置文件
webpack.base.config.js
/**
* 公共配置
*/
const VueLoaderPlugin = require('vue-loader/lib/plugin')
const path = require('path')
const FriendlyErrorsWebpackPlugin = require('friendly-errors-webpack-plugin')
const resolve = file => path.resolve(__dirname, file)
const isProd = process.env.NODE_ENV === 'production'
module.exports = {
mode: isProd ? 'production' : 'development',
output: {
path: resolve('../dist/'),
publicPath: '/dist/',
filename: '[name].[chunkhash].js'
},
resolve: {
alias: {
// 路径别名,@ 指向 src
'@': resolve('../src/')
},
// 可以省略的扩展名
// 当省略扩展名的时候,按照从前往后的顺序依次解析
extensions: ['.js', '.vue', '.json']
},
devtool: isProd ? 'source-map' : 'cheap-module-eval-source-map',
module: {
rules: [
// 处理图片资源
{
test: /\.(png|jpg|gif)$/i,
use: [
{
loader: 'url-loader',
options: {
limit: 8192,
},
},
],
},
// 处理字体资源
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
use: [
'file-loader',
],
},
// 处理 .vue 资源
{
test: /\.vue$/,
loader: 'vue-loader'
},
// 处理 CSS 资源
// 它会应用到普通的 `.css` 文件
// 以及 `.vue` 文件中的 `<style>` 块
{
test: /\.css$/,
use: [
'vue-style-loader',
'css-loader'
]
},
// CSS 预处理器,参考:https://vue-loader.vuejs.org/zh/guide/preprocessors.html
// 例如处理 Less 资源
// {
// test: /\.less$/,
// use: [
// 'vue-style-loader',
// 'css-loader',
// 'less-loader'
// ]
// },
]
},
plugins: [
new VueLoaderPlugin(),
new FriendlyErrorsWebpackPlugin()
]
}
webpack.client.config.js
/**
* 客户端打包配置
*/
const webpack = require('webpack')
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: '/src/entry-client.js',
module: {
rules: [
// ES6 转 ES5
{
test: /\.m?js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']