vue-cli3 專案從搭建優化到docker部署

lentoo發表於1970-01-01

專案地址 vue-cli3-project 歡迎 star

原文地址 www.ccode.live/lentoo/list…

1. 建立一個vue專案

相信大部分人都已經知道怎麼建立專案的,可以跳過這一節,看下一節。

1.1 安裝@vue/cli

# 全域性安裝 vue-cli腳手架npm install -g @vue/cli複製程式碼

等待安裝完成後開始下一步

1.2 初始化專案

vue create vue-cli3-project複製程式碼
  1. 選擇一個預設
vue-cli3 專案從搭建優化到docker部署

可以選擇預設預設,預設預設包含了babel,eslint

我們選擇更多功能 Manually select features

回車後來到選擇外掛

  1. 外掛選擇

這邊選擇了(Babel、Router、Vuex、Css前處理器、Linter / Formatter 格式檢查、Unit測試框架)

vue-cli3 專案從搭建優化到docker部署
  1. 路由模式選擇

是否使用 history模式的路由 (Yes)

vue-cli3 專案從搭建優化到docker部署
  1. 選擇一個css前處理器 (Sass/SCSS)
vue-cli3 專案從搭建優化到docker部署
  1. 選擇一個eslint配置

這邊選擇 ESLint + Standard config,個人比較喜歡這個程式碼規範

vue-cli3 專案從搭建優化到docker部署
  1. 選擇什麼時候進行 eslint 校驗

選擇(Lint on save)儲存是檢查

如果你正在使用的vscode編輯器的話,可以配置eslint外掛進行程式碼自動格式化

vue-cli3 專案從搭建優化到docker部署

7. 選擇測試框架 (Mocha + Chai)

vue-cli3 專案從搭建優化到docker部署

8. 選擇將這些配置檔案寫入到什麼地方 (In dedicated config files)

vue-cli3 專案從搭建優化到docker部署
  1. 是否儲存這份預設配置?(y)

選是的話,下次建立一個vue專案,可以直接使用這個預設檔案,而無需再進行配置。

vue-cli3 專案從搭建優化到docker部署

等待依賴完成

vue-cli3 專案從搭建優化到docker部署

2. 全域性元件自動註冊

components目錄下建立一個global目錄,裡面放置一些需要全域性註冊的元件。

index.js作用只要是引入main.vue,匯出元件物件

vue-cli3 專案從搭建優化到docker部署

components中建立一個index.js,用來掃描全域性物件並自動註冊。

// components/index.jsimport Vue from 'vue'// 自動載入 global 目錄下的 .js 結尾的檔案const componentsContext = require.context('./global', true, /\.js$/)componentsContext.keys().forEach(component =>
{
const componentConfig = componentsContext(component) /** * 相容 import export 和 require module.export 兩種規範 */ const ctrl = componentConfig.default || componentConfig Vue.component(ctrl.name, ctrl)
})複製程式碼

最後在入口檔案main.js中匯入這個index.js中就可以了

3.路由自動引入

Vue專案中使用路由,相信想熟的人已經很熟悉怎麼使用了,要新增一個頁面的話,需要到路由配置中配置該頁面的資訊。

如果頁面越來越多的話,那麼如何讓我們的路由更簡潔呢?

3.1 拆分路由

根據不同的業務模組進行拆分路由

vue-cli3 專案從搭建優化到docker部署

在每個子模組中匯出一個路由配置陣列

vue-cli3 專案從搭建優化到docker部署

在根 index.js中匯入所有子模組

vue-cli3 專案從搭建優化到docker部署

3.2 自動掃描子模組路由並匯入

當我們的業務越來越龐大,每次新增業務模組的時候,我們都要在路由下面新增一個子路由模組,然後在index.js中匯入。

那麼如何簡化這種操作呢?

通過上面的自動掃描全域性元件註冊,我們也可以實現自動掃描子模組路由並匯入

vue-cli3 專案從搭建優化到docker部署

4. 通過node來生成元件

作為前端開發者,放著 node這麼好用的東西如果不能運用起來,豈不是很浪費?

vue-cli3 專案從搭建優化到docker部署

雖然我們通過上面已經實現了元件的自動註冊,不過每次新建元件的時候,都要建立一個目錄,然後新增一個.vue檔案,然後寫templatescriptstyle這些東西,然後新建一個index.js、匯出vue元件、雖然有外掛能實現自動補全,但還是很麻煩有木有。

那麼我們能不能通過node來幫助我們幹這些事情呢?只要告訴node幫我生成的元件名稱就行了。其它的事情讓node來幹

vue-cli3 專案從搭建優化到docker部署

4.1 通過node來生成元件

  • 安裝一下chalk,這個外掛能讓我們的控制檯輸出語句有各種顏色區分
npm install chalk --save-dev複製程式碼

在根目錄中建立一個 scripts 資料夾,

新增一個generateComponent.js檔案,放置生成元件的程式碼、

新增一個template.js檔案,放置元件模板的程式碼

  • template.js
// template.jsmodule.exports = { 
vueTemplate: compoenntName =>
{
return `<
template>
<
div class="${compoenntName
}
">
${compoenntName
}
元件 <
/div>
<
/template>
<
script>
export default {
name: '${compoenntName
}
'
}<
/script>
<
style lang="scss" scoped>
.${compoenntName
}
{
}<
/style>
`

}, entryTemplate: `import Main from './main.vue'export default Main`
}複製程式碼
  • generateComponent.js`
// generateComponent.js`const chalk = require('chalk')const path = require('path')const fs = require('fs')const resolve = (...file) =>
path.resolve(__dirname, ...file)const log = message =>
console.log(chalk.green(`${message
}
`
))const successLog = message =>
console.log(chalk.blue(`${message
}
`
))const errorLog = error =>
console.log(chalk.red(`${error
}
`
))const {
vueTemplate, entryTemplate
} = require('./template')const generateFile = (path, data) =>
{
if (fs.existsSync(path)) {
errorLog(`${path
}
檔案已存在`
) return
} return new Promise((resolve, reject) =>
{
fs.writeFile(path, data, 'utf8', err =>
{
if (err) {
errorLog(err.message) reject(err)
} else {
resolve(true)
}
})
})
}log('請輸入要生成的元件名稱、如需生成全域性元件,請加 global/ 字首')let componentName = ''process.stdin.on('data', async chunk =>
{
const inputName = String(chunk).trim().toString() /** * 元件目錄路徑 */ const componentDirectory = resolve('../src/components', inputName) /** * vue元件路徑 */ const componentVueName = resolve(componentDirectory, 'main.vue') /** * 入口檔案路徑 */ const entryComponentName = resolve(componentDirectory, 'index.js') const hasComponentDirectory = fs.existsSync(componentDirectory) if (hasComponentDirectory) {
errorLog(`${inputName
}
元件目錄已存在,請重新輸入`
) return
} else {
log(`正在生成 component 目錄 ${componentDirectory
}
`
) await dotExistDirectoryCreate(componentDirectory) // fs.mkdirSync(componentDirectory);

} try {
if (inputName.includes('/')) {
const inputArr = inputName.split('/') componentName = inputArr[inputArr.length - 1]
} else {
componentName = inputName
} log(`正在生成 vue 檔案 ${componentVueName
}
`
) await generateFile(componentVueName, vueTemplate(componentName)) log(`正在生成 entry 檔案 ${entryComponentName
}
`
) await generateFile(entryComponentName, entryTemplate) successLog('生成成功')
} catch (e) {
errorLog(e.message)
} process.stdin.emit('end')
})process.stdin.on('end', () =>
{
log('exit') process.exit()
})function dotExistDirectoryCreate (directory) {
return new Promise((resolve) =>
{
mkdirs(directory, function () {
resolve(true)
})
})
}// 遞迴建立目錄function mkdirs (directory, callback) {
var exists = fs.existsSync(directory) if (exists) {
callback()
} else {
mkdirs(path.dirname(directory), function () {
fs.mkdirSync(directory) callback()
})
}
}複製程式碼
  • 配置package.json
"new:comp": "node ./scripts/generateComponent"複製程式碼
  • 執行

如果使用 npm 的話 就是 npm run new:comp

如果使用 yarn 的話 就是 yarn new:comp

vue-cli3 專案從搭建優化到docker部署

4.2 通過node來生成頁面元件

通過上面的邏輯程式碼我們可以通過node來生成元件了,那麼也可以舉一反三來生成頁面元件。只需稍微修改一下生成元件程式碼的邏輯。在scripts目錄下新建一個generateView.js檔案

// generateView.jsconst chalk = require('chalk')const path = require('path')const fs = require('fs')const resolve = (...file) =>
path.resolve(__dirname, ...file)const log = message =>
console.log(chalk.green(`${message
}
`
))const successLog = message =>
console.log(chalk.blue(`${message
}
`
))const errorLog = error =>
console.log(chalk.red(`${error
}
`
))const {
vueTemplate
} = require('./template')const generateFile = (path, data) =>
{
if (fs.existsSync(path)) {
errorLog(`${path
}
檔案已存在`
) return
} return new Promise((resolve, reject) =>
{
fs.writeFile(path, data, 'utf8', err =>
{
if (err) {
errorLog(err.message) reject(err)
} else {
resolve(true)
}
})
})
}log('請輸入要生成的頁面元件名稱、會生成在 views/目錄下')let componentName = ''process.stdin.on('data', async chunk =>
{
const inputName = String(chunk).trim().toString() /** * Vue頁面元件路徑 */ let componentVueName = resolve('../src/views', inputName) // 如果不是以 .vue 結尾的話,自動加上 if (!componentVueName.endsWith('.vue')) {
componentVueName += '.vue'
} /** * vue元件目錄路徑 */ const componentDirectory = path.dirname(componentVueName) const hasComponentExists = fs.existsSync(componentVueName) if (hasComponentExists) {
errorLog(`${inputName
}
頁面元件已存在,請重新輸入`
) return
} else {
log(`正在生成 component 目錄 ${componentDirectory
}
`
) await dotExistDirectoryCreate(componentDirectory)
} try {
if (inputName.includes('/')) {
const inputArr = inputName.split('/') componentName = inputArr[inputArr.length - 1]
} else {
componentName = inputName
} log(`正在生成 vue 檔案 ${componentVueName
}
`
) await generateFile(componentVueName, vueTemplate(componentName)) successLog('生成成功')
} catch (e) {
errorLog(e.message)
} process.stdin.emit('end')
})process.stdin.on('end', () =>
{
log('exit') process.exit()
})function dotExistDirectoryCreate (directory) {
return new Promise((resolve) =>
{
mkdirs(directory, function () {
resolve(true)
})
})
}// 遞迴建立目錄function mkdirs (directory, callback) {
var exists = fs.existsSync(directory) if (exists) {
callback()
} else {
mkdirs(path.dirname(directory), function () {
fs.mkdirSync(directory) callback()
})
}
}複製程式碼
  • 配置package.json新增一個scripts指令碼
"new:view": "node ./scripts/generateView"複製程式碼
  • 執行

如果使用 npm 的話 就是 npm run new:view

如果使用 yarn 的話 就是 yarn new:view

vue-cli3 專案從搭建優化到docker部署

5. axios封裝

  • 安裝 axios
npm install axios --save// oryarn add axios複製程式碼

5.1 配置不同的環境

在根目錄新建三個環境變數檔案

vue-cli3 專案從搭建優化到docker部署

分別輸入不同的地址,比如dev就寫 dev的api地址、test就寫test的api地址

# // .envNODE_ENV = "development"BASE_URL = "https://easy-mock.com/mock/5c4c50b9888ef15de01bec2c/api"複製程式碼

接著在根目錄中新建一個 vue.config.js

// vue.config.jsmodule.exports = { 
chainWebpack: config =>
{
// 這裡是對環境的配置,不同環境對應不同的BASE_URL,以便axios的請求地址不同 config.plugin('define').tap(args =>
{
args[0]['process.env'].BASE_URL = JSON.stringify(process.env.BASE_URL) return args
})
}
}複製程式碼

然後在src目錄下新建一個 api資料夾,建立一個 index.js用來配置 axios的配置資訊

// src/api/index.jsimport axios from 'axios'import router from '../router'import { 
Message
} from 'element-ui'const service = axios.create({
// 設定超時時間 timeout: 60000, baseURL: process.env.BASE_URL
})// post請求的時候,我們需要加上一個請求頭,所以可以在這裡進行一個預設的設定// 即設定post的請求頭為application/x-www-form-urlencoded;
charset=UTF-8service.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;
charset=UTF-8''export default service複製程式碼

5.2 請求響應封裝

import axios from 'axios'import router from '../router'import { 
Message
} from 'element-ui'const service = axios.create({
// 設定超時時間 timeout: 60000, baseURL: process.env.BASE_URL
})/** * 請求前攔截 * 用於處理需要在請求前的操作 */service.interceptors.request.use(config =>
{
const token = localStorage.getItem('token') if (token) {
config.headers['Authorization'] = token
} return config
}, (error) =>
{
return Promise.reject(error)
})/** * 請求響應攔截 * 用於處理需要在請求返回後的操作 */service.interceptors.response.use(response =>
{
const responseCode = response.status // 如果返回的狀態碼為200,說明介面請求成功,可以正常拿到資料 // 否則的話丟擲錯誤 if (responseCode === 200) {
return Promise.resolve(response)
} else {
return Promise.reject(response)
}
}, error =>
{
// 伺服器返回不是 2 開頭的情況,會進入這個回撥 // 可以根據後端返回的狀態碼進行不同的操作 const responseCode = error.response.status switch (responseCode) {
// 401:未登入 case 401: // 跳轉登入頁 router.replace({
path: '/login', query: {
redirect: router.currentRoute.fullPath
}
}) break // 403: token過期 case 403: // 彈出錯誤資訊 Message({
type: 'error', message: '登入資訊過期,請重新登入'
}) // 清除token localStorage.removeItem('token') // 跳轉登入頁面,並將要瀏覽的頁面fullPath傳過去,登入成功後跳轉需要訪問的頁面 setTimeout(() =>
{
router.replace({
path: '/login', query: {
redirect: router.currentRoute.fullPath
}
})
}, 1000) break // 404請求不存在 case 404: Message({
message: '網路請求不存在', type: 'error'
}) break // 其他錯誤,直接丟擲錯誤提示 default: Message({
message: error.response.data.message, type: 'error'
})
} return Promise.reject(error)
})export default service複製程式碼

Message 方法是 element-ui 提供的一個訊息提示元件、大家可以根據自己的訊息提示元件進行替換

5.3 斷網處理

在響應攔截中新增處理邏輯

service.interceptors.response.use(response =>
{
const responseCode = response.status // 如果返回的狀態碼為200,說明介面請求成功,可以正常拿到資料 // 否則的話丟擲錯誤 if (responseCode === 200) {
return Promise.resolve(response.data)
} else {
return Promise.reject(response)
}
}, error =>
{
// 斷網 或者 請求超時 狀態 if (!error.response) {
// 請求超時狀態 if (error.message.includes('timeout')) {
console.log('超時了') Message.error('請求超時,請檢查網路是否連線正常')
} else {
// 可以展示斷網元件 console.log('斷網了') Message.error('請求失敗,請檢查網路是否已連線')
} return
} // 省略其它程式碼 ······ return Promise.reject(error)
})複製程式碼

5.4 封裝圖片上傳

// src/api/index.jsexport const uploadFile = formData =>
{
const res = service.request({
method: 'post', url: '/upload', data: formData, headers: {
'Content-Type': 'multipart/form-data'
}
}) return res
}複製程式碼

呼叫

async uploadFile (e) { 
const file = document.getElementById('file').files[0] const formdata = new FormData() formdata.append('file', file) await uploadFile(formdata)
}複製程式碼

5.5 請求 顯示 Loading 效果

let loading = nullservice.interceptors.request.use(config =>
{
// 在請求先展示載入框 loading = Loading.service({
text: '正在載入中......'
}) // 省略其它程式碼 ······ return config
}, (error) =>
{
return Promise.reject(error)
})service.interceptors.response.use(response =>
{
// 請求響應後關閉載入框 if (loading) {
loading.close()
} // 省略其它程式碼 ······
}, error =>
{
// 請求響應後關閉載入框 if (loading) {
loading.close()
} // 省略其它程式碼 ······ return Promise.reject(error)
})複製程式碼

6. 巧用 Mixins

vue-cli3 專案從搭建優化到docker部署

6.1 封裝 store 公用方法

假設有這樣一個場景,我們通過 vuex 封裝了獲取新聞列表的 function

import Vue from 'vue'import Vuex from 'vuex'import { 
getNewsList
} from '../api/news'Vue.use(Vuex)const types = {
NEWS_LIST: 'NEWS_LIST'
}export default new Vuex.Store({
state: {
[types.NEWS_LIST]: []
}, mutations: {
[types.NEWS_LIST]: (state, res) =>
{
state[types.NEWS_LIST] = res
}
}, actions: {
[types.NEWS_LIST]: async ({
commit
}, params) =>
{
const res = await getNewsList(params) return commit(types.NEWS_LIST, res)
}
}, getters: {
getNewsResponse (state) {
return state[types.NEWS_LIST]
}
}
})複製程式碼

然後在新聞列表頁,我們通過 mapActionmapGetters來呼叫Actiongetters我們需要寫上這些程式碼

import { 
mapActions, mapGetters
} from 'vuex'computed: {
...mapGetters(['getNewsResponse'])
},methods: {
...mapActions(['NEWS_LIST'])
}複製程式碼

在假設,在另一個頁面又需要重新呼叫獲取新聞列表的介面,我們又要在寫一遍上面的程式碼對吧?

複製貼上就是幹有木有?

如果介面突然加了一個引數,那豈不是每個要用到這個介面的程式碼都得加這個引數。

複製貼上一時爽,需求一改你就爽

vue-cli3 專案從搭建優化到docker部署

既然是重複的程式碼,我們肯定要複用,這時候Vue提供的Mixin就起了大作用了

  • 封裝 news-mixin.js在 src下建立一個mixins目錄,用來管理所有的mixins新建一個news-mixin.js
import { 
mapActions, mapGetters
} from 'vuex'export default {
computed: {
...mapGetters(['getNewsResponse'])
}, methods: {
...mapActions(['NEWS_LIST'])
}
}複製程式碼

然後在需要用到的元件中引入這個mixin,就能直接呼叫這個方法了。不管多少個頁面,只要引入這個mixin,直接就能使用。

需求一改的話,也只需要修改這個mixin檔案

// news/index.vueimport Vue from 'vue'import newsMixin from '@/mixins/news-mixin'export default { 
name: 'news', mixins: [newsMixin], data () {
return {
}
}, async created () {
await this.NEWS_LIST() console.log(this.getNewsResponse)
}
}複製程式碼

6.2 擴充套件

除了封裝 vuex 的公用方法,其實還有很多的東西也能做封裝。例如:分頁物件,表格資料,公用方法、等等就不一一舉例了。可以看github

在多個地方經常使用,就可以考慮封裝成mixin,不過請寫好註釋哦。不然就會有人在背後罵你了!!你懂的~~

7. 優化

7.1 gzip壓縮

  • 安裝compression-webpack-plugin外掛
npm install compression-webpack-plugin --save-dev// oryarn add compression-webpack-plugin --dev複製程式碼
  • 在 vue.config.js 中新增配置
// vue.config.jsconst CompressionPlugin = require('compression-webpack-plugin')module.exports = { 
chainWebpack: config =>
{
// 這裡是對環境的配置,不同環境對應不同的BASE_URL,以便axios的請求地址不同 config.plugin('define').tap(args =>
{
args[0]['process.env'].BASE_URL = JSON.stringify(process.env.BASE_URL) return args
}) if (process.env.NODE_ENV === 'production') {
// #region 啟用GZip壓縮 config .plugin('compression') .use(CompressionPlugin, {
asset: '[path].gz[query]', algorithm: 'gzip', test: new RegExp('\\.(' + ['js', 'css'].join('|') + ')$'), threshold: 10240, minRatio: 0.8, cache: true
}) .tap(args =>
{

}) // #endregion
}
}
}複製程式碼

npm run build後能看到生成 .gz 檔案就OK了。如果你的伺服器使用nginx的話,nginx也需要配置開啟GZIP、下面會講到如何在nginx中開啟GZIP

vue-cli3 專案從搭建優化到docker部署

7.2 第三方庫引用cdn

對於 vuevue-routervuexaxioselement-ui等等這些不經常改動的庫、我們讓webpack不對他們進行打包,通過cdn引入,可以減少程式碼的大小、也可以減少伺服器的頻寬,更能把這些檔案快取到客戶端,客戶端載入的會更快。

  • 配置vue.config.js
const CompressionPlugin = require('compression-webpack-plugin')module.exports = { 
chainWebpack: config =>
{
// 省略其它程式碼 ······ // #region 忽略生成環境打包的檔案 var externals = {
vue: 'Vue', axios: 'axios', 'element-ui': 'ELEMENT', 'vue-router': 'VueRouter', vuex: 'Vuex'
} config.externals(externals) const cdn = {
css: [ // element-ui css '//unpkg.com/element-ui/lib/theme-chalk/index.css' ], js: [ // vue '//cdn.staticfile.org/vue/2.5.22/vue.min.js', // vue-router '//cdn.staticfile.org/vue-router/3.0.2/vue-router.min.js', // vuex '//cdn.staticfile.org/vuex/3.1.0/vuex.min.js', // axios '//cdn.staticfile.org/axios/0.19.0-beta.1/axios.min.js', // element-ui js '//unpkg.com/element-ui/lib/index.js' ]
} config.plugin('html') .tap(args =>
{
args[0].cdn = cdn return args
}) // #endregion
}
}
}複製程式碼
  • 修改index.html
<
!--public/index.html-->
<
!DOCTYPE html>
<
html lang="en">
<
head>
<
meta charset="utf-8">
<
meta http-equiv="X-UA-Compatible" content="IE=edge">
<
meta name="viewport" content="width=device-width,initial-scale=1.0">
<
link rel="icon" href="<
%= BASE_URL %>
favicon.ico"
>
<
% if (process.env.NODE_ENV === 'production') {
%>
<
% for(var css of htmlWebpackPlugin.options.cdn.css) {
%>
<
link href="<
%=css%>
"
rel="preload" as="style">
<
link rel="stylesheet" href="<
%=css%>
"
as="style">
<
%
} %>
<
% for(var js of htmlWebpackPlugin.options.cdn.js) {
%>
<
link href="<
%=js%>
"
rel="preload" as="script">
<
script src="<
%=js%>
"
>
<
/script>
<
%
} %>
<
%
} %>
<
title>
vue-cli3-project<
/title>
<
/head>
<
body>
<
noscript>
<
strong>
We're sorry but vue-cli3-project doesn't work properly without JavaScript enabled. Please enable it to continue.<
/strong>
<
/noscript>
<
div id="app">
<
/div>
<
!-- built files will be auto injected -->
<
/body>
<
/html>
複製程式碼

7.3 全站cdn

我們已經把第三方庫使用cdn替代了,那麼我們build後生成的 js,css之類的檔案能否也用cdn呢?

vue-cli3 專案從搭建優化到docker部署

申請自己的cdn域名

要想把自己的資源上傳到cdn上,前提是得有自己的cdn域名,如果沒有的話,可以到七牛雲官網上註冊申請一個

  1. 註冊七牛雲賬號
  2. 到七牛雲物件儲存模組中新建儲存空間
  3. 輸入儲存空間資訊
    vue-cli3 專案從搭建優化到docker部署
  4. 確定建立
  5. 建立成功後會跳轉到這個儲存空間的控制檯頁面
    vue-cli3 專案從搭建優化到docker部署
  6. 其中有個域名就是你的測試域名
  7. 我們可以在內容管理那上傳我們的jscss之類的檔案、不過我們的檔案那麼多,一個一個上傳明顯不合理。要你你也不幹。

這時候,這些批量又重複的操作應該由我們的node出馬,讓我們來通過 node來批量上傳我們的資原始檔

將生成的js、css資源上傳到七牛cdn

在七牛雲官網的文件中心有介紹如何通過node上傳檔案、感興趣的人可以自己去研究一下。

  1. 檢視AccessKeySecretKey,在你的個人皮膚 ->
    祕鑰管理 ,這兩個祕鑰待會會用到
vue-cli3 專案從搭建優化到docker部署
  1. 安裝需要的外掛
npm install qiniu glob mime --save-dev複製程式碼
  1. scripts目錄下建立一個 upcdn.js 檔案
// /scripts/upcdn.jsconst qiniu = require('qiniu')const glob = require('glob')const mime = require('mime')const path = require('path')const isWindow = /^win/.test(process.platform)let pre = path.resolve(__dirname, '../dist/') + (isWindow ? '\\' : '')const files = glob.sync(  `${path.join(    __dirname,    '../dist/**/*.?(js|css|map|png|jpg|svg|woff|woff2|ttf|eot)'  )
}
`
)pre = pre.replace(/\\/g, '/')const options = {
scope: 'source' // 空間物件名稱
}var config = {
qiniu: {
accessKey: '', // 個人中心 祕鑰管理裡的 AccessKey secretKey: '', // 個人中心 祕鑰管理裡的 SecretKey bucket: options.scope, domain: 'http://ply4cszel.bkt.clouddn.com'
}
}var accessKey = config.qiniu.accessKeyvar secretKey = config.qiniu.secretKeyvar mac = new qiniu.auth.digest.Mac(accessKey, secretKey)var putPolicy = new qiniu.rs.PutPolicy(options)var uploadToken = putPolicy.uploadToken(mac)var cf = new qiniu.conf.Config({
zone: qiniu.zone.Zone_z2
})var formUploader = new qiniu.form_up.FormUploader(cf)async function uploadFileCDN (files) {
files.map(async file =>
{
const key = getFileKey(pre, file) try {
await uploadFIle(key, file) console.log(`上傳成功 key: ${key
}
`
)
} catch (err) {
console.log('error', err)
}
})
}async function uploadFIle (key, localFile) {
const extname = path.extname(localFile) const mimeName = mime.getType(extname) const putExtra = new qiniu.form_up.PutExtra({
mimeType: mimeName
}) return new Promise((resolve, reject) =>
{
formUploader.putFile(uploadToken, key, localFile, putExtra, function ( respErr, respBody, respInfo ) {
if (respErr) {
reject(respErr)
} resolve({
respBody, respInfo
})
})
})
}function getFileKey (pre, file) {
if (file.indexOf(pre) >
-1) {
const key = file.split(pre)[1] return key.startsWith('/') ? key.substring(1) : key
} return file
}(async () =>
{
console.time('上傳檔案到cdn') await uploadFileCDN(files) console.timeEnd('上傳檔案到cdn')
})()複製程式碼

修改 publicPath

修改vue.config.js的配置資訊,讓其publicPath指向我們cdn的域名

const IS_PROD = process.env.NODE_ENV === 'production'const cdnDomian = 'http://ply4cszel.bkt.clouddn.com'module.exports = { 
publicPath: IS_PROD ? cdnDomian : '/', // 省略其它程式碼 ·······
}複製程式碼

修改package.json配置

修改package.json配置,使我們build完成後自動上傳資原始檔到cdn伺服器

"build": "vue-cli-service build --mode prod &
&
node ./scripts/upcdn.js"
,複製程式碼

執行檢視效果

npm run build

vue-cli3 專案從搭建優化到docker部署

然後到你的cdn控制檯的內容管理看看檔案是否已經上傳成功

vue-cli3 專案從搭建優化到docker部署
vue-cli3 專案從搭建優化到docker部署

8. docker部署

這邊使用的是 centOS7 環境,不過使用的是不同的系統,可以參考一下其它系統的安裝方法

8.1 安裝docker

  • 更新軟體庫
yum update -y複製程式碼
  • 安裝docker
yum install docker複製程式碼
  • 啟動docker服務
service docker start複製程式碼
  • 安裝docker-compose
// 安裝epel源yum install -y epel-release// 安裝docker-composeyum install docker-compose複製程式碼

8.2 編寫docker-compose.yaml

version: '2.1'services:  nginx:    restart: always    image: nginx    volumes:      #~ /var/local/nginx/nginx.conf為本機目錄, /etc/nginx為容器目錄      - /var/local/nginx/nginx.conf:/etc/nginx/nginx.conf      #~ /var/local/app/dist 為本機 build 後的dist目錄, /usr/src/app為容器目錄,      - /var/local/app/dist:/usr/src/app    ports:      - 80:80    privileged: true複製程式碼

8.3 編寫 nginx.conf 配置

#user  nobody;
worker_processes 2;
#工作模式及連線數上線events {
worker_connections 1024;
#單個工作程式 處理程式的最大併發數
}http {
include mime.types;
default_type application/octet-stream;
#sendfile 指令指定 nginx 是否呼叫 sendfile 函式(zero copy 方式)來輸出檔案,對於普通應用, sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
# 開啟GZIP gzip on;
# # 監聽 80 埠,轉發請求到 3000 埠 server {
#監聽埠 listen 80;
#編碼格式 charset utf-8;
# 前端靜態檔案資源 location / {
root /usr/src/app;
index index.html index.htm;
try_files $uri $uri/ @rewrites;

} # 配置如果匹配不到資源,將url指向 index.html, 在 vue-router 的 history 模式下使用,就不會顯示404 location @rewrites {
rewrite ^(.*)$ /index.html last;

} error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;

}
}
}複製程式碼

8.4 執行 docker-compose

docker-compose -d up複製程式碼
vue-cli3 專案從搭建優化到docker部署

5.5 docker + jenkins 自動化部署

使用docker + jenkins 能實現程式碼提交到github後自動部署環境、這個要講起來內容太多,有興趣的可以看我這一篇文章

從零搭建docker+jenkins+node.js自動化部署環境

6. 擴充套件

如果大家還有什麼更好的實踐方式,歡迎評論區指教!!

vue-cli3 專案從搭建優化到docker部署

專案地址 vue-cli3-project 歡迎 star

原文地址 www.ccode.live/lentoo/list…

歡迎關注

歡迎關注公眾號“碼上開發”,每天分享最新技術資訊

image

來源:https://juejin.im/post/5c4a6fcd518825469414e062

相關文章