基于vue-cli4.0+Typescript+SSR的項(xiàng)目實(shí)踐

簡(jiǎn)介

極速傳送門: 基于vue-cli4.0+Typescript+SSR的小Demo

最終效果:
訪問秕噪,返回的是html片段,并且從chunk中分離了vue依賴



Vue SSR Demo

使用Vue-cli4.0+Typescript+SSR 的小目Demo
怎么說呢,從vue3開始,之前的build目錄舊沒有了,想要對(duì)webpack配置進(jìn)行修改的話嘁酿,只能在根目錄下新建 vue.config.js文件,具體修改可參照vue-cli官網(wǎng)
之前用的是vue-cli2.+,此次直接升級(jí)到vue-cli4.+并且直接上了TS男应,踩了不少坑闹司,不過好在是熬過來了,分享一下我的項(xiàng)目Demo

已實(shí)現(xiàn):

  • 項(xiàng)目搭建
  • 本地ssr開發(fā)環(huán)境搭建(koa)
  • 使用Vuex實(shí)現(xiàn)數(shù)據(jù)預(yù)取(demo刪掉了該部分)
  • 打包c(diǎn)hunk分離優(yōu)化
  • Jenkins + Docker 持續(xù)集成沐飘、部署
  • 集成到后端項(xiàng)目(egg.js)

主要命令

$ npm install   # 安裝依賴
$ npm run dev   # 本地開發(fā)
 ├── 8080  本地非ssr環(huán)境
 └── 3000  本地ssr環(huán)境
$ npm run build   # window下打包命令
$ npm run build:linux   # linux下打包命令

項(xiàng)目目錄

┌── .vscode IDE工作區(qū)配置
│   └── settings.json
├── dist # 靜態(tài)資源(自動(dòng)生成)
│   └── index.temp.html # ssr模板文件
├── public # 靜態(tài)目錄游桩,打包的時(shí)候該目錄會(huì)原封不動(dòng)的復(fù)制到dist目錄下
├── server # koa服務(wù)
│   ├── index.js # koa入口
│   └── server.js # 服務(wù)邏輯
├── src # 主要源碼
│   ├── api # 請(qǐng)求管理
│   │   └── api.config.ts 接口管理
│   │   └── axios.config.ts 攔截器管理
│   ├── assets # 資源
│   │   └── ......
│   ├── plugins # 插件
│   │   └── ......
│   ├── utils # 全局方法等
│   │   └── ......
│   ├── views #  頁面/視圖
│   │   └── ......
│   ├── App.vue # 入口Vue
│   ├── entry-client.ts # 客戶端入口
│   ├── entry-server.ts # 服務(wù)端入口
│   ├── main # 公共入口
│   ├── router.index.ts # 路由配置
│   ├── store.index.ts # Vuex配置
│   ├── vue-shim.d.ts # ts模塊聲明
└── .browserslistrc # 瀏覽器設(shè)置
└── .eslintrc.js # eslintrc設(shè)置
└── .gitignore # git忽略
└── babel.config.js # babel配置
└── Jenkinsfile # jenkins配置
└── package-lock.json # 版本鎖定
└── package.json # 項(xiàng)目依賴
└── tsconfig.json # ts配置文件
└── vue.config.js # webpack配置文件

webpack配置文件 解析

  1. 關(guān)閉css分離
extract: false, // 目前還沒分離出css,正在努力嘗試
  1. 本地ssr搭建
本地搭建ssr環(huán)境,webpack-dev-server跑本地服務(wù)時(shí)耐朴,會(huì)打一次包并進(jìn)行熱更新借卧,所以思路是再起一個(gè)node服務(wù),讀取監(jiān)聽打包的chunk文件進(jìn)行ssr的操作筛峭,這里有兩個(gè)點(diǎn)
- 設(shè)置 webpack-dev-serve 允許跨域
  headers: { 'Access-Control-Allow-Origin': '*' },
- 設(shè)置publicPath
// 加上端口前綴才能訪問到靜態(tài)資源铐刘,生產(chǎn)環(huán)境因?yàn)槭羌傻胶蠖隧?xiàng)目設(shè)置跟路徑就OK了
  process.env.NODE_ENV !== 'production' ? 'http://localhost:8080' : '/',
  1. 分離 chunk 減少打包體積
// 可以分離大部分依賴,使打包出來的chunk體積變小
// 客戶端生產(chǎn)環(huán)境  才分離
externals:
  // 可以分離大部分依賴影晓,使打包出來的chunk體積變小
  process.env.NODE_ENV === 'production' && !TARGET_NODE
  ? {
      vue: 'Vue',
    }
  : undefined,
  1. 注入版本信息
new webpack.DefinePlugin({
  'process.env.NODE_ENV': `"${process.env.NODE_ENV || 'development'}"`, // 注意需要用雙引號(hào)包住
}),
  1. 關(guān)閉splitChunks
chainWebpack: (config) => {
  config.optimization.splitChunks(undefined);
},

ssr 基本搭建

  1. 公共入口 main.ts
// 防止單例污染镰吵,需要導(dǎo)出一個(gè)工廠函數(shù)  
export function createApp(): any {
  const router = createRouter();
  const store = createStore();
  const app = new Vue({
    router,
    store,
    render: (h) => h(App),
  });
  return { app, router, store };
}
  1. 客戶端入口 entry-client.ts
// 掛載到app上
const { app, router } = createApp();
router.onReady(() => {
  app.$mount('#app');
});
  1. 服務(wù)端入口 entry-server.ts
// 匹配路由,需要返回一個(gè)promise挂签,因?yàn)橛锌赡苁钱惒浇M件疤祭,若無匹配,則返回404
import { createApp } from './main';
export default (context: any) =>
  new Promise((resolve, reject) => {
    const { app, router } = createApp();
    router.push(context.url);
    router.onReady(() => {
      const matchedComponents = router.getMatchedComponents();
      if (!matchedComponents.length) {
        return reject({
          code: 404,
        });
      }
      resolve(app);
    }, reject);
});

4 路由 router.index.ts

// 注意要模式改為 history饵婆,讓路由請(qǐng)求能到后端
export function createRouter() {
  return new Router({
    mode: 'history',
    routes: [
      {
        path: '/',
        name: 'Home',
        component: () => import(/* webpackChunkName: "Home" */ './views/Home.vue'),
      },
      {
        path: '/about',
        name: 'About',
        component: () => import(/* webpackChunkName: "about" */ './views/About.vue'),
      },
    ],
  });
}

5 注意不要在組件的 mounted 鉤子之前進(jìn)行 dom 相關(guān)的操作勺馆,因?yàn)榉?wù)端會(huì)執(zhí)行到這些鉤子

6 實(shí)現(xiàn)本地 ssr

  - 讀取web-dev-server打包出來的chunk并實(shí)時(shí)監(jiān)聽
  - 當(dāng)chunk變化時(shí),使用'vue-server-renderer'的renderToString,渲染成html字符串

7 本地 ssr 環(huán)境下谓传,接口轉(zhuǎn)發(fā)問題

  // 雖然可以配置 devServer proxy,但是ssr環(huán)境在另一個(gè)node端口下芹关,需要對(duì)接口進(jìn)行轉(zhuǎn)發(fā)
  - 對(duì)接口進(jìn)行規(guī)范续挟,接口類的請(qǐng)求都加上'/api'前綴
  - koa server.js 下,對(duì)匹配的接口類請(qǐng)求侥衬,使用'http-proxy-middleware'和'koa2-connect'進(jìn)行接口轉(zhuǎn)發(fā)

參考文獻(xiàn)

帶你五步學(xué)會(huì)Vue SSR

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末诗祸,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子轴总,更是在濱河造成了極大的恐慌直颅,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,039評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件怀樟,死亡現(xiàn)場(chǎng)離奇詭異功偿,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)往堡,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門械荷,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人虑灰,你說我怎么就攤上這事吨瞎。” “怎么了穆咐?”我有些...
    開封第一講書人閱讀 165,417評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵颤诀,是天一觀的道長。 經(jīng)常有香客問我对湃,道長崖叫,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,868評(píng)論 1 295
  • 正文 為了忘掉前任熟尉,我火速辦了婚禮归露,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘斤儿。我一直安慰自己剧包,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,892評(píng)論 6 392
  • 文/花漫 我一把揭開白布往果。 她就那樣靜靜地躺著疆液,像睡著了一般。 火紅的嫁衣襯著肌膚如雪陕贮。 梳的紋絲不亂的頭發(fā)上堕油,一...
    開封第一講書人閱讀 51,692評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼掉缺。 笑死卜录,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的眶明。 我是一名探鬼主播艰毒,決...
    沈念sama閱讀 40,416評(píng)論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼搜囱!你這毒婦竟也來了丑瞧?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,326評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤蜀肘,失蹤者是張志新(化名)和其女友劉穎绊汹,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體扮宠,經(jīng)...
    沈念sama閱讀 45,782評(píng)論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡西乖,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,957評(píng)論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了涵卵。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片浴栽。...
    茶點(diǎn)故事閱讀 40,102評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖轿偎,靈堂內(nèi)的尸體忽然破棺而出典鸡,到底是詐尸還是另有隱情,我是刑警寧澤坏晦,帶...
    沈念sama閱讀 35,790評(píng)論 5 346
  • 正文 年R本政府宣布萝玷,位于F島的核電站,受9級(jí)特大地震影響昆婿,放射性物質(zhì)發(fā)生泄漏球碉。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,442評(píng)論 3 331
  • 文/蒙蒙 一仓蛆、第九天 我趴在偏房一處隱蔽的房頂上張望睁冬。 院中可真熱鬧看疙,春花似錦、人聲如沸能庆。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,996評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽邮绿。三九已至,卻和暖如春攀例,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背粤铭。 一陣腳步聲響...
    開封第一講書人閱讀 33,113評(píng)論 1 272
  • 我被黑心中介騙來泰國打工傻唾, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留承耿,地道東北人伪煤。 一個(gè)月前我還...
    沈念sama閱讀 48,332評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像抱既,于是被迫代替她去往敵國和親职烧。 傳聞我的和親對(duì)象是個(gè)殘疾皇子防泵,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,044評(píng)論 2 355