Історія про Handlebars та управління станом

текст перекладу
pic

Фото Josh Sorenson: https://www.pexels.com/photo/black-flat-screen-computer-monitor-1714208/

Управління станом.

Ці два слова можуть викликати страх навіть у найбільш досвідчених інженерів. Кілька тижнів тому наша команда стикнулася з особливо складною проблемою управління станом під час роботи з застарілим кодом, який містив серверно-рендерений додаток на Handlebars.

Місія? Зберегти синхронізований стан додатка між сервером, де рендеряться шаблони, та клієнтом, де користувачі взаємодіють з додатком.

Це не була типова ситуація для управління станом на клієнтській стороні. Нам потрібне було рішення, яке б легко зв'язувало сервер і клієнт, забезпечуючи ініціалізацію стану на сервері, передачу його в шаблони і потім «магічну» доступність на клієнті без важких маніпуляцій.

Стан нашої боротьби

Традиційні бібліотеки для управління станом на клієнтській стороні виглядали як надмірне рішення, вводили непотрібну складність і не вирішували унікальні проблеми ініціалізації стану на сервері та повторної гідратації на клієнті.

Ми експериментували з різними обхідними шляхами:

  • Передача стану як JSON: Ми спробували вставити стан як JSON-об'єкт у HTML, але це швидко стало громіздким і важким для підтримки.
  • Повторна гідратація на клієнті: Отримання даних стану повторно на клієнті після початкового рендеру призводило до зайвих мережевих запитів та вузьких місць у продуктивності.
  • Інші рішення для управління станом: Ми досліджували повноцінні бібліотеки для управління станом на клієнтській стороні, але вони не зовсім підходили для нашого унікального випадку.

Pico State на допомогу

Розчаровані обмеженнями існуючих рішень, я вирішив створити Pico State, легку бібліотеку для управління станом, спеціально розроблену для серверно-рендерених додатків. Pico State була створена з трьома основними принципами:

  • Простота: Інтуїтивно зрозумілий API, який легко освоїти і використовувати, мінімізуючи обсяг шаблонного коду.
  • Ізоморфність: Легко використовувана як на сервері, так і на клієнті.
  • Легкість: Мінімальний обсяг з нульовими зовнішніми залежностями, що забезпечує оптимальну продуктивність.

Як ми з'єднали сервер і клієнт

Магія Pico State полягає в її здатності створювати спільний об'єкт стану, доступний як на сервері, так і на клієнті. Ось як ми інтегрували його в наш додаток на Handlebars:

  1. Ініціалізація на сервері (src/store/index.js)
const { Store } = require('@uche-exe/pico-state');  

// Інтелектуальна гідратація: перевірка наявності стану в localStorage або window  
let existingState = JSON.parse(localStorage.getItem("appState")) ?? window.storeInstance?.state;  
let store;  

if (existingState) {  
 // Гідратуємо магазин з існуючим станом  
 store = new Store({ initialState: existingState });  
} else {  
 // Створюємо новий екземпляр магазину  
 store = new Store();  

 // Розрізаємо та обробляємо: ініціалізуємо слайси для різних доменів додатку (auth, post, cart)  
 // з можливими початковими значеннями  
 const { auth } = store.createSlice({  
 name: "auth",  
 initialState: [  
 { username: "uche" },   
 { fullName: "Uchechukwu Samuel Ottah" },  
 { imageUrl: "my_img_url" }   
 ]  
 });  

 const { post } = store.createSlice({  
 name: "post",  
 });  

 const { cart } = store.createSlice({  
 name: "cart",  
 initialState: {  
 cartItems: [  
 // ... початкові елементи корзини  
 ]  
 }  
 });  
}  

// Доступ до екземпляру магазину з боку клієнта, прикріплюючи його до об'єкта "window"  
if (typeof window !== "undefined") {  
 console.log("Ініціалізація магазину на об'єкті window...");  
 window.storeInstance = store;   
}  

module.exports = { store };

текст перекладу
**Webpack пакування (**`webpack.config.js`**)**

Щоб зробити наш `store` доступним у браузерах, ми використовуємо Webpack для пакування файлу `store/index.js`, який відповідає за ініціалізацію стану та створення слайсів. Цей процес забезпечує сумісність з браузерами, оскільки як Pico State, так і наш додаток на Handlebars є модулями [_CommonJS_](https://nodejs.org/api/modules.html#modules-commonjs-modules) (тому ми використовуємо синтаксис ‘require’).

module.exports = {
entry: './src/store/index.js',
output: {
filename: 'store.bundle.js',
path: path.resolve(__dirname, 'public/js'),
},
};
```

Ця конфігурація вказує Webpack взяти store/index.js як точку входу, упакувати його разом із залежностями та вивести результат як store.bundle.js у директорії public/js. Цей упакований файл потім включається в наш HTML, щоб зробити store доступним на клієнтській стороні.

  1. Взаємодія на клієнтській стороні (public/js/store.js)

Тут міститься логіка клієнтської частини для взаємодії з нашим store. Ми використовували jQuery для доступу до storeInstance, який був відкритий на об'єкті window, і виконували дії, наприклад, оновлюючи інтерфейс користувача на основі стану.

$(document).ready(async function () {  
 const store = window.storeInstance;   

 if (!store) {  
 console.error("Екземпляр store не знайдено. Перевірте ініціалізацію.");  
 return;  
 }  

 // Динамічний підрахунок товарів у корзині: Оновлюємо кількість товарів у корзині на основі store.state.cart  
 async function updateCartCount() {  
 const cartItems = store.state.cart?.cartItems ?? [];  
 $(".cart-count").text(cartItems.length);  
 }  
 // Ініціалізуємо кількість товарів у корзині при завантаженні сторінки  
 await updateCartCount();  

 // ... інші функції jQuery для взаємодії з store та оновлення інтерфейсу користувача ...  
});
  1. Інтеграція на клієнтській стороні (_shared_global_component.hbs)

Нарешті, ми можемо імпортувати необхідні скрипти, щоб зробити наш state та логіку маніпуляцій з клієнтської частини доступними в браузері. Ми імпортуємо їх лише одного разу, в одному спільному частковому компоненті (щоб уникнути множинних імпортів, що можуть викликати кілька виконань події).




Результати

Інтеграція Pico State в наш додаток на Handlebars принесла значні переваги:

  • Легкість управління станом: Команда могла зосередитись на розробці функцій, замість того, щоб боротися з складнощами синхронізації стану.
  • Неймовірна продуктивність: Вилучення зайвих запитів на клієнтській стороні призвело до помітного покращення часу початкового завантаження.
  • Краща організація коду: Централізоване управління станом призвело до чистішого та більш підтримуваного коду.
  • Підвищена продуктивність розробників: Спрощений підхід до управління станом дозволив команді зосередитись на наданні цінності нашим користувачам.

Кінець саги

Pico State став героєм у нашій сазі управління станом. Його простота, ізоморфність і легка конструкція зробили його ідеальним рішенням для нашого серверно-рендереного додатку на Handlebars. Легко з'єднуючи сервер і клієнт, Pico State дозволив нам створити більш ефективний, підтримуваний і продуктивний додаток.

Якщо ви стикаєтеся з проблемами управління станом у подібному середовищі, раджу вам спробувати Pico State. Це може бути той самий герой, який потрібен вашому проекту.

Якщо вам подобається pico-state і ви хочете зробити його кращим, ви можете просто зайти на сторінку github і створити issue або відкрити PR.

Внесок вітається.

Github: https://github.com/uche-exe/pico-state

NPM: https://www.npmjs.com/package/@uche-exe/pico-state

https://tenor.com: Skeletor Running Away

До наступного разу!

Перекладено з: A tale of Handlebars and State Management

Leave a Reply

Your email address will not be published. Required fields are marked *