написать впереди
TypeScript давно отсутствует, и многие крупные компании и крупные проекты также используют его для разработки. В прошлом месяце я также официально руководил крупномасштабным проектом по эксплуатации и техническому обслуживанию группы.
Проект, который нужно сделать, примерно разделен на следующие основные модули.
- Единая платформа управления
- Широкие возможности эксплуатации и обслуживания
- Платформа плана
- Инспекционная платформа
- Стресс-тест полной ссылки и т. д.
В каждом модуле очень много дел, так как это связано с бизнесом компании, я не буду здесь перечислять некоторые конкретные дела, но в любом случае общий масштаб проекта все равно очень велик.
1. О выборе
После проведения некоторых технических исследований в сочетании с уровнем затрат на разработку и обслуживание после завершения проекта. В конце концов, мои коллеги и я пришли к одному и тому же выводу по техническому выбору, и окончательный выбор был последним семейным ведром Vue + TypeScript.
Так вот вопрос, зачем в крупных проектах использовать TypeScript, ES6 и 7 не хватает?
На самом деле я не говорил «нет», но лично я предпочитаю использовать TypeScript в некоторых крупномасштабных проектах совместной разработки. Вот некоторые из моих мыслей после проведения исследования
-
Во-первых, TypeScript имеет систему типов и является надмножеством JavaScript. Что может JavaScript, он может. Чего JavaScript не может, он может.
-
Во-вторых, TypeScript относительно зрел, и на рынке есть много материалов по теме, и большинство библиотек и фреймворков также хорошо читают и поддерживают TypeScript.
-
Затем, обеспечивая отличную предпосылку, он активно развивается, чтобы улучшить, продолжать добавлять новые функции.
-
JavaScript — слабый тип и не имеет пространства имен, что затрудняет модульность, что не очень удобно в больших совместных проектах.
-
Такие редакторы, как vscode и ws, поддерживают TypeScript.
-
TypeScript лучше поддерживает проверку компонентов и бизнес-типа, например
// 定义枚举 const enum StateEnum { TO_BE_DONE = 0, DOING = 1, DONE = 2 } // 定义 item 接口 interface SrvItem { val: string, key: string } // 定义服务接口 interface SrvType { name: string, key: string, state?: StateEnum, item: Array<SrvItem> } // 然后定义初始值(如果不按照类型来,报错肯定是避免不了的) const types: SrvType = { name: '', key: '', item: [] }
Сотрудничайте с редактором.Если вы не будете следовать определенному типу, редактор сам выдаст вам ошибку, вместо того, чтобы ждать, пока компиляция сообщит об ошибке.
-
Объявление пространства имен + интерфейса более удобно для проверки типов и предотвращает ошибки в коде.
Например, вы определяете возвращаемый тип ajax в файле ajax.d.ts.
declare namespace Ajax { // axios 返回数据 export interface AxiosResponse { data: AjaxResponse } // 请求接口数据 export interface AjaxResponse { code: number, data: object | null | Array<any>, message: string } }
Затем можно использовать, когда требуется
this.axiosRequest({ key: 'idc' }).then((res: Ajax.AjaxResponse) => { console.log(res) })
-
Обобщения можно использовать для создания повторно используемых компонентов. Например, вы хотите создать универсальный метод, тип параметра которого совпадает с типом возвращаемого значения.
function foo<T> (arg: T): T { return arg } let output = foo('string') // type of output will be 'string'
Другой пример: вы хотите использовать дженерики для блокировки типов, используемых в коде.
interface GenericInterface<T> { (arg: T): T } function foo<T> (arg: T): T { return arg } // 锁定 myFoo 只能传入 number 类型的参数,传其他类型的参数则会报错 let myFoo: GenericInterface<number> = foo myFoo(123)
Короче говоря, плюсов от использования TypeScript еще много, я не буду их здесь перечислять, заинтересованные друзья могут сами проверить информацию
2. Инфраструктура
1. Инициализировать структуру
Для инициализации проекта я использую последнюю версию скаффолдинга vue-cli 3. Варианты инициализации следующие:
Результирующая структура каталогов выглядит следующим образом
├── public // 静态页面
├── src // 主目录
├── assets // 静态资源
├── components // 组件
├── views // 页面
├── App.vue // 页面主入口
├── main.ts // 脚本主入口
├── registerServiceWorker.ts // PWA 配置
├── router.ts // 路由
├── shims-tsx.d.ts // 相关 tsx 模块注入
├── shims-vue.d.ts // Vue 模块注入
└── store.ts // vuex 配置
├── tests // 测试用例
├── .postcssrc.js // postcss 配置
├── package.json // 依赖
├── tsconfig.json // ts 配置
└── tslint.json // tslint 配置
2. Реконструированная структура
Очевидно, что они не могут соответствовать развитию нормального бизнеса, поэтому я сделал вариант преобразования инфраструктуры здесь. После ремонта структура проекта выглядит следующим образом.
├── public // 静态页面
├── scripts // 相关脚本配置
├── src // 主目录
├── assets // 静态资源
├── filters // 过滤
├── lib // 全局插件
├── router // 路由配置
├── store // vuex 配置
├── styles // 样式
├── types // 全局注入
├── utils // 工具方法(axios封装,全局方法等)
├── views // 页面
├── App.vue // 页面主入口
├── main.ts // 脚本主入口
├── registerServiceWorker.ts // PWA 配置
├── tests // 测试用例
├── .editorconfig // 编辑相关配置
├── .npmrc // npm 源配置
├── .postcssrc.js // postcss 配置
├── babel.config.js // preset 记录
├── cypress.json // e2e plugins
├── f2eci.json // 部署相关配置
├── package.json // 依赖
├── README.md // 项目 readme
├── tsconfig.json // ts 配置
├── tslint.json // tslint 配置
└── vue.config.js // webpack 配置
3. Модульное преобразование
Далее я представлю трансформацию некоторых модулей в проекте
I. Маршрутизация ленивой загрузки
Импорт нагрузки на посяжению по требованию используется здесь, а вещи того же модуля введены в тот же кусок.router/index.ts
написать в
import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router)
export default new Router({
routes: [
{ path: '/', name: 'home', component: () => import(/* webpackChunkName: "home" */ 'views/home/index.vue') }
]
})
ii, пакет axios
существуетutils/config.ts
написать вaxios
Соответствующая конфигурация (перечислена лишь небольшая часть, пожалуйста, настройте ее в соответствии с вашим бизнесом)
import http from 'http'
import https from 'https'
import qs from 'qs'
import { AxiosResponse, AxiosRequestConfig } from 'axios'
const axiosConfig: AxiosRequestConfig = {
baseURL: '/',
// 请求后的数据处理
transformResponse: [function (data: AxiosResponse) {
return data
}],
// 查询对象序列化函数
paramsSerializer: function (params: any) {
return qs.stringify(params)
},
// 超时设置s
timeout: 30000,
// 跨域是否带Token
withCredentials: true,
responseType: 'json',
// xsrf 设置
xsrfCookieName: 'XSRF-TOKEN',
xsrfHeaderName: 'X-XSRF-TOKEN',
// 最多转发数,用于node.js
maxRedirects: 5,
// 最大响应数据大小
maxContentLength: 2000,
// 自定义错误状态码范围
validateStatus: function (status: number) {
return status >= 200 && status < 300
},
// 用于node.js
httpAgent: new http.Agent({ keepAlive: true }),
httpsAgent: new https.Agent({ keepAlive: true })
}
export default axiosConfig
Далее вам необходимоutils/api.ts
Делайте какие-то глобальные операции по перехвату в перехватчике, здесь я единообразно обрабатываю отмену повторных запросов в перехватчике, если вашему бизнесу это не нужно, пожалуйста, уберите это сами
import axios from 'axios'
import config from './config'
// 取消重复请求
let pending: Array<{
url: string,
cancel: Function
}> = []
const cancelToken = axios.CancelToken
const removePending = (config) => {
for (let p in pending) {
let item: any = p
let list: any = pending[p]
// 当前请求在数组中存在时执行函数体
if (list.url === config.url + '&request_type=' + config.method) {
// 执行取消操作
list.cancel()
// 从数组中移除记录
pending.splice(item, 1)
}
}
}
const service = axios.create(config)
// 添加请求拦截器
service.interceptors.request.use(
config => {
removePending(config)
config.cancelToken = new cancelToken((c) => {
pending.push({ url: config.url + '&request_type=' + config.method, cancel: c })
})
return config
},
error => {
return Promise.reject(error)
}
)
// 返回状态判断(添加响应拦截器)
service.interceptors.response.use(
res => {
removePending(res.config)
return res
},
error => {
return Promise.reject(error)
}
)
export default service
Для удобства нам также необходимо определить фиксированный набор форматов, возвращаемых axios, которые мы можем определить глобально. существуетtypes/ajax.d.ts
записать в файл
declare namespace Ajax {
// axios 返回数据
export interface AxiosResponse {
data: AjaxResponse
}
// 请求接口数据
export interface AjaxResponse {
code: number,
data: any,
message: string
}
}
Далее мы поместим всеaxios
помещатьvuex
изactions
единое управление
iii, модульное управление vuex
Под магазином папка представляет собой модуль, а приблизительный каталог магазина выглядит следующим образом.
├── home // 主目录
├── index.ts // vuex state getters mutations action 管理
├── interface.ts // 接口管理
└── index.ts // vuex 主入口
существуетhome/interface.ts
Интерфейсы для управления связанными модулями в
export interface HomeContent {
name: string
m1?: boolean
}
export interface State {
count: number,
test1?: Array<HomeContent>
}
затем вhome/index.ts
Связанные с определениемvuex
Содержание модуля
import request from '@/service'
import { State } from './interface'
import { Commit } from 'vuex'
interface GetTodayWeatherParam {
city: string
}
const state: State = {
count: 0,
test1: []
}
const getters = {
count: (state: State) => state.count,
message: (state: State) => state.message
}
const mutations = {
INCREMENT (state: State, num: number) {
state.count += num
}
}
const actions = {
async getTodayWeather (context: { commit: Commit }, params: GetTodayWeatherParam) {
return request.get('/api/weatherApi', { params: params })
}
}
export default {
state,
getters,
mutations,
actions
}
Затем мы можем использовать его на странице
<template>
<div class="home">
<p>{{ count }}</p>
<el-button type="default" @click="INCREMENT(2)">INCREMENT</el-button>
<el-button type="primary" @click="DECREMENT(2)">DECREMENT</el-button>
<el-input v-model="city" placeholder="请输入城市" />
<el-button type="danger" @click="getCityWeather(city)">获取天气</el-button>
</div>
</template>
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator'
import { State, Getter, Mutation, Action } from 'vuex-class'
@Component
export default class Home extends Vue {
city: string = '上海'
@Getter('count') count: number
@Mutation('INCREMENT') INCREMENT: Function
@Mutation('DECREMENT') DECREMENT: Function
@Action('getTodayWeather') getTodayWeather: Function
getCityWeather (city: string) {
this.getTodayWeather({ city: city }).then((res: Ajax.AjaxResponse) => {
const { low, high, type } = res.data.forecast[0]
this.$message.success(`${city}今日:${type} ${low} - ${high}`)
})
}
}
</script>
Что касается других трансформаций, я не буду их здесь приводить. В следующих подразделах будут представлены некоторые способы написания ts в файле vue.
3. Использование ts в vue
1. vue-свойство-декоратор
Здесь одностраничный компонент написан с использованиемvue-property-decoratorбиблиотека, которая полностью зависит отvue-class-component, которая также является библиотекой, официально рекомендованной vue.
В одном компоненте страницы, в@Component({})
написать внутриprops
,data
Крайне неудобно звонить, иvue-property-decorator
Он содержит 8 декораторов для решения таких задач, они
-
@Emit
Укажите событие для генерации, вы можете использовать этот модификатор, или вы можете использовать его напрямуюthis.$emit()
-
@Inject
указать внедрение зависимостей) -
@Mixins
инъекция миксина -
@Model
указать модель -
@Prop
Укажите опору -
@Provide
Указать Предоставить -
@Watch
Указать часы -
@Component
export fromvue-class-component
дать 🌰
import {
Component, Prop, Watch, Vue
} from 'vue-property-decorator'
@Component
export class MyComponent extends Vue {
dataA: string = 'test'
@Prop({ default: 0 })
propA: number
// watcher
@Watch('child')
onChildChanged (val: string, oldVal: string) {}
@Watch('person', { immediate: true, deep: true })
onPersonChanged (val: Person, oldVal: Person) {}
// 其他修饰符详情见上面的 github 地址,这里就不一一做说明了
}
После разбора становится
export default {
data () {
return {
dataA: 'test'
}
},
props: {
propA: {
type: Number,
default: 0
}
},
watch: {
'child': {
handler: 'onChildChanged',
immediate: false,
deep: false
},
'person': {
handler: 'onPersonChanged',
immediate: true,
deep: true
}
},
methods: {
onChildChanged (val, oldVal) {},
onPersonChanged (val, oldVal) {}
}
}
2. vuex-класс
vuex-classосновывается наVue,Vuex,vue-class-componentбиблиотека иvue-property-decorator
Точно так же он также предоставляет 4 модификатора и пространства имен, которые устраняют неудобства использования vuex в файлах .vue.
- @State
- @Getter
- @Mutation
- @Action
- namespace
скопируйте официальную 🌰
import Vue from 'vue'
import Component from 'vue-class-component'
import {
State,
Getter,
Action,
Mutation,
namespace
} from 'vuex-class'
const someModule = namespace('path/to/module')
@Component
export class MyComp extends Vue {
@State('foo') stateFoo
@State(state => state.bar) stateBar
@Getter('foo') getterFoo
@Action('foo') actionFoo
@Mutation('foo') mutationFoo
@someModule.Getter('foo') moduleGetterFoo
// If the argument is omitted, use the property name
// for each state/getter/action/mutation type
@State foo
@Getter bar
@Action baz
@Mutation qux
created () {
this.stateFoo // -> store.state.foo
this.stateBar // -> store.state.bar
this.getterFoo // -> store.getters.foo
this.actionFoo({ value: true }) // -> store.dispatch('foo', { value: true })
this.mutationFoo({ value: true }) // -> store.commit('foo', { value: true })
this.moduleGetterFoo // -> store.getters['path/to/module/foo']
}
}
На данный момент использование ts в файлах .vue почти такое же. Я также считаю, что мои друзья видели это и имеют определенное представление об общем синтаксическом сахаре.
3. Некоторые предложения
- если определено
.d.ts
файл, пожалуйста, перезапустите службу, чтобы ваша служба могла распознать определенный вами модуль, и перезапустите vscode, чтобы редактор также мог его распознать (действительно отвратительно) - установите свой
tsconfig
, например, не забудьте поставитьstrictPropertyInitialization
Установите значение false, в противном случае вы должны задать ему начальное значение при определении переменной. - Обязательно хорошо управляйте уровнем маршрутизации, иначе даже регулярность вас не спасет
- На бизнес-уровне определение типов или перечисление должно быть выполнено хорошо, что не только облегчает разработку, но и позволяет быстро обнаруживать проблемы при их возникновении.
- Чтобы использовать vuex в модулях, используйте его напрямую.
rootGetters
- Если вам нужно изменить тему библиотеки компонентов, откройте один файл для централизованного управления и не изменяйте каждый компонент в одном файле, иначе скорость компиляции будет беспокоить.
- Уметь повторно использовать вещи, разработанные другими людьми в команде, стараться не разрабатывать это во второй раз, иначе потерянное время может быть не только временем разработки, но и временем проверки кода
Есть еще куча подобных, но вам придется узнать больше для себя. Далее я расскажу о некоторых нормах совместной работы в больших проектах.
4. Как сотрудничать в командах
Большой проект должен быть распараллелен многими людьми, это не только сотрудничество команды фронтенда, но и исследование спроса (си) и обсуждение (би) с одноклассниками по продукту, а также совместная отладка с бэком -конец одноклассникам, а то и необходимости самому Или полагаться на SRE для настройки некоторых сервисов.
1. Спецификации фронтенд-разработки
Поскольку проект основан на vue + ts и совместной работе нескольких человек, определенно необходимы спецификации разработки, которые могут упростить параллельную разработку. Ниже я взял некоторые спецификации, которые я сделал в то время, в качестве справки для моих друзей (просто для справки).
I. Порядок разработки страницы
- HTML
- TypeScript
- CSS
<template>
</template>
<script lang="ts">
</script>
<style lang="scss">
</style>
2. Правила CSS (используйте правила именования БЭМ, чтобы избежать конфликтов стилей, не используйте область действия)
<template>
<div class="home">
<div class="home__count">{{ count }}</div>
<div class="home__input"></div>
</div>
</template>
<style lang="scss">
.home {
text-align: center;
&__count {}
&__input {}
}
</style>
iii. Порядок контекста TS в файле vue
-
data
-
@Prop
-
@State
-
@Getter
-
@Action
-
@Mutation
-
@Watch
-
крючки жизненного цикла
-
beforeCreate (сверху вниз в соответствии с крючками жизненного цикла)
-
created
-
beforeMount
-
mounted
-
beforeUpdate
-
updated
-
activated
-
deactivated
-
beforeDestroy
-
destroyed
-
errorCaptured (последний хук жизненного цикла)
-
-
крючок маршрутизации
-
beforeRouteEnter
-
beforeRouteUpdate
-
beforeRouteLeave
-
-
computed
-
methods
Ссылки на компоненты, примеси, фильтры и т. д. размещаются в @Component.
<script lang="ts">
@Component({
components: { HelloWorld },
mixins: [ Emitter ]
})
export default class Home extends Vue {
city: string = '上海'
@Prop({ type: [ Number, String ], default: 16 })
size: number | string
@State('state') state: StateInterface
@Getter('count') count: Function
@Action('getTodayWeather') getTodayWeather: Function
@Mutation('DECREMENT') DECREMENT: Function
@Watch('count')
onWatchCount (val: number) {
console.log('onWatchCount', val)
}
// computed
get styles () {}
created () {}
mounted () {}
destroyed () {}
// methods
getCityWeather (city: string) {}
}
</script>
iv. модульное управление vuex
Папка под магазином соответствует модулю, и каждый модуль имеет интерфейс для управления интерфейсом.Конкретный пример упомянут выше.
v. Поза введения маршрута
Маршрутизация ленивой загрузки, также есть примеры выше
vi. Соглашения об именах файлов
Слова в нижнем регистре, разделенные знаком «-», как показано на рисунке.
Существительные идут первыми, глаголы идут после
Один и тот же модуль описан первым, другие описания идут после
2. Сотрудничайте с продуктом + серверной частью и т. д.
Запомните эти три вещи:
-
Будьте вежливы, чтобы исследовать (си), чтобы спросить (би)
-
Будьте вежливы, чтобы исследовать (си), чтобы спросить (би)
-
Прощупать (си) спросить (би) очень вежливо
Конкретные детали были даны ранее в Zhihu, поэтому я не буду повторять их здесь. Портал:Внешняя и внутренняя части разделены, и данные, возвращаемые серверной частью, не могут быть записаны во внешнюю часть. Что мне делать?
3. Повышение эффективности человека
В предыдущем пункте я говорил о сотрудничестве на уровне разработки. Здесь давайте поговорим о повышении эффективности человека.
Всем известно, что если проект сможет завершить разработку + совместную отладку + тестирование + запуск в заданные сроки, самое главное — это эффективность работы каждого. Мы не можем гарантировать, что все будут очень эффективными, но мы должны гарантировать собственную эффективность разработки.
Когда появляется спрос, первое, что мы должны обеспечить, — это наше собственное понимание спроса. Как правило, ветераны, пройдя требования один раз, будут иметь общее представление о том, сколько времени потребуется для выполнения требований, в то время как новички никогда не будут иметь четкого представления о времени выполнения.
Итак, как повысить эффективность разработки?
- Разделите требования на модули
- Снова разделите вещи в модулях на мелкие детали
- Оцените время разработки самих мелких деталей
- Время разработки для оценки некоторых возможных точек риска в мелких деталях
- Оцените время совместной отладки
- Зарезервировать тест + исправить ошибку
- Крайний срок бронирования (обычно 1 * (1 + 0,2))
- Организуйте свои собственные узлы разработки в единицах 1D (один день)
- Причины риска записи, точки риска и соответствующие планы избегания
- Если есть подозрение, что оно будет отложено, следует вовремя дать план исправления (например, сверхурочная работа).
- Запишите количество BUG и соответствующий персонал BUG (на самом деле не для сброса)
Суммировать
Статья почти здесь. Я рассказал об отборе до создания проекта, инфраструктуре на ранней стадии проекта, использовании ts в .vue и даже некоторых вещах о совместной работе в команде при разработке проекта. Но ведь стиль написания ограничен, и многие моменты нельзя объяснить прямолинейно, и большинство из них останавливается на конце. Если вы считаете, что статья будет полезна вашим друзьям, не скупитесь на лайки.
Если вы, ребята, хотите узнать больше, присоединяйтесь к моей группе общения: 731175396