مشاركة التعليمات البرمجية بين الخادم والعميل في Clojurescript/Clojure

StackOverflow https://stackoverflow.com/questions/7830077

  •  27-10-2019
  •  | 
  •  

سؤال

لنفترض أنني أردت استبعاد بعض التعليمات البرمجية الشائعة بين جانب العميل *.cljs الخاص بي و*.clj من جانب الخادم الخاص بي، على سبيل المثال.هياكل البيانات المختلفة والعمليات المشتركة، هل يمكنني القيام بذلك؟هل يعقل أن تفعل ذلك؟

هل كانت مفيدة؟

المحلول

تحديث: اعتبارًا من clojure 1.7 ، راجع شروط قارئ Clojure أو cljc . لقد استخدمت cljc بنجاح كبير لمشاركة الكثير من التعليمات البرمجية بين الخادم والمتصفح بسهولة شديدة.

سؤال رائع! لقد كنت أفكر كثيرًا في هذا أيضًا مؤخرًا وقد كتبت بعض التطبيقات للتجربة.

فيما يلي قائمة بأنواع الأشياء التي قد ترغب في مشاركتها وإيجابيات / سلبيات كل منها:

  • تحتوي معظم ملفات cljs الخاصة بعملائي على تعليمات برمجية تتعامل مع dom. لذلك ، لن يكون من المنطقي مشاركة أي من ذلك مع الخادم
  • تتعامل معظم عناصر جانب الخادم مع استدعاءات نظام الملفات وقواعد البيانات. أفترض أنك قد ترغب في الاتصال بقاعدة البيانات من العميل (خاصة إذا كنت تستخدم أحد أنظمة no-sql db التي تدعم مكالمات جافا سكريبت). ولكن ، حتى ذلك الحين ، أشعر أنه يجب عليك اختيار إما الاتصال بـ db من العميل أو الاتصال بـ db من الخادم ، وبالتالي ، ليس من المنطقي مشاركة رمز db أيضًا.
  • من المجالات التي تكون فيها المشاركة قيمة بالتأكيد هي القدرة على مشاركة هياكل بيانات clojure وتمريرها (مجموعات متداخلة من القوائم والمتجهات والمجموعات وما إلى ذلك) بين العميل والخادم. لا حاجة للتحويل إلى json (أو xml) والعكس. على سبيل المثال ، القدرة على تمرير تمثيلات دوم على غرار الفواق هو أمر مريح للغاية. في gwt ، لقد استخدمت gilead لمشاركة النماذج بين العميل والخادم. ولكن ، في clojure ، يمكنك ببساطة تمرير هياكل البيانات ، لذلك ليست هناك حاجة حقًا لمشاركة تعريفات الفئات كما هو الحال في gwt.
  • من المجالات التي أشعر أنني بحاجة إلى تجربة المزيد منها مشاركة الحالة بين العميل والخادم. في رأيي ، هناك بعض الاستراتيجيات: حالة التخزين على العميل (تطبيقات نوع ajax ذات الصفحة الواحدة) أو حالة المتجر على الخادم (مثل تطبيقات jsp القديمة) أو مزيج من الاثنين معًا. ربما يمكن مشاركة الكود المسؤول عن تحديث الحالة (الذرات أو المراجع أو العوامل أو أي شيء آخر) ومن ثم يمكن تمرير الحالة ذهابًا وإيابًا عبر الطلب والاستجابة للحفاظ على تزامن المستويين؟ حتى الآن ، يبدو أن كتابة الخادم باستخدام أفضل ممارسات REST ثم تخزين الحالة على العميل يعمل بشكل جيد. لكن يمكنني أن أرى كيف يمكن أن تكون هناك فوائد لمشاركة الحالة بين العميل والخادم.
  • لم أحتاج إلى مشاركة الثوابت و / أو الخصائص حتى الآن ، ولكن قد يكون هذا شيئًا من الجيد إعادة استخدامه. إذا وضعت جميع الثوابت العامة لتطبيقك في ملف clj ثم كتبت نصًا لنسخه إلى cljs كلما جمعت clojurescript ، فمن المفترض أن يعمل ذلك بشكل جيد ، وقد يوفر القليل من تكرار الكود.

أتمنى أن تكون هذه الأفكار مفيدة ، أنا مهتم جدًا بما وجده الآخرون حتى الآن!

نصائح أخرى

لقد كتبت cljx ملحق Leiningen خصيصًا للتعامل مع مشاركة أكواد Clojure/ClojureScript لمكتبة تصور بيانات Clojure.95% من التعليمات البرمجية للتشغيل المتبادل غير المضيف تبدو متشابهة، ويتيح لك cljx إعادة كتابة الـ 5% الأخيرة تلقائيًا عن طريق تحديد قواعد إعادة الكتابة باستخدام core.logic.ومع ذلك، في أغلب الأحيان، يكون الأمر عبارة عن استبدالات بسيطة للرموز؛ clojure.lang.IFn في كلوجور هو مجرد IFn في ClojureScript، على سبيل المثال.

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

يحتوي المكون الإضافي lein-cljsbuild الجديد لـ Leiningen على دعم لمشاركة كود Clojure الخالص.

Wrote a quick bit of code to copy a subset of my server clojure code over to my clojurescript code, renaming as .cljs before building:

(ns clj-cljs.build
  (use
    [clojure.java.io]
  )
  (require
    [cljs.closure :as cljsc]
  )
)

(defn list-files [path]
 (.listFiles (as-file path))
)

(defn copy-file* [from to]
 ;(println " coping " from " to " to)
 (make-parents to)
 (copy from to)
)    

(defn rename [to-path common-path f]
 (str to-path common-path (.replaceAll (.getName f) ".clj" ".cljs"))
)

(defn clj-cljs* [files common-path to-path]
  (doseq [i (filter #(.endsWith (.getName %) ".clj") files)]
    (copy-file* i (file (rename to-path common-path i)))
  )
  (doseq [i (filter #(.isDirectory %) files)]
    (clj-cljs* (list-files i) (str common-path (.getName i) "/") to-path)
  )
)

(defn build [{:keys [common-path clj-path cljs-path js-path module-name]}]
  (clj-cljs* (list-files (str clj-path common-path)) common-path cljs-path)
  (cljsc/build
    cljs-path
    {
     :output-dir js-path
     :output-to (str js-path module-name ".js")
    }
  )
)

(defn build-default []
  (build
   {
    :clj-path "/home/user/projects/example/code/src/main/clojure/"
    :cljs-path "/home/user/projects/example/code/src/main/cljs/"
    :js-path "/home/user/projects/example/code/public/js/cljs/"
    :common-path "example/common/" ; the root of your common server-client code
    :module-name "example"
   }
  )
)

This question predates cljc, but since I stumbled upon it, I thought I would mention Clojure reader conditionals.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top