Ember.js: [ميتا] الاستعداد للتطريز

تم إنشاؤها على ١٨ أغسطس ٢٠٢٠  ·  17تعليقات  ·  مصدر: emberjs/ember.js

اليوم ، يمكن استخدام Embroider في وضع التوافق في التطبيقات الجديدة وفي العديد من التطبيقات الحالية. من الأصعب استخدام وضع Embroider في staticComponents ، وهو أمر ضروري للاستفادة من وضع splitAtRoutes .

تتعقب المشكلة رقم 501 في مستودع Embroider المشكلات المتبقية اللازمة لتحقيق الاستقرار في Embroider كجزء من إصدار Ember.js.

تتعقب هذه المشكلة الخطوات التي نحتاج إلى اتخاذها قبل أن يتمكن الأشخاص عمليًا من استخدام Ember مع Embroider كخيار مدعوم مع تقسيم الكود المستند إلى المسار ("جاهزية Embroider"). في حين أن هناك العديد من الطرق الدقيقة لاستخدام Embroider (بما في ذلك وضع التوافق الذي يقدم بعض الفوائد الملموسة ولكنه مهم لترحيل Ember نفسه إلى Embroider افتراضيًا) ، تركز هذه المشكلة على القدرة على استخدام Embroider مع تطبيق Ember العادي والحصول على الفوائد من تقسيم التعليمات البرمجية المستندة إلى المسار.

متطلبات تقنية

كما هو موضح في Embroider README ، من أجل تمكين تقسيم الكود المستند إلى المسار ( splitAtRoutes ) ، يجب أن يكون التطبيق قادرًا على تمكين هذه العلامات:

  • [] staticAddonTestSupportTrees
  • [] staticAddonTrees
  • [] staticHelpers
  • [] staticComponents

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

MVP: قم بإيقاف واستبدال (component dynamicString)

بالنسبة للهدف الأول من جاهزية Embroider ("MVP") ، نحتاج إلى التخلص من أكثر حواجز الطرق شيوعًا التي وجدناها عند محاولة تمكين العلامات الثابتة في تطبيقات العالم الحقيقي.

بالنسبة إلى معلم MVP ، فهو ليس هدفًا لجميع إضافات النظام البيئي التي تدعم هذه العلامات.

بدلاً من ذلك ، يتمثل الهدف في أن يكون للتطبيقات مسار انتقال معقول إلى splitAtRoutes ، وأنه من الممكن إنشاء تطبيقات كبيرة وغير تافهة في هذا الوضع. هذا يعني أن جميع الوظائف الإضافية المضمنة في المخطط الافتراضي يجب أن يتم ترحيلها بعيدًا عن الميزات الديناميكية الكلاسيكية. وهذا يعني أيضًا أن الوظائف الإضافية التي يتم استخدامها بشكل متكرر في تطبيقات العالم الحقيقي ، مثل Ember concurrency ، يجب ألا تستخدم الميزات الديناميكية الكلاسيكية.

staticComponents

هذا هو العلم الثابت الأكثر أهمية ، ويشكل مطلبه أكبر عقبة أمام هدف MVP.

من أجل تمكين staticComponents ، يجب أن يكون التطبيق ( بما في ذلك الوظائف الإضافية ) خاليًا من جميع استخدامات (component dynamicString) .

الأهم من ذلك ، يُسمح للتطبيقات ووظائفها الإضافية باستخدام (component "static string") في الوضع staticComponents .

في الممارسة العملية ، هذا يعني أننا سنحتاج إلى الهجرة بعيدًا عن أنماط مثل هذا :

{{#let (component this.componentName) as | Component |}}

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

هذا موقف شائك بشكل خاص ، حيث يتم تعريف this.component على أنه this.componentName = <code i="29">scaffolding/${dasherize(csId!)}/${dasherize(this.args.feature)}</code> . مثل هذه المواقف هي بالتحديد السبب الذي يجعلنا بحاجة إلى التفكير في إستراتيجية انتقالية وطرحها بعناية.

على الأقل ، للسماح للوظائف الإضافية بالانتقال بعيدًا عن (component dynamicString) ، سنحتاج إلى إنشاء إصدار جديد من الكلمة الرئيسية component التي لا تسمح باستدعاء المكونات الديناميكية.

بالإضافة إلى ذلك ، نحتاج إلى إصلاح خطأ يسمح عن غير قصد باستدعاء المكون باستخدام بنية قوس الزاوية للعمل بنفس طريقة الكلمة الأساسية الديناميكية component . يجب القيام بذلك قريبًا ، لأنه بمجرد أن يبدأ الناس في محاولة الهجرة بعيدًا عن (component dynamic) ، هناك احتمال كبير أن الناس سوف يهاجرون بطريق الخطأ إلى <dynamic> ، ويلاحظون أنه يعمل ، والمضي قدمًا.

خطوات العمل:

  • [] تصميم وإصدار نسخة جديدة من (component) تدعم فقط السلاسل الثابتة (تتطلب RFC)
  • [] إصلاح الخطأ الذي يسمح باستدعاء قوس الزاوية بالتصرف مثل استدعاء المكون الديناميكي في Ember (bugfix ، ربما واجهة برمجة تطبيقات حميمية)

staticHelpers

لا تقلل علامة staticHelpers من تعبير قوالب Ember ، لكنها تعني أن القائمة الكاملة لمساعدي التطبيق لن تكون متاحة في مجموعة الوحدات في أداة التحميل.

نفترض أن هذا سيكون له تأثيرات معطلة على تطبيقات Ember ، لكن مشاكل أقل بكثير من staticComponents . لا نتوقع حاليًا أن يؤثر staticHelpers على هدف MVP ، ولكن قد يتغير ذلك عندما نحاول ترقية التطبيقات إلى splitAtRoutes . إذا حدث ذلك ، فسنحتاج إلى تقييم حالات الاستخدام الإشكالية والنظر في واجهات برمجة التطبيقات الجديدة لتسهيل الترحيل.

staticAddonTrees و staticAddonTestSupportTrees

الافتراض الحالي هو أن هذه العلامات متوافقة مع معظم تطبيقات وإضافات Ember الاصطلاحية ، وبالتالي لا تشكل أي مشاكل جوهرية لمتطلبات هدف MVP.

الخطوات التالية

الغرض من هذه المشكلة هو أن تظل مشكلة تتبع بعد أن نحقق هدف MVP. بعد هدف MVP ، سنحتاج إلى تسهيل الانتقال الكامل للنظام البيئي وتحسين بيئة العمل لحالات الاستخدام الديناميكية (التي تحافظ على دعم تقسيم الكود). من المحتمل أن تساعد عمليات

Help Wanted

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

تضمين التغريدة

بشكل عام ، طريقة التفكير فيما يحتاج الناس إلى فعله بدلاً من (component dynamicString) هي أنهم بحاجة إلى import أو (component "staticString") للذهاب إلى مكان ما .

تشمل الخيارات:

  • سيقوم المتصل بالمكون بعمل (component "staticString")
  • الكود الذي يحتوي على الديناميكية سيحدد الاحتمالات ويضعها في الخريطة ويستخدم (get componentMap dynamicString) لإخراجها

قد تفكر الآن: كيف يمكن أن يكون (get components dynamicString) أفضل من (component dynamicString) ؟ الجواب هو أن componentMap يجب أن يبنى في مكان ما ، والقواعد تطبق بشكل متكرر.

لنفترض أنك تكتب مكونًا يسمح لك بكتابة <InputField @type="text" /> أو <InputField @type="checkbox" /> (مثل <input> في HTML).

سيبدو نموذجك لـ input-field كما يلي:

{{#let (hash text=(component "inputs/text-field") checkbox=(component "inputs/checkbox")) as |components|}}
  {{component (get components @type)}}
{{/let}}

عندما تكتب الرمز بهذه الطريقة ، يمكن أن يرى Embroider أنه يحتاج فقط إلى تضمين مكونين في الحزمة. هل كتبتها بهذه الطريقة:

{{component (concat "inputs/" <strong i="33">@type</strong> "-field")}}

(نعم ، أشياء كهذه شائعة بشكل مدهش)

لا يمكن لـ Embroider تحليل الكود بسهولة وتحديد المكونات التي سيتم تضمينها في الحزمة. هذا أسوأ إذا قمت بالعمل في JavaScript (وهو أمر شائع أيضًا ):

export default class extends Component {
  get innerComponent() {
    return `inputs/${this.args.type}-field`;
  }
}

مع هذا النموذج:

{{component this.innerComponent}}

إنه تعديل صغير ، لكنه يجعل من الممكن لـ Embroider تحديد المكونات المستخدمة بالفعل.

ال 17 كومينتر

تتمثل إحدى طرق تخفيف تكلفة الانتقال في السماح للوظائف الإضافية بالإشارة بشكل ثابت إلى أي من وسيطاتها يتوافق مع سلسلة ثابتة تم تمريرها من قبل مستدعي المكون

كلعبة spitball (حيث يكون better-component عنصرًا نائبًا لاسم الكلمة الأساسية المكونة الثابتة).

{{better-component <strong i="8">@arg</strong> staticString=true}}

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

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

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

https://github.com/NullVoxPopuli/emberclear/pull/784

لذا ، إذا واجه الناس مشكلات ، فربما تساعد وثائق آبي؟ لا أعرف

أيضًا ، أنا متحمس جدًا للتطريز ، ولدي بالفعل خطط كبيرة بمجرد تحقيق السكون الكامل
https://github.com/emberjs/rfcs/issues/611

تطبيقنا هو نظام توصيل محتوى ديناميكي. يقوم منشئو المحتوى بتجميع المحتوى من "عناصر النشاط" ، ولكل منها مكون Ember مقابل ، يتم تحديد اسمها في نموذج Ember Data. يبدو قلب هذا النظام بشكل أو بآخر كما يلي:

// example model definition
export default class TextElement extends Model {
  _componentName = 'text-element';
}
  {{#each (sort-by "position" @activityElements) as |activityElement|}}
    {{component (get activityElement "_componentName")}}

تشير قراءتي لما سبق إلى أن هذا سيناريو (component dynamicString) . هل هذا دقيق؟

تشير قراءتي لما سبق إلى أن هذا سيناريو (سلسلة ديناميكية مكونة). هل هذا دقيق؟

ما هو @activityElements وأين يتم تعريفه؟

سيكون هذا مصفوفة من مثيلات Ember Data Model التي تم تمريرها إلى مكون تحكم .

لقد استثمرنا أيضًا بشكل كبير في المكونات الديناميكية ، FYI. سألت عنها هنا العام الماضي: https://discuss.emberjs.com/t/the-perils-of-dynamic-component-invocation/16784.

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

هل يمكن استخدام خريطة لجميع المكونات الصالحة لهذا السيناريو؟

فمثلا:

{{#let (hash
   Foo=(import 'path/to/foo')
   Etc=...
) as |validComponents|
}}
  {{component (get validComponents @someDynamicValue)}}
{{/let}}

؟

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

هل يمكن استخدام خريطة لجميع المكونات الصالحة لهذا السيناريو؟

سيغطي هذا بالتأكيد حالة الاستخدام الخاصة بنا.

تضمين التغريدة

بشكل عام ، طريقة التفكير فيما يحتاج الناس إلى فعله بدلاً من (component dynamicString) هي أنهم بحاجة إلى import أو (component "staticString") للذهاب إلى مكان ما .

تشمل الخيارات:

  • سيقوم المتصل بالمكون بعمل (component "staticString")
  • الكود الذي يحتوي على الديناميكية سيحدد الاحتمالات ويضعها في الخريطة ويستخدم (get componentMap dynamicString) لإخراجها

قد تفكر الآن: كيف يمكن أن يكون (get components dynamicString) أفضل من (component dynamicString) ؟ الجواب هو أن componentMap يجب أن يبنى في مكان ما ، والقواعد تطبق بشكل متكرر.

لنفترض أنك تكتب مكونًا يسمح لك بكتابة <InputField @type="text" /> أو <InputField @type="checkbox" /> (مثل <input> في HTML).

سيبدو نموذجك لـ input-field كما يلي:

{{#let (hash text=(component "inputs/text-field") checkbox=(component "inputs/checkbox")) as |components|}}
  {{component (get components @type)}}
{{/let}}

عندما تكتب الرمز بهذه الطريقة ، يمكن أن يرى Embroider أنه يحتاج فقط إلى تضمين مكونين في الحزمة. هل كتبتها بهذه الطريقة:

{{component (concat "inputs/" <strong i="33">@type</strong> "-field")}}

(نعم ، أشياء كهذه شائعة بشكل مدهش)

لا يمكن لـ Embroider تحليل الكود بسهولة وتحديد المكونات التي سيتم تضمينها في الحزمة. هذا أسوأ إذا قمت بالعمل في JavaScript (وهو أمر شائع أيضًا ):

export default class extends Component {
  get innerComponent() {
    return `inputs/${this.args.type}-field`;
  }
}

مع هذا النموذج:

{{component this.innerComponent}}

إنه تعديل صغير ، لكنه يجعل من الممكن لـ Embroider تحديد المكونات المستخدمة بالفعل.

أريد أيضًا توضيح الاتصالات بميزتين أخريين على متن الطائرة بعناية أكبر.

  1. واردات القوالب
  2. استخدام فئات المكونات باعتبارها Invokables

إذا أعدنا كتابة المثال السابق باستخدام هاتين الميزتين ، فسيبدو كما يلي:

---
import TextField from "./text-field";
import Checkbox from "./checkbox";
---
{{#let (hash text=TextField checkbox=Checkbox) as |components|}}
  {{component (get components @type)}}
{{/let}}

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

استخدام فئات المكونات باعتبارها Invokables

منذ RFC # 481 ، كانت فئة المكون عبارة عن وحدة قائمة بذاتها تحتوي على جميع المعلومات المطلوبة لـ Glimmer VM لاستدعاءها كمكون.

ملاحظة: هذا لا ينطبق فقط على الفئات التي ترث من @ember/component أو @glimmer/component . منذ RFC 481 ، أصبح تعريف Ember لـ "المكون" "كائنًا مرتبطًا بقالب ومدير مكون" ، والذي يتضمن مكونات مخصصة مثل المكونات الموصولة .

نظرًا لأن RFC # 432 (المساعدون السياقيون والمعدلات) و RFC # 496 (الوضع المتشدد للمقاود) ، فإن التصميم لمستقبل بناء جملة قالب Ember هو: يمكن استدعاء التعبيرات التي تحتوي على مساعدين أو مكونات أو معدِّلات كمساعدين أو مكونات أو معدِّلات.

دلالة المجموعة الحالية لـ RFCs المعتمدة هي أن <SomeComponentClass /> (أو <this.componentClass> حيث this.componentClass يتحول إلى فئة مكون) من شأنه أن "يعمل فقط". إنها أيضًا خطة التسجيل لأعمال التنفيذ.

ومع ذلك ، من أجل الوضوح ، يجب علينا إنشاء RFC جديد يحدد هذا السلوك صراحة.

إن تحديد قائمة بالمكونات الصالحة في HBS في مكان ما أمر ممكن بالنسبة لنا ، ولكن هناك بعض التحذيرات التي تستحق الذكر:

  1. حاليًا ، نستخدم حل JS المشار إليه من
  2. هذا غير موجود في JS (مع API العامة على أي حال) afaik ، ولكن استخدام بنية الدليل لصالحنا سيكون أمرًا رائعًا هنا. على سبيل المثال:

    {{#let (lookup-directory "components/inputs/") as |components|}}
    {{/let}}
    

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

على أي حال ، أشعر أن المكونات الديناميكية تحتاج إلى مشكلتها الخاصة للمناقشة بدلاً من الاستيلاء على هذا 🙈 😄

على أي حال ، أشعر أن المكونات الديناميكية تحتاج إلى مشكلتها الخاصة للمناقشة بدلاً من الاستيلاء على هذا 🙈 😄

أوافق ، وسأفتح واحدًا قريبًا في RFC repo ، وأنشر رابطًا هنا.

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

import Component1 from './dynamic/component-1';
import Component2 from './dynamic/component-2';
import Component3 from './dynamic/component-3';

export default class extends Component {
  get innerComponent() {
    switch(this.args.type) {
      case 'one':
        return Component1;
      case 'two':
        return Component2;
      case 'three':
        return Component3;
      default:
        // handle invalid type
    }
  }
}

ثم يمكن للقالب أن يفعل: {{#let (component this.innerComponent) as |DynamicComponent|}} أو شيء مشابه.

أفضل شيئًا كهذا يكون أسهل في البحث / القراءة / التحليل ، ويكتشف بسهولة مكان استخدام هذه المكونات. أفكار؟

Samsinite نعم أعتقد أن هذه هي الفكرة. سيكون المساعد في HBS في الغالب سكرًا نحويًا ومفيدًا لمكونات النموذج فقط.

Samsinite هو أساسًا ما اقترحته

سيتطلب منا السماح بأن تكون فئات المكون قابلة للاستدعاء ، وهو ما كنت أتحدث عنه في هذا التعليق .

دعنا نذهب نفعل ذلك!

آه ، هذا منطقي بالنسبة لمكونات النموذج فقط ، آسف لسوء الفهم :). يعجبني أيضًا بناء الجملة لمكونات النموذج فقط:

---
import TextField from "./text-field";
import Checkbox from "./checkbox";
---
{{#let (hash text=TextField checkbox=Checkbox) as |components|}}
  {{component (get components @type)}}
{{/let}}

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

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