摘要:有兩種方法,一種是在開(kāi)發(fā)環(huán)境中設(shè)置通過(guò)的,另一種是在服務(wù)器上修改的配置設(shè)置。這樣我們以后使用訪問(wèn)接口就可以不加了,打包后訪問(wèn)也不用手動(dòng)去除統(tǒng)一管理在項(xiàng)目開(kāi)發(fā)過(guò)程中,會(huì)涉及到很多接口的處理,當(dāng)項(xiàng)目足夠大時(shí),就需要統(tǒng)一管理接口。
一、環(huán)境依賴安裝 1. node環(huán)境 1.1 node和npm環(huán)境的安裝這篇文章總結(jié)了vue項(xiàng)目的所遇到的問(wèn)題,包括跨域、用戶認(rèn)證、接口統(tǒng)一管理、路由配置、兼容性處理,性能優(yōu)化等內(nèi)容。
項(xiàng)目github地址 :
前端 https://github.com/huangyangt...
后端: https://github.com/huangyangt...
根據(jù)以下教程安裝,然后設(shè)置好環(huán)境變量
http://www.runoob.com/nodejs/...
視頻教程 http://101.110.118.22/github....
centos如果裝不上看這里:https://www.rosehosting.com/b...
1.2 為npm更改源npm默認(rèn)使用的源的服務(wù)器在國(guó)外下載速度慢,所以需要更換源1.2.1使用cnpm代替npm以下兩種方法任選一種
參考鏈接:https://npm.taobao.org/
# 安裝 npm install -g cnpm --registry=https://registry.npm.taobao.org #安裝完cnpm,之后再按照依賴就要使用cnpm cnpm install [包名]1.2.2為npm更換源
參考鏈接 https://segmentfault.com/a/11...
修改源為淘寶的源
npm config set registry http://registry.npm.taobao.org/
我們?cè)诎l(fā)布自己包的時(shí)候需要將官方的源改回來(lái)
npm config set registry https://registry.npmjs.org/1.3 管理(更新)nodejs的版本
切換nodejs版本有兩種方式,分別是nvm和n,n更簡(jiǎn)單推薦使用使用n管理nodejs版本
參考鏈接 https://www.jianshu.com/p/c64...官網(wǎng) https://github.com/tj/n
#安裝 npm install -g n #使用n下載所需node版本 n 版本號(hào) #下載最新版本 n latest # 切換版本 輸入 n, 然后選中所需版本 #以指定的版本來(lái)執(zhí)行版本 n use 7.4.0 index.js
linux使用n安裝新版本nodejs之后,如果node -v還是原來(lái)的版本,那么就需要改變一下環(huán)境變量
vim .bash_profile
export NODE_HOME=/usr/local #NODE_HOME改成新版本nodejs安裝的目錄,如果找不到,find / -name node export PATH=$NODE_HOME/bin:$PATH export NODE_PATH=$NODE_HOME/lib/node_modules:$PATH
修改環(huán)境變量參考:https://blog.csdn.net/yi412/a...
1.4 package.json文件詳解參考文檔 http://javascript.ruanyifeng....2. vue腳手架
vue-cli目前已經(jīng)更新到3版本,vue-cli3把webpack相關(guān)的配置隱藏起來(lái)了,所有的配置都在vue.config.js文件夾中,所以使用vue-cli3需要的webpack水平較高,建議使用vue-cli23.1 vue-cli2.x安裝
參考鏈接:https://github.com/vuejs/vue-...
安裝:
npm install -g vue-cli
用法:
$ vue init < template-name > < project-name >
例:
$ vue init webpack my-project
目前可用的模塊包括:
webpack - 一個(gè)功能齊全的Webpack + vue-loader設(shè)置,具有熱重載,linting,測(cè)試和css提取功能。
webpack-simple - 一個(gè)簡(jiǎn)單的Webpack + vue-loader設(shè)置,用于快速原型設(shè)計(jì)。
browserify -全功能Browserify + vueify設(shè)置用熱重裝載,linting&單元測(cè)試。
browserify -simple - 一個(gè)簡(jiǎn)單的Browserify + vueify設(shè)置,用于快速原型設(shè)計(jì)。
pwa - 基于webpack模板的vue-cli的PWA模板
simple - 單個(gè)HTML文件中最簡(jiǎn)單的Vue設(shè)置
3.2 vue-cli3.x安裝及配置(僅供參考)vue-cli3x的官方文檔:https://cli.vuejs.org/
Vue-cli3 中vue.config.js文件配置參考文檔:https://cli.vuejs.org/zh/conf...
Vue CLI 的包名稱由 vue-cli 改成了 @vue/cli。 如果你已經(jīng)全局安裝了舊版本的 vue-cli(1.x 或 2.x),你需要先通過(guò) npm uninstall vue-cli -g 或 yarn global remove vue-cli 卸載它。
安裝
npm install -g @vue/cli
安裝了vue-cli3如果還想使用vue-cli2的init功能,需要安裝一個(gè)橋接功能
npm install -g @vue/cli-init
// vue.config.js 配置說(shuō)明 //官方vue.config.js 參考文檔 https://cli.vuejs.org/zh/config/#css-loaderoptions // 這里只列一部分,具體配置參考文檔 module.exports = { // 部署生產(chǎn)環(huán)境和開(kāi)發(fā)環(huán)境下的URL。 // 默認(rèn)情況下,Vue CLI 會(huì)假設(shè)你的應(yīng)用是被部署在一個(gè)域名的根路徑上 //例如 https://www.my-app.com/。如果應(yīng)用被部署在一個(gè)子路徑上,你就需要用這個(gè)選項(xiàng)指定這個(gè)子路徑。例如,如果你的應(yīng)用被部署在 https://www.my-app.com/my-app/,則設(shè)置 baseUrl 為 /my-app/。 baseUrl: process.env.NODE_ENV === "production" ? "./" : "/", // outputDir: 在npm run build 或 yarn build 時(shí) ,生成文件的目錄名稱(要和baseUrl的生產(chǎn)環(huán)境路徑一致) outputDir: "dist", //用于放置生成的靜態(tài)資源 (js、css、img、fonts) 的;(項(xiàng)目打包之后,靜態(tài)資源會(huì)放在這個(gè)文件夾下) assetsDir: "assets", //指定生成的 index.html 的輸出路徑 (打包之后,改變系統(tǒng)默認(rèn)的index.html的文件名) // indexPath: "myIndex.html", //默認(rèn)情況下,生成的靜態(tài)資源在它們的文件名中包含了 hash 以便更好的控制緩存。你可以通過(guò)將這個(gè)選項(xiàng)設(shè)為 false 來(lái)關(guān)閉文件名哈希。(false的時(shí)候就是讓原來(lái)的文件名不改變) filenameHashing: false, // lintOnSave:{ type:Boolean default:true } 問(wèn)你是否使用eslint `lintOnSave`: true, //如果你想要在生產(chǎn)構(gòu)建時(shí)禁用 eslint-loader,你可以用如下配置 // lintOnSave: process.env.NODE_ENV !== "production", //是否使用包含運(yùn)行時(shí)編譯器的 Vue 構(gòu)建版本。設(shè)置為 true 后你就可以在 Vue 組件中使用 template 選項(xiàng)了,但是這會(huì)讓你的應(yīng)用額外增加 10kb 左右。(默認(rèn)false) // runtimeCompiler: false, /** * 如果你不需要生產(chǎn)環(huán)境的 source map,可以將其設(shè)置為 false 以加速生產(chǎn)環(huán)境構(gòu)建。 * 打包之后發(fā)現(xiàn)map文件過(guò)大,項(xiàng)目文件體積很大,設(shè)置為false就可以不輸出map文件 * map文件的作用在于:項(xiàng)目打包后,代碼都是經(jīng)過(guò)壓縮加密的,如果運(yùn)行時(shí)報(bào)錯(cuò),輸出的錯(cuò)誤信息無(wú)法準(zhǔn)確得知是哪里的代碼報(bào)錯(cuò)。 * 有了map就可以像未加密的代碼一樣,準(zhǔn)確的輸出是哪一行哪一列有錯(cuò)。 * */ productionSourceMap: false, // 它支持webPack-dev-server的所有選項(xiàng) devServer: { host: "localhost", port: 1111, // 端口號(hào) https: false, // https:{type:Boolean} open: true, //配置自動(dòng)啟動(dòng)瀏覽器 // proxy: "http://localhost:4000" // 配置跨域處理,只有一個(gè)代理 // 配置多個(gè)代理 proxy: { "/api": { target: "二、開(kāi)發(fā)", ws: true, changeOrigin: true }, "/foo": { target: " " } } } };
以下內(nèi)容依賴環(huán)境為 : vue-cli 版本2.9.x
項(xiàng)目github地址 :
前端 https://github.com/huangyangt...
后端: https://github.com/huangyangt...
安裝完以上依賴后,就可以開(kāi)始一個(gè)項(xiàng)目了,我們先看下后端api的定義
前后端交互報(bào)文定義以及數(shù)據(jù)api接口 前后端交互報(bào)文定義請(qǐng)求
http request header{ //除登錄注冊(cè)以外的請(qǐng)求,發(fā)起請(qǐng)求時(shí)要在請(qǐng)求頭中加入token authorization:jwt } http request body{ }
返回
http response header{ } http response body{ code:業(yè)務(wù)處理狀態(tài)碼 msg:業(yè)務(wù)處理描述 token:jwt token data:業(yè)務(wù)數(shù)據(jù) }項(xiàng)目中使用的后臺(tái)api定義如下
注:服務(wù)器端的host為118.24.85.97,端口為22222
1.測(cè)試api是否可用uri: http://118.24.85.97:22222/api
描述:測(cè)試接口是否能用,能用的話返回 "API WORDS"字符串
請(qǐng)求類型 GET
請(qǐng)求參數(shù) 無(wú)
返回值 {"Api Works"}
2.注冊(cè)uri: http://118.24.85.97:22222/api/users/reg
描述:注冊(cè)
請(qǐng)求類型 POST
請(qǐng)求參數(shù)
序號(hào) | 參數(shù)名 | 是否必填 | 描述 |
---|---|---|---|
1 | name | y | 用戶名 |
2 | pass | y | 密碼 |
返回參數(shù) 不重要
3.登錄uri: http://118.24.85.97:22222/api/users/login
描述:登錄
請(qǐng)求類型 POST
請(qǐng)求參數(shù)
序號(hào) | 參數(shù)名 | 是否必填 | 描述 |
---|---|---|---|
1 | name | y | 用戶名 |
2 | pass | y | 密碼 |
返回參數(shù)
序號(hào) | 參數(shù)名 | 描述 |
---|---|---|
1 | msg | ok |
2 | token | 用于驗(yàn)證用戶身份的token |
uri: http://118.24.85.97:22222/api/users/current
描述:獲取用戶信息
請(qǐng)求類型 GET
請(qǐng)求參數(shù) 無(wú)
返回參數(shù)
序號(hào) | 參數(shù)名 | 描述 |
---|---|---|
1 | id | 用戶id |
2 | token | 用于驗(yàn)證用戶身份的token |
在終端中輸入
vue init webpack vue2_template
然后會(huì)有一些選項(xiàng)讓你選,按照項(xiàng)目需求選擇,例如我不需要eslint,unit test,就可以選No,現(xiàn)在選no將來(lái)如果需要的話也可以自己安裝
安裝完成之后,按照提示切換到相應(yīng)目錄,執(zhí)行相應(yīng)指令,然后在瀏覽器打開(kāi)網(wǎng)址,這樣一個(gè)簡(jiǎn)單的vue項(xiàng)目就啟動(dòng)起來(lái)了
1. 項(xiàng)目文件介紹 整個(gè)文件介紹:注意:
開(kāi)發(fā)主要使用src文件夾
webpack的配置文件配置文件詳解看這里:https://segmentfault.com/a/11...
package.json配置詳解 http://javascript.ruanyifeng....
src目錄介紹首先在src目錄下新建一個(gè)文件夾views,用來(lái)放我們的主要頁(yè)面,然后在assets文件夾中建立fonts styles imgs,用來(lái)存放相應(yīng)的資源,建完之后,文件夾如下
2. 跨域、axios配置與api管理在這個(gè)項(xiàng)目中,我們使用axios進(jìn)行數(shù)據(jù)請(qǐng)求
axios中文文檔: https://www.kancloud.cn/yunye...
# 安裝axios npm/cnpm i axios -S # -S 指安裝到package.json中的dependencies中
安裝完成后,我們要在main.js中引入,然后測(cè)試一下是否成功引入
//main.js文件 import axios from "axios" axios.get("https://api.github.com/users?since=10") //使用github接口做一下測(cè)試 .then(res=>console.log(res)) .catch(err=>console.log(err))
瀏覽器顯示以下信息,說(shuō)明引入成功
github提供的接口配置了cors,所以我們能夠能夠在瀏覽器正常訪問(wèn)到,但cors兼容性最低到ie10,而且后臺(tái)不一定會(huì)配置cors,所以在開(kāi)發(fā)時(shí)我們需要配置一下跨域
參考鏈接:
cors詳解 http://www.ruanyifeng.com/blo...
2.1配置跨域參考文檔:https://segmentfault.com/a/11...
先找個(gè)沒(méi)有設(shè)置cors的api使用axios訪問(wèn)一下
axios.get("http://118.24.85.97:22222/api") .then(res=>console.log(res)) .catch(err=>console.log(err))
瀏覽器會(huì)因?yàn)橥床呗詧?bào)錯(cuò)
下面進(jìn)行跨域的配置
配置目錄 config/index.js 13行
proxyTable: { "/apis":{ target:"http://118.24.85.97:22222",//后臺(tái)地址 proxyTable 把/apis映射成target 即 /apis=http://118.24.85.97:22222 changeOrigin:true,//是否跨域 pathRewrite:{ "^/apis":"" } } }
再進(jìn)行訪問(wèn)數(shù)據(jù)時(shí)就要在接口前面加上/apis(/apis就相當(dāng)于http://118.24.85.97:22222)
axios.get("/apis/api") .then(res=>console.log(res)) .catch(err=>console.log(err))
然后就發(fā)現(xiàn)瀏覽器訪問(wèn)成功了
proxyTable原理:跨域是瀏覽器禁止的,服務(wù)端并不禁止跨域 ,所以瀏覽器可以發(fā)給自己的服務(wù)端然后,由自己的服務(wù)端再轉(zhuǎn)發(fā)給要跨域的服務(wù)端,做一層代理。proxyTable使用的是http-proxy-middleware中間件,內(nèi)部用的是http-proxy
以上配置的跨域是開(kāi)發(fā)環(huán)境下的,在生產(chǎn)環(huán)境就自動(dòng)失效了,而且這樣配置我們開(kāi)發(fā)時(shí)訪問(wèn)接口時(shí),都要寫成/apis/xxx/xxx格式,在部署到服務(wù)器中時(shí),我們要把/apis拿掉,才能訪問(wèn)到正確的url。有兩種方法,一種是在開(kāi)發(fā)環(huán)境中設(shè)置(通過(guò)axios的baseURL),另一種是在服務(wù)器上修改nginx的配置設(shè)置。
2.2生產(chǎn)環(huán)境去除/apis前綴在這里詳細(xì)說(shuō)下第一種方式,原理是這樣的:
通過(guò)檢測(cè)是開(kāi)發(fā)環(huán)境和生產(chǎn)環(huán)境,設(shè)置不同的baseURL,使生產(chǎn)環(huán)境和開(kāi)發(fā)環(huán)境都能正確訪問(wèn)url
在src目錄下新建一個(gè)apis目錄,然后在apis目錄下新建一個(gè)api.config.js文件
//判斷是否是生產(chǎn)環(huán)境 //webpack在開(kāi)發(fā)環(huán)境和生產(chǎn)環(huán)境分別執(zhí)行不同的js文件,process.env.NODE_ENV設(shè)置了不同的值,process.env.NODE_ENV在生產(chǎn)環(huán)境中值為"production"(這個(gè)值是在build/build.js中第4行設(shè)置的) var isPro = process.env.NODE_ENV=== "production" // 如果是生產(chǎn)環(huán)境 我們就使用服務(wù)器的uri,如果是開(kāi)發(fā)環(huán)境,我們就添加/apis前綴 module.exports = { baseUrl: isPro ? "http://118.24.85.97:22222" : "/apis" }
在main.js中引入這個(gè)文件,然后設(shè)置axios的baseURL
//引入api.config.js文件,然后設(shè)置axios的baseURL import apiConfig from "./apis/api.config" axios.defaults.baseURL=apiConfig.baseUrl
再來(lái)測(cè)試一下不加/apis的接口
axios.get("/api") .then(res=>console.log(res)) .catch(err=>console.log(err))
瀏覽器顯示是ok的。這樣我們以后使用axios訪問(wèn)接口就可以不加/apis了,打包后訪問(wèn)也不用手動(dòng)去除/apis
2.3 api統(tǒng)一管理在vue項(xiàng)目開(kāi)發(fā)過(guò)程中,會(huì)涉及到很多接口的處理,當(dāng)項(xiàng)目足夠大時(shí),就需要統(tǒng)一管理接口。具體方法應(yīng)該挺多的,這里只介紹一種:使用axios+async/await進(jìn)行接口的統(tǒng)一管理
一般來(lái)說(shuō),后臺(tái)的接口是分模塊的,例如我們后臺(tái)的測(cè)試接口
身份認(rèn)證 /api/login /api/reg
用戶信息 /v1/api/user
我們首先在src目錄下新建一個(gè)apis文件夾,后臺(tái)提供的所有接口都在這里定義
第二步,按照后臺(tái)提供的模塊新建js文件,我們新建user.js auth.js
第三步,引入axios,做相應(yīng)的配置
在apis目錄下新建一個(gè)http.js,在里面做axios相應(yīng)的配置
我們上文中是在main.js文件引入的axios,設(shè)置的baseURL,以上代碼可以去除,改為在http.js中引入
我們做的主要是:引入axios,創(chuàng)建一個(gè)axios的實(shí)例(實(shí)例的功能和axios一樣)
import axios from "axios" import apiConfig from "./api.config" //創(chuàng)建axios的一個(gè)實(shí)例 var instance = axios.create({ baseURL:apiConfig.baseUrl, timeout: 6000 }) //------------------- 一、請(qǐng)求攔截器 后面介紹 instance.interceptors.request.use(function (config) { return config; }, function (error) { // 對(duì)請(qǐng)求錯(cuò)誤做些什么 return Promise.reject(error); }); //----------------- 二、響應(yīng)攔截器 后面介紹 instance.interceptors.response.use(function (response) { return response.data; }, function (error) { // 對(duì)響應(yīng)錯(cuò)誤做點(diǎn)什么 return Promise.reject(error); }); /** * 使用es6的export default導(dǎo)出了一個(gè)函數(shù),導(dǎo)出的函數(shù)代替axios去幫我們請(qǐng)求數(shù)據(jù), * 函數(shù)的參數(shù)及返回值如下: * @param {String} method 請(qǐng)求的方法:get、post、delete、put * @param {String} url 請(qǐng)求的url: * @param {Object} data 請(qǐng)求的參數(shù) * @returns {Promise} 返回一個(gè)promise對(duì)象,其實(shí)就相當(dāng)于axios請(qǐng)求數(shù)據(jù)的返回值 */ export default function (method, url, data = null) { method = method.toLowerCase(); if (method == "post") { return instance.post(url, data) } else if (method == "get") { return instance.get(url, { params: data }) } else if (method == "delete") { return instance.delete(url, { params: data }) }else if(method == "put"){ return instance.put(url,data) }else{ console.error("未知的method"+method) return false } }
第四步,在apis/xxx.js文件中引入http.js導(dǎo)出的函數(shù),拿其中一個(gè)文件auth.js說(shuō)明
//auth.js 用于定義用戶的登錄、注冊(cè)、注銷等 import req from "./http.js" //定義接口 //在這里定義了一個(gè)登陸的接口,把登陸的接口暴露出去給組件使用 export const LOGIN =params=>req("post","/api/users/login",params) //這里使用了箭頭函數(shù),轉(zhuǎn)換一下寫法: // export const LOGIN=function(params){ // return req("post","/api/login",params) // } //定義注冊(cè)接口 export const REG =params=>req("post","/api/users/reg",params)
最后一步,在需要用的該api的組件中引入并調(diào)用,我們?cè)贏pp.vue文件中測(cè)試下
登錄
用戶名 密碼
注:如果要打開(kāi)Login.vue,需要配置對(duì)應(yīng)的路由
上面的代碼引入了auth.js定義的api,并在對(duì)應(yīng)的方法中使用。代碼中用到了async/await,其實(shí)很簡(jiǎn)單,可以假設(shè)async是個(gè)標(biāo)識(shí),說(shuō)明這個(gè)函數(shù)中有異步請(qǐng)求,await翻譯為"等",后面接一個(gè)異步請(qǐng)求,等后面的異步請(qǐng)求執(zhí)行完成之后,會(huì)把結(jié)果賦給=左邊的值
參考鏈接 http://www.runoob.com/w3cnote...
總結(jié)一下,像上面那樣定義接口雖然麻煩點(diǎn),但有兩個(gè)好處:
代碼看起來(lái)規(guī)范,所有的接口都在一個(gè)文件夾定義,不用分散的各個(gè)組件,維護(hù)起來(lái)簡(jiǎn)單,例如后臺(tái)的一些url變了,改起來(lái)也方便
可以做到接口一次定義,到處使用
3. 路由配置Vue Router官方文檔 https://router.vuejs.org/zh/3.1 最簡(jiǎn)配置前端路由原理:https://segmentfault.com/a/11...
路由的配置文件在router/index.js文件中先引入文件,再進(jìn)行配置
首先在views目錄中新建以下頁(yè)面,主頁(yè)(Home/Home.vue),登錄頁(yè)(Login/Login.vue),測(cè)試頁(yè)(Test/Test.vue)
然后配置下路由
import Vue from "vue" import Router from "vue-router" //@表示 src目錄 webpack的配置在webpack.base.conf.js第29行 alias{"@":resolve("src")} import Home from "@/views/Home/Home.vue" import Login from "@/views/Login/Login.vue" import Test from "@/views/Test/Test.vue" Vue.use(Router) export default new Router({ routes: [//路由規(guī)則 { path: "/", name: "Home", component: Home }, { path:"/login", name:"Login", component:Login }, { path:"/test", name:"Test", component:Test } ] })
路由規(guī)則在routes中進(jìn)行配置,routes是一個(gè)數(shù)組,接受一系列路由規(guī)則,每個(gè)路由規(guī)則是一個(gè)對(duì)象,包括路徑、路由名字,和路徑匹配的組件,建議給每個(gè)路由加個(gè)名字,在后面可能會(huì)用到。
打開(kāi)瀏覽器,輸入相應(yīng)的url查看配置的路由是否正確,不正確的話檢查下自己的配置
3.2配置路由懶加載參考文檔:路由懶加載官方文檔:https://router.vuejs.org/zh/g...
webpack之mainfest解讀:https://github.com/younth/blo...
當(dāng)打包構(gòu)建應(yīng)用時(shí),Javascript 包會(huì)變得非常大,影響頁(yè)面加載。如果我們能把不同路由對(duì)應(yīng)的組件分割成不同的代碼塊,然后當(dāng)路由被訪問(wèn)的時(shí)候才加載對(duì)應(yīng)組件,這樣就更加高效了。所以,懶加載的含義是當(dāng)路由被訪問(wèn)時(shí)再去加載對(duì)應(yīng)的js代碼。
首先,不做路由懶加載的情況下,我們打包一下(切換到項(xiàng)目目錄,執(zhí)行npm run build),然后會(huì)發(fā)現(xiàn)項(xiàng)目下生產(chǎn)了3個(gè)js文件
簡(jiǎn)單介紹一下作用:
vendor.js 第三方庫(kù),一般是 node_modules里面的依賴進(jìn)行打包 體積最大
app.js 入口js打包的結(jié)果,即我們編寫的所有代碼都會(huì)打包進(jìn)去
manifest.js 主要是一些異步加載的實(shí)現(xiàn)方法(通過(guò)建立script方式動(dòng)態(tài)引入js),內(nèi)容上包含異步j(luò)s的文件名和路徑。
然后我們實(shí)現(xiàn)一下路由懶加載 @/router/router.js
import Vue from "vue" import Router from "vue-router" // import Home from "@/views/Home/Home.vue" // import Login from "@/views/Login/Login.vue" // import Test from "@/views/Test/Test.vue" // 懶加載方式 const Home=()=>import("@/views/Home/Home.vue") const Login=()=>import("@/views/Login/Login.vue") const Test=()=>import("@/views/Test/Test.vue") Vue.use(Router) export default new Router({ routes: [ { path: "/", name: "Home", component: Home }, { path:"/login", name:"Login", component:Login }, { path:"/test", name:"Test", component:Test } ] })
懶加載只是改變了一下組件的引用方式,由原來(lái)的直接引入變成異步引入,當(dāng)我們?cè)L問(wèn)對(duì)應(yīng)的路由path時(shí),才會(huì)加載相應(yīng)的路由組件。
配置完成后再執(zhí)行一次打包,結(jié)果如下:
我們會(huì)發(fā)現(xiàn)目錄中多出來(lái)3個(gè)js文件,并且app.js文件變小了。這說(shuō)明配置了懶加載之后,app.js中其他組件的內(nèi)容被抽離出來(lái),分配到各自的js文件中。配置懶加載之后,剛開(kāi)始打開(kāi)頁(yè)面只會(huì)加載app.js文件,只有在用戶點(diǎn)擊相應(yīng)路由時(shí),才會(huì)加載對(duì)應(yīng)的js代碼。當(dāng)我們的業(yè)務(wù)代碼非常多時(shí),懶加載是個(gè)很好的選擇。
3.3 配置history模式官方文檔:https://router.vuejs.org/zh/g...
配置history模式有兩個(gè)原因,一是因?yàn)閔ash模式看很丑,二是因?yàn)轭A(yù)加載要用到History模式,配置非常簡(jiǎn)單,只需要配置屬性mode的值為"history"
const router = new VueRouter({ mode: "history", routes: [...] })
不過(guò)這種方式需要后臺(tái)的支持,當(dāng)匹配不到url時(shí),返回url/index.html頁(yè)面
nginx配置如下
location / { try_files $uri /index.html; }4. 權(quán)限管理
參考鏈接:4.1 token驗(yàn)證json web token入門教程 http://www.ruanyifeng.com/blo...
jwt官網(wǎng) https://jwt.io/
我們通過(guò)jwt進(jìn)行用戶認(rèn)證,jwt的原理是:服務(wù)器認(rèn)證以后,生成一個(gè)json對(duì)象,發(fā)回給用戶.
{ "id":"001", "姓名":"小明", "角色":"管理員", "到期時(shí)間":"2019年3月3日12時(shí)30分" }
以后用戶與服務(wù)端通信的時(shí)候,都要發(fā)回這個(gè)json對(duì)象。服務(wù)器完全靠這個(gè)對(duì)象認(rèn)定用戶身份(一般是通過(guò)這個(gè)對(duì)象的中id去數(shù)據(jù)庫(kù)請(qǐng)求數(shù)據(jù))。為了防止用戶篡改數(shù)據(jù),服務(wù)器會(huì)在生成這個(gè)對(duì)象的時(shí)候,加上簽名。就像這種形式:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
關(guān)于JWT保存更新的業(yè)務(wù)流程如下:
保存:登錄后保存token
添加:每次發(fā)送請(qǐng)求之前檢查token是否存在,存在,添加到請(qǐng)求頭中,發(fā)送請(qǐng)求
更新:每次發(fā)送請(qǐng)求服務(wù)器返回?cái)?shù)據(jù)之后更新token
主要邏輯包括:
登錄之后,在localStorage中保存token
每次發(fā)送請(qǐng)求之前,使用axios請(qǐng)求攔截器將token放到請(qǐng)求頭中
每次發(fā)送請(qǐng)求服務(wù)器返回?cái)?shù)據(jù)之后在axios的響應(yīng)攔截器中更新token
//1.登錄之后保存token login.vue async login(){ const data = await LOGIN({ name: this.user,pass: this.pass }) //保存token localStorage.setItem("token",data.token) //查看是否保存成功 console.log(localStorage.getItem("token")) }
//每次發(fā)送請(qǐng)求之前,講token放到請(qǐng)求頭中 api/http.js //---使用axios的請(qǐng)求攔截器,每次發(fā)送請(qǐng)求之前攔截一下 instance.interceptors.request.use(function (config) { // 給頭添加token if (localStorage.getItem("token")){//存在token,加入頭 config.headers.authorization=localStorage.getItem("token") } return config; }, function (error) { // 對(duì)請(qǐng)求錯(cuò)誤做些什么 return Promise.reject(error); }); //完成之后,記得發(fā)送一個(gè)請(qǐng)求,看看是否正確添加token //---響應(yīng)攔截器,服務(wù)器響應(yīng)后先到達(dá)這里 instance.interceptors.response.use(function (response) { if(response.data.code=="2000"){//成功響應(yīng),更新token if(response.data.token){ localStorage.setItem("token",response.data.token) } }else{ //錯(cuò)誤處理 根據(jù)不同的狀態(tài)碼,進(jìn)行錯(cuò)誤處理 } return response.data; }, function (error) { // 對(duì)響應(yīng)錯(cuò)誤做點(diǎn)什么 return Promise.reject(error); });4.2 對(duì)頁(yè)面的訪問(wèn)權(quán)限
除了對(duì)token的操作,我們還要判斷用戶有沒(méi)有權(quán)限訪問(wèn)這個(gè)頁(yè)面(有些頁(yè)面是用戶必須登錄才能訪問(wèn)的),具體配置要使用Vue Router的導(dǎo)航守衛(wèi)
參考鏈接:https://router.vuejs.org/zh/g...
在全局前置守衛(wèi)中進(jìn)行驗(yàn)證
//在router/index.js進(jìn)行配置 //在每次進(jìn)行路由跳轉(zhuǎn)之前進(jìn)行 router.beforeEach((to,from,next)=>{//增加登錄驗(yàn)證 const isLogin=localStorage.getItem("token")?true:false; if(to.path=="/login"){//如果是登錄頁(yè)面,不需要token next(); }else{//如果不是登錄頁(yè)面就要判斷是否登錄 isLogin?next():next("/login"); } })5. 將界面交給第三方UI庫(kù)
iview官網(wǎng):https://www.iviewui.com/
為節(jié)省開(kāi)發(fā)時(shí)間,我們往往會(huì)使用一些第三方ui庫(kù),比如iview elementui等
我們?cè)谶@里只介紹iview,其他ui庫(kù)大同小異
iview的安裝與引入 安裝cnpm i iview --save按需引入組件
官網(wǎng)說(shuō),需要下載插件才能按需引入,官網(wǎng)說(shuō)明,但是不下好像也可以正常引入
//在main.js文件中引入項(xiàng)目需要的組件 import {Button,Table,Message} from "iview" //然后注冊(cè)組件 Vue.component("Button",Button) Vue.component("Table",Table) Vue.component("Message",Message)
這樣注冊(cè)的話太繁瑣,所以需要優(yōu)化一下
//main.js import {Button,Table,Message} from "iview" const iviewComs={Button,Table,Message} Object.keys(iviewComs).forEach(key=>{Vue.component(key,component[key])})
代碼都寫在main.js中顯得太擁擠,我們可以把代碼拿出去,寫成一個(gè)插件
我們?cè)赾omponents文件夾中新建一個(gè)文件iview-coms,用來(lái)放iview中引入的組件
//components/iview-coms.js import {Button,Table,Message} from "iview" const components={Button,Table,Message} const install = function(Vue, opts = {}){ Object.keys(components).forEach(key=>{ Vue.component(key,components[key]) }) } export default install
然后在main.js中引入,use這個(gè)插件
import iviewComs from "./components/iview-coms" Vue.use(iviewComs)
ok了,接下來(lái)看自定義主題
自定義主題官網(wǎng)鏈接:https://www.iviewui.com/docs/...
原理很簡(jiǎn)單,就是把ivew的less文件引入,并且覆蓋掉,然后在main.js文件中引入自己的less文件
首先,我們需要下載解析less文件的loader ,less和less-loader,這里有個(gè)坑,下載less的時(shí)候要下載3版本以下的,不然會(huì)報(bào)一堆錯(cuò)誤
cnpm i less@2.7.2 less-loader -D
下載完就ok了,不需要在webpack中進(jìn)行配置,因?yàn)橐呀?jīng)配置好了
然后,在assets/styles/base.less(沒(méi)有需要自己新建)中,引入iview的樣式文件,并且覆蓋掉
默認(rèn)變量列表:https://github.com/iview/ivie...
//assets/styles/base.less //------ 引入iview樣式 @import "~iview/src/styles/index.less"; //------ 覆蓋iview的樣式 @primary-color: #E91E63; @error-color : #FF3300;
最后在main.js引入該less文件
//main.js import "./assets/styles/base.less"
此時(shí),引入的組件就可以在.vue文件中使用了,看一下效果:
ok了。最后還要補(bǔ)充一下,在項(xiàng)目開(kāi)發(fā)過(guò)程中,不可避免的要覆蓋iview默認(rèn)的樣式,我們分為兩種情況,一種是全局覆蓋,一種是局部覆蓋。
全局覆蓋的話我們要新建一個(gè)less文件,比如叫cover-iview.less所有覆蓋iview樣式的代碼都放在這里,然后在base.less中引入這個(gè)文件。
局部覆蓋的話要注意不要影響到別的樣式,所以要充分利用less的作用域,例如我們只需要改home頁(yè)面下的iview按鈕樣式,我們可以這樣:
.home{ .ivu-btn{ } }6.開(kāi)發(fā)中注意問(wèn)題 6.1編寫自己的工具庫(kù)插件
參考文檔:vue插件說(shuō)明:https://cn.vuejs.org/v2/guide...
項(xiàng)目中往往會(huì)使用一些通用的函數(shù),比如獲取當(dāng)前時(shí)間、時(shí)間格式轉(zhuǎn)化,防抖,節(jié)流等,我們可以把這個(gè)公用的部分封裝成插件,在main.js中引入。
首先,在src目錄下新建utils文件夾,在里面新建index.js,utils.js文件
我們?cè)?b>utils.js中編寫自己的工具庫(kù),然后導(dǎo)出
class Utils{ constructor(){ this.d=new Date();//date對(duì)象 this.instance=null; } static getInstance(){//單例模式 if(!this.instance){ this.instance = new Utils(); } return this.instance; } pick(obj,arr){//pick({ a: 1, b: "2", "c": 3 }, ["a", "c"]) =>{a:1,c:3} return arr.reduce((acc,curr)=>{ return (curr in obj && (acc[curr] = obj[curr]), acc) },{}) } dateFormat(datetime,pattern=""){ let vWeek = ["星期天","星期一","星期二","星期三","星期四","星期五","星期六"]; let dt=new Date(datetime); let y=dt.getFullYear(); let m=(dt.getMonth()+1).toString().padStart(2,"0"); let d=dt.getDate().toString().padStart(2,"0"); let hh=dt.getHours().toString().padStart(2,"0"); let mm=dt.getMinutes().toString().padStart(2,"0"); let ss=dt.getSeconds().toString().padStart(2,"0"); let vWeek_s = dt.getDay();//星期 if(pattern.toLowerCase() === "yyyy-mm-dd"){ return `${y}-${m}-$dnkpnhlp` }else if(pattern.toLowerCase() === "mm-dd"){ return `${m}-$dnkpnhlp` }else if(pattern.toLowerCase() === "yyyymmddhhmmss"){ return `${y}${m}$dnkpnhlp${hh}${mm}${ss}` }else { return `${y}-${m}-$dnkpnhlp ${hh}:${mm}:${ss} ${vWeek[vWeek_s]}` } } } const UTIL = Utils.getInstance(); // console.log(UTIL.dateFormat(new Date(),"yyyymmddhhmmss")) //=>20190312110722 // console.log(UTIL.dateFormat(new Date()))//=>2019-03-12 11:07:22 星期二 // console.log(UTIL.pick({ a: 1, b: "2", "c": 3 }, ["a", "c"]))//=>{a:1,c:3} export default UTIL;
然后在index.js中編寫插件,導(dǎo)出
//utils/index.js import UTIL from "./utils.js" const UtilPlugin={} UtilPlugin.install=function(Vue,options){//插件必須有install方法,接受兩個(gè)參數(shù),一個(gè)是Vue構(gòu)造器,一個(gè)是參數(shù) Vue.prototype.$utils=UTIL//在vue prototype上添加實(shí)例方法 } export default UtilPlugin
最后在main.js中引入并use插件
// utils import Util from "./utils/index" Vue.use(Util) console.log(Vue.prototype.$util)//打印下是否引入成功
之后就可以在組件中通過(guò)使用this.$utils調(diào)用方法了
7. 兼容性處理我們的目標(biāo)是兼容到ie9,對(duì)ie8及以下的瀏覽器做相應(yīng)的跳轉(zhuǎn)處理(跳轉(zhuǎn)到瀏覽器下載界面)7.1 對(duì)ie8及以下瀏覽器的跳轉(zhuǎn)處理兼容性對(duì)一個(gè)程序來(lái)說(shuō)是非常重要的,兼容性測(cè)試越早越好
在項(xiàng)目根目錄下中的html中head中加入下面代碼
目的是檢測(cè)ie瀏覽器的版本,如果低于<=ie8,就跳轉(zhuǎn)到下面這個(gè)頁(yè)面
7.2 兼容ie9參考鏈接:https://juejin.im/post/5b2868...7.2.1 ES6兼容
我們把瀏覽器調(diào)到ie9,然后看控制臺(tái)報(bào)錯(cuò)信息
報(bào)這個(gè)錯(cuò)的原因是es6的新對(duì)象,新表達(dá)式,ie9不支持,為解決這個(gè)問(wèn)題,我們需要引入babel-polyfill
cnpm i babel-polyfill -D
安裝完成之后,在main.js文件中引入
import "babel-polyfill"
在項(xiàng)目使用 vue-cli 生成的代碼中,根目錄有一個(gè) .babelrc 文件,這是項(xiàng)目使用 babel 的配置文件。在默認(rèn)生成的模板內(nèi)容中,增加 "useBuiltIns": "entry" 的設(shè)置內(nèi)容,這是一個(gè)指定哪些內(nèi)容需要被 polyfill(兼容) 的設(shè)置
useBuiltIns 有三個(gè)設(shè)置選項(xiàng)
false - 不做任何操作
entry - 根據(jù)瀏覽器版本的支持,將 polyfill 需求拆分引入,僅引入有瀏覽器不支持的polyfill
usage - 檢測(cè)代碼中 ES6/7/8 等的使用情況,僅僅加載代碼中用到的 polyfill
7.2.2建立自己的polyfill加入這些代碼后,工程中大部分代碼已可以兼容到ie9版本,但還是會(huì)有少部分不兼容的特性,例如requestAnimationFrame、classList等。對(duì)于這些內(nèi)容,我們需要自己定義polyfill來(lái)解決,在src目錄下新建一個(gè)文件夾polyfill,然后在polyfill文件夾下面建一個(gè)polyfill.js,我們?cè)趐olyfill.js中加入我們的兼容代碼
然后在main.js中引入這個(gè)文件
import "./polyfill/polyfill"
解決兼容方式的正確姿勢(shì)是:拿到ie9瀏覽器下的報(bào)錯(cuò)信息,去goole或者baidu搜索,得到polyfill,然后加入到自己的polyfill.js文件中
三、優(yōu)化 1. webpack3.x優(yōu)化打包速度我們執(zhí)行一下npm run build,結(jié)果如下:
整個(gè)打包過(guò)程花了32s左右,現(xiàn)在我們的項(xiàng)目只是引入了相關(guān)的依賴,一些業(yè)務(wù)邏輯還沒(méi)有寫,打包速度就那么慢了,等到我們寫完整個(gè)項(xiàng)目,打包速度還會(huì)繼續(xù)變長(zhǎng),所以我們需要優(yōu)化一下。
優(yōu)化打包速度,我們修改的主要是webpack.prod.conf.js文件替換代碼壓縮工具
Webpack 默認(rèn)提供的 UglifyJS 插件,由于采用單線程壓縮,速度慢 ;
webpack-parallel-uglify-plugin 插件可以并行運(yùn)行 UglifyJS 插件,更加充分而合理的使用 CPU 資源,這可以大大減少的構(gòu)建時(shí)間;
//安裝 cnpm i webpack-parallel-uglify-plugin -D
//配置 webpack.prod.conf.js //首先刪除項(xiàng)目中的 UglifyJsPlugin插件及配置,第二次打包時(shí)提高速度,要把.cache文件加入到gitignore中 // new webpack.optimize.UglifyJsPlugin({ // compress: { // warnings: false, // drop_console: true // }, // sourceMap: true // }), //然后引入并使用我們剛才裝的插件
==注意:版本控制工具提交時(shí),要忽略.cache文件==
配置完后我們執(zhí)行npm run build,發(fā)現(xiàn)打包速度降到了23s
再執(zhí)行一次npm run build,發(fā)現(xiàn)打包速度降到了12s
時(shí)間降低那么多是因?yàn)槲募](méi)有改動(dòng),直接利用了緩存中的js文件
happypack開(kāi)啟多核構(gòu)建項(xiàng)目一般node.js是單線程執(zhí)行編譯,而happypack則是啟動(dòng)node的多線程進(jìn)行構(gòu)建,大大提高了構(gòu)建速度。
首先安裝,
修改webpack.base.conf.js
const HappyPack = require("happypack"); const os = require("os"); const happyThreadPool = HappyPack.ThreadPool({ size: os.cpus().length }); ... ... // 增加plugins plugins: [ new HappyPack({ id: "happy-babel-js", loaders: ["babel-loader?cacheDirectory=true"], threadPool: happyThreadPool, }) ] ... ... // 修改對(duì)應(yīng)loader { test: /.js$/, loader: "happypack/loader?id=happy-babel-js", include: [resolve("src"), resolve("test")], }
配置完成,執(zhí)行npm run build
what??并沒(méi)有提高速度 不要用這個(gè)鬼東西了
hardSourceWebpackPlugin節(jié)省70%的時(shí)間https://github.com/mzgoddard/...
#安裝 cnpm install --save-dev hard-source-webpack-plugin
使用,在webpack.prod.conf.js中引入并使用
const HardSourceWebpackPlugin = require("hard-source-webpack-plugin"); module.exports = { context: // ... entry: // ... output: // ... plugins: [ new HardSourceWebpackPlugin() ] }
結(jié)果:
注:要第二次打包才生效
總結(jié)下,使用了三個(gè)插件,我們的打包速度從30s降低到4s,awesome!
2. webpack3.x優(yōu)化首屏加載速度首先要說(shuō)明一下,首屏加載速度優(yōu)化針對(duì)的是打包后dist文件。我們?nèi)绻诒镜剡M(jìn)行測(cè)試的話,需要本地有個(gè)服務(wù)器,我們?cè)谶@里使用nginx。
2.1本地安裝nginx下載地址: http://nginx.org/en/download....
在官網(wǎng)上找到自己系統(tǒng)適合的nginx版本,下載到本地
2.1.1window安裝解壓文件
雙擊運(yùn)行nginx.exe,在任務(wù)管理器中出現(xiàn)nginx的進(jìn)程,則表示安裝成功
2.1.2 mac/linux安裝#1.解壓文件 tar -xzf nginx-1.14.0.tar.gz #mac可以使用解壓縮工具解壓,不必用命令行 #2. 配置安裝路徑 --prefix指定安裝路徑 假設(shè)我要裝到/usr/local/nginx文件夾中 ./configure --prefix=/Users/best9/local/nginx #編譯 make ##安裝 make install
安裝完成后進(jìn)入到—prefix指定的文件夾中,執(zhí)行ll,會(huì)發(fā)現(xiàn)文件夾下有以下目錄
我們要關(guān)心就是我上面標(biāo)出來(lái)的三個(gè)目錄
進(jìn)到sbin目錄中,啟動(dòng)nginx程序
cd sbin #需要使用root權(quán)限,否則會(huì)報(bào)錯(cuò) 報(bào)錯(cuò)信息可以在日志中查看到,錯(cuò)誤日志目錄 /logs/error.log sudo ./nginx
正常的話,nginx會(huì)默認(rèn)在localhost:80端口啟動(dòng),在瀏覽器訪問(wèn)localhost,就會(huì)顯示默認(rèn)界面
如果電腦的80端口被占用的話,在conf/nginx.conf文件中修改端口
2.2 nginx常用命令nginx使用-s發(fā)送信號(hào)操作運(yùn)行中的進(jìn)程,常用命令如下:
注意:使用命令需要在sbin目錄下
#啟動(dòng)nginx ./nginx #立即停止服務(wù) -s stop ./nginx -s stop #優(yōu)雅地停止服務(wù) -s quit ./nginx -s quit #重啟服務(wù) -s reload ./nginx -s reload2.3 nginx配置靜態(tài)文件服務(wù)器
我們?cè)谶@里使用nginx配置一個(gè)最簡(jiǎn)單的靜態(tài)文件服務(wù)器,更復(fù)雜的配置稍后再講
nginx的配置文件地址:conf/nginx.conf
使用vim或者其他編輯器打開(kāi)該文件,修改配置文件第43-45行:
vim conf/nginx.conf
location / { alias /Users/best9/github/vue2_template/dist; #訪問(wèn)/相當(dāng)于訪問(wèn)alias配置的目錄 }
配置完成后保存,然后重啟服務(wù)
sudo ./sbin/nginx -s reload 要使用root權(quán)限重啟
打開(kāi)瀏覽器訪問(wèn)localhost
因?yàn)闆](méi)有登錄,會(huì)自動(dòng)跳轉(zhuǎn)到登錄界面
到這里靜態(tài)文件服務(wù)器就配置好了,但我們刷新下頁(yè)面,會(huì)報(bào)錯(cuò)404
這是因?yàn)槲覀兪褂昧藇ue router的history模式,我們需要在nginx中加入以下配置
location / { try_files $uri $uri/ /index.html; }
然后重啟nginx,再刷新頁(yè)面就沒(méi)問(wèn)題了
2.4 優(yōu)化首屏加載速度以上步驟就緒后,我們就可以來(lái)優(yōu)化加載速度了
打開(kāi)chrome的devTools面板,切換到Network,禁用瀏覽器緩存,刷新測(cè)試下加載速度,發(fā)現(xiàn)整個(gè)應(yīng)用加載大約需要1.97s,如下圖:
把網(wǎng)絡(luò)環(huán)境切換到Fast 3G,再測(cè)試一次,發(fā)現(xiàn)加載用了7.56s,白屏?xí)r間6.89s
我們使用預(yù)渲染插件進(jìn)行優(yōu)化
2.4.1 預(yù)渲染使用插件:prerender-spa-plugin參考鏈接:https://juejin.im/post/59d49d...
首先,安裝 prerender-spa-plugin,安裝時(shí)件略長(zhǎng),因?yàn)槠湟蕾嚵?phantomjs
cnpm install prerender-spa-plugin --save-dev
我們只在生產(chǎn)環(huán)境中進(jìn)行預(yù)渲染,修改 build/webpack.prod.conf.js,在配置插件的地方加入如下代碼。
//引入 預(yù)渲染插件 const PrerenderSpaP=require("prerender-spa-plugin") //在plugins中配置 new PrerenderSpaP( // 輸出目錄的絕對(duì)路徑 path.join(__dirname,"../dist"), //預(yù)渲染路由 ["/home","/login"] )
再次執(zhí)行打包,然后再進(jìn)行測(cè)試:
發(fā)現(xiàn)白屏?xí)r間為4.10s,在弱網(wǎng)環(huán)境下,使用預(yù)渲染,大約能縮減2.5秒的白屏?xí)r間
預(yù)渲染的路由不能是動(dòng)態(tài)加載的,否則會(huì)報(bào)webpackJsonp is not define的錯(cuò)誤,要想解決這個(gè)錯(cuò)誤,可以看這里 https://juejin.im/entry/5911a...
預(yù)渲染的路由不能是需要權(quán)限才能訪問(wèn)的頁(yè)面。預(yù)渲染的機(jī)制是在本地跑一個(gè)chromium瀏覽器,然后去爬取你預(yù)渲染頁(yè)面的Html,如果你的頁(yè)面需要權(quán)限(登錄)才能進(jìn)入,就爬不到,也不會(huì)報(bào)錯(cuò),最終只會(huì)渲染不需要權(quán)限的頁(yè)面
舉個(gè)例子:
插件配置如下:
new PrerenderPlugin({ staticDir:path.join(__dirname,"../dist") routes:["/","/about","/login"] })
路由配置如下:
2.4.2 配置gzip壓縮gzip官方文檔 http://nginx.org/en/docs/http...
nginx默認(rèn)是關(guān)閉gzip的,我們需要自己打開(kāi),并進(jìn)行一些配置:
gzip:on; #打開(kāi)gzip,關(guān)閉為off gzip_min_length 1; #小于gzip_min_length,不進(jìn)行壓縮(默認(rèn)單位為byte) gzip_comp_level 2; #壓縮級(jí)別 gzip_types text/plain text/css application/javascript text/javascript image/jpeg image/gif image/png;#指定類型進(jìn)行g(shù)zip壓縮
配置完成后,我們?cè)贉y(cè)試一下加載速度:
發(fā)現(xiàn)白屏?xí)r間為1.95s,加載文件的體積也變小了
四、部署 1. nginx配置反向代理我們要在本地部署測(cè)試,所以后臺(tái)的地址是127.0.0.1:22222
項(xiàng)目開(kāi)發(fā)完成后需要部署到服務(wù)器,因?yàn)槭乔昂蠖朔蛛x,所以前端的應(yīng)用部署到nginx,后端的應(yīng)用部署到自己對(duì)應(yīng)的服務(wù)器,所以我們需要配置一下,把后端的服務(wù)器變成上游服務(wù),nginx做反向代理服務(wù)器
反向代理:服務(wù)器根據(jù)客戶端的請(qǐng)求,從其關(guān)系的一組或多組后端服務(wù)器上獲取資源,然后將這些資源返回給客戶端。
由于上游服務(wù)器(后臺(tái)服務(wù)器)要處理非常復(fù)雜的邏輯,所以性能不怎么樣,我們使用nginx作為反向代理服務(wù)器后,可以將請(qǐng)求按照負(fù)載均衡算法代理給多臺(tái)上游服務(wù)器。配置如下:
以上配置是將所有的請(qǐng)求轉(zhuǎn)發(fā)給上游服務(wù)器,但如果我們只想將動(dòng)態(tài)請(qǐng)求轉(zhuǎn)發(fā)給上游服務(wù)器,靜態(tài)資源由nginx自己處理,就可以這樣做:
判斷是否是后臺(tái)api(根據(jù)location的匹配規(guī)則),如果是的話,就進(jìn)行轉(zhuǎn)發(fā)
匹配規(guī)則看這里:https://stackoverflow.com/que...
upstream local{ server 127.0.0.1:22222; #假設(shè)在本地部署 } server{ listen:80; server_name localhost; location ~ /api/ { #以`/api/`開(kāi)頭的uri就行轉(zhuǎn)發(fā),否則不轉(zhuǎn)發(fā) ~代表正則表達(dá)式匹配 proxy_set_header: Host $host; proxy_set_header: X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_pass http://local; } location / { #... alias index等配置 } }
這里需要注意一個(gè)問(wèn)題:proxy_pass是轉(zhuǎn)發(fā)請(qǐng)求的模塊,當(dāng)你訪問(wèn)localhost:80/api/users/login時(shí),會(huì)被轉(zhuǎn)發(fā)到local的地址,即127.0.0.1:22222/api/users/login,所以開(kāi)發(fā)環(huán)境下訪問(wèn)后臺(tái)接口的URI要寫你部署到nginx的URI,而不是真正的后臺(tái)地址(因?yàn)楸晦D(zhuǎn)發(fā)了)
前端配置
//apis/api.config.js //判斷是否是生產(chǎn)環(huán)境 var isPro = process.env.NODE_ENV=== "production" module.exports = { baseUrl: isPro ? "http://localhost:80" : "/apis"http://生產(chǎn)環(huán)境下的baseURl是nginx的hoost:port }2. 持續(xù)部署
項(xiàng)目做完需要發(fā)布到服務(wù)器,但每次手動(dòng)打包,然后ftp傳上去的話就太麻煩了,所以我們的需求是:git或者svn提交后,自動(dòng)打包發(fā)布到服務(wù)器。使用的工具是jenkins.
參考文檔:https://juejin.im/post/5ad198...jenkins安裝與啟動(dòng)官網(wǎng):https://jenkins.io/
jenkins一般情況下會(huì)裝在服務(wù)器,但如果是同一個(gè)局域網(wǎng)的話,裝在本機(jī)也可以
linux:
https://blog.csdn.net/fenglai...
https://www.jianshu.com/p/8a7... (centos)
配置文件地址 /etc/sysconfig/jenkins
工作空間 /var/lib/jenkins
windows下:
從Jenkins官網(wǎng)下載最新war文件。
運(yùn)行java -jar jenkins.war即可。
mac:
從官網(wǎng)下載pkg文件
雙擊安裝,安裝之后自己就會(huì)啟動(dòng)
jenkins初始化jenkins的默認(rèn)端口是8080,啟動(dòng)成功后在瀏覽器打開(kāi)。
進(jìn)入后會(huì)讓我們輸管理員密碼,打開(kāi)網(wǎng)頁(yè)上提示路徑下的文件,復(fù)制密碼粘貼輸入即可。
然后會(huì)讓安裝需要的插件,此處選默認(rèn)即可,等待安裝完成。
創(chuàng)建一個(gè)管理員賬戶。
上面都完成后會(huì)看到這個(gè)界面。
創(chuàng)建任務(wù)在主頁(yè)上點(diǎn)擊創(chuàng)建
直接點(diǎn)保存,然后去安裝插件
安裝插件首先返回主頁(yè),然后點(diǎn)擊左側(cè)菜單 系統(tǒng)管理->插件管理
需要安裝的插件有:
Generic Webhook Trigger 實(shí)現(xiàn)git提交觸發(fā)更新功能
Publish Over SSH 實(shí)現(xiàn)服務(wù)器部署功能
nvm wrapper 引入node
安裝插件的方式:
安裝完插件之后重啟一下jenkins(安裝完插件后,有個(gè)重啟的選項(xiàng),勾選即可)
實(shí)現(xiàn)git鉤子功能當(dāng)我們向github/碼云等遠(yuǎn)程倉(cāng)庫(kù)push我們的代碼時(shí),jenkins能知道我們提交了代碼,這是自動(dòng)構(gòu)建自動(dòng)部署的前提,鉤子的實(shí)現(xiàn)原理是在遠(yuǎn)端倉(cāng)庫(kù)上配置一個(gè)Jenkins服務(wù)器的接口地址,當(dāng)本地向遠(yuǎn)端倉(cāng)庫(kù)發(fā)起push時(shí),遠(yuǎn)端倉(cāng)庫(kù)會(huì)向配置的Jenkins服務(wù)器的接口地址發(fā)起一個(gè)帶參數(shù)的請(qǐng)求,jenkins收到后開(kāi)始工作
打開(kāi)創(chuàng)建的項(xiàng)目(進(jìn)入工程->點(diǎn)擊配置)
構(gòu)建觸發(fā)器
勾選 Generic Webhook Trigger
github倉(cāng)庫(kù)配置鉤子:
進(jìn)入github項(xiàng)目中該項(xiàng)目頁(yè)面,點(diǎn)擊setting->webhooks,添加payload URL,
URL格式為 http://
自動(dòng)化構(gòu)建:jenkins實(shí)現(xiàn)安裝依賴,打包(npm install && npm run build),此外還可以執(zhí)行一些測(cè)試行為
點(diǎn)擊構(gòu)建環(huán)境,勾選nvm,輸入node版本
點(diǎn)擊構(gòu)建,選擇執(zhí)行shell,輸入執(zhí)行命令,多個(gè)命令使用&&分開(kāi)
npm config set registry http://registry.npm.taobao.org/ && npm install && npm run build
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/102842.html
摘要:特意對(duì)前端學(xué)習(xí)資源做一個(gè)匯總,方便自己學(xué)習(xí)查閱參考,和好友們共同進(jìn)步。 特意對(duì)前端學(xué)習(xí)資源做一個(gè)匯總,方便自己學(xué)習(xí)查閱參考,和好友們共同進(jìn)步。 本以為自己收藏的站點(diǎn)多,可以很快搞定,沒(méi)想到一入?yún)R總深似海。還有很多不足&遺漏的地方,歡迎補(bǔ)充。有錯(cuò)誤的地方,還請(qǐng)斧正... 托管: welcome to git,歡迎交流,感謝star 有好友反應(yīng)和斧正,會(huì)及時(shí)更新,平時(shí)業(yè)務(wù)工作時(shí)也會(huì)不定期更...
摘要:引入全面指南系列目錄引入全面指南引入全面指南篇寫在前面寫這篇文章時(shí)的我,使用經(jīng)驗(yàn)三個(gè)多月,完全空白,花了大概三個(gè)晚上把手頭項(xiàng)目遷移至,因此這篇文章更像個(gè)入門指引。見(jiàn)文章引入全面指南篇完整代碼見(jiàn)庫(kù),分支為整合示例,分支為不含的基礎(chǔ)示例。 Vue2.5+ Typescript 引入全面指南 系列目錄: Vue2.5+ Typescript 引入全面指南 Vue2.5+ Typescrip...
摘要:月份前端資源分享更多資源請(qǐng)文章轉(zhuǎn)自前端生成好看的二維碼十大經(jīng)典排序算法帶動(dòng)圖演示為什么知乎前端圈普遍認(rèn)為游戲和展示的個(gè)人整理和封裝的庫(kù)中文詳細(xì)注釋供新手學(xué)習(xí)使用擴(kuò)展語(yǔ)法記錄掉坑初期工具漢字拼音轉(zhuǎn)換工具實(shí)現(xiàn)漢字轉(zhuǎn)拼音的插件下拉列表支持拼音簡(jiǎn) 2月份前端資源分享 更多資源請(qǐng)Star:https://github.com/maidishike... 文章轉(zhuǎn)自:https://github...
平日學(xué)習(xí)接觸過(guò)的網(wǎng)站積累,以每月的形式發(fā)布。2017年以前看這個(gè)網(wǎng)址:http://www.kancloud.cn/jsfron... 1. Javascript 前端生成好看的二維碼 十大經(jīng)典排序算法(帶動(dòng)圖演示) 為什么知乎前端圈普遍認(rèn)為H5游戲和H5展示的JSer 個(gè)人整理和封裝的YU.js庫(kù)|中文詳細(xì)注釋|供新手學(xué)習(xí)使用 擴(kuò)展JavaScript語(yǔ)法記錄 - 掉坑初期工具 漢字拼音轉(zhuǎn)換...
平日學(xué)習(xí)接觸過(guò)的網(wǎng)站積累,以每月的形式發(fā)布。2017年以前看這個(gè)網(wǎng)址:http://www.kancloud.cn/jsfron... 1. Javascript 前端生成好看的二維碼 十大經(jīng)典排序算法(帶動(dòng)圖演示) 為什么知乎前端圈普遍認(rèn)為H5游戲和H5展示的JSer 個(gè)人整理和封裝的YU.js庫(kù)|中文詳細(xì)注釋|供新手學(xué)習(xí)使用 擴(kuò)展JavaScript語(yǔ)法記錄 - 掉坑初期工具 漢字拼音轉(zhuǎn)換...
平日學(xué)習(xí)接觸過(guò)的網(wǎng)站積累,以每月的形式發(fā)布。2017年以前看這個(gè)網(wǎng)址:http://www.kancloud.cn/jsfron... 1. Javascript 前端生成好看的二維碼 十大經(jīng)典排序算法(帶動(dòng)圖演示) 為什么知乎前端圈普遍認(rèn)為H5游戲和H5展示的JSer 個(gè)人整理和封裝的YU.js庫(kù)|中文詳細(xì)注釋|供新手學(xué)習(xí)使用 擴(kuò)展JavaScript語(yǔ)法記錄 - 掉坑初期工具 漢字拼音轉(zhuǎn)換...
閱讀 2107·2021-10-08 10:05
閱讀 1947·2021-09-22 15:31
閱讀 3138·2021-09-22 15:13
閱讀 3655·2021-09-09 09:34
閱讀 2265·2021-09-03 10:46
閱讀 3217·2019-08-30 15:56
閱讀 1762·2019-08-30 15:53
閱讀 2419·2019-08-30 15:44