vue-cli3搭建服務端渲染vue-ssr,node+express+vue-cli3+vue-ssr

看了vue 官方的文檔浑度,還是有點懵的寇窑。百度了一堆東西,終于成功的配置出基于vue-cli3的vue-ssr 服務端預渲染箩张。

有幫助的話甩骏,還請點個贊

建議使用nuxt,可以更好的做服務端渲染先慷。

需要自己創(chuàng)建index.template.html文件饮笛。這個文件在

一、創(chuàng)建vue項目

$ vue create vue-ssr 創(chuàng)建目錄名為vue-ssr的項目
選擇項目需要的選項论熙,直接創(chuàng)建即可福青。

$ cd vue-ssr 創(chuàng)建完成后,進入項目目錄。

二无午、改造vue-ssr

1媒役、安裝環(huán)境


$ npm install vue-server-renderer lodash.merge webpack-node-externals cross-env express --registry=https://registry.npm.taobao.org --save-dev 

2、創(chuàng)建ssr配置文件

  • 在根目錄新建 server.js 文件宪迟,用于集成node服務
//  server.js
const express = require('express')
const fs = require('fs')
const { minify } = require('html-minifier')
const path = require('path') 
const { createBundleRenderer } = require('vue-server-renderer')
const app = express() 
const resolve = file => path.resolve(__dirname, file) 
const renderer = createBundleRenderer(require('./dist/vue-ssr-server-bundle.json'), {
    runInNewContext: false,
    template: fs.readFileSync(resolve('./index.template.html'), 'utf-8'),
    clientManifest: require('./dist/vue-ssr-client-manifest.json'),
    basedir: resolve('./dist')
})
app.use(express.static(path.join(__dirname, 'dist')))
app.get('*', (req, res) => { 
    res.setHeader('Content-Type', 'text/html')
    const handleError = err => {
        if (err.url) {
            res.redirect(err.url)
        } else if (err.code === 404) {
            res.status(404).send('404 | Page Not Found')
        } else {
            res.status(500).send('500 | Internal Server Error')
            console.error(`error during render : ${req.url}`)
            console.error(err.stack)
        }
    }
    const context = {
        title: 'document',
        url: req.url,
        keywords: '',
        description: '',
    }
    renderer.renderToString(context, (err, html) => {
        if (err) {
            return handleError(err)
        }
        res.send(minify(html, { collapseWhitespace: true, minifyCSS: true }))
    })
})

app.on('error', err => console.log(err))
app.listen(8000, () => {
    console.log(`vue ssr started at http://localhost:8000`)
})

  • 在src目錄下新建以下兩個文件
  • /src/entry-client.js
  • /src/entry-server.js

1酣衷、entry-client.js

//  entry-client.js
import { createApp } from './main'

// 客戶端特定引導邏輯……
const { app } = createApp()

// 這里假定 App.vue 模板中根元素具有 `id="app"`
app.$mount('#app')

2、entry-server.js

// entry-server.js

import { createApp } from "./main";
export default context => {
    // 因為有可能會是異步路由鉤子函數(shù)或組件次泽,所以我們將返回一個 Promise穿仪,
    // 以便服務器能夠等待所有的內(nèi)容在渲染前,
    // 就已經(jīng)準備就緒意荤。
    return new Promise((resolve, reject) => {
        const { app, router } = createApp();

        // 設置服務器端 router 的位置
        router.push(context.url);

        // 等到 router 將可能的異步組件和鉤子函數(shù)解析完
        router.onReady(() => {
            const matchedComponents = router.getMatchedComponents();
            // 匹配不到的路由啊片,執(zhí)行 reject 函數(shù),并返回 404
            if (!matchedComponents.length) {
                return reject({
                    code: 404
                });
            }
            // Promise 應該 resolve 應用程序?qū)嵗料瘢员闼梢凿秩?            resolve(app);
        }, reject);
    });
};
  • 在根目錄下新建webpack配置文件紫谷,vue-cli3+對webpack的配置,已經(jīng)轉(zhuǎn)移到根目錄下的vue.config.js文件內(nèi)捐寥。
    所以需要在根目錄下新建一個 vue.config.js文件碴里。
// vue.config.js
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
    },
    configureWebpack: () => ({
        // 將 entry 指向應用程序的 server / client 文件
        entry: `./src/entry-${target}.js`,
        // 對 bundle renderer 提供 source map 支持
        devtool: 'source-map',
        target: TARGET_NODE ? "node" : "web",
        node: TARGET_NODE ? undefined : false,
        output: {
            libraryTarget: TARGET_NODE ? "commonjs2" : undefined
        },
        // https://webpack.js.org/configuration/externals/#function
        // https://github.com/liady/webpack-node-externals
        // 外置化應用程序依賴模塊∩险妫可以使服務器構建速度更快,
        // 并生成較小的 bundle 文件羹膳。
        externals: TARGET_NODE
            ? nodeExternals({
                // 不要外置化 webpack 需要處理的依賴模塊睡互。
                // 你可以在這里添加更多的文件類型。例如陵像,未處理 *.vue 原始文件就珠,
                // 你還應該將修改 `global`(例如 polyfill)的依賴模塊列入白名單
                whitelist: [/\.css$/]
            })
            : undefined,
        optimization: {
            splitChunks: false // 這里設置為false,不然會一直build 不成功
        },
        plugins: [TARGET_NODE ? new VueSSRServerPlugin() : new VueSSRClientPlugin()]
    }),
    chainWebpack: config => {
        config.module
            .rule("vue")
            .use("vue-loader")
            .tap(options => {
                merge(options, {
                    optimizeSSR: false
                });
            });
    }
};
  • 修改package.json文件,在scripts屬性中添加以下代碼:
    "build:client": "vue-cli-service build",
    "build:server": "cross-env WEBPACK_TARGET=node vue-cli-service build --mode server",
    "build:win": "npm run build:server && move dist\\vue-ssr-server-bundle.json bundle && npm run build:client && move bundle dist\\vue-ssr-server-bundle.json"
  • 修改main.js醒颖、router/index.js妻怎、store/index.js文件

1、main.js

// main.js
import Vue from "vue";
import App from "./App.vue";
import { createRouter } from "./router";
import { createStore } from "./store";
Vue.config.productionTip = false; 
export function createApp() {
  const router = createRouter();
  const store = createStore();
  const app = new Vue({
    router,
    store,
    render: h => h(App)
  })
  return { app, router, store }
}

2泞歉、router/index.js

// 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
  },
];
export function createRouter() {
  return new VueRouter({
    mode: "history",
    base: process.env.BASE_URL,
    routes
  });
}

3逼侦、store/index.js

// store/index.js
import Vue from "vue";
import Vuex from "vuex";

Vue.use(Vuex);
export function createStore() {
  return new Vuex.Store({
    state: {},
    mutations: {},
    actions: {},
    modules: {}
  })
}

最后一步,運行命令:
$ npm run build:win
構建完成后運行命令:
$ node server
然后到瀏覽器打開 http://localhost:8000 如果出現(xiàn)了頁面內(nèi)容腰耙,則證明配置成功榛丢!

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市挺庞,隨后出現(xiàn)的幾起案子晰赞,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,383評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件掖鱼,死亡現(xiàn)場離奇詭異然走,居然都是意外死亡,警方通過查閱死者的電腦和手機戏挡,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評論 3 385
  • 文/潘曉璐 我一進店門芍瑞,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人增拥,你說我怎么就攤上這事啄巧。” “怎么了掌栅?”我有些...
    開封第一講書人閱讀 157,852評論 0 348
  • 文/不壞的土叔 我叫張陵秩仆,是天一觀的道長。 經(jīng)常有香客問我猾封,道長澄耍,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,621評論 1 284
  • 正文 為了忘掉前任晌缘,我火速辦了婚禮齐莲,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘磷箕。我一直安慰自己选酗,他們只是感情好,可當我...
    茶點故事閱讀 65,741評論 6 386
  • 文/花漫 我一把揭開白布岳枷。 她就那樣靜靜地躺著芒填,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,929評論 1 290
  • 那天燎窘,我揣著相機與錄音慢蜓,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播凯砍,決...
    沈念sama閱讀 39,076評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼掰吕!你這毒婦竟也來了果覆?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,803評論 0 268
  • 序言:老撾萬榮一對情侶失蹤殖熟,失蹤者是張志新(化名)和其女友劉穎局待,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,265評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡钳榨,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,582評論 2 327
  • 正文 我和宋清朗相戀三年舰罚,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片薛耻。...
    茶點故事閱讀 38,716評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡营罢,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出饼齿,到底是詐尸還是另有隱情饲漾,我是刑警寧澤,帶...
    沈念sama閱讀 34,395評論 4 333
  • 正文 年R本政府宣布缕溉,位于F島的核電站考传,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏证鸥。R本人自食惡果不足惜僚楞,卻給世界環(huán)境...
    茶點故事閱讀 40,039評論 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望枉层。 院中可真熱鬧泉褐,春花似錦、人聲如沸鸟蜡。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,798評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽揉忘。三九已至财剖,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間癌淮,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,027評論 1 266
  • 我被黑心中介騙來泰國打工沦补, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留乳蓄,地道東北人。 一個月前我還...
    沈念sama閱讀 46,488評論 2 361
  • 正文 我出身青樓夕膀,卻偏偏與公主長得像虚倒,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子产舞,可洞房花燭夜當晚...
    茶點故事閱讀 43,612評論 2 350