CMS tanpa kepala. Kenapa aku menulis milikku

Halo semuanya!

Artikel terbaru ini mendorong saya untuk menulis publikasi ini (saya melihatnya kemarin).

Ceritakan kembali fitur utama Headless / content-first / api-first, dll. Saya tidak akan menjadi CMS, materi sudah penuh dan mungkin banyak yang sudah terbiasa dengan tren ini. Dan saya ingin memberi tahu Anda mengapa dan bagaimana saya menulis sistem saya, mengapa saya tidak bisa memilih dari yang ada, apa yang saya pikirkan tentang sistem lain yang telah saya temui sebelumnya dan prospek apa yang saya lihat untuk semua ini. Fiksi akan banyak sekali (untuk materi dalam dua tahun), tetapi saya akan mencoba menulis lebih menarik dan bermanfaat. Siapa yang peduli, tolong, di bawah kucing.

Secara umum, ceritanya sangat panjang dan saya akan mencoba menceritakannya terlebih dahulu. Entah untuk membuatnya lebih jelas apa alasan sebenarnya untuk membuat mesin ini sendiri, atau hanya karena tanpa ini akan sulit di lapangan untuk menjelaskan mengapa saya melakukannya dengan cara ini, dan bukan dengan cara tertentu.

Tetapi untuk memulainya, saya akan secara singkat menuliskan kriteria seleksi utama untuk CMS Tanpa Kepala modern bagi saya secara pribadi, mengapa saya masih tidak dapat memilih solusi yang sudah jadi untuk saya sendiri. Supaya orang-orang tidak berhenti membaca banyak beech, tidak mengerti apa yang pada akhirnya akan diceritakan.

Secara singkat: Saya ingin semuanya berada di satu tempat: bagian belakang dan depan (dan bukan ini atau itu), dan GraphQL-API, dan bahwa basis data dikelola dan banyak lagi, termasuk tombol "Make Beautiful". Saya belum menemukan ini. Saya sendiri belum melakukan ini, tetapi secara keseluruhan ternyata cukup banyak, dan yang paling penting, ini memungkinkan saya untuk melakukan proyek nyata.

Jadi, pendekatan saya hampir tidak bisa disebut ilmiah dan dibenarkan. Faktanya adalah saya biasanya sangat sering menulis sesuatu sendiri. Saya suka program di sini. Dan dua tahun lalu (dan sebelum itu 8 tahun lagi) saya duduk di MODX CMF (di mana saya juga menemukan banyak kruk saya). Dan selama tiga tahun kami memulai satu proyek berskala besar, di mana, menurut saya, saya bisa menggunakan MODX. Tapi ternyata, saya tidak bisa ... Alasan utamanya adalah itu adalah startup tanpa persyaratan teknis, dengan banyak ide yang berubah dan ditambah setiap hari (dan beberapa kali sehari). Dan sekarang, setiap kali ketika di bawah ide baru perlu menambahkan beberapa entitas baru, mendaftar / mengubah bidang untuk yang sudah ada, membuat / menghapus / mengubah hubungan antara entitas-entitas ini (masing-masing, dengan perubahan dalam struktur database), saya memiliki beberapa titik Mulai beberapa jam untuk mengubah entitas ini. Memang, selain fakta bahwa perlu mendaftarkan perubahan-perubahan ini dalam skema, perlu mengubah database (hampir secara manual), memperbarui API, menulis ulang kode program, dll., Dll. Karenanya, bagian depan harus diperbarui berdasarkan semua ini. Akibatnya, saya memutuskan bahwa kita harus mencari sesuatu yang baru, lebih nyaman, yang entah bagaimana akan menyederhanakan semua ini. Saya akan mengklarifikasi sekali lagi bahwa pada saat itu saya adalah backend php, jadi jangan kaget atau tertawa bahwa saya mulai menemukan berbagai pembangun front-end, prosesor yang lebih sedikit, npm, dll. dll. Tapi bagaimanapun, secara bertahap dalam proyek kami sebuah front muncul pada reaksi + kurang, API pada GraphQL, dan server pada express.

Tetapi tidak semuanya semarak seperti kelihatannya bagi banyak orang sekarang. Biarkan saya mengingatkan Anda, ini lebih dari dua tahun yang lalu. Jika Anda berada di web JS modern selama kurang dari dua tahun, saya menyarankan Anda untuk membaca artikel ini: N alasan untuk menggunakan Aplikasi Buat Reaksi (habr). Singkatnya, terlalu malas: dengan munculnya skrip reaksi, Anda tidak dapat repot dengan mengonfigurasi webpack, dll. Semua ini masuk ke latar belakang. Orang-orang baik telah mengonfigurasi webpack sehingga sebagian besar proyek reaksi hampir dijamin untuk mengerjakannya, dan pengembang akhir berfokus langsung pada pemrograman produk akhir, daripada mengonfigurasi banyak dependensi, loader, dll. Tapi ini nanti. Dan sebelum itu, saya hanya perlu mengkonfigurasi paket web ini, ikuti pembaruan tumpukan semua yang terbang dengannya untuk mengejar ketinggalan, dll. dll. Tapi ini hanya bagian dari pekerjaan, pada dasarnya hanya bagian depan. Dan Anda juga membutuhkan server. Dan Anda juga membutuhkan API. Dan Anda juga perlu SSR (Server-side rendering), yang, omong-omong, masih bereaksi-skrip tidak memberikan, sejauh yang saya tahu. Secara umum, semuanya jauh lebih rumit daripada daripada sekarang, tidak ada banyak, dan semua orang mengeruk sebaik mungkin. Dan bagaimana saya kruk lalu ...

Bayangkan saja:

  • Konfigurasi webpack asli secara terpisah untuk depan dan server.
  • Implementasi SSR sendiri, sehingga async bekerja secara normal dengan server reaksi, dan gaya segera siap tiba, dan diindeks secara normal, dan status server untuk halaman yang tidak ditemukan diberikan.
  • Tidak ada redux. Yah, saya tidak langsung suka redux. Saya menyukai ide menggunakan fluks reaksi asli saya (walaupun saya harus menulis ulang sedikit untuk diri saya sendiri).
  • Skema dan resolver GraphQL yang diresepkan secara manual, tanpa penyebaran database secara otomatis (server API digunakan sebagai perantara untuk situs MODX).
  • Tidak ada reaksi-apollo / apollo-klien, dll. Semuanya ditulis secara independen dengan permintaan melalui fetch, repositori dalam browser berdasarkan fluks kustom.

Akibatnya: sampai sekarang, salah satu versi pertama ini memiliki satu proyek dengan kehadiran lebih dari 500, dan di musim (musim dingin) 1000-1700 siswa unik per hari. Waktu kerja 2 bulan. Ini karena saya secara manual me-reboot server setelah pembaruan perangkat lunak pencegahan. Dan sebelum reboot ini, uptime adalah 6+ bulan lagi. Namun yang paling menarik adalah konsumsi memori. Saat ini ada hampir 700 megabytes proses js. Ya, ya, saya juga tertawa dengan Anda di sini :) Tentu saja, ini banyak. Dan sebelum itu saya melakukan sedikit pencegahan dan meningkatkan indikator ini. Sebelumnya, ada total 1000 juta + per proses ... Namun demikian, ini berhasil dan cukup dapat ditoleransi. Dan sebelum Google mengubah algoritma PageSpeed ​​Insights pada bulan November, situs tersebut memiliki metrik kinerja 97/100. Bukti

Kesimpulan antara berdasarkan proyek ini berdasarkan pada sistem yang dikembangkan lebih lanjut tanpa proyek ini (proyek tertinggal):

Pro

  1. API proyek menjadi lebih fleksibel melalui penggunaan GraphQL, dan jumlah permintaan server telah berkurang secara signifikan.
  2. Proyek ini memiliki akses ke sejumlah besar komponen pada npm.
  3. Manajemen proyek menjadi lebih transparan melalui penggunaan dependensi, git, dll.
  4. Skrip dan gaya bawaan jelas lebih menyenangkan daripada banyak skrip terpisah di situs lama, ketika Anda tidak tahu apa yang dapat Anda hapus dari kebun binatang ini tanpa konsekuensi (dan Anda sering melihat beberapa versi bug di satu situs).
  5. Situs ini menjadi lebih interaktif, halaman berfungsi tanpa me-reboot, kembali ke halaman yang dilihat sebelumnya tidak memerlukan panggilan berulang ke server.
  6. Pengeditan data dilakukan langsung di halaman, dengan prinsip "edit apa yang Anda lihat dan di mana Anda melihat", tanpa panel admin yang terpisah.

Kontra (terutama untuk pengembang)

  1. Semuanya sangat rumit. Sungguh. Tidak realistis untuk menghubungkan beberapa pengembang pihak ketiga ke proyek. Saya sendiri sulit menemukan apa dan bagaimana cara kerjanya dan dari mana kaki saya tumbuh. Jika Anda melihat hal 3 dari plus, di mana dikatakan tentang transparansi, maka transparansi hanya dalam hal itu jika Anda mengaitkan sesuatu di suatu tempat, Anda dapat langsung melihat apa yang rusak (skrip tidak membangun, dll.), Tetapi dengan komit dan berbeda Anda bisa menemukan di mana ketagihan itu. Nah, jika Anda berhasil menambahkan sesuatu yang baru dan berfungsi, setidaknya Anda jelas memahami itu, ya, semuanya berjalan dengan baik. Tapi secara keseluruhan itu masih neraka.
  2. Kesulitan dengan caching. Kemudian, saya menemukan klien-apollo untuk diri saya sendiri. Dan sebelum itu, seperti yang saya katakan, saya menulis penyimpanan berbasis fluks. Karena penyimpanan ini, dimungkinkan untuk mendapatkan data yang diperlukan untuk rendering dari komponen yang berbeda, tetapi volume cache pada sisi klien sangat besar (setiap set entitas yang khas memiliki repositori sendiri). Akibatnya, sulit untuk memverifikasi apakah objek diminta sebelumnya atau tidak (yaitu, apakah layak untuk membuat permintaan ke server untuk menemukannya), apakah semua data terkait tersedia, dll.
  3. Kesulitan dengan skema, struktur database dan resolvers (fungsi API untuk menerima / memodifikasi data). Seperti yang saya katakan, saya menulis skema secara manual, dan resolvers juga. Pada apa dalam resolvers saya mencoba memberikan caching, dan memproses permintaan bersarang dan seluk-beluk lainnya. Pada saat itu saya harus masuk jauh ke esensi dan kode program GraphQL. Keuntungannya adalah saya secara umum memahami dengan baik bagaimana GraphQL bekerja, apa kelebihan dan kekurangannya, dan cara memasaknya dengan lebih baik. Kelemahannya adalah, tentu saja, Anda tidak dapat menulis semua fasilitas dan roti yang ditulis dengan perintah seperti apollo dalam satu. Akibatnya, ketika saya menemukan apollo, tentu saja, saya mulai menggunakan komponen mereka dengan sangat senang (tetapi terutama di bagian depan, saya akan memberi tahu Anda alasannya di bawah).

Secara umum, proyek ini menggunakan teknologi yang sudah ketinggalan zaman secara pribadi adalah milik saya pada 100%, jadi saya dapat meninggalkannya sampai waktu yang lebih baik. Tetapi ada proyek-proyek lain yang saya harus melangkah lebih jauh dan mengembangkan platform. Dan beberapa kali saya harus menulis ulang semuanya dari awal. Selanjutnya, saya akan berbicara lebih detail tentang tugas-tugas individu yang saya temui dan solusi apa yang saya kembangkan dan terapkan sebagai hasilnya.

Skema-pertama. Pertama sirkuit, dan kemudian segalanya

Situs (antarmuka web, thin client, dll.) Adalah semua tampilan informasi (well, manajemen informasi, jika diizinkan dan fungsionalitas memungkinkan). Tapi pertama-tama, semuanya sama, sebuah basis data (tabel, kolom, dll.). Setelah menemui beberapa pendekatan berbeda untuk bekerja dengan database dalam perjalanan, saya paling menyukai pendekatan Schema-first. Yaitu, Anda menggambarkan skema entitas dan tipe data (secara manual atau melalui antarmuka), menggunakan skema, dan Anda segera memiliki perubahan yang dijelaskan dalam database (tabel / kolom dibuat / dihapus, serta hubungan di antara mereka). Bergantung pada implementasinya, Anda juga akan menghasilkan semua fungsi penyelesai yang diperlukan untuk mengelola data ini. Yang paling penting dalam arah ini saya menyukai proyek prisma.io .

Dengan izin Anda, karena bahkan di hub saya belum melihat satu artikel tentang prisma, saya akan menarik perhatian mereka sedikit, karena proyek ini sangat menarik, dan tanpa mereka saya tidak akan memiliki platform seperti sekarang yang membuat saya sangat bahagia . Sebenarnya, itu sebabnya saya menyebut platform saya prisma-cms, karena prisma.io memainkan peran yang sangat besar di dalamnya.

Sebenarnya, prisma.io adalah proyek SaaS, tetapi dengan peringatan besar: mereka menempatkan hampir semua yang mereka lakukan pada github. Artinya, Anda dapat menggunakan server mereka dengan biaya yang sangat masuk akal (dan konfigurasikan database dan API Anda sendiri untuk diri sendiri dalam hitungan menit), atau Anda dapat sepenuhnya menggunakan semuanya di rumah. Dalam hal ini, prisma harus secara logis dibagi menjadi dua bagian terpisah yang penting:

  1. Prisma-server, yaitu server tempat basis data juga berputar.
  2. Prisma-klien. Ini pada dasarnya juga merupakan server, tetapi dalam kaitannya dengan sumber data (prisma-server) itu adalah klien.

Sekarang saya akan mencoba menjelaskan situasi yang membingungkan ini. Secara umum, inti dari prisma adalah menggunakan titik akhir API tunggal, Anda dapat bekerja dengan sumber data yang berbeda. Ya, di sini siapa pun akan mengatakan bahwa mereka semua datang dengan GraphQL dan prisma tidak diperlukan di sini. Secara umum, semua orang akan benar, tetapi ada poin serius: GraphQL hanya mendefinisikan prinsip-prinsip dan pekerjaan secara keseluruhan, tetapi dengan sendirinya, itu tidak memberikan pekerjaan dengan sumber data akhir di luar kotak. Dia mengatakan, "Anda dapat membuat API untuk menggambarkan permintaan apa yang dapat dikirim pengguna, tetapi bagaimana Anda menangani permintaan ini terserah Anda." Dan prisma juga, tentu saja, menggunakan GraphQL (omong-omong, dan banyak hal lainnya, termasuk berbagai produk apollo). Tetapi prisma plus untuk ini hanya menyediakan pekerjaan dengan database. Artinya, menggambarkan skema dan penyebarannya, tabel dan kolom yang diperlukan (serta hubungan di antara mereka) akan segera dibuat dalam database yang ditentukan, dan bahkan segera menghasilkan semua fungsi CRUD yang diperlukan. Artinya, dengan prisma, Anda tidak hanya mendapatkan server GraphQL, tetapi API kerja lengkap yang segera memungkinkan Anda untuk bekerja dengan database. Jadi, Prisma-server menyediakan basis data dan interaksi dengannya, dan prisma-klien memungkinkan Anda untuk menulis resolver dan mengirim permintaan ke server-prisma (atau di tempat lain, bahkan untuk beberapa server prisma). Dan ternyata Anda hanya dapat menggunakan prisma-klien sendiri (dan prisma.io SaaS akan digunakan sebagai prisma-server), dan Anda dapat menggunakan prisma-server sendiri, dan umumnya tidak bergantung pada prisma dengan cara apa pun, itu saja milikmu.

Di sini saya telah memilih prisma untuk diri saya sendiri, sebagai dasar untuk platform saya. Tapi kemudian saya harus memutarnya sendiri untuk mendapatkan platform penuh.

1. Gabungkan skema


Pada saat itu, prisma tidak dapat menggabungkan sirkuit. Artinya, tugasnya adalah sebagai berikut:

Anda memiliki model pengguna yang dijelaskan dalam satu modul

type User { id: ID! @unique username: String! @unique email: String @unique } 

dan dalam modul lain

 type User { id: ID! @unique username: String! @unique firstname: String lastname: String } 

Sebagai bagian dari satu proyek, Anda ingin menggabungkan kedua skema ini secara otomatis untuk mendapatkan hasil

 type User { id: ID! @unique username: String! @unique email: String @unique firstname: String lastname: String } 

Tapi kemudian prisma ini tidak bisa dilakukan. Ternyata mengimplementasikan ini menggunakan pustaka merge-graphql-schemas .

Bekerja dengan prisma-server sewenang-wenang.


Dalam prisma, konfigurasi ditulis dalam file konfigurasi khusus. Jika Anda ingin mengubah alamat server prisma yang digunakan, Anda harus mengedit file. Agak, tidak menyenangkan. Saya ingin membuat URL mungkin untuk ditentukan dalam perintah, misalnya endpoint = http: // endpoint-address yarn deploy (awal benang). Itu terbunuh selama beberapa hari ... Tapi sekarang Anda dapat menggunakan satu proyek prisma untuk sejumlah titik akhir. By the way, prisma-cms sejauh ini dengan mudah bekerja bahkan dengan database lokal, bahkan dengan server prisma SaaS.

Modul / Plugin


Ini umumnya tidak cukup. Seperti yang saya katakan, tugas utama prisma adalah menyediakan pekerjaan dengan berbagai basis data. Dan mereka melakukan pekerjaan dengan sangat baik. Sudah, mereka mendukung bekerja dengan MySQL, PostgreSQL, Amazon RDS dan MongoDB, beberapa jenis lebih banyak sumber di jalan. Tetapi mereka tidak menyediakan infrastruktur modular apa pun. Sejauh ini tidak ada pasar atau sesuatu seperti itu. Hanya ada beberapa kekosongan khas. Tetapi Anda tidak dapat memilih dua atau tiga dari beberapa kekosongan dan menginstal pada satu proyek. Kita harus memilih satu. Saya ingin sehingga mungkin untuk menginstal sejumlah modul yang berbeda pada tugas akhir, dan ketika memasang sirkuit dan resolver akan bergembira dan mendapatkan proyek tunggal dengan fungsionalitas total. Dan meskipun belum ada antarmuka grafis, sudah ada lebih dari dua lusin modul dan komponen yang dapat digabungkan pada tugas akhir. Di sini saya akan segera memutuskan sedikit tentang definisi pribadi: modul adalah apa yang dipasang di belakang (memperluas database dan API), dan komponen adalah apa yang dipasang di depan (untuk menambahkan berbagai elemen antarmuka). Sejauh ini, tidak ada antarmuka grafis untuk menghubungkan modul, tetapi tidak sulit bagi saya untuk menulis dengan cara ini (ini tidak sering dilakukan):

  constructor(options = {}) { super(options); this.mergeModules([ LogModule, MailModule, UploadModule, SocietyModule, EthereumModule, WebrtcModule, UserModule, RouterModule, ]); } 

Setelah menambahkan modul baru, cukup hanya melakukan penyebaran dengan satu perintah lagi dan hanya itu, di sini kita sudah memiliki tabel / kolom baru dan fungsi tambahan.

5 depan, responsif terhadap perubahan di backend


Ini sama sekali tidak cukup. Ini akan diikuti oleh penyimpangan. Faktanya adalah bahwa semua CMS API-pertama yang saya lihat mengatakan "Kami luar biasa untuk menyediakan API, dan Anda mengacaukan bagian depan yang Anda inginkan." Ini adalah apa yang mereka "sekrupkan apa pun yang kamu suka" sebenarnya berarti "mengganggu sesukamu." Persis sama dengan kerangka kerja UI mengatakan, "lihat apa tombol keren kita dan lakukan semua itu, dan bingung dengan backend sendiri". Itu selalu membunuh. Saya hanya ingin menemukan CMS komprehensif yang ditulis dalam javascript, menggunakan GraphQL dan menyediakan bagian belakang dan depan. Tetapi saya tidak menemukan yang seperti itu. Saya benar-benar ingin perubahan API segera dirasakan di depan. Dan untuk ini, beberapa subteps diselesaikan:

5.1 Menghasilkan fragmen API


Di depan, fragmen dari file skema terdaftar dalam permintaan. Ketika API dibangun kembali di server, file JS baru dengan fragmen API juga dihasilkan. Dan dalam permintaan tertulis seperti ini:

 const { UserNoNestingFragment, EthAccountNoNestingFragment, NotificationTypeNoNestingFragment, BatchPayloadNoNestingFragment, } = queryFragments; const userFragment = ` fragment user on User { ...UserNoNesting EthAccounts{ ...EthAccountNoNesting } NotificationTypes{ ...NotificationTypeNoNesting } } ${UserNoNestingFragment} ${EthAccountNoNestingFragment} ${NotificationTypeNoNestingFragment} `; const usersConnection = ` query usersConnection ( $where: UserWhereInput $orderBy: UserOrderByInput $skip: Int $after: String $before: String $first: Int $last: Int ){ objectsConnection: usersConnection ( where: $where orderBy: $orderBy skip: $skip after: $after before: $before first: $first last: $last ){ aggregate{ count } edges{ node{ ...user } } } } ${userFragment} `; 

5.2 Satu konteks untuk semua komponen


Bereaksi 16.3 memperkenalkan API konteks baru . Saya membuatnya sehingga dalam komponen anak di tingkat mana pun dimungkinkan untuk mengakses konteks tunggal tanpa mencantumkan jenis yang sebelumnya diinginkan dari konteks, tetapi hanya menunjukkan static contextType = PrismaCmsContext dan mendapatkan semua pesona melalui konteks ini-> (termasuk klien API, skema , permintaan, dll.).

5.3 filter dinamis


Saya juga sangat ingin. GraphQL memungkinkan Anda membangun kueri kompleks dengan struktur bersarang. Saya ingin filter menjadi dinamis juga, dibentuk dari skema API, dan memungkinkan kami membuat kondisi bersarang. Inilah yang terjadi:


5.4 Pembuat Situs Web


Dan akhirnya, yang kurang dari saya adalah editor situs eksternal, yaitu seorang desainer. Saya hanya menginginkan tindakan minimum yang dilakukan di server, dan semua desain akhir harus dilakukan di depan (termasuk mengatur rute, membuat pilihan, dll.). Ini adalah topik untuk artikel terpisah, karena di antara hal-hal lain, saya juga menulis editor wysiwyg kruk saya untuk itu pada contentEditable murni, dan ada banyak seluk-beluk. Jika saya dikembalikan ke hak saya dan siapa yang akan tertarik, saya akan menulis artikel terpisah.

Yah, akhirnya, video demo pendek dari perancang beraksi. Masih cukup mentah, tetapi saya menyukainya.


Saya akan menyelesaikannya. Saya belum banyak menulis, apa yang ingin saya tulis, tetapi banyak yang telah terjadi. Saya akan senang berkomentar.

PS: semua kode sumber, termasuk kode sumber situs itu sendiri, ada di sini .

Source: https://habr.com/ru/post/id448982/


All Articles