اليوم ، يمكن استخدام Embroider في وضع التوافق في التطبيقات الجديدة وفي العديد من التطبيقات الحالية. من الأصعب استخدام وضع Embroider في staticComponents
، وهو أمر ضروري للاستفادة من وضع splitAtRoutes
.
تتعقب المشكلة رقم 501 في مستودع Embroider المشكلات المتبقية اللازمة لتحقيق الاستقرار في Embroider كجزء من إصدار Ember.js.
تتعقب هذه المشكلة الخطوات التي نحتاج إلى اتخاذها قبل أن يتمكن الأشخاص عمليًا من استخدام Ember مع Embroider كخيار مدعوم مع تقسيم الكود المستند إلى المسار ("جاهزية Embroider"). في حين أن هناك العديد من الطرق الدقيقة لاستخدام Embroider (بما في ذلك وضع التوافق الذي يقدم بعض الفوائد الملموسة ولكنه مهم لترحيل Ember نفسه إلى Embroider افتراضيًا) ، تركز هذه المشكلة على القدرة على استخدام Embroider مع تطبيق Ember العادي والحصول على الفوائد من تقسيم التعليمات البرمجية المستندة إلى المسار.
كما هو موضح في Embroider README ، من أجل تمكين تقسيم الكود المستند إلى المسار ( splitAtRoutes
) ، يجب أن يكون التطبيق قادرًا على تمكين هذه العلامات:
staticAddonTestSupportTrees
staticAddonTrees
staticHelpers
staticComponents
إذا تعذر على الملحق أو التطبيق العمل في وجود هذه العلامات ، فإنهم يستخدمون "ميزات ديناميكية كلاسيكية".
(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)staticHelpers
لا تقلل علامة staticHelpers
من تعبير قوالب Ember ، لكنها تعني أن القائمة الكاملة لمساعدي التطبيق لن تكون متاحة في مجموعة الوحدات في أداة التحميل.
نفترض أن هذا سيكون له تأثيرات معطلة على تطبيقات Ember ، لكن مشاكل أقل بكثير من staticComponents
. لا نتوقع حاليًا أن يؤثر staticHelpers
على هدف MVP ، ولكن قد يتغير ذلك عندما نحاول ترقية التطبيقات إلى splitAtRoutes
. إذا حدث ذلك ، فسنحتاج إلى تقييم حالات الاستخدام الإشكالية والنظر في واجهات برمجة التطبيقات الجديدة لتسهيل الترحيل.
staticAddonTrees
و staticAddonTestSupportTrees
الافتراض الحالي هو أن هذه العلامات متوافقة مع معظم تطبيقات وإضافات Ember الاصطلاحية ، وبالتالي لا تشكل أي مشاكل جوهرية لمتطلبات هدف MVP.
الغرض من هذه المشكلة هو أن تظل مشكلة تتبع بعد أن نحقق هدف MVP. بعد هدف MVP ، سنحتاج إلى تسهيل الانتقال الكامل للنظام البيئي وتحسين بيئة العمل لحالات الاستخدام الديناميكية (التي تحافظ على دعم تقسيم الكود). من المحتمل أن تساعد عمليات
تتمثل إحدى طرق تخفيف تكلفة الانتقال في السماح للوظائف الإضافية بالإشارة بشكل ثابت إلى أي من وسيطاتها يتوافق مع سلسلة ثابتة تم تمريرها من قبل مستدعي المكون
كلعبة 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 تحديد المكونات المستخدمة بالفعل.
أريد أيضًا توضيح الاتصالات بميزتين أخريين على متن الطائرة بعناية أكبر.
إذا أعدنا كتابة المثال السابق باستخدام هاتين الميزتين ، فسيبدو كما يلي:
---
import TextField from "./text-field";
import Checkbox from "./checkbox";
---
{{#let (hash text=TextField checkbox=Checkbox) as |components|}}
{{component (get components @type)}}
{{/let}}
يتمتع هذا بخاصية رائعة تتمثل في التخلص من قاعدة خاصة يجب على Embroider فهمها ، وجعل نموذج المستخدم لتقسيم الكود أكثر حول الوحدات النمطية.
منذ RFC # 481 ، كانت فئة المكون عبارة عن وحدة قائمة بذاتها تحتوي على جميع المعلومات المطلوبة لـ Glimmer VM لاستدعاءها كمكون.
ملاحظة: هذا لا ينطبق فقط على الفئات التي ترث من
@ember/component
أو@glimmer/component
. منذ RFC 481 ، أصبح تعريف Ember لـ "المكون" "كائنًا مرتبطًا بقالب ومدير مكون" ، والذي يتضمن مكونات مخصصة مثل المكونات الموصولة .
نظرًا لأن RFC # 432 (المساعدون السياقيون والمعدلات) و RFC # 496 (الوضع المتشدد للمقاود) ، فإن التصميم لمستقبل بناء جملة قالب Ember هو: يمكن استدعاء التعبيرات التي تحتوي على مساعدين أو مكونات أو معدِّلات كمساعدين أو مكونات أو معدِّلات.
دلالة المجموعة الحالية لـ RFCs المعتمدة هي أن <SomeComponentClass />
(أو <this.componentClass>
حيث this.componentClass
يتحول إلى فئة مكون) من شأنه أن "يعمل فقط". إنها أيضًا خطة التسجيل لأعمال التنفيذ.
ومع ذلك ، من أجل الوضوح ، يجب علينا إنشاء RFC جديد يحدد هذا السلوك صراحة.
إن تحديد قائمة بالمكونات الصالحة في HBS في مكان ما أمر ممكن بالنسبة لنا ، ولكن هناك بعض التحذيرات التي تستحق الذكر:
هذا غير موجود في 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 ، اعتمادًا على ما يجد الآخرون في الفريق أنه من الأسهل قراءته.
التعليق الأكثر فائدة
تضمين التغريدة
بشكل عام ، طريقة التفكير فيما يحتاج الناس إلى فعله بدلاً من
(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
كما يلي:عندما تكتب الرمز بهذه الطريقة ، يمكن أن يرى Embroider أنه يحتاج فقط إلى تضمين مكونين في الحزمة. هل كتبتها بهذه الطريقة:
(نعم ، أشياء كهذه شائعة بشكل مدهش)
لا يمكن لـ Embroider تحليل الكود بسهولة وتحديد المكونات التي سيتم تضمينها في الحزمة. هذا أسوأ إذا قمت بالعمل في JavaScript (وهو أمر شائع أيضًا ):
مع هذا النموذج:
إنه تعديل صغير ، لكنه يجعل من الممكن لـ Embroider تحديد المكونات المستخدمة بالفعل.