⬆️ ⬇️

Derby.js Warrior's Way





We continue our “no day without Derby” rubric. Today we will begin (finally!) To write code and consider the basic moments of Derby.js. And also, you will find out why Derby programmers are usually alone, while their happier colleagues using other frameworks are working on similar projects in a fun friendly team and with longer deadlines.







')

How to set up the environment, read here .



Let's start with creating and launching an application layout:



derby bare habr cd habr npm start 




We type in the browser http: // localhost: 3000 / .



We see the inscription Bare.

What just happened? Your request went to the server where all connect middleware was processed in turn from /lib/server/index.js, up to:



 .use(app.router()) 




What is the client app app router and located here /lib/app/index.js in the form:



 app.get('/', function(page) { page.render(); }); 




Here for the path '/' we generate html from the template /views/app/index.html. Why index.html? This is the default. You can write like this, nothing will change:



 app.get('/', function(page) { page.render('index'); }); 




In index.html we have only the Body section. There may also be Head, Header, Footer, Scripts, Title, etc. Derby template engine, when it will collect html for us, will find the Body section and put its value in the appropriate place, and instead of other sections (since they are not specified), put empty or default values. As a result, back to the client will return:



 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title></title> <style id="$_css"></style> </head> <!--$_page--> <body> Bare <!--$$_page--> <script defer="" async="" src="/derby/lib-app-index.js"></script> </body> </html> 




What we see? Title is empty. There are no styles. Head is also almost empty. As expected. But something lies in the body.

Why styles will be inline, not a separate file? Nate somewhere wrote that when he worked in Google Search, they conducted a bunch of tests about this and came to the conclusion that in the vast majority of scripts, inline styles load faster than a separate file, so all styles from the / styles folder are loaded inline. Nothing prevents you from adding links to your styles in the Head section.

The /derby/lib-app-index.js script is just our client application that will connect as soon as the html generation is loaded and is already on the client.

- these are official tags of the derby template engine. They are used to ensure that when the data is dynamically linked between the html and the model, when the model is changed, not to completely refresh the whole page, but to update only part of the html. In this case, when the router is triggered, only the Body section will be overloaded, because we were too lazy to others, we didn’t specify and they are the same for all pages.



You can change the text in the template (as well as styles) and see instant changes in the browser. This is not related to any kind of dynamic data synchronization. This is for the convenience of the developer. If you change html and css, then it is automatically compiled, loaded onto the client and substituted for the old one. If you change js, then the application restarts completely.



Let's separate the view from the data. There are two ways to do this in Derby. Let's start with the context. This is an object that we can add as the next argument to page.render () and the data from which we can display in html.



 app.get('/', function(page) { page.render({text: 'text from Context'}); }); 




 <Body:> {{text}} 




Double {{}} brackets in the template mean that the view is not dynamically associated with the data. The template engine does not monitor data changes or html. For context, this is not necessary, since the context is a simple js-object and does not change, therefore the use of this output method (context) is rather limited and is used, perhaps, only for some static pages. All the power of working with data appears when using the Model object.



There is already something written about the model, so as not to repeat.

Where to get the model? There are many ways (depending on whether you are on the client or on the server), but on the router it goes as the second argument (after page) and it is very convenient for us in this situation:



 app.get('/', function(page, model) { page.render(); }); 




Let's put the data into it:



 app.get('/', function(page, model) { model.set('_page.text', 'text in model'); page.render(); }); 




_page.text is the path (path) in the model where our text will be located. It corresponds to the object json. In this case:



 var obj = model.get('_page'); obj === {text: 'text in model'} 




An underscore means that this path is local. That is, it exists only in this model. And it does not synchronize with the database and other models (on other clients). You can create any local paths, but the _page object is a bit special. It is cleared every time the router is triggered, so it’s convenient to store data associated with this page.

In order to see the data from the model, we change the template:



 <Body:> {{_page.text}} 




Let's try to make a dynamic data link and html:



 <Body:> <input type="text" value={_page.text} /> {_page.text} 




Single brackets mean that the data from the model is dynamically linked to html. If you change the value in input, the value in the model changes, which in turn changes the value of the text next to input. This is how a two-way connection between the data and html is implemented.



Well, that seems to be nothing complicated yet? 3 lines of code? Somehow not even serious?

Let's do some really serious stuff! We will now create a web application whose clients are synchronized with each other. We change html on one client, the data on this client dynamically changes, then this data flies to the server, where the conflict resolution algorithm works, there are clients who also subscribe to this data and, finally, the data is sent to all these clients, where they turn into html. Will fit? How long does it take to write this on your favorite (before Derby) framework? How many lines of code?



 app.get('/', function(page, model) { model.subscribe('page.text', function(err) { if (!model.get('page.text')) { model.set('page.text', 'text in model'); } page.render(); }) }); 




 <Body:> <input type="text" value={page.text} /> {page.text} 




And it's all? o_O Well, in general, yes. Open http: // localhost: 3000 / in several browser windows and play around.



page.text is the remote path. Unlike the local path, it points to the database. In this case, we create a collection page and an object with an id text. In real life, remote paths look like this: 'users.8ddd02f1-b82d-4a9c-9253-fe5b3b86ef41.name', 'customers.8ddd02f1-b82d-4a9c-9253-fe5b3b86ef41.properties.isLead', 'products.8ddd02f1-b82d 4a9c-9253-fe5b3b86ef41.prices.1.value '.

model.subscribe - so we subscribe our client to the data in the path 'page.text'. When changing this data in the database, the server will send us a new version of this data.



Sources :-)

Do not forget to run npm install



Derby.js materials

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



All Articles