亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > JavaScript > 正文

vue-cli3 項目從搭建優化到docker部署的方法

2019-11-19 12:12:16
字體:
來源:轉載
供稿:網友

1. 創建一個vue項目

相信大部分人都已經知道怎么創建項目的,可以跳過這一節,看下一節。

1.1 安裝@vue/cli

# 全局安裝 vue-cli腳手架npm install -g @vue/cli

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

1.2 初始化項目

vue create vue-cli3-project

(1)選擇一個預設

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

我們選擇更多功能 Manually select features

回車后來到選擇插件

(2)插件選擇

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

(3)路由模式選擇

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

(4)選擇一個css預處理器 (Sass/SCSS)

(5)選擇一個eslint配置

這邊選擇 ESLint + Standard config ,個人比較喜歡這個代碼規范

(6)選擇什么時候進行 eslint 校驗

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

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

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

8. 選擇將這些配置文件寫入到什么地方 (In dedicated config files)

9. 是否保存這份預設配置?(y)

選是的話,下次創建一個vue項目,可以直接使用這個預設文件,而無需再進行配置。

等待依賴完成

2. 全局組件自動注冊

components 目錄下創建一個 global 目錄,里面放置一些需要全局注冊的組件。

index.js 作用只要是引入 main.vue ,導出組件對象

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 拆分路由

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

在每個子模塊中導出一個路由配置數組

在根 index.js 中導入所有子模塊

3.2 自動掃描子模塊路由并導入

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

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

通過上面的自動掃描全局組件注冊,我們也可以實現自動掃描子模塊路由并導入

4. 通過node來生成組件

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

雖然我們通過上面已經實現了組件的自動注冊,不過每次新建組件的時候,都要創建一個目錄,然后新增一個 .vue 文件,然后寫 template 、 scriptstyle 這些東西,然后新建一個 index.js

、導出vue組件、雖然有插件能實現自動補全,但還是很麻煩有木有。

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

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

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

5. axios封裝 安裝 axios

npm install axios --save// oryarn add axios

5.1 配置不同的環境

在根目錄新建三個環境變量文件

分別輸入不同的地址, 比如 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

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] } }})

然后在新聞列表頁,我們通過 mapAction 、 mapGetters 來調用 Actiongetters 我們需要寫上這些代碼

import { mapActions, mapGetters } from 'vuex'computed: { ...mapGetters(['getNewsResponse'])},methods: { ...mapActions(['NEWS_LIST'])}

在假設,在另一個頁面又需要重新調用獲取新聞列表的接口,我們又要在寫一遍上面的代碼對吧?

復制粘貼就是干有木有?

如果接口突然加了一個參數,那豈不是每個要用到這個接口的代碼都得加這個參數。

復制粘貼一時爽,需求一改你就爽

既然是重復的代碼,我們肯定要復用,這時候 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 的公用方法,其實還有很多的東西也能做封裝。例如: 分頁對象 , 表格數據 , 公用方法 、等等就不一一舉例了??梢钥?a rel="external nofollow" target="_blank" >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

7.2 第三方庫引用cdn

對于 vue 、 vue-router 、 vuex 、 axioselement-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 呢?

申請自己的cdn域名

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

  • 注冊七牛云賬號
  • 到七牛云對象存儲模塊中新建存儲空間
  • 輸入存儲空間信息

確定創建

創建成功后會跳轉到這個存儲空間的控制臺頁面

其中有個域名就是你的測試域名

我們可以在內容管理那上傳我們的 js 、 css 之類的文件、不過我們的文件那么多,一個一個上傳明顯不合理。要你你也不干。

這時候,這些批量又重復的操作應該由我們的 node 出馬,讓我們來通過 node 來批量上傳我們的資源文件

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

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

查看 AccessKeySecretKey ,在你的個人面板 -> 秘鑰管理 ,這兩個秘鑰待會會用到

安裝需要的插件

npm install qiniu glob mime --save-dev

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

然后到你的 cdn

控制臺的內容管理看看文件是否已經上傳成功

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

8.5 docker + jenkins 自動化部署

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

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

擴展

使用pm2自動化部署node項目
通過vue-cli3構建一個SSR應用程序

項目地址 vue-cli3-project 歡迎 star

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持武林網。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
国产精品观看在线亚洲人成网| 国产精品一区=区| 国产免费一区二区三区在线能观看| 久久在线视频在线| 欧美在线影院在线视频| 国产亚洲视频在线观看| 中文字幕亚洲激情| 色多多国产成人永久免费网站| 色噜噜国产精品视频一区二区| 午夜欧美不卡精品aaaaa| 91成人福利在线| 91精品视频免费| xxxxx91麻豆| 亚洲欧洲免费视频| 97久久精品国产| 欧美日韩国产精品专区| 91av在线网站| 日韩动漫免费观看电视剧高清| 日韩av中文在线| 国产精品永久免费观看| 亚洲精品电影网在线观看| 色www亚洲国产张柏芝| 久久久999精品免费| 欧美丝袜美女中出在线| 成人黄色免费在线观看| 国产精品都在这里| 亚洲成人激情在线| 国产日韩欧美在线| 日韩视频免费在线观看| 色妞一区二区三区| 国产这里只有精品| 日韩精品中文字| 日韩电影大片中文字幕| 久久久久久久999精品视频| 久久免费视频观看| 91av国产在线| 亚洲国产私拍精品国模在线观看| 亚洲国产精品悠悠久久琪琪| 亚洲在线www| 国产精品视频网| 久久久亚洲福利精品午夜| 国产一区二区三区视频在线观看| 欧美性xxxx极品hd欧美风情| 91精品国产综合久久香蕉| 日韩av在线网页| 在线观看欧美www| 欧美猛交免费看| 自拍偷拍亚洲欧美| 亚洲影视九九影院在线观看| 亚洲伦理中文字幕| 国产精品自产拍在线观看中文| 日韩av有码在线| 欧美成人精品在线视频| 欧美亚洲国产日本| 亚洲成人av资源网| 中文字幕在线国产精品| 久久99久久亚洲国产| 韩国三级日本三级少妇99| 国产成人一区二区在线| 久久久久中文字幕2018| 亚洲大胆人体在线| 国产精品www色诱视频| 欧美中文字幕在线观看| 久久中文字幕一区| 亚洲成人在线网| 亚洲欧洲日产国码av系列天堂| 秋霞成人午夜鲁丝一区二区三区| 日韩精品欧美国产精品忘忧草| 2019中文字幕在线观看| 亚洲xxxxx| 亚洲国产日韩欧美在线99| 色天天综合狠狠色| 久久人人爽人人爽人人片av高请| 97精品伊人久久久大香线蕉| 欧美一区第一页| 国产精品永久免费视频| 国产精品2018| 精品中文字幕在线观看| 午夜精品久久久久久99热| 尤物99国产成人精品视频| 国产91精品青草社区| 91国产美女视频| 欧美性色xo影院| 欧美孕妇毛茸茸xxxx| 在线播放亚洲激情| 久久成人人人人精品欧| 午夜精品一区二区三区视频免费看| 欧美亚洲国产成人精品| 欧美亚洲视频一区二区| 久久久精品2019中文字幕神马| 国产女精品视频网站免费| 亚洲自拍偷拍福利| 国产精品久久久久久亚洲影视| 奇米四色中文综合久久| 疯狂做受xxxx高潮欧美日本| 日韩av在线网| 国产日韩欧美在线看| 91麻豆国产语对白在线观看| 亚洲毛茸茸少妇高潮呻吟| 久久精品国产一区二区电影| 亚洲天堂av综合网| 国产综合视频在线观看| 精品一区精品二区| 国产精品三级在线| 亚洲精品美女久久久| 亚洲男人天堂久| 大桥未久av一区二区三区| 91精品免费久久久久久久久| 国产精品激情自拍| 欧美午夜视频在线观看| 国产精品午夜视频| 欧美第一黄网免费网站| 欧美老女人在线视频| 欧美大全免费观看电视剧大泉洋| 亚洲欧美另类中文字幕| 亚洲自拍小视频免费观看| 久久久久久久久久久网站| 欧美国产乱视频| 1769国内精品视频在线播放| 91欧美精品成人综合在线观看| 97在线观看免费高清| 色综合视频一区中文字幕| 亚洲国内高清视频| 日韩免费观看在线观看| 久久免费视频网| 欧美香蕉大胸在线视频观看| 亚洲综合日韩在线| 疯狂做受xxxx欧美肥白少妇| 在线国产精品视频| 91精品视频观看| 国产精品欧美风情| 亚洲精品二三区| 欧美肥老太性生活视频| 亚洲欧美国产日韩天堂区| 2019中文字幕在线观看| 国产成人在线一区| 日韩精品免费电影| 亚洲国产欧美一区二区丝袜黑人| 亚洲人成亚洲人成在线观看| 国产精品久久久久久久av电影| 欧美高清在线播放| 欧美黑人一区二区三区| 国产欧美日韩中文字幕在线| 国产欧美日韩精品在线观看| 操日韩av在线电影| 18久久久久久| 亚洲sss综合天堂久久| 色综久久综合桃花网| 日韩国产高清视频在线| 国产精品高清免费在线观看| 国产亚洲a∨片在线观看| 亚洲免费精彩视频| 红桃视频成人在线观看| 亚洲国产欧美一区二区丝袜黑人| 久久精品国产清自在天天线| 91精品视频免费观看| 黄色成人av在线| 成人妇女淫片aaaa视频| 国产日韩在线观看av| 欧美激情亚洲一区| 欧美丰满少妇xxxxx做受| 91av视频在线观看| 欧美亚洲激情视频| 亚州成人av在线|