📜 ⬆️ ⬇️

Collect the best of two worlds - frameworks and CMS (part 3)

Much time has passed since the release of the second article ( part 1 , part 2 ), and then there is just something to tell, since the first release of the third version of the system was released.

Briefly about the changes


The third version is moving in the direction of micronuclear architecture. This means that the kernel code is still quite tightly connected (although a little less than before), some minor features were simply removed and there were more points of contact, where the developer can, if necessary, intervene in the system if he wishes.

On the server side, a large-scale refactoring aimed at the simplicity and quality of the code was carried out, which over the last six months resulted in an increase in the Scrutinizer score from 5.4 or so to the current 7.74 / 10, which is not bad at all.
There was a revolution on the client side, Polymer 0.5.x was upgraded to Polymer 1.x and all components were rewritten accordingly, the UI framework was completely cut and some other changes were made.

Polymer


Perhaps you should start with Polymer. The first stable version of Polymer 1.0 was announced on Google I / O 2015, which is quite significant, though not radically different from the version 0.5 used in CleverStyle CMS at that time.
Unfortunately, the first version was quite a curve with a lot of inconvenience, and even version 1.1 didn't fix it much.
')
CleverStyle CMS 3 comes with Polymer 1.2 and a number of patches on top, which fix many irregularities in the work of the library, as well as bring some convenience. Many of the early patches have already been taken into the Polymer codebase, but not all.
Also, for faster loading, the Polymer assembly supplied with the system is a mini-JS version instead of a set of official non-modified HTML files.
Thus, Polymer in the system is a much better development environment than the vanilla version.
Patches over Polymer have been tested and backward compatible, so there will be no problems when using my own or third-party components (at the time of writing, I’m in the top 10 Polymer developers by contributing to the code base, so I know what I'm talking about).

For example:

// Before Polymer({ is : 'my-element', properties : { username : { type : String, value : 'Guest' }, registered : { type : Boolean, value : false } } }); // After Polymer({ is : 'my-element', properties : { username : 'Guest', registered : false } }); 

That is, having a default value, there is no problem to deduce the type of property, but the developers will not accept the corresponding PR , although this is their P1.

Or an example regarding styles:

 // Before :host ::content div {} // After ::content div {} 

Trifle, but it's nice that this crutch is no longer needed (this is a problem in Polymer, according to the specification: the host is not needed there), PR is also waiting in the wings.

The last thing worth mentioning is that at the time of this writing Polymer 1.x does not support the expansion of custom elements, but the hack with the redefinition of elements was still ported and allows the developer to completely or partially override the appearance and device of the built-in system and any other custom items. Read more with examples in the documentation .

TinyMCE and Shadow DOM



Full-fledged WYSIWYG editors are large and complex applications and none of the popular solutions support the work inside the Shadow DOM due to the complexity of implementation and support (at the time of writing, although judging by the developers' initiative, this will be important for a long time).

After spending a few days in the wilds of megabytes of JavaScript code and a step-by-step browser debugger, I managed to get back a compatible version of TinyMCE, which fully works inside the shadow tree.
As far as I know, this is the first in the world implementation of a full-featured WYSIWYG editor with Shadow DOM support, and CleverStyle CMS is the first product where you can use it out of the box.

In order to connect the editor, you need to install the TinyMCE plugin and wrap the <textarea> as follows:

 <cs-editor> <textarea></textarea> </cs-editor> 

Under the hood, the wrapper element will apply the Shadow DOM-compatible version of TinyMCE to <textarea> , as well as connect the CSS styles to the editor in addition to the global ones used by default so that the interface elements are displayed correctly even inside the Shadow DOM.
And the wrapper element understands when it moves to the DOM, focuses, and so on, updating the link with the text field accordingly.

There is also a variation with the inline mode used for the edited <div> :

 <cs-editor-inline> <div></div> </cs-editor-inline> 

Interestingly, in the absence of the TinyMCE plugin, the wrapper element simply will not be updated to the web component and the user will see a plain text field, this is a progressive improvement :)

So now for the first time in the history of mankind, you can use the WYSIWYG editor anywhere in the document at any nesting level of the shadow tree.

Read more in the documentation .

UI framework


Historically, the system was supplied with some kind of UI framework. A long time ago it was jQuery UI , which was later replaced by UIkit .
The latter served quite well until the moment when the web components began to be used in the system, after which several critical flaws of UIkit caused its complete cutting out.
First, the same Shadow DOM support. UIkit has no idea (as well as Bootstrap , Foundation and other friends) what a shadow tree is. And if it only concerned styles, there were problems with event handling and other nuances.
For many months, the system came with a growing number of patches over the vanilla version to provide support for the Shadow DOM, but the developers were in no hurry to accept patches, unfortunately.
The second major problem is the excessive layout and lack of data-binding support from Polymer. As a result, the connection of the UIkit components turned into a mess on the side of the markup, as well as in JavaScript, causing pain and suffering for each attempt to use.

The decision was not easy. It took three days to find an alternative, a couple more days to think about the implementation, and as a result, the CleverStyle Widgets sub-project has emerged (there are plans to single out a separate stand-alone project).

CleverStyle Widgets



As the name suggests, this is not a framework, although it replaced 99% of UIkit.
Widgets are a collection of web components.
All web components work fine with Shadow DOM by definition, as they use Polymer and support its data-binding system (unlike UIkit, Bootstrap, Foundation, and other buddies).
They have a radically simple API for the user, most often this is one tag that does everything it needs - no five-floor nesting of faceless <div> .
But more importantly, the elements themselves do not have a visual style - it is externally defined using CSS mixins (as opposed to the fixed appearance of Paper Elements with Material Design and Strand , which generally comes in a single visual design). In this way, you can make the look the way you need it.

The set of widgets includes buttons, switches, tooltips, modal windows and similar necessary things.

A few examples of use:

 <button is="cs-button" type="button" icon="home" primary>Primary button with home icon</button> <label is="cs-label-switcher"> <input checked type="radio" value="0"> Zero </label> <label is="cs-label-switcher"> <input checked type="radio" value="1"> One </label> <nav is="cs-nav-pagination" page="3" pages="10"></nav> <cs-notify success left>Hello</cs-notify> <button is="cs-button" type="button">Button will open modal</button> <section is="cs-section-modal">One Two Three</section> 

Emphasis is placed on maximum similarity with native elements, maximum use of the built-in browser functionality.

More examples and description of the properties of each item in the documentation .

Frontend without default styles


Using the UI framework you get a huge pile of styles applied to the entire document, which periodically forces you to fight these styles, sometimes even resorting to the use of !important .
What is good about CleverStyle CMS 3 is that NO STYLES ARE APPLIED TO DOCUMENT DOCUMENT!
In practice, this means that even normalize.css is not used by default. The developer has complete freedom to customize the look and, if desired, can use the built-in shared styles . It also means that you can port any ready-made HTML template as a design theme without conflict, you can use the same Bootstrap, UIkit or something else if you like without style overlay.

More frontend


The system has never used a template engine and never will. To generate markup, BananaHTML is used, which was also updated with a partial loss of backward compatibility and is now much more convenient and straightforward than before.

However, now the amount of code on the server that generates the markup has become significantly less (in the kernel of the system it is just a few lines). Instead, the entire admin works now completely on the client, including navigation between pages and interacts with the server through the API.
It also means that the developer can either modify the admin interface without changing the kernel, or even write an alternative admin panel using the API if the project requires it. The same applies to user settings.

Quality code



Refactoring to the server not only simplified the understanding of the code, but also improved its overall quality by a number of objective metrics. At the same time, Scrutinizer has access to even more code, since the system's API uses routing based on the controller, and the OOP is better with Scrutinizer.

Other interesting changes


The cs.Event object was reworked on the frontend, now the events are based on Promise.

This is the latest stable branch with support for IE10 (and, possibly, IE11), so the IE / Edge polyfills are now moved to a separate folder and are connected for these outdated browsers, other browsers do not spend traffic on it.

To the minification of CSS and the union of CSS / JS / HTML added minification JS. The implementation is very simple, like CSS minification, but very fast and very effective.
And the CSS minifier has stopped embedding images and other resources larger than 4 KiB, instead, it simply adjusts the relative paths, in practice this means a much more initial fast page load.

Plupload module has been declared obsolete, an Uploader module has now appeared instead, which has an independent implementation of everything needed to upload files (including Drag'n'Drop, multiple file uploads), but at the same time, in non-minimized form, the JavaScript code is 15 times smaller than minified Plupload.

Interfaces with multilingual both on the client and on the server have been improved, a number of events have been added for which the developer can subscribe, many optimizations have been made, third-party components have been updated to relevant versions and much more ( full list of changes ).

Small performance test


Having a lot of functionality out of the box in the core, the CleverStyle CMS remains an extremely fast system.

It is clear that such comparisons do not have much practical use, but nevertheless they show the overhead costs created by the core of the system itself; it is impossible to jump above these results in the general case.

For fun, the latest git version of the CleverStyle CMS at the time of this writing (3.146.4 + build-1793) and an absolutely empty Symfony Standard Edition 3.0.1 was taken.

It should be noted that CleverStyle CMS does not work without a database, since it initiates a session for each visitor in the database (in this case, without the support of cookies, this means that the session was created with each request) + the file cache engine was used. Symfony Standard Edition was installed via Composer and was not connected to the database when prompted.

The state of both systems is “out of the box”, an empty main page was loaded into CleverStyle CMS, a standard page with the inscription “Welcome to Symfony 3.0.1” was loaded into Symfony.

Other software: Apache 2.4.17, PHP 7.0.2, MariaDB 10.1, Ubuntu 16.04 x64
Runs on laptop: Core i7 4900MQ, SSD

Results:
CleverStyle CMS
nazar-pc @ nazar-pc ~> ab -c256 -n10000 cscms.loc
This is ApacheBench, Version 2.3 <$ Revision: $ 1706008>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, www.zeustech.net
Licensed to The Apache Software Foundation, www.apache.org

Benchmarking cscms.loc (be patient)
Completed 1000 requests
Completed 2000 requests
Completed 3000 requests
Completed 4000 requests
Completed 5000 requests
Completed 6000 requests
Completed 7000 requests
Completed 8000 requests
Completed 9000 requests
Completed 10,000 requests
Finished 10,000 requests

Server Software: Apache / 2.4.17
Server Hostname: cscms.loc
Server Port: 80

Document Path: /
Document Length: 2132 bytes

Concurrency Level: 256
Time taken for tests: 7.813 seconds
Complete requests: 10,000
Failed requests: 8468
(Connect: 0, Receive: 0, Length: 8468, Exceptions: 0)
Total transferred: 25217819 bytes
HTML transferred: 21327819 bytes
Requests per second: 1279.86 [# / sec] (mean)
Time per request: 200.022 [ms] (mean)
Time per request: 0.781 [ms] (mean, across all concurrent requests)
Transfer rate: 3151.89 [Kbytes / sec] received

Connection Times (ms)
min mean [± sd] median max
Connect: 0 4 58.3 0 1003
Processing: 5,171,670.6 96,6888
Waiting: 4,171 670.7 96 6888
Total: 9 175 673.2 96 6892

Percentage of the requests served within a certain time (ms)
50% 96
66% 103
75% 108
80% 112
90% 126
95% 148
98% 221
99% 3507
100% 6892 (longest request)

UPD: CleverStyle CMS 3.156.3 + build-1823
nazar-pc @ nazar-pc ~> ab -c256 -n10000 test.com
This is ApacheBench, Version 2.3 <$ Revision: $ 1706008>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, www.zeustech.net
Licensed to The Apache Software Foundation, www.apache.org

Benchmarking test.com (be patient)
Completed 1000 requests
Completed 2000 requests
Completed 3000 requests
Completed 4000 requests
Completed 5000 requests
Completed 6000 requests
Completed 7000 requests
Completed 8000 requests
Completed 9000 requests
Completed 10,000 requests
Finished 10,000 requests

Server Software: Apache / 2.4.18
Server Hostname: test.com
Server Port: 80

Document Path: /
Document Length: 2191 bytes

Concurrency Level: 256
Time taken for tests: 3.733 seconds
Complete requests: 10,000
Failed requests: 940
(Connect: 0, Receive: 0, Length: 940, Exceptions: 0)
Total transferred: 24388762 bytes
HTML transferred: 21908762 bytes
Requests per second: 2678.93 [# / sec] (mean)
Time per request: 95.561 [ms] (mean)
Time per request: 0.373 [ms] (mean, across all concurrent requests)
Transfer rate: 6380.45 [Kbytes / sec] received

Connection Times (ms)
min mean [± sd] median max
Connect: 0 10 100.7 0 1003
Processing: 4 84 29.6 79 359
Waiting: 4 81 26.5 78 359
Total: 9 94 104.5 80 1136

Percentage of the requests served within a certain time (ms)
50% 80
66% 88
75% 95
80% 100
90% 118
95% 137
98% 199
99% 1038
100% 1136 (longest request)

Symfony standard edition
nazar-pc @ nazar-pc ~> ab -c256 -n10000 symfony.loc / web
This is ApacheBench, Version 2.3 <$ Revision: $ 1706008>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, www.zeustech.net
Licensed to The Apache Software Foundation, www.apache.org

Benchmarking symfony.loc (be patient)
Completed 1000 requests
Completed 2000 requests
Completed 3000 requests
Completed 4000 requests
Completed 5000 requests
Completed 6000 requests
Completed 7000 requests
Completed 8000 requests
Completed 9000 requests
Completed 10,000 requests
Finished 10,000 requests

Server Software: Apache / 2.4.17
Server Hostname: symfony.loc
Server Port: 80

Document Path: / web /
Document Length: 4580 bytes

Concurrency Level: 256
Time taken for tests: 8.290 seconds
Complete requests: 10,000
Failed requests: 0
Total transferred: 48440000 bytes
HTML transferred: 45800000 bytes
Requests per second: 1206.22 [# / sec] (mean)
Time per request: 212.233 [ms] (mean)
Time per request: 0.829 [ms] (mean, across all concurrent requests)
Transfer rate: 5706.01 [Kbytes / sec] received

Connection Times (ms)
min mean [± sd] median max
Connect: 0 14 119.0 0 3003
Processing: 6,197 43.7 194,594
Waiting: 6 194 40.3 192 594
Total: 15 211 127.4 194 3226

Percentage of the requests served within a certain time (ms)
50% 194
66% 203
75% 210
80% 216
90% 242
95% 283
98% 387
99% 1182
100% 3226 (longest request)

Conclusions everyone will do for himself.

That's all, waiting for comments.
Those who want to chat can do it in Gitter .
Code on GitHub , documentation in the same section of the wiki.
You can start feeling in one line with Docker:

 docker run --rm -p 8888:8888 nazarpc/cleverstyle-cms 

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


All Articles