这是一篇教程,从创立我的项目到革新我的项目

vue-cli创立一个我的项目

在放你做demo的中央,创立一个我的项目

vue create vue-ssr// 如果你装置了vue-cli4,抉择vue2的版本,以下的改良过程是按vue2来做的

通过漫长的期待,下载好文件开始咱们的革新之路

文件目录

进入vue-ssr文件夹,应用命令

vue ui

把vue-router装上

先装置几个依赖插件

// 安不上用cnpm,yarn,npxnpm i vue-server-renderer express -Dnpm install webpack-node-externals lodash.merge -Dnpm i cross-env -D

批改package.json文件

"scripts": {    "serve": "vue-cli-service serve",    "build": "vue-cli-service build",    "lint": "vue-cli-service lint"}改成"scripts": {    "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

// 服务器渲染的两个插件,管制server和clientconst 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");// 环境变量:决定入口是客户端还是服务端,WEBPACK_TARGET在启动项中设置的,见package.json文件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: {      // 此处配置服务器端应用node的格调构建      libraryTarget: TARGET_NODE ? "commonjs2" : undefined    },    // 外置化应用程序依赖模块。能够使服务器构建速度更快,并生成较小的 bundle 文件。    externals: TARGET_NODE      ? nodeExternals({          // 不要外置化 webpack 须要解决的依赖模块。          // 能够在这里增加更多的文件类型。例如,未解决 *.vue 原始文件,          // 你还应该将批改 `global`(例如 polyfill)的依赖模块列入白名单(以前叫whitelist,为了防止美国的人种歧视,改成了allowlist)          allowlist: [/\.css$/]        })      : undefined,    optimization: {      splitChunks: TARGET_NODE ? false : undefined    },    // 这是将服务器的整个输入构建为单个 JSON 文件的插件。    // 服务端默认文件名为 `vue-ssr-server-bundle.json`    // 客户端默认文件名为 `vue-ssr-client-manifest.json`    plugins: [TARGET_NODE ? new VueSSRServerPlugin() : new VueSSRClientPlugin()]  }),  chainWebpack: config => {    config.module      .rule("vue")      .use("vue-loader")      .tap(options => {        merge(options, {          optimizeSSR: false        });      });  }};

批改路由文件

import Vue from 'vue';import Router from 'vue-router';import Home from '../views/Home.vue';import About from '../views/About.vue';Vue.use(Router);// 这里为什么不导出一个router实例?// 每次用户申请都须要创立新router实例,如果用户申请屡次都用一个实例会造成数据净化export function createRouter() {    return new Router({        // 肯定要history模式,因为,hash模式更改门路不会刷新,具体起因自行查问        mode: 'history',        routes: [            {path: '/', name: 'Home',component: Home},            {path: '/about', name: 'About', component: About},        ]    })}

批改main.js文件

import Vue from "vue";import App from "./App.vue";import { createRouter } from "./router";import store from "./store";Vue.config.productionTip = false;const router = createRouter();// 这里的挂载($mount("#app"))放到entry-client.js文件外面,前面会说到export function createApp() {    const app = new Vue({        router,        store,        render: (h) => h(App),    });    return { app, router };}

在src下增加entry-client.js和entry-server.js文件

entry-client.js

import {createApp} from './main.js';const {app, router} = createApp();router.onReady(()=>{    app.$mount("#app");})

entry-server.js

import {createApp} from "./main.js";// context实际上就是server/index.js外面传参,前面会说到server/index.jsexport default context => {    return new Promise((resolve, reject) => {        const {app, router} = createApp();        router.push(context.url)        router.onReady(()=>{            // 是否匹配到咱们要用的组件            const matchs = router.getMatchedComponents();            if(!matchs) {                return reject({code: 404})            }            resolve(app);        }, reject);    })}

在src下创立server/index.js

// nodejs服务器const express = require("express");const fs = require("fs");// 创立express实例和vue实例const app = express();// 创立渲染器const { createBundleRenderer } = require("vue-server-renderer");const serverBundle = require("../../dist/server/vue-ssr-server-bundle.json");const clientManifest = require("../../dist/client/vue-ssr-client-manifest.json");// 这儿引入的文件是不同于index.html的问题,具体文件上面会讲到const template = fs.readFileSync("../../public/index.ssr.html", "utf-8"); // 宿主模板文件const renderer = createBundleRenderer(serverBundle, {    runInNewContext: false,    template,    clientManifest,});// 中间件解决动态文件申请app.use(express.static("../../dist/client", { index: false })); // 为false是不让它渲染成dist/client/index.html// app.use(express.static('../dist/client'))// 前端申请什么我都不关怀,所有的路由解决交给vueapp.get("*", async (req, res) => {    try {        const context = {            url: req.url,            title: "ssr test",        };        // nodejs流数据,文件太大,用renderToString会卡        const stream = renderer.renderToStream(context);        let buffer = [];        stream.on("data", (chunk) => {            buffer.push(chunk);        });        stream.on("end", () => {            res.end(Buffer.concat(buffer));        });    } catch (error) {        console.log(error);        res.status(500).send("服务器外部谬误");    }});app.listen(3000, () => {    console.log("渲染服务器启动胜利");});

在public上面创立index.ssr.html文件

<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <meta name="viewport" content="width=device-width, initial-scale=1.0">    <title>Document</title></head><body>    <!--vue-ssr-outlet-->    <!--下面这个肯定要留着,它是服务端渲染模版的标记,没有就会报错,不信能够删了试一下--></body></html>

而后所有的革新实现,运行命令

// 先构建两个json文件npm run build

再到server文件夹下运行

node index.js// 如果显示: `渲染服务器启动胜利`, 在浏览器关上 `localhost:3000` 端口,就能看到咱们的页面

整完这,你再去玩儿nuxt,你感觉好多了,因为nuxt不必配路由,本人生成,连路由传参都设定好了