📜 ⬆️ ⬇️

Tutorial Derby.js


I hope you have already read the post about comparing frameworks and made the right choice. Now it's up to you - to curb this recalcitrant stallion, to learn not plowed virgin soil, so to speak, well, in general, you understand. I warn you, learning Derby causes a paradigm shift. The world of web development for you will never be the same.




Instead of the preface


')
The post is written based on the questions in the comments and posts on Habré.
I believe that you are already familiar with Derby and created your first hello world . If not, I highly recommend doing it right now. And here are some sample applications with comments . For here we will talk about common, difficult to understand points.
In the code examples - Coffeescript. I hope people familiar only with js will not have problems with this.
Also in the examples I use the id in the form of 12341243. in reality it will be a guid.

Derby application



Each Derby application is an enhanced Express application. That is, you can use connect.js, server routes, etc., as you do in the usual Express application.
One Derby application consists of one server application (Express) and one or several client applications. For example, you can separate the site for users and admin panel, and do not load users with templates and business logic from the admin panel.

First request



The first request from the client on the server processes the required route and the generated html is sent to the client along with the client part of the Derby application (templates, model, browserify with modules, business logic). The client first sees the html, and everything else is loaded next. In the future, when you change the url, the routes will be processed on the client and generate html in the same place. If js is disabled in the browser, then routes are processed only on the server and html is always generated on the server, just like a regular static site.

Routes



Routes work both on the server and on the client using tracks . If the client does not have the required route, then the request simply fails to the server. That is, there can be more routes on the server than on the client, for example, for downloading files, etc.

Html



Derby has a built-in template engine - slightly modified Handlebars . There is a module for Jade .

Data binding is performed as follows:
dynamic (data changes when html changes and vice versa)
<input type="text" value="{_page.name}" />, <h2>{users.12431243.age}</h2> 

static (fired and forgotten)
 <input type="text" value="{{_page.name}}" />, <h2>{{users.12431243.age}}</h2> 


Templates consist of sections: Tille, Head, Body, Footer, Scripts, etc. You can, for example, in the layout template set the Head and Scripts (if they are the same for all pages), and in others set only the Title and Body.

Model



Model is an object with api for working with data. All data manipulations occur through it.
Model can exist both on the server and on the client. There can be several models on the server, only one on the client.
Models on the server can be created for each request.
 model = req.getModel() 

either regardless of requests from the store
 model = store.createModel() 

On the client, the model is always here:
 model = require('derby').app.model 


If a model is created for the first request from the client, then after all the manipulations with it, it is serialized and sent to the client. Otherwise, an empty model is sent to the client.

Path



All data is presented in the form of a path, which consists of the collection name, id and properties of this object.
For example:
 user = model.get 'users.12341234' userName = model.get 'users.12341243.name' model.set 'customers.12341234.properties.isIdiot', true model.set 'customers.12341243.properties', {justMadeOrderForBillionDollars: true, isIdiot: false} 


Fetch Subscribe



When creating a model, it is empty.
 emptyObject = model.get() 

There are two ways to fill it with the fetch and subscribe data.
fetch - simply retrieves data from the database and puts it into the model.
 model.fetch 'product.12341243', 'users', -> console.log '        ' 

subscribe - dynamically binds data from the database with the data in the model
 model.subscribe 'products', -> console.log '  ' 

Now if we change the data in the model
 model.add 'products', {name: 'Awesome brand new product'} 

These changes will also be recorded in the database. And if there are other models (on other clients or on the server), signed (subscribe) for this data, then the changes will also be added to these models.

Queries



You do not have to subscribe to the entire collection. You can subscribe to a specific sample using queries.
 ids = model.get '_page.ids' $customersWithSomeIdQuery = model.query 'customers', {'id' => { "$in" => ids}} model.subscribe $customersWithSomeIdQuery, -> myCustomers = model.get $customersWithSomeIdQuery 


For each database query syntax will be different. In this case, Mongo Queries.

Store



An object on the server in a single copy, from which all models are created and in which all the magic happens.
Store is associated with all models. The browserchannel is used to communicate with models on clients. Web sockets are not used because they do not guarantee the order of message delivery, which is extremely important for OT. The browserchannel is Google's "socket.io", also used in Gmail.
Data from clients merzhatsya in DB using Share.js , this is the implementation of Operational Transformation . Allows you to resolve conflicts, given the version of the data. Clients can go offline for a long time, change the data in their models, after that their data will be recorded in the database taking into account changes from other clients during this time. This is very similar to how Google Waves worked at the time (OT in share.js and Google Waves is written by one person).

Live db



Live-db is the data store for share.js. Consists of two parts:
1) Redis - required. Share.js uses redis pub-sub to synchronize clients, because the pub-sub in mongo introduces a number of restrictions (collections must be of a certain size) , so redis with its speed and no restrictions is ideal for this. Also in redis is the cache of the last operations (you yourself set how much). This cache just allows merzhit data from customers who went offline for a long time.
2) The data itself can be stored in any database. But at the moment there is an adapter for Mongo DB only . Writing an adapter is pretty easy.
The history of all operations can not be stored, it can be stored in the same database as the data, it can be stored in another database.

Architecture



Down up:
live-db is wrapping over redis and mongo to make event database.
share.js is OT using live-db
racer is working with data: store, model. Based on share.js
derby is routes (tracks), templates, views.

You can separately use live-db, share.js, racer, tracks and other parts. You can not use racer separately from share.js, or share.js separately from live-db. You cannot use derby separately from racer, for derby is tied to the racer data model.

Scaling



You can run several Derby applications (each with its own store), working with one database (live-db).

What else is the difficulty?

Derby.js materials

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


All Articles