Language-tools: نظرة عامة على الأساليب على خادم اللغة

تم إنشاؤها على ٢٤ مارس ٢٠٢٠  ·  37تعليقات  ·  مصدر: sveltejs/language-tools

هذا الخيط مخصص لإلقاء نظرة عامة على الطرق الخاصة بكيفية تنفيذ خادم لغة لملفات svelte. يمكن إجراء مناقشة حول الحل المفضل هنا أيضًا.

الحالة الحالية لخادم اللغة

تسليط الضوء حاليًا على بناء الجملة وبعض أعمال الإكمال التلقائي الأساسية لملفات svelte.
ومع ذلك ، لا يتم توفير التحسس الغني ، ولا يعرف عن جميع ملفات الكتابة المطبوعة في مساحة العمل ، كما أنه لا يحتوي على معلومات حول نوع المكونات السفلية.
وينطبق الشيء نفسه على جزء html حيث يتم تمييز بناء جملة خاص ولكن intellisense لا يعمل. يتم استخدام vscode-html-languageservice التي لا تعرف بناء الجملة الخاصة افتراضيًا.
يستخدم خادم اللغة الحالي مترجم svelte لتحليل الملفات والحصول على تشخيصات مثل "لا توجد سمة بديلة في علامة img هذه".
تحليل أكثر عمقًا: التعليق

الأساليب / الحلول الحالية

إخلاء المسؤولية: أنا لست مؤلفًا لأي من الحلول الحالية ، ولكني نظرت في الكود. إذا كانت بعض المعلومات خاطئة أو غير مفصلة بشكل كافٍ ، أو كنت تفتقد حلاً ، فلا تتردد في التعليق ، وسأقوم بتعديلها.

https://github.com/alexprey/sveltedoc-parser

يستخدم htmlparser2 لتحليل جزء html من ملف svelte. يستخدم خطافات محلل html لإضافة تحليل مخصص واستخراج المعلومات ذات الصلة.
يستخدم espree لتحليل أجزاء البرنامج النصي من ملف svelte. ثم يمشي في AST لاستخراج المعلومات ذات الصلة.
يوفر النتائج بتنسيق JSON.

https://github.com/ArdenIvanov/svelte-intellisense يستخدمه لتحليل الملفات المنفردة. يستخدم النتيجة لإرفاق بعض السلوك الإضافي.

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

https://github.com/halfnelson/svelte2tsx

يستخدم مترجم svelte لتحليل جزء HTMLx من مكون svelte. ثم يحول HTMLx بالإضافة إلى جزء البرنامج النصي الأصلي إلى ملف tsx بمحول مكتوب ذاتيًا.

https://github.com/simlrh/svelte-language-server/blob/feature/extend-ts-support/src/plugins/ts-svelte/service.ts (تفرع من svelte-language-server) يستخدمه في إنشاء ملفات الظل tsx للملفات الرشيقة. ثم يستخدم خدمة اللغة الخاصة بالطباعة ، ولكنه يقوم بتوكيل الطلبات: فهو يستبدل مسار الملف الأصلي بمسار الملف إلى ملف tsx الذي تم إنشاؤه. وبالتالي ، يتحقق خادم اللغة المطبوع عليها من ملفات tsx التي تم إنشاؤها. يتم تحويل النتائج مرة أخرى للحصول على مواضع المستندات الصحيحة.

https://github.com/halfnelson/svelte-type-checker-vscode هو خادم لغة آخر يستخدم مكتبة svelte2tsx.

https://github.com/marcus-sa/svelte-ts

الوصف مأخوذ من تعليق المنفذ :

مترجم:

  1. يقرأ المترجم جميع الملفات المصدر
  2. يتم التخلص من كل شيء باستثناء محتوى علامات البرنامج النصي
  3. يتم تجميع الكود المصدري للبرنامج النصي في JS وملفات التصريح الصالحة.
  4. ينتقل إلى الخطوة 2 ، حيث يستبدل مصدر TS في علامات البرنامج النصي بـ JS المترجم
  5. المترجم Svelte يجمع الملف المصدر بأكمله
  6. يتم تخزين تجميع الإخراج للخطوة أعلاه مؤقتًا ، حيث يتم استخدام HTML AST في مدقق النوع.

يستهلك المتغيرات والوظائف التي تم تصديرها من داخل برنامج Svelte النصي ، ثم يقوم بإنشائه كملفات إعلان تحتوي على فئة تعمل على تمديد وقت تشغيل SvelteComponent.

فاحص الطابعات:

  1. يبحث مدقق النوع عن جميع المكونات في ذاكرة التخزين المؤقت AST.
  2. التحقق من أن جميع المكونات في القالب هي فئة صالحة تعمل على توسيع SvelteComponent
  3. التحقق من صحة الإعلانات والخصائص وما إلى ذلك.

مناهج أخرى

انظر تعليقات هذا الموضوع.

التعليق الأكثر فائدة

حسنا عظيم! سأقوم بعمل بعض العلاقات العامة لإعادة هيكلة بعض الكود وإعداده حتى نتمكن بعد ذلك من موازنة العمل على العناصر الفردية.

ال 37 كومينتر

لذلك لا أحد منهم يستخدم محلل Svelte؟

يقوم svelte2tsx بإخراج علامات النمط / البرنامج النصي ثم يستخدم مترجم svelte لتحليل جزء htmlx.
يستخدم svelte-ts مترجم svelte كخطوة ثانية.
لا يستخدم خادم اللغة الحالي مترجم svelte للتحليل.
سوف أقوم بتحديث المنشور الأولي.

لم أكن متأكدًا مما إذا كان يجب علي مشاركة هذا ، ولكن قد يكون جزءًا منه مفيدًا. في العام الماضي (يوليو / أغسطس 2019) بدأت في اللعب بفحص الكتابة على Svelte ، مع العلم أنني كنت أقوم بعمل رمي للتعلم فقط. إنه يدعم قدرًا غير معروف من الحل الكامل ، ربما 30٪ ، وله بعض القيود (المزيد عن تلك لاحقًا). لا توجد أي اختبارات أو وثائق خارجية لأنني اعتبرها دائمًا طريقًا مسدودًا.

يسير تجميع Svelte كما هو الحال اليوم مع معالج TS غير مطبعي. إذا كنت تريد أنواعًا في ترميز HTMLx الخاص بك ، وليس فقط علامة البرنامج النصي الخاص بك ، فستحتاج إلى معالج مسبق للتعامل مع ذلك ، أو ستحتاج Svelte إلى التعامل مع TS داخليًا.

أداة فحص الكتابة عبارة عن خطوة بناء منفصلة تستخدم رمز TypeScript غير المعالج مسبقًا من كتل script وعلامة AST من svelte.compile لإنشاء ملف Svelte TypeScript افتراضي لأغراض فحص الكتابة فقط. (هنا حيث ينشئ المكون الإضافي Rollup بفحصه ) إنه مشابه لاستراتيجيةhalfnelson ، ولكنه مختلف من حيث أنه ينتج TS عادي ، وليس TSX ، لذلك في الترميز لا يحاول كتابة علامات HTML و السمات ، فقط الأشياء الموجودة داخل علامات الشارب ومكونات Svelte. إنه يحول مكونات Svelte إلى مُنشئين يحصلون على new ed مع الدعائم الخاصة بهم. لقد حصلت على جزء من الطريق من خلال دعم الكثير من تصميمات Svelte قبل أن أدرك أنني انجرفت أكثر مما كنت أقصده ، ويجب أن يكون التقدم الإضافي في الهندسة الجادة.

تُستخدم واجهة برمجة تطبيقات التحويل البرمجي TypeScript لإنشاء برنامج في الذاكرة وفحص Svelte TS الظاهري. على عكس Svelte ، فإن نظرتها للعالم هي برامج كاملة ، وليست ملفات فردية. في ذلك الوقت ، بدا أنه سيكون من السهل إضافة تجميع تراكمي وخيوط عامل كتحسينات مستقبلية.

يتم إنشاء ملف Svelte TS الظاهري باستخدام خريطة مصدر يتم استخدامها بعد ذلك

كانت إحدى المشكلات التي أتذكرها والتي لم أستطع اكتشافها هي التشخيصات التي لم تكن محددة بما يكفي في بعض الحالات. مثال IIRC كان مع فحص الكتابة على دعائم مُنشئ مكون Svelte - سيشير VSCode بطريقة ما إلى أخطاء الخاصية الفردية ، لكن تشخيصات TS التي كنت أحصل عليها كانت تشير فقط إلى المُنشئ ، وليس خاصية المشكلة.

إذا نظرت في الكود ، فاحذر من أن الأجزاء في حالة من الفوضى وقد تكون بعض التعليقات قديمة. لقد استخدمت في الأصل magic-string وفي وقت ما تغيرت إلى source-map . وتذكر أنه كان مسعى محكوم عليه بالفشل منذ البداية! لاحظ أن كل هذا موجود في فرع ts من هذا الريبو ، وليس master .

فيما يلي الملفات الأربعة المشار إليها أعلاه:

لقد قمت ببعض التنقيب في الكود المصدري لخادم اللغة svelte الحالي. فيما يلي أفكاري حول الجزء المطبوع منه:

ملخص

يعمل خادم اللغة على نطاق واسع مثل هذا:

  • يتعامل DocumentManager مع كافة المستندات التي يتم فتحها.
  • يتم استدعاء تسجيلات TypescriptPlugin في DocumentManager ليتم استدعاؤها في أحداث خادم اللغة ("doHover" وما إلى ذلك). لا يتم تسجيله مباشرة: يتم تغليفه بـ wrapFragmentPlugin مما يضمن أن TypescriptPlugin يحصل فقط على المحتوى داخل علامة script . يتم تعيين المواضع (الماوس / مؤشر النص) في wrapFragmentPlugin لضمان عرض المعلومات في الموضع الصحيح.
  • يستخدم TypescriptPlugin service ، وهو برنامج تضمين لخدمة اللغة المطبوعة. يقوم بشكل أساسي بتفويض جميع الأحداث إلى خادم اللغة هذا ، مع بعض التعيين للالتزام بأنواع إرجاع الطريقة.
  • يأخذ service المستند لأداء العمل بالإضافة إلى طريقة createDocument من TypescriptPlugin . يحتفظ service بخريطة المستندات الخاصة به والتي هي في الأساس مجرد مندوب إلى مستند DocumentsManager . في كل مرة يتم استدعاء service من TypescriptPlugin ، يقوم service بتحديث خريطة مستنداته بالمستند المحدد (بعد تغليفه). سيتم استدعاء createDocument إذا فتحت خدمة اللغة مستندًا لم يكن بعد جزءًا من خريطة المستندات - لكن هذا لن يحدث أبدًا لأن خدمة اللغة المطبوعة لا تعثر على وحدات نمطية أخرى (انظر القسم التالي).

أوجه القصور الحالية والأفكار للتحسين

  • نظرًا لأن علامة البرنامج النصي تُعطى كما هي لخدمة اللغة المطبوعة ، فلا يمكنها التعامل مع بناء الجملة الرقيق الخاص ($).
  • تحاول خدمة اللغة المطبوعة البحث عن الملفات الأخرى المشار إليها في ملف svelte المفتوح حاليًا. بالنسبة لملفات .ts / .js ، لا يعمل هذا الأمر بالنسبة لملفات .svelte . السبب: لا تعرف خدمة اللغة المطبوعة عن نهاية .svelte ، لذلك تفترض فقط أنه ملف منسوخ عادي ويبحث عن ملفات مثل ../Component.svelte.ts ، وهذا خطأ. لإصلاح ذلك ، نحتاج إلى تنفيذ الطريقة resolveModuleNames على LanguageServiceHost وإعادة توجيه جميع عمليات البحث عن الملفات .svelte.ts إلى .svelte . ثم ستعمل خدمة اللغة على السير مع جميع الملفات الرشيقة. ملاحظة: من أجل تنفيذ هذا ، نحتاج أيضًا إلى إصلاح الخطأ التالي: نظرًا لأن خدمة اللغة المطبوعة الآن ستعمل على نقل جميع الملفات ، فإنها ستستدعي createDocument من TypescriptPlugin . لكن هذا حاليًا يعيد المستند بالكامل ، وليس المحتوى الموجود داخل علامة البرنامج النصي فقط. هذا خطأ داخل wrapFragmentPlugin لا يلتف openDocument .
  • من أجل تنفيذ المزيد من الميزات المتقدمة مثل "go to svelte file" من خلال النقر على اسم استيراد المكون svelte ، أو إنشاء علامات $ ، نحتاج إلى إضافة معالج مسبق. هذا المعالج سيضيف بطريقة ما الأجزاء المفقودة للطباعة. من الناحية المثالية ، يمكن وضع جميع العناصر الإضافية فوق الكود الحالي ، بحيث يكون تعيين المواضع سهلاً مثل تعيين المواضع باستخدام الإزاحات. وهذا يمثل تحديًا آخر: سيكون لدينا الآن تعيينان للموضع: أحدهما من ملف svelte بالكامل إلى علامة البرنامج النصي ، والآخر من علامة البرنامج النصي إلى التعليمات البرمجية المطبوعة مسبقًا. لست متأكدًا في هذه المرحلة مما إذا كان هذا هو السبيل للذهاب أو إذا كان علينا إعادة صياغة كيفية الحصول على المستند TypescriptPlugin (وآخرون) - ربما يجب أن يتم استخراج علامة البرنامج النصي والمعالجة المسبقة في خطوة واحدة . قد يعني هذا تغيير أو استبدال wrapFragmentPlugin بالكامل. حجة أخرى لإعادة العمل هي أنه من أجل تحديد أشياء بشكل صحيح مثل "وظيفة غير مستخدمة" ، يجب أن نأخذ جزء html في الاعتبار ، وبالتالي فإن علامة البرنامج النصي ليست كافية.

أفكار؟

في resolveModuleNames ، إليك الطريقة التي فعلها أحد أعضاء فريق TypeScript لصالح Vetur ، وإليك إصدارًا مشابهًا قمت به من أجل Svelte ، والذي يتضمن تعليقًا يذكر استراتيجية بديلة نجحت ، ولكن يبدو أن نسخ Vetur أفضل.

dummdidumm هل تمانع في أن تتصرف

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

يتم أيضًا الربط إلى منشور LSP الأصلي الخاص بـ orta للآخرين الذين يتصفحون https://github.com/sveltejs/svelte/issues/4518

بالتأكيد أرغب في المساعدة في هذا الأمر ، لكن في الوقت الحالي أنا مجرد شخص عشوائي متحمس جدًا لخادم اللغة ، والبحث في الشفرة وتقديم بعض الاقتراحات 😄 أحتاج أيضًا إلى مزيد من الوقت للتعرف على الكود ، هندستها المعمارية و lsp بشكل عام. لكنني بالتأكيد على استعداد لدفع الأمور إلى الأمام. orta بما أنك

👋 نعم ، كلانا شخص عشوائي يهتم فقط - ليس لدي حتى أي أكواد برمجية دقيقة لتشغيل حكة "يجب أن يكون هذا أفضل". لذلك ، أنا سعيد جدًا برؤية أي حركة على الإطلاق - @ dummdidumm -

حسنا عظيم! سأقوم بعمل بعض العلاقات العامة لإعادة هيكلة بعض الكود وإعداده حتى نتمكن بعد ذلك من موازنة العمل على العناصر الفردية.

ربما يمكننا الجمع بين نهجryanatkn و svelete-ts وطريقة eslint-plugin-svelte3 المتغيرة:

  1. استخدام svelte preprocess للمعالجة المسبقة للبرنامج النصي إلى js.
    هنا يمكننا الانتقال إلى الإصدار الأحدث أو التالي من ES لإجراء أقل قدر ممكن من التحول.
  2. اسمحوا svelte ترجمة المصدر المجهز مسبقًا.
  3. يمكننا بعد ذلك حقن متغيرات النتائج حيث injected = true في مثيل ts source أو ts AST ثم استخدامها مع خريطة المصدر لتوفير التحقق من النوع والإكمال التلقائي.

يمكن أن يحتوي البرنامج النصي على ثلاثة أجزاء: الوحدة النمطية <script context="module"> ، مثيل وشارب (نموذج). يمكن أن يكون جزء الشارب مجرد تفريغ في template.js في الوقت الحالي. ولكن على المدى الطويل يمكننا عكس القالب في tsx أو ts عادي مثل نهج ryanatkn.

متغيرات الوحدة النمطية ، حيث يتم حقن module = true في template.js والمثيل وليس العكس.

بهذه الطريقة ، لا يتعين علينا إعادة التنفيذ بشأن كيفية العثور على المتغير التفاعلي $: a = 1 أو $ -prefixed store في نسخة مطبوعة من AST. هذه المتغيرات التي تم حقنها بواسطة مترجم svelte مستمدة من بيان المستوى الأعلى ونقوم بتحويله إلى أحدث ES. لذلك لا ينبغي في الغالب إعادة تسميته بالطباعة.

حول المتغير التفاعلي $: a يمكن كتابته على النحو التالي:

$: a = 1

""
اسمحوا a: number
$: أ = 1

```ts
$: a = someFunction(b) as Type

كل ما هو صالح ولا يحتاج إلى تحويل قبل التحويل

و$ مخزن -prefixed يمكننا خلق وظيفة عامة مثل ممشوق / مخزن الحصول على استخراج نوع مخزن

/** injected */
let $store = getType(store)
  1. استخدام svelte preprocess للمعالجة المسبقة للبرنامج النصي إلى js.
    هنا يمكننا الانتقال إلى الإصدار الأحدث أو التالي من ES لإجراء أقل قدر ممكن من التحول.
  2. اسمحوا svelte ترجمة المصدر المجهز مسبقًا.
  3. يمكننا بعد ذلك حقن متغيرات النتائج حيث injected = true في مثيل ts source أو ts AST ثم استخدامها مع خريطة المصدر لتوفير التحقق من النوع والإكمال التلقائي.

أعتقد أن svelte-ts تفعل شيئًا من هذا القبيل. تبدو فكرة جيدة. في injected = true : ما الرمز الذي يحتوي على هذه الخاصية بالضبط؟

يمكن أن يحتوي البرنامج النصي على ثلاثة أجزاء: الوحدة النمطية <script context="module"> ، مثيل وشارب (نموذج). يمكن أن يكون جزء الشارب مجرد تفريغ في template.js في الوقت الحالي. ولكن على المدى الطويل يمكننا عكس القالب في tsx أو ts عادي مثل نهج ryanatkn.

متغيرات الوحدة النمطية ، حيث يتم حقن module = true ، في template.js والمثيل وليس العكس.

بهذه الطريقة ، لا يتعين علينا إعادة التنفيذ بشأن كيفية العثور على المتغير التفاعلي $: a = 1 أو $ -prefixed store في نسخة مطبوعة AST. هذه المتغيرات التي تم حقنها بواسطة مترجم svelte مستمدة من بيان المستوى الأعلى ونقوم بتحويله إلى أحدث ES. لذلك لا ينبغي في الغالب إعادة تسميته بالطباعة.

هل تريد تقسيم الملف إلى ملف افتراضي .ts وملف .template -file؟ لماذا لا توجد أجزاء الشارب أسفل الملف .ts ؟ بهذه الطريقة نتخلص أيضًا من تحذيرات "الطريقة غير المستخدمة". عند السير في AST: نعم ، أعتقد أننا يمكن أن نكون أذكياء هنا ونتخطى النظر في AST كثيرًا لأن كل ما تتم الإشارة إليه في النموذج يجب أن يكون على أعلى مستوى في البرنامج النصي.

حول المتغير التفاعلي $: a يمكن كتابته على النحو التالي:

$: a = 1
let a: number
$: a = 1

أو

$: a = someFunction(b) as Type

كل ما هو صالح ولا يحتاج إلى تحويل قبل التحويل

هل من الممكن استنتاج النوع؟ ربما يكون هذا مجرد شيء نتركه كما هو وإذا أراد المستخدم استخدام الكتابة المطبوعة ، فعليه تحديد let a: number بنفسه. كبديل ، يمكننا إدخال let a; ، لكن بعد ذلك سيكون any .

و$ مخزن -prefixed يمكننا خلق وظيفة عامة مثل ممشوق / مخزن الحصول على استخراج نوع مخزن

/** injected */
let $store = getType(store)

نعم هذا يبدو لطيفا. كانت الفكرة الأخرى التي خطرت لي هي بناء حاصل على / أدوات تثبيت.

أعتقد أن svelte-ts تفعل شيئًا من هذا القبيل. تبدو فكرة جيدة. في injected = true : ما الرمز الذي يحتوي على هذه الخاصية بالضبط؟

نتيجة التحويل البرمجي لها خاصية متغيرات ، وهي عبارة عن مصفوفة من العناصر التي لها الخاصية التالية:
الاسم ، والاسم_الصادر ، والحقنة ، والوحدة النمطية ، والمتحوَرة ، والمعاد تعيينها ، والمشار إليها_النص_الصادر ، والقابل للكتابة
يمكنك أن ترى svelte compile api لمزيد من المعلومات

هل تريد تقسيم الملف إلى ملف ظاهري .ts وملف نموذجي؟ لماذا لا توجد أجزاء الشارب في الجزء السفلي من ملف .ts؟ بهذه الطريقة نتخلص أيضًا من تحذيرات "الطريقة غير المستخدمة".

هذا هو نهج eslint-plugin-svelte3 . لقد فكرت فقط إذا كنا نريد دعم ts في القالب لأنه لا توجد سمة لتحديد اللغة.

هل من الممكن استنتاج النوع؟

نظرًا لأن هذا المصدر الافتراضي يستخدم فقط لفحص النوع والإكمال التلقائي ، أفترض أنه يمكن تحقيقه بمجرد نسخ أول بيان تعيين لتهيئته ولكن يبدو أنه يحتاج إلى مزيد من العمل.

هل من الممكن استنتاج النوع؟ ربما يكون هذا مجرد شيء نتركه كما هو ، وإذا أراد المستخدم استخدام الكتابة المطبوعة ، فعليه تحديد let a: number بنفسه. كبديل ، يمكننا إدخال let a ؛ ولكن بعد ذلك سيكون أي.

يبدو أن الاستدلال العادي لا يقودنا إلى كل هذا الطريق. (هل تقصد استدلال وقت الترجمة؟ لست متأكدًا مما إذا كان ذلك ممكنًا أم لا)

let a; // type is "any" initially
$: a = 5;
a; // type is now "number", good
const cb = () => a; // type is implicitly "any", noo

والسبب هو أنه في تدفق التعليمات البرمجية الخطي ، يمكن أن ترى TypeScript a لم تتم إعادة تعيينه ، لكن نطاقات الوظائف المتداخلة لا تحتوي على هذا الضمان ، ويخطئ TypeScript في جانب أمان النوع.

مثال الملعب

بالضبط ، هذه كانت مخاوفي من ذلك. ولكن كما أشار @ jasonlyu123 ، يمكننا فقط نسخ التعريف (كل شيء بعد = ).

قبل

$: a = true;

بعد، بعدما

let a = true;
$: a = true;

لكني لا أعرف ما إذا كان ذلك ممكنًا في جميع الظروف. خاصة مع الكائنات الكبيرة حيث يقوم شخص ما بتنفيذ واجهة ، لن يستنتج هذا كل شيء كما قد يتوقع المستخدم. أيضا ، يمكن أن تصبح نسخ المعكرونة كبيرة جدًا. لذلك ما زلت أؤيد "السماح للمستخدم بكتابته".

شكرًا للتوضيح ، لقد أساءت فهم ما قاله

هل هناك مثال عندما لا يكون هذا سلوكًا افتراضيًا جيدًا؟ يبدو أنه يفعل الشيء الصحيح المريح في معظم الأوقات ، ويمكن إصلاح الحالات الأخرى يدويًا. إليك بعض الأمثلة.

أعتقد أنك على حق. إنه الشيء الأكثر راحة. ما يقلقني هو ما إذا كان النوع المستنتج خاطئًا ، على سبيل المثال الخاصية هي string بدلاً من اتحاد محدد من السلاسل ( 'a' | 'b' ). ولكن كما قلت ، فإن هذه الحالات ليست شائعة ومن ثم لا يزال بإمكان المستخدم كتابتها يدويًا.

هناك جزء مني مثل: "رائع ، بناء الجملة الصريح يعمل بشكل رائع" ولكن هذا لن يعمل مع دعم JS خارج الصندوق

ماذا عن مجرد استبدال الملصق الأول للسماح بما يلي:

$: a = 1
$: a = 2

الحصول على تحويل

/** injected  */
let a = 1
$: a = 2

أعيد التفكير قليلاً ولا يمكنني العثور على ميزة "تعريف النسخ" على "استبدال $: بـ let ". هل يمكنكم التفكير في أي عيب في استبدال $: بـ let ؟

حول اختلاف النوع المستنتج إلى ما توقعه المستخدم ، هل يمكننا توفير إجراءات إعادة البناء لتحويله إلى تعريف يدوي؟ سيحث هذا الإجراء المستخدم على كتابة متغير يدويًا مثل هذا ، أو إعادة معاملته لنوعه المستنتج إن أمكن.

قبل

$: a = 'const1'

بعد، بعدما

let a : AskUserForType
$: a = 'const1'

يفكر أيضًا في الأشياء التي تشير إليها ، تعلمت شيئًا 👍

Ha ، فكرة ذكية ، استبدل بالكامل $: خلال let . أنا أيضًا لا أعرف أي مواقف قد ينتهي بها الأمر بشكل سيء.
يمكننا أيضًا التفكير في إجراء التحويل دائمًا ، ليس فقط من أجل التسمية الأولى. ثم سيكون هناك خطأ "لا يمكن إعادة التصريح" والذي يلمح للمستخدم عند "woops ، لقد حددت هذا المتغير مرتين" - أو هل هناك حالات يكون فيها هذا ممكنًا وليس خطأ؟

جميل ، لا يمكنني التفكير في أي سبب لاستبدال الملصق أيضًا. (بما أن break $ لا يعمل أبدًا داخل الواجبات ، أليس كذلك؟)

لإعادة تعريف نفس المتغير التفاعلي ، يبدو أن Svelte يسمح بذلك ويعمل بالترتيب الذي تتوقعه. ( انظر مثال الرد هذا ) لا أرى نفسي شخصيًا أستخدم هذا النمط عن قصد وأريد الخطأ ، لكنه يقع في نطاق تفسير دلالات Svelte ، لذا لا تأخذ كلامي على هذا النحو!

حسنًا ، إعادة تعريفه هو نمط يعمل بالفعل. أود أن أقول إننا نسمح بذلك بشكل أفضل بعد ذلك - أو نجعل علامة ميزة "إعادة الإعلان غير مسموح بها" لاحقًا والتي يتم إيقاف تشغيلها افتراضيًا.

أنشأhalfnelson خادم لغة بناءً على منهجه svelte2tsx في https://github.com/halfnelson/svelte-type-checker-vscode . أنا حقًا أحب مدى جودة كل هذا بالفعل ، لكنني ما زلت أفضل عدم استخدام tsx كمخرجات وسيطة لأنني أخشى أنه قد يكون بطيئًا بعض الشيء ولديه بعض القيود - لكن هذا مجرد شعوري الغريزي. ومع ذلك ، يمكننا أخذ الكثير من svelte2tsx: كيف يتم إجراء تحويل التحويل التجميعي ، وكذلك مجموعة الاختبار الشاملة. كيف يرى الآخرون نهج تحويل الشفرة إلى tsx؟

كنت أفكر في كيف يمكن أن تبدو التحولات الأخرى. وهنا بعض الأمثلة. نرحب بالتعليقات.

كيف يبدو تعريف المكون

إبداعي:

<script>
    import { createEventDispatcher } from 'svelte';
    const dispatch = createEventDispatcher();

    export let todo: string;

    function doneChange() {
        dispatch('doneChange', true);
    }
</script>

تم تحويله:

export default class Component {
   constructor(props: {todo: string; 'on:doneChange': (evt: CustomEvent<boolean>) => void}) {}
}

import { createEventDispatcher } from 'svelte';
const dispatch = createEventDispatcher();

export let todo: string;

function doneChange() {
    dispatch('doneChange', !todo.done);
}

تفسير:
بطريقة ما ، احصل على جميع الدعائم (سهلة) والأحداث المرسلة (الصعبة) وأضفها إلى كائن دعائم كبير واحد. يجب أن تؤدي إضافة الأحداث باستخدام on: -prefix إلى تقليل التصادمات وتسهيل تنفيذ اقتراحات الإكمال التلقائي.

(في الأمثلة التالية ، تم حذف تعريف المكون للإيجاز)

استخدم المتغير في النموذج

إبداعي:

<script>const bla = {bla: 'bla'};</script>
<p>{bla.bla}</p>

تم تحويله:

const bla = 'bla';
const _bla = bla.bla;

تفسير:
أضف عناصر const عشوائية ، ربما تكون مسبوقة ببعض رموز unicode الغامضة ، للتحقق من الاستخدامات الصحيحة للمتغيرات ولجعل التحذير "غير المستخدم" يختفي. ربما نحتاج بعد ذلك إلى التفكير في كيفية التخلص من تحذير _bla غير المستخدم ...

استخدم مستمع الحدث الأصلي

إبداعي:

<script>function bla() {return true;}</script>
<button on:click={bla}>bla</button>

تم تحويله:

function bla() {return true;}
const btn = document.createElement('button');
btn.addEventListener('click', bla);

تفسير:
عند استخدام مستمعي الأحداث الأصليين ، أنشئ العنصر المقابل ثم أضف مستمعًا للحدث. بهذه الطريقة نستفيد من أنماط addEventListener التي تحتوي على أعباء زائدة إلى حد كبير لكل مستمع هناك: حدث .addEventListener('click', ...); -> من النوع MouseEvent . يمكن استخدام هذا النمط بعد التحقق مما إذا كان العنصر مكونًا رشيقًا آخر تم تحديد الحدث فيه (انظر أيضًا المثال التالي). أوجه القصور: ماذا لو تم استخدام Svelte في بيئة غير ويب (Nativescript)؟

استخدم مكونًا آخر

إبداعي:

<script>
import Bla from './bla.svelte';
function blub() {}
</script>
<Bla bla={1} on:blubb={blub} />

تم تحويله:

import Bla from './bla.svelte';
function blub() {}
const bla = new Bla({bla: 1, 'on:blubb': blub});

تفسير:
يحصل كل مكون على تعريف صنف ، لذلك نقوم فقط بإنشاء مثيل لتلك الفئة.

كل حلقة

إبداعي:

{#each todos as todo,i (todo.id)}
    <p>{todo.text}</p>
{/each}

تم تحويله:

todos.forEach((todo, i) => {
    const _todoText = todo.text;
});

تفسير:
forEach هو الأسهل في التحويل إليه. في الداخل ، يمكننا تطبيق جميع الميزات الأخرى بشكل متكرر.

لو

إبداعي:

{#if x === 1}
    <p>if</p>
{else if x === 2}
    <p>elseif</p>
{else}
    <p>else</p>
{/if}

تم تحويله:

if (x === 1) {

} else if (x === 2) {

} else {

}

تفسير:
جميلة لا تحتاج إلى شرح.

القطع المفقودة

  • فتحات
  • مكونات خاصة svelte:x
  • توجيهات العناصر / المكونات الأخرى مثل use:action ، transition ، bind
  • - بناء الجملة

ماذا تظنون يا جماعة؟ هل هذه التحولات قابلة للحياة وقابلة للتنفيذ؟ هل فاتني شيء؟

حول فئة المكون ، أفضل تمديد فئة SvelteComponent الخاصة بـ svelte ، لكنني لا أعرف ما إذا كان هذا سهل التنفيذ أم لا

import { SvelteComponent } from "svelte";

export default class Component extends SvelteComponent {
    constructor(options: ComponentOption<{ propA: string }>) {
        super(options)
    }

    $on(
        event: 'input',
        callback: (event: CustomEvent<string>) => void
    ): () => void
    $on(
        event: 'click',
        callback: (event: CustomEvent<number>) => void
    ): () => void 
    $on(
        event: string,
        callback: (event: CustomEvent<any>) => void
    ): () => void {
        return () => { }
    }
}

واستيراد هذه الواجهة

interface ComponentOption<TProps, TSlot = undefined> {
    target: Element,
    props: TProps | SlotProp<TSlot>
}

type SlotOption<T> = [unknown, unknown, unknown]

interface SlotProp<TSlot> {
    $$slots: Record<string, SlotOption<TSlot>>
}

لاحظ أن $$slots هو على الأرجح واجهة برمجة تطبيقات svelte الداخلية ، لقد قمت فقط بحفره من التعليمات البرمجية المجمعة

والسبب في ذلك هو أنه يمكن استخدامه بعد ذلك لإصدار .d.ts والذي يمكن استخدامه لكتابة Vanilla ts / js.
أيضًا لأنه ، على الرغم من كونه غريبًا بدرجة كافية ، إلا أن هذا بناء صحيح:

<script>
onMount(() => {
    new Component({
        target: document.getElementById('foo')
    })
})
</script>

توجيهات العنصر

Transition ، use:action وتوجيهات العناصر الأخرى يمكن أن تكون مثل التحويل

fade(null as Element, {  } /* option in attribute*/)

انتظر

{#await promise}
    <p>...waiting</p>
{:then number}
    <p>The number is {number}</p>
{:catch error}
    <p style="color: red">{error.message}</p>
{/await}

إلى

    promise.then(number => {  number })
    promise.catch(error => { error.message })

ربط: هذا

<script>
let a;
</script>
<div bind:this={a}><div>

إلى

let a;
onMount(() => {
 a = document.createElement('div')
})

بحاجة إلى التفافه في رد الاتصال لأنه غير متاح على الفور

السياق = "وحدة"

هذا هو صعبة بعض الشيء

<script context="module">
 let count = 1;
</script>

<script>
import _ from "lodash"
let b;
</script>

يجب تجميعها إلى

import _ from "lodash"

let count = 1;

// any block is ok
{
    let b;
{

وأيضًا ماذا لو استخدم المستخدم بطريقة ما لغة مختلفة في نصين ، مثل js في الوحدة النمطية و ts على سبيل المثال؟

جميل المظهر. بالنسبة إلى "استخدام المتغير في القالب" ، يمكن أن يكون const _bla = bla.bla; bla.bla; والسماح لـ TypeScript بفحصها دون الحاجة إلى تصفية تشخيص "var غير المستخدم". لا يمكنني التفكير في أي حالات جانبية لا يعمل فيها هذا.

يستكشف بعض فريق Vue مكونًا إضافيًا لخادم اللغة المطبوعة - https://github.com/znck/vue-developer-experience

إنها زاوية مثيرة للاهتمام لأن هذه التجارب اليوم تأتي من خارج TypeScript وداخل (كما يفعل vetur ، حيث يتم تشغيله tsserver-ish الخاص به ، وكذلك html / css / etc LSPs) أو هل تحاول الانتقال من داخل TypeScript والعمل للخارج ( على سبيل المثال هذا الاقتراح) حيث تقوم بمعالجة TSServer للاعتقاد بشكل فعال بأن ملفات .vue هي TypeScript شرعية عن طريق إخفاء كود غير TS.

على الرغم من أنه لا يمكن أن يعمل اليوم إلا من خلال وجود تصحيحات للطباعة

هذا نهج مثير للاهتمام. ولكن كيف ستعمل ميزات مثل عمليات الإكمال التلقائي لـ html أو css بعد ذلك؟ هل سيضطر المرء إلى تنفيذ كل هذا "يدويًا" وعدم الاعتماد على خوادم اللغة خارج الصندوق بعد الآن ، أم أنني أفتقد شيئًا ما؟

هل ترى أي مزايا للقيام بواحد أكثر من ذلك؟

سيتم التعامل مع أي شيء باستثناء دعم JS / TS بواسطة vscode LSP منفصل. سيكون الأمر كما لو أن هذا الامتداد أزال كل الدعم لـ JS / TS ولم يتعامل إلا مع الباقي ، فعندئذٍ سيتعامل المكون الإضافي المطبوع على الحروف مع الباقي.

من الحكمة أن تحصل على جميع أدوات TS "مجانًا" في هذه الحالة ، انتقل إلى الرمز ، وتعيينات الملفات ، إلخ.

ربما لا أوصي به ، فهو يتطلب اليوم تفرعًا أو تصحيحات من TypeScript للعمل وهو ما يمثل حاجزًا كبيرًا جدًا للدخول - ولا يزال فريق TypeScript غير متأكد من / متى يمكن أن يكون للمكونات الإضافية للمترجم هذا النوع من الوصول.

شكرا على الرؤى. أود أن أقول إننا مع النهج الحالي إذن (من الخارج إلى الداخل).

إذا استخدمنا أسلوب "إنشاء ملف ts افتراضي" الذي تمت مناقشته أعلاه ، فكيف يمكننا تنفيذ ذلك والحفاظ على تعيينات المصدر؟

اليوم ، الأمر سهل لأنه مجرد "العثور على بداية البرنامج النصي ، والعثور على نهاية البرنامج النصي" ، و "استخراج جزء البرنامج النصي" وللتعيين "إضافة إزاحة للملف svelte إلى المواضع".
إذا قمنا بتغيير جزء البرنامج النصي الآن ، فنحن بحاجة إلى تعيين أكثر تعقيدًا:

إبداعي

<script lang="typescript">
  let a = 1;
  $: b = a + 1;
</script>
<p>{b}</p>

معين:

export default class Bla extends SvelteComponent { ... } // <- prepended, no mapping needed as far as I know
let a = 1; // <- untouched
let b = a + 1; // <- modified in place. How to map? Do we need to adjust all following code positions now to have a new offset/position?
b; // <- appended. Needs mapping from {b} inside svelte-mustache-tag to here. We can get the original position from the html ast which is part of the output of svelte.parse

أيه أفكار؟ لم أقم بتخطيط المصادر من قبل ..

يستكشف بعض فريق Vue مكونًا إضافيًا لخادم اللغة المطبوعة - https://github.com/znck/vue-developer-experience

إنها زاوية مثيرة للاهتمام لأن هذه التجارب اليوم تأتي من خارج TypeScript وداخل (كما يفعل vetur ، حيث يتم تشغيله tsserver-ish الخاص به ، وكذلك html / css / etc LSPs) أو هل تحاول الانتقال من داخل TypeScript والعمل للخارج ( على سبيل المثال هذا الاقتراح) حيث تقوم بمعالجة TSServer للاعتقاد بشكل فعال بأن ملفات .vue هي TypeScript شرعية عن طريق إخفاء كود غير TS.

على الرغم من أنه لا يمكن أن يعمل اليوم إلا من خلال وجود تصحيحات للطباعة

تم دمج تصحيح TypeScript PR.
https://github.com/znck/vue-developer-experience/pull/7

لذا ... orta هذا يعني أن المساوئ المتعلقة بـ "غير رسمي" لم تعد كذلك؟ أم أنه لا يزال نوعًا ما غير رسمي ، ليس فقط من خلال التصحيح ولكن من خلال بعض الإعدادات package.json التي يجب أن تعرفها ويمكن أن تتغير في أي وقت؟

موضوع آخر: في الوقت الحالي أشعر أننا ما زلنا في نقاش حول كيفية التعامل مع هذا بشكل أفضل ، وإذا قررنا ، فسيستغرق تنفيذه بعض الوقت. ما رأيكم يا رفاق في استخدام svelte2tsx في هذه الأثناء؟ يمكن أن يكون بمثابة نقطة انطلاق جيدة جدًا ، ويمكننا إجراء بعض الاختبارات حوله ومن ثم إما أن نرى "حسنًا ، هذا يعمل بشكل رائع بالفعل ، دعونا لا نغيره" أو نرحل تدريجياً بعيدًا عنه. أفكار؟

نعم ، كانت هناك طريقتان لتعديل تدفق TS الافتراضي ، لا يزال يتم تصحيح TypeScript - ولكن في وقت التشغيل عن طريق استبدال وظائف TS. أعتقد أنه أمر منطقي ، نظرًا لأن تطوير البرنامج المساعد ليس على خريطة الطريق بعد.

سأكون عضوًا سيئًا في الفريق إذا أوصيت بذلك ؛)

تبدو تجربة svelte2ts وسيلة جيدة للاستكشاف!

يمكنك أن ترى كيف سيكون الأمر مع svelte2tsx باستخدام هذا المكون الإضافي vscode: https://marketplace.visualstudio.com/items؟ خيارات الكتابة المطبوعة حتى لا تحصل على التلميحات المزدوجة :))

حتى إذا لم تكن تستخدم svelte2tsx ، فإنني أرى مناقشة حول التحولات التي يجب إجراؤها على كود JS الخاص بـ svelte للحفاظ على الحروف المطبوعة سعيدة. لا تغطي مجموعة الاختبار الخاصة بـ svelte2tsx التغييرات التي يجب إجراؤها على القالب فحسب ، بل تغطي أيضًا علامة البرنامج النصي ، والتي قد تكون نقطة انطلاق جيدة إذا كنت تريد الحصول على علامة البرنامج النصي فقط: https://github.com/halfnelson / svelte2tsx / شجرة / ماستر / اختبار / svelte2tsx / عينات

htmlx2jsx هو المجلد الذي يختبر فيه تغيير القالب (htmlx) ، بينما عينات svelte2tsx هي التغييرات المحددة المطلوبة لإساءة استخدام svelte الخاصة لبناء جملة js :)

اكتشفت للتو هذا الريبو https://github.com/pivaszbs/svelte-autoimport . ربما يستحق النظر في ما إذا كنا نريد استيراد intellisense بشكل مستقل عن svelte2tsx .

أعتقد أننا في مرحلة يتم فيها فرز معظم الاتجاه العام لهذا المشروع ويبدو أنه يعمل بشكل جيد. سأمنح هذا أسبوعًا للتعليق ، لكنني سعيد جدًا لأننا لسنا بحاجة إلى إعادة التفكير به من الناحية المعمارية الآن.

يبدو أن لا أحد لديه اعتراضات ، لذلك سأغلق هذا. شكرا للجميع لمناقشة هذا!

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات