
Ketika datang ke perpustakaan Ext JS, Anda harus mendengar cukup banyak hal negatif dari para pecinta: berat, mahal, kereta. Biasanya, sebagian besar masalah terkait dengan ketidakmampuan memasaknya. Sebuah proyek yang dirakit dengan benar menggunakan Sencha Cmd dengan semua css, gambar berbobot dalam produksi di wilayah 1Mb, yang sebanding dengan Angular yang sama. Ya, dan gangguan tidak lebih ...
Ada kemungkinan bahwa gagasan Sencha terkait dengan keturunan ini, tetapi bahkan para lawannya yang berprinsip mengakui bahwa sulit untuk menemukan solusi terbaik untuk membangun proyek intranet yang serius.
Menurut pendapat saya, hal yang paling berharga di Ext JS bukanlah kumpulan komponen UI, melainkan arsitektur OOP yang baik. Bahkan dengan mempertimbangkan perkembangan JS yang cepat dalam beberapa tahun terakhir, banyak hal penting yang diimplementasikan dalam Ext JS 7 tahun yang lalu masih hilang di kelas asli (ruang nama, mixin, properti statis, panggilan metode induk yang nyaman). Inilah yang mendorong saya beberapa tahun yang lalu untuk bereksperimen dengan peluncuran kelas Ext JS di backend. Tentang eksperimen serupa pertama yang sudah saya posting di Habré. Artikel ini menjelaskan implementasi baru dari gagasan lama dan sejumlah gagasan baru.
Sebelum kita mulai, perhatikan pertanyaan: bagaimana menurut Anda, di mana dieksekusi dan apa yang dilakukan cuplikan kode di bawah ini?
Ext.define('Module.message.model.Message', { .... ,async newMessage() { ......... this.fireEvent('newmessage', data); ...... } ... })
Kode ini dieksekusi di server dan menyebabkan acara "pesan baru" di semua contoh kelas "Module.message.model.Message" di semua mesin klien yang terhubung ke server.
Untuk mengilustrasikan kemungkinan menggunakan Ext JS sisi server, kami akan menganalisis proyek obrolan sederhana. Kami tidak akan melakukan login apa pun, hanya ketika Anda memasukkan pengguna memasukkan nama panggilan. Anda dapat memposting pesan umum atau pribadi. Obrolan harus bekerja secara real time. Mereka yang berharap dapat segera mencoba semua ekonomi ini dalam bisnis.
Instalasi
Untuk memulai, kita memerlukan nodejs 9+ dan redis-server (diasumsikan bahwa mereka sudah diinstal).
git clone https://github.com/Kolbaskin/extjs-backend-example cd extjs-backend-example npm i
Kami memulai server:
node server
Di browser, buka halaman
localhost : 3000 / www / auth /
Masukkan beberapa nama panggilan dan tekan enter.
Proyek ini demo, jadi tidak ada dukungan untuk browser lama (ada desain ES8), gunakan Chrome atau FF baru.
Server
Mari kita mulai.
Kode Server (server.js)
Seperti yang Anda lihat, di sini semuanya lebih atau kurang standar untuk server pada express. Yang menarik adalah dimasukkannya kelas Ext JS untuk melayani rute yang sesuai:
app.use('/api/auth', Ext.create('Api.auth.Main')); app.use('/www/auth', Ext.create('Www.login.controller.Login'));
Implementasi REST API
Kelas Api.auth.Main melayani permintaan ke REST API (protected / rest / auth / Main.js).
Ext.define('Api.auth.Main', { extend: 'Api.Base',
Pembuatan halaman HTML, menggunakan XTemplate di server
Kelas kedua, Www.login.controller.Login, membangun halaman html biasa dengan formulir login (protected / www / login / controller / Login.js).
Ext.define('Www.login.controller.Login', {
Template menggunakan XTemplate standar (protected / www / login / view / login.tpl)
<h2>{pageTitle} (date: {[Ext.Date.format(values.date,'dmY')]})</h2> <form method="post"> <input name="name" placeholder="name"> <button type="submit">enter</button> </form>
Segala sesuatu yang dijelaskan di atas adalah set yang sepenuhnya standar, pembaca yang teliti akan mengatakan, dan untuk ini tidak perlu pagar taman ini dengan transfer Ext JS ke server. Oleh karena itu, kami beralih ke bagian kedua artikel, yang akan menunjukkan apa yang dimaksudkan untuk semua.
Pelanggan
Mari kita buat aplikasi Ext JS klien biasa di direktori statis. Dalam contoh ini, saya sengaja tidak mempertimbangkan penggunaan cmd, saya mengambil tema ext-all dan standar yang sudah dibangun. Masalah majelis adalah topik terpisah, yang, mungkin, akan mencurahkan pos terpisah.
Semuanya dimulai dengan app.js
Kehadiran socket web adalah poin penting, itu yang memungkinkan Anda untuk menerapkan semua keajaiban yang dijelaskan di bawah ini.
Tata letak elemen pada halaman terdapat di kelas Admin.view.Viewport (statis / app / view / Viewport.js). Tidak ada yang menarik di sana.
Elemen fungsional utama (daftar pengguna, bilah pesan dan formulir pengiriman) diimplementasikan sebagai modul terpisah.
Daftar Pengguna
Algoritma sederhana dari daftar ini adalah sebagai berikut: pada saat membuka halaman, pengguna saat ini diambil dari server. Ketika pengguna baru terhubung, server menghasilkan "tambah" acara di kelas "Module.users.model.UserModel", ketika terputus, di kelas yang sama, acara "hapus" dinaikkan. Masalahnya adalah bahwa peristiwa tersebut dipicu di sisi server, dan Anda dapat melacaknya di klien.
Sekarang, hal pertama yang pertama. Di sisi klien, Simpan data juggles (static / app / modules / users / store / UsersStore.js)
Ext.define('Module.users.store.UsersStore', { extend: 'Ext.data.Store' ,autoLoad: true ,total: 0 ,constructor() {
Ada 2 poin menarik. Pertama, di baris "const data = tunggu this.dataModel. $ Read ();" Metode server dari model ini disebut. Sekarang Anda tidak perlu menggunakan Ajax, protokol pendukung, dll., Cukup panggil metode server sebagai lokal. Pada saat yang sama, keselamatan tidak dikorbankan (lebih dari itu di bawah).
Kedua, konstruksi standar this.dataModel.on (...) memungkinkan Anda untuk melacak peristiwa yang akan dihasilkan oleh server.
Model adalah jembatan antara bagian klien dan server aplikasi. Ini seperti dualisme cahaya - ini mengimplementasikan sifat-sifat baik frontend maupun backend. Mari kita lihat modelnya dengan cermat.
Ext.define('Module.users.model.UserModel', { extend: 'Core.data.DataModel' ,testClientMethod() { ... } ,testGlobalMethod() { ... } ,privateServerMethod() { .... } ,async $read(params) {
Perhatikan komentar / * ruang lingkup: server * / dan / * ruang lingkup: klien * / - konstruksi ini adalah label untuk server dengan mana ia menentukan jenis metode.
testClientMethod - metode ini berjalan secara eksklusif pada klien dan hanya tersedia di sisi klien.
testGlobalMethod - metode ini berjalan di klien dan di server dan tersedia untuk digunakan di sisi klien dan server.
privateServerMethod - metode ini dijalankan di server dan tersedia hanya untuk panggilan di server.
$ read adalah jenis metode yang paling menarik yang hanya berjalan di sisi server, tetapi Anda dapat memanggilnya baik di klien maupun di server. $ Awalan membuat setiap metode sisi server tersedia di sisi klien.
Anda dapat melacak koneksi dan pemutusan klien menggunakan soket web. Sebuah instance dari kelas Base.wsClient dibuat untuk setiap koneksi pengguna (protected / base / wsClient.js)
Ext.define('Base.wsClient', { extend: 'Core.WsClient'
Metode fireEvent, tidak seperti yang standar, memiliki parameter tambahan, di mana ia diteruskan ke klien mana acara harus dipicu. Dapat diterima untuk melewati pengidentifikasi klien tunggal, array pengidentifikasi, atau string "semua". Dalam kasus terakhir, acara akan dipicu pada semua klien yang terhubung. Kalau tidak, ini adalah FireEvent standar.
Mengirim dan menerima pesan
Pengontrol formulir (statis / app / admin / modul / pesan / tampilan / FormController.js) bertanggung jawab untuk mengirim pesan.
Ext.define('Module.messages.view.FormController', { extend: 'Ext.app.ViewController' ,init(view) { this.view = view;
Pesan tidak disimpan di mana pun di server, acara "pesan baru" hanya dipicu. Yang menarik adalah panggilan "this.fireEvent ('pesan baru', data.to, msg);", di mana pengidentifikasi klien dilewatkan sebagai penerima pesan. Dengan demikian, distribusi pesan pribadi diimplementasikan (static / app / admin / modules / messages / model / Model.js).
Ext.define('Module.messages.model.Model', { extend: 'Core.data.DataModel' ,async $newmessage(data) { const msg = { user: data.user, message: data.message } if(data.to && Ext.isArray(data.to) && data.to.length) { this.fireEvent('newmessage', data.to, msg); } else { this.fireEvent('newmessage', 'all', msg); } return true; } })
Seperti halnya pengguna, data untuk daftar pesan didorong oleh Store (static / app / admin / modules / messages / store / MessagesStore.js)
Ext.define('Module.messages.store.MessagesStore', { extend: 'Ext.data.Store', fields: ['user', 'message'], constructor() {
Secara umum, ini semua yang menarik dalam contoh ini.
Kemungkinan pertanyaan
Ketersediaan metode server pada klien, tentu saja, bagus, tetapi bagaimana dengan keamanan? Ternyata seorang peretas jahat dapat melihat kode server dan mencoba memecahkan backend?Tidak, dia tidak akan berhasil. Pertama, semua metode server dihapus dari kode kelas ketika dikirim ke browser klien. Untuk tujuan ini, komentar / arahan / * ruang lingkup dimaksudkan: ... * /. Kedua, kode metode sisi server yang paling publik digantikan oleh konstruksi menengah yang mengimplementasikan mekanisme panggilan jarak jauh di sisi klien.
Lagi tentang keamanan. Jika metode server dapat dipanggil pada klien, ternyata, dapatkah saya memanggil metode semacam itu? Dan jika ini adalah metode pembersihan basis data?Dari klien, Anda hanya dapat memanggil metode yang memiliki $ awalan dalam namanya. Untuk metode semacam itu, Anda sendiri yang menentukan logika pemeriksaan dan akses. Seorang pengguna eksternal tidak memiliki akses ke metode server tanpa $, ia bahkan tidak akan melihatnya (lihat jawaban sebelumnya)
Sepertinya Anda memiliki sistem monolitik di mana klien dan server saling terkait. Apakah penskalaan horizontal mungkin?Sistemnya memang tampak monolitik, tetapi sebenarnya tidak. Klien dan server dapat "hidup" pada mesin yang berbeda. Klien dapat dijalankan di server web pihak ketiga mana pun (Nginx, Apache, dll.). Masalah pemisahan klien dan server sangat mudah diselesaikan oleh pembuat proyek otomatis (saya dapat menulis posting terpisah tentang ini). Untuk menerapkan mekanisme pesan layanan internal, sistem menggunakan antrian (yaitu, Redis diperlukan untuk ini). Dengan demikian, bagian server dapat dengan mudah diskalakan secara horizontal dengan hanya menambahkan mesin baru.
Dengan pendekatan pengembangan yang biasa, sebagai aturan, backend menyediakan satu set API tertentu yang dapat Anda hubungkan dengan beragam aplikasi klien (situs web, aplikasi seluler). Dalam kasus Anda, ternyata hanya klien yang ditulis dalam Ext JS yang dapat bekerja dengan backend?Di server, khususnya dalam model modul, logika bisnis tertentu diterapkan. Untuk menyediakan akses ke sana melalui REST API, "pembungkus" kecil sudah cukup. Contoh yang sesuai disajikan di bagian pertama artikel ini.
Kesimpulan
Seperti yang Anda lihat, untuk pengkodean yang nyaman dari aplikasi yang cukup rumit, sangat mungkin untuk bertahan dengan satu perpustakaan di bagian depan dan belakang. Ini memiliki manfaat yang signifikan.
Mempercepat proses pengembangan. Setiap anggota tim dapat bekerja di backend dan frontend. Downtime karena alasan "Saya menunggu API ini muncul di server" tidak lagi relevan.
Kode lebih sedikit. Bagian kode yang sama dapat digunakan pada klien dan di server (pemeriksaan, verifikasi, dll.).
Mempertahankan sistem seperti itu jauh lebih sederhana dan lebih murah. Alih-alih dua programmer yang beragam, sistem akan dapat mendukung satu (atau dua yang sama tetapi dapat dipertukarkan). Untuk alasan yang sama, risiko yang terkait dengan pergantian tim juga lebih rendah.
Kemampuan untuk membuat sistem waktu nyata di luar kotak.Menggunakan sistem pengujian tunggal untuk backend dan frontent.