حقا vue الكتابة

شعار


inb4: هذا ليس آخر "إعداد" مشروع جديد مع البرنامج التعليمي Vue و TypeScript. دعونا نفعل بعض الغوص العميق في مواضيع أكثر تعقيدا!


typescript هو رائع. Vue رائع. لا شك أن الكثير من الناس يحاولون تجميعهم معًا . ولكن ، لأسباب مختلفة ، من الصعب حقًا كتابة تطبيق Vue . دعنا نتعرف على المشكلات وما الذي يمكن عمله لحلها (أو على الأقل تقليل التأثير).


TLDR


لدينا هذا القالب الرائع مع Nuxt و Vue و Vuex و jest المكتوب بالكامل. مجرد تثبيته وسيتم تغطية كل شيء بالنسبة لك. انتقل إلى المستندات لمعرفة المزيد.


وكما قلت ، لن أرشدك خلال الإعداد الأساسي لثلاثة أسباب:


  1. هناك الكثير من الدروس الموجودة حول هذا الموضوع
  2. هناك الكثير من الأدوات للبدء بنقرة واحدة مثل Nuxt و vue-cli Nuxt مع البرنامج المساعد typescript
  3. لدينا بالفعل wemake-vue-template حيث يتم بالفعل تغطية كل جزء من الإعداد الذي سأتحدث عنه

كتابة المكونات


أول توقّع عند بدء العمل باستخدام Vue و typescript وبعد كتابة مكونات فصلك بالفعل هو أن علامات <template> و <style> لا تزال غير مكتوبة. دعني أريك مثالاً:


 <template> <h1 :class="$style.headr"> Hello, {{ usr }}! </h1> </template> <script lang="ts"> import Vue from 'vue' import Component from 'vue-class-component' import { Prop } from 'vue-property-decorator' @Component({}) export default class HelloComponent extends Vue { @Prop() user!: string } </script> <style module> .header { /* ... */ } </style> 

لقد قمت بعمل خطأين هنا: {{ usr }} بدلاً من {{ user }} و $style.headr بدلاً من $style.header . هل typescript من هذه الأخطاء؟ كلا ، لن.


ما الذي يمكن عمله لإصلاحه؟ حسنا ، هناك العديد من الخارقة.


كتابة القالب


يمكن للمرء استخدام Vetur مع خيار vetur.experimental.templateInterpolationService لكتابة القوالب الخاصة بك. نعم ، هذه مجرد عملية تدقيق تعتمد على المحرر ولا يمكن استخدامها داخل CI حتى الآن. ولكن ، فريق Vetur يعمل بجد لتوفير CLI للسماح بذلك. تتبع القضية الأصلية في حال كنت مهتما.


vetur


الخيار الثاني هو اثنين من اختبارات لقطة الكتابة مع jest . وسوف يمسك الكثير من الأخطاء المستندة إلى القالب. وهي رخيصة جدا في الصيانة.


لذلك ، يوفر لك الجمع بين هاتين الأداتين تجربة مطور لطيفة مع ردود فعل سريعة وطريقة موثوقة للوقوف على الأخطاء داخل CI.


أنماط الكتابة


تتم تغطية الكتابة css-module s أيضًا بالعديد من الأدوات الخارجية:



الفكرة الرئيسية لهذه الأدوات هي جلب css-module s ثم إنشاء ملفات .d.ts منها. ثم سيتم كتابة الأنماط الخاصة بك بالكامل. لا يزال غير مطبق على Nuxt أو Vue ، ولكن يمكنك Nuxt هذه المشكلة للتقدم.


ومع ذلك ، لا أستخدم أيًا من هذه الأدوات شخصيًا في مشاريعي. قد تكون مفيدة للمشروعات ذات قواعد الشفرة الكبيرة والكثير من الأنماط ، لكنني بخير مع لقطات فقط.


كما تساعد دلائل التصميم مع اختبارات الانحدار المرئي الكثير. @storybook/addon-storyshots مثال جميل على هذه التقنية.


Vuex


الشيء الكبير التالي هو Vuex . لديها بعض التعقيد المدمج في التصميم للكتابة:


 const result: Promise<number> = this.$store.dispatch('action_name', { payload: 1 }) 

المشكلة هي أنه قد لا يوجد 'action_name' ، أو يأخذ وسيطات أخرى ، أو يعرض نوعًا مختلفًا. هذا ليس شيئًا تتوقعه للتطبيق المكتوب بالكامل.


ما هي الحلول الحالية؟


vuex من الدرجة


vuex-class هي مجموعة من الديكورات تتيح الوصول بسهولة من المكونات القائمة على الفصل إلى Vuex الداخلية من Vuex .


لكن ، لم يتم كتابتها بشكل آمن نظرًا لأنه لا يمكن أن يتداخل مع أنواع الحالة والأخطاء والطفرات والإجراءات.


vuex من الدرجة


بالطبع ، يمكنك تعليق أنواع الخصائص يدويًا.


فئة vuex المشروح


ولكن ماذا ستفعل عندما يتغير النوع الحقيقي لحالتك أو حيلتك أو طفراتك أو أفعالك؟ سيكون لديك عدم تطابق نوع مخفي.


vuex-بسيطة


حيث vuex-simple . إنه يوفر بالفعل طريقة مختلفة تمامًا لكتابة كود Vuex وهذا ما يجعله آمنًا. دعونا نلقي نظرة:


 import { Action, Mutation, State, Getter } from 'vuex-simple' class MyStore { // State @State() public comments: CommentType[] = [] // Getters @Getter() public get hasComments (): boolean { return Boolean(this.comments && this.comments.length > 0) } // Mutations @Mutation() public setComments (payload: CommentType[]): void { this.comments = updatedComments } // Actions @Action() public async fetchComments (): Promise<CommentType[]> { // Calling some API: const commentsList = await api.fetchComments() this.setComments(commentsList) // typed mutation return commentsList } } 

في وقت لاحق ، يمكن تسجيل هذه الوحدة النمطية المكتوبة داخل Vuex مثل:


 import Vue from 'vue' import Vuex from 'vuex' import { createVuexStore } from 'vuex-simple' import { MyStore } from './store' Vue.use(Vuex) // Creates our typed module instance: const instance = new MyStore() // Returns valid Vuex.Store instance: export default createVuexStore(instance) 

الآن لدينا نسخة Vuex.Store أصلية 100 ٪ من Vuex.Store وجميع معلومات النوع Vuex.Store به. لاستخدام هذا المتجر المكتوب في المكون ، يمكننا كتابة سطر واحد فقط من الكود:


 import Vue from 'vue' import Component from 'nuxt-class-component' import { useStore } from 'vuex-simple' import MyStore from './store' @Component({}) export default class MyComponent extends Vue { // That's all we need! typedStore: MyStore = useStore(this.$store) // Demo: will be typed as `Comment[]`: comments = typedStore.comments } 

الآن Vuex التي يمكن استخدامها بأمان داخل مشروعنا.
عندما نغير شيئًا ما داخل تعريف متجرنا ، فإنه ينعكس تلقائيًا على المكونات التي تستخدم هذا المتجر. إذا فشل شيء ما - فنحن نعرف ذلك في أسرع وقت ممكن.


هناك أيضًا مكتبات مختلفة تفعل الشيء نفسه ولكن لها واجهة برمجة تطبيقات مختلفة. اختر ما يناسبك.


مكالمات API


عندما يكون لدينا إعداد Vuex بشكل صحيح ، نحتاج إلى ملء البيانات.
دعونا نلقي نظرة على تعريف عملنا مرة أخرى:


 @Action() public async fetchComments (): Promise<CommentType[]> { // Calling some API: const commentsList = await api.fetchComments() // ... return commentsList } 

كيف يمكننا أن نعرف أنه سيعود حقًا بقائمة CommentType وليس رقمًا واحدًا أو مجموعة من مثيلات AuthorType ؟


لا يمكننا التحكم في الخادم. وقد يكسر الخادم العقد بالفعل. أو يمكننا ببساطة اجتياز مثيل api الخاطئ أو عمل خطأ مطبعي في عنوان URL أو أيًا كان.


كيف يمكن أن نكون آمنين؟ يمكننا استخدام الكتابة وقت التشغيل! اسمحوا لي أن أعرض io-ts لك:


 import * as ts from 'io-ts' export const Comment = ts.type({ 'id': ts.number, 'body': ts.string, 'email': ts.string, }) // Static TypeScript type, that can be used as a regular `type`: export type CommentType = ts.TypeOf<typeof Comment> 

ماذا نفعل هنا؟


  1. نحدد مثيل ts.type مع الحقول التي نحتاج إلى التحقق منها في وقت التشغيل عندما نتلقى استجابة من الخادم
  2. نحدد نوعًا ثابتًا ليتم استخدامه في التعليق التوضيحي دون أي غليان إضافي

وفي وقت لاحق يمكننا استخدامه ندعو api لدينا:


 import * as ts from 'io-ts' import * as tPromise from 'io-ts-promise' public async fetchComments (): Promise<CommentType[]> { const response = await axios.get('comments') return tPromise.decode(ts.array(Comment), response.data) } 

بمساعدة io-ts-promise ، يمكننا إرجاع Promise في حالة فاشلة إذا كانت استجابة الخادم لا تتطابق مع نوع ts.array(Comment) . انها تعمل حقا مثل التحقق من الصحة.


 fetchComments() .then((data) => /* ... */ .catch(/* Happens with both request failure and incorrect response type */) 

علاوة على ذلك ، فإن التعليقات التوضيحية لنوع الإرجاع تكون متزامنة مع طريقة .decode . ولا يمكنك وضع هراء عشوائي هناك:


IO-TS


مع الجمع بين وقت التشغيل والشيكات الثابتة ، يمكننا أن نتأكد من أن طلباتنا لن تفشل بسبب عدم تطابق النوع.
ولكي أكون متأكداً 100 ٪ من أن كل شيء يعمل ، أوصي باستخدام اختبار قائم على العقود: إلقاء نظرة على pact كمثال. ومراقبة التطبيق الخاص بك مع Sentry .


جهاز التوجيه فو


المشكلة التالية هي أن this.$router.push({ name: 'wrong!' }) لا يعمل بالطريقة التي نريدها.


أود أن أقول أنه سيكون من المثالي أن يحذر من قبل المترجم أننا نوجه إلى الاتجاه الخاطئ وهذا الطريق غير موجود.
لكن هذا غير ممكن. ولا يمكن القيام بالكثير: هناك الكثير من الطرق الديناميكية ، و regex ، و backbacks ، والأذونات ، وغيرها التي يمكن أن تنهار في النهاية. الخيار الوحيد هو اختبار كل this.$router call في تطبيقك.


VUE اختبار تيلس


بالحديث عن الاختبارات ، ليس لدي أي أعذار ناهيك عن ذكرها @vue/test-utils التي لديها أيضًا بعض المشكلات في الكتابة.


عندما سنحاول اختبار typedStore اللامع الجديد باستخدام خاصية typedStore ، typedStore أننا لا نستطيع فعل ذلك وفقًا typescript :


VUE اختبار تيلس


لماذا يحدث هذا؟ يحدث ذلك لأن استدعاء mount() لا يعرف شيئًا عن نوع المكون الخاص بك ، لأن جميع المكونات لها نوع VueConstructor<Vue> افتراضيًا:


VUE-منشئ


هذا هو المكان الذي تأتي منه جميع المشاكل. ما الذي يمكن عمله؟
يمكنك استخدام vuetype لإنتاج YouComponent.vue.d.ts YouComponent.vue.d.ts التي ستخبر اختباراتك بالنوع الدقيق للمكون المركب.


يمكنك أيضًا تتبع هذه المشكلة للتقدم.


ولكن ، أنا لا أحب هذه الفكرة. هذه اختبارات ، يمكن أن تفشل. لا صفقة كبيرة.
لهذا السبب أنا (wrapper.vm as any).whatever . (wrapper.vm as any).whatever النهج. هذا يوفر لي الكثير من الوقت لكتابة الاختبارات. ولكن يفسد تجربة المطور قليلاً.


اتخذ قرارك الخاص هنا:


  • استخدام vuetype على طول الطريق
  • قم بتطبيقه جزئيًا على أهم المكونات مع أكبر قدر من الاختبارات وقم بتحديثه بانتظام
  • استخدم any كاحتياطي

استنتاج


زاد متوسط ​​مستوى دعم typescript في نظام Vue على مدار العامين الماضيين:


  • Nuxt أولاً قدم nuxt-ts والآن السفن ts يبني بشكل افتراضي
  • سوف Vue@3 قد تحسنت دعم typescript
  • المزيد من تطبيقات الطرف الثالث والإضافات ستوفر تعريفات النوع

ولكن ، هو الإنتاج جاهزة في الوقت الراهن. هذه مجرد أشياء يجب تحسينها! إن كتابة كود Vue الآمن من نوعه يحسن حقًا تجربة Developer الخاصة بك ويسمح لك بالتركيز على الأشياء المهمة مع ترك الرفع الثقيل للمترجم.


ما هي الاختراقات والأدوات المفضلة لكتابة تطبيقات Vue ؟ دعنا نناقشه في قسم التعليقات.

Source: https://habr.com/ru/post/ar458632/


All Articles