адрес проектаvue-cli3-projectприветственная звезда
исходный адресWoohoo.C code.live/Len too/list…
1. Создайте проект vue
Я полагаю, что большинство из вас уже знают, как создать проект, вы можете пропустить этот раздел и перейти к следующему.
1.1 Установите @vue/cli
# 全局安装 vue-cli脚手架
npm install -g @vue/cli
Дождитесь завершения установки и начните следующий шаг.
1.2 Инициализация проекта
vue create vue-cli3-project
- выбрать предустановку
babel
,eslint
Мы выбираем больше возможностейManually select features
Введите и выберите плагин
- Выбор плагина
Выбрано здесь (Babel, Router, Vuex, препроцессор Css, проверка формата Linter/Formatter, фреймворк модульного тестирования)
- Выбор режима маршрутизации
использовать или нетhistory
Режим маршрутизации (Да)
- Выберите препроцессор css (Sass/SCSS)
- Выберите конфигурацию eslint
выбрать здесьESLint + Standard config
, я лично предпочитаю эту спецификацию кода
- выбрать, когда
eslint
чек об оплате
Выберите (Lint при сохранении), чтобы сохранить флажок
Если вы используете редактор vscode, вы можете настроить плагин eslint для автоматического форматирования кода.
7. Выберите тестовую среду (Mocha + Chai)8. Выберите, куда записать эти файлы конфигурации (в специальные файлы конфигурации)- Вы хотите сохранить эту конфигурацию по умолчанию? (у)
Если вы выберете «да», в следующий раз, когда вы будете создавать проект vue, вы сможете использовать этот предустановленный файл напрямую без дополнительной настройки.
дождитесь завершения зависимостей
2. Автоматическая регистрация глобальных компонентов
существуетcomponents
создать каталогglobal
Каталог, в котором размещены некоторые компоненты, которые необходимо зарегистрировать глобально.
index.js
Эффект сохраняется до тех пор, пока введениеmain.vue
, экспортировать объект компонента
components
создатьindex.js
, который сканирует глобальные объекты и автоматически их регистрирует.
// components/index.js
import 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
Разве не было бы расточительством, если бы нельзя было использовать что-то столь полезное?
.vue
файл, затем напишитеtemplate
,script
,style
эти вещи, а затем создать новыйindex.js
, Экспорт компонентов vue, хотя есть плагины, которые могут добиться автоматического завершения, но это все еще очень хлопотно.
Так мы можем пройтиnode
чтобы помочь нам сделать это? просто скажиnode
Просто помогите мне сгенерировать имя компонента. другие вещи делаютnode
приходить делать
4.1 Создание компонентов через узел
- установить его
chalk
, этот плагин может сделать наш оператор вывода консоли различным цветовым различием
npm install chalk --save-dev
создать один в корневом каталогеscripts
папка,
добавить одинgenerateComponent.js
файл для размещения кода для создания компонента,
добавить одинtemplate.js
файл, код для размещения шаблона компонента
- template.js
// template.js
module.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
Чтобы создать компоненты, вы также можете сделать выводы для создания компонентов страницы. Просто немного измените логику, которая генерирует код компонента.
существуетscripts
Создайте новый в каталогеgenerateView.js
документ
// generateView.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 } = 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. пакет аксиом
- установить аксиомы
npm install axios --save
// or
yarn add axios
5.1 Настройка различных сред
Создайте три файла переменных среды в корневом каталоге.
Введите разные адреса соответственно, Напримерdev
просто пишиdev
API-адрес,test
просто пишиtest
API-адрес
# // .env
NODE_ENV = "development"
BASE_URL = "https://easy-mock.com/mock/5c4c50b9888ef15de01bec2c/api"
Затем создайте новый в корневом каталогеvue.config.js
// vue.config.js
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
})
}
}
затем вsrc
Создайте новый в каталогеapi
папку, создайтеindex.js
используется для настройкиaxios
информация о конфигурации
// src/api/index.js
import 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-8
service.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.js
export 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 Запрос на отображение эффекта загрузки
let loading = null
service.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. Используйте миксины
6.1 Инкапсуляция общедоступных методов хранилища
Рассмотрим сценарий, который мы прошли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
звонитьAction
а такжеgetters
нам нужно написать этот код
import { mapActions, mapGetters } from 'vuex'
computed: {
...mapGetters(['getNewsResponse'])
},
methods: {
...mapActions(['NEWS_LIST'])
}
Предполагая, что интерфейс для получения списка новостей нужно снова вызвать на другой странице, мы должны снова написать приведенный выше код, верно?
Копировать и вставить это сухое или дерево?
Если интерфейс вдруг добавляет параметр, то каждый код, использующий интерфейс, должен добавить этот параметр.
Круто копировать и вставлять какое-то время, и вы будете круты, когда измените свои потребности
Поскольку это повторяющийся код, мы должны использовать его повторно.Vue
который предоставилMixin
это сработало отлично
- Пакет news-mixin.js
существует
src
создать следующийmixins
Каталог для управления всеми миксинами создать новыйnews-mixin.js
import { mapActions, mapGetters } from 'vuex'
export default {
computed: {
...mapGetters(['getNewsResponse'])
},
methods: {
...mapActions(['NEWS_LIST'])
}
}
Затем импортируйте это в компоненты, которые вам нужно использовать.mixin
, вы можете вызвать этот метод напрямую. Неважно, сколько страниц, просто импортируйте этоmixin
, можно использовать напрямую.
Если вам нужно изменить его, вам нужно только изменить этоmixin
документ
// news/index.vue
import 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
// or
yarn add compression-webpack-plugin --dev
- Добавьте конфигурацию в vue.config.js
// vue.config.js
const 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
Файл в порядке. Если ваш сервер использует nginx, nginx также должен быть включен.GZIP
, далее будет описано, какnginx
открыть вGZIP
7.2 Справочник по сторонней библиотеке cdn
дляvue
,vue-router
,vuex
,axios
а такжеelement-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
доменное имя, если оно недоступно, вы можете перейти наОфициальный сайт Qiniu CloudПодать заявку на регистрацию на
- Зарегистрируйте учетную запись Qiniu Cloud
- Создайте новое пространство для хранения в модуле хранения облачных объектов Qiniu.
- Введите информацию о месте для хранения
- ОК, чтобы создать
- После успешного создания он перейдет на страницу консоли этого хранилища.
- Один из доменов является вашим тестовым доменом
- Мы можем загрузить нашу
js
,css
Такие файлы, а у нас так много файлов, заливать по одному явно неразумно. Не делай этого, если хочешь.
В настоящее время эти пакетные и повторяющиеся операции должны выполняться нашимиnode
Выходи, пройдёмnode
для массовой загрузки наших файлов ресурсов
Загрузите сгенерированные ресурсы js и css в Qiniu cdn
На официальном сайте QiniuyunЦентр документацииЕсть инструкция как пройтиnode
Загрузите файл, и те, кто заинтересован, могут изучить его самостоятельно.
- Проверить
AccessKey
а такжеSecretKey
На вашей личной панели -> Управление ключами, которые будут использоваться два ключа
- Установите необходимые плагины
npm install qiniu glob mime --save-dev
- существует
scripts
создать каталогupcdn.js
документ
// /scripts/upcdn.js
const 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.accessKey
var secretKey = config.qiniu.secretKey
var 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')
})()
Изменить общедоступный путь
Исправлять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. развертывание докера
Здесь используетсяcentOS7
среду, но используя другую систему, вы можете обратиться к методу установки других систем
8.1 Установка докера
- Обновление библиотеки программного обеспечения
yum update -y
- установить докер
yum install docker
- запустить докер-сервис
service docker start
- Установить докер-компоновку
// 安装epel源
yum install -y epel-release
// 安装docker-compose
yum 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 + jenkins
использоватьdocker
+ jenkins
Он может реализовать среду автоматического развертывания после отправки кода на github.Об этом слишком много говорить.Если вам интересно, вы можете прочитать мою статью.
Создайте среду автоматического развертывания docker+jenkins+node.js с нуля
6. Расширение
- Использование pm2 для автоматизации развертывания проектов узлов
- Создайте приложение SSR с помощью vue-cli3.
Если у вас есть лучшие практические методы, добро пожаловать в область комментариев за советом! !
адрес проектаvue-cli3-projectприветственная звезда
исходный адресWoohoo.C code.live/Len too/list…
Добро пожаловать, чтобы следовать
Добро пожаловать в общедоступный номер»разработка кода», делясь последней технической информацией каждый день