كيفية إنشاء تطبيق Electron Desktop في JavaScript: Multithreading و SQLite والوحدات الأصلية ونقاط الألم الشائعة الأخرى

كإطار عمل لتطوير تطبيقات سطح المكتب ، لدى Electron الكثير لتقدمه. يمنح الوصول الكامل إلى Node's API والمحيط البيئي. يتم نشره على جميع أنظمة التشغيل الرئيسية (مع قاعدة بيانات واحدة). وبفضل بنيتها القائمة على الويب ، يمكنك استخدام أحدث ميزات CSS لإنشاء واجهات مستخدم متقدمة.

هناك الكثير من المقالات التي تتناول بدء العمل مع Electron ، ولكن القليل منها مخصص لاستخدام SQLite أو كيفية التعامل مع تعدد مؤشرات الترابط. سننظر في كيفية استخدام Electron لبناء تطبيقات تتعامل مع كميات كبيرة من البيانات أو تشغل الكثير من المهام.

على وجه الخصوص ، سوف نغطي:

  • كيف يعمل Electron (باختصار) ، وكيف تؤثر هندسته المعمارية على ما يمكننا القيام به
  • تعدد
  • استخدام قواعد البيانات المحلية مثل SQLite ، أو الكتابة إلى أي ملف داخل تطبيق Electron
  • الوحدات الأصلية
  • عدد قليل من المشاكل التي يجب أن تكون على دراية بها
  • حزم تطبيق باستخدام وحدات أصلية

كيف يعمل الإلكترون - مختصر

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

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

محاذير معمارية إلكترون

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

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

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

تعدد

هناك ثلاث طرق عامة لتعدد مؤشرات الترابط في الإلكترون:

  • استخدم عمال الويب
  • شوكة عمليات جديدة لتشغيل المهام
  • تشغيل عمليات العارض (المخفية) كعاملين

عمال الويب

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

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

تفرع عمليات جديدة

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

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

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

استخدام عمليات العارض كخيوط عامل

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

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

التحدي الوحيد عند استخدام Electron هو IPC. على الرغم من بساطته ، إلا أنه يتطلب قدرًا هائلاً من البيانات المعيارية ويفرض صعوبة تصحيح أخطاء أعداد كبيرة من مستمعي الأحداث. إنه أيضًا شيء آخر يجب عليك اختباره. باستخدام عملية العارض باعتباره مؤشر ترابط عامل ، يمكنك التحايل على هذا تمامًا. تمامًا كما تفعل مع الخادم ، يمكنك الاستماع على منفذ محلي وتلقي الطلبات ، مما يتيح لك استخدام أدوات مثل GraphQL + React Apollo. يمكنك أيضًا استخدام مآخذ الويب للاتصال في الوقت الفعلي. ميزة أخرى هي أنك لست بحاجة إلى استخدام ipcRenderer ، ويمكنك الاحتفاظ بتطبيقات الويب والإلكترون الخاصة بك متشابهة (إذا كنت ترغب في استخدام قاعدة بيانات مشتركة لتطبيق سطح المكتب والويب).

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

كيفية استخدام SQLite (أو أي شيء تريد الكتابة إليه)

هناك عدة طرق لإدارة الحالة لا تتطلب وحدات أصلية. على سبيل المثال ، التعامل مع كل حالتك في سياق العارض باستخدام Redux.

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

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

بدلاً من ذلك ، قم بتضمين قاعدة البيانات الخاصة بك في دليل الموارد لحزمة الإلكترون الخاصة بك. يمكن رؤية هيكل ملف تطبيق Electron المعبأ ومكان وضع قاعدة البيانات أدناه:

أرشيف ASAR المعبأ والمسمى app.asar موجود في ./Contents/Resources. يمكنك وضع قاعدة البيانات الخاصة بك ، أو أي ملف تريد الكتابة إليه مع تضمينه في التطبيق المحزم ، في نفس الدليل. يمكن تحقيق ذلك باستخدام Electron Builder باستخدام تكوين "extraResources".

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

التعبئة والتغليف مع الوحدات الأصلية

الغالبية العظمى من وحدات Node هي نصوص مكتوبة بلغة JavaScript. الوحدات الأصلية هي وحدات مكتوبة بلغة C ++ لها روابط للاستخدام مع Node. تعمل كواجهة للمكتبات الأخرى المكتوبة بلغة C / C ++ ، ويتم تكوينها عادةً للترجمة بعد التثبيت.

كوحدات نمطية منخفضة المستوى ، يجب تجميعها للبنى وأنظمة التشغيل المستهدفة. لن تعمل الوحدة الأصلية التي تم تجميعها على جهاز Windows على جهاز Linux - على الرغم من أن الوحدة العادية ستعمل. هذه مشكلة بالنسبة إلى Electron ، حيث نحتاج في النهاية إلى تجميع كل شيء في ملف قابل للتنفيذ .dmg (OSX) أو .exe (Windows) أو .deb (Linux).

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

إذا كنت تقوم بتطوير مشروع مفتوح المصدر غير تجاري ، فيمكنك استخدام TravisCI (Linux و OSX) و Appveyor (Windows) لإنشاء تطبيقك واختباره ونشره تلقائيًا مجانًا.

قد يكون الإعداد لهذا الأمر صعبًا إذا كان لديك اختبارات تكامل ، حيث ستحتاج إلى تثبيت بعض التبعيات حتى تعمل الاختبارات بدون رأس. يمكن العثور هنا على مثال لتكوين OSX و Linux مع TravisCI ، ومثال لتكوين Appveyor هنا (تستند هذه الأمثلة إلى التكوين في مشروع الإلكترون-التفاعل-المتداول ، مع إضافة OSX والنشر)

مسكتك

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

لن تتصرف المتغيرات مثل __dirname و __filename وطرق مثل process.cwd كما هو متوقع في تطبيق مجمع (راجع المشكلات هنا وهنا وهنا). استخدم app.getAppPath بدلاً من ذلك.

ملاحظة أخيرة على العبوة

أثناء تطوير تطبيق Electron ، قد ترغب في استخدام كل من أوضاع الإنتاج (تقديم رمز مجمعة مع ثنائي تم إنشاؤه مسبقًا) والتطوير (باستخدام webpack-dev-server أو webpack-serve لمشاهدة ملفاتك).

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

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

تعتبر مشكلات تصحيح الأخطاء المتعلقة بمسارات الملفات غير الصحيحة في تطبيق محزّم حالة من حالات التجربة والخطأ.

ملخص

هناك عدة طرق لتعدد مؤشرات الترابط في الإلكترون. عمال الويب ملائمون ، لكنهم يفتقرون إلى القدرة على استخدام الوحدات الأصلية. تعمل عمليات التشعب الجديدة كما هو الحال في Node ، لكن عدم القدرة على استخدام مكتبة Electron يفرض استخدام IPC للمهام الشائعة ويمكن أن تصبح معقدة بسرعة. يمنح استخدام عمليات التصيير كعاملين القوة الكاملة لجميع أدوات خادم Node المتاحة كبديل للاتصال عبر IPC ، مع الاحتفاظ بالوصول إلى الوحدات والطرق الأصلية من مكتبة جهاز عرض Electron.

نظرًا لأن Electron حزم ملفات في أرشيف ASAR للقراءة فقط ، لا يمكن تضمين أي ملف نحتاج إلى الكتابة إليه (مثل قاعدة بيانات SQLite). بدلاً من ذلك ، يمكن وضعها في دليل الموارد حيث ستبقى في التطبيق المحزم.

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