📜 ⬆️ ⬇️

BEM layout in Ruby on Rails

Introduction


In this article I would like to talk about the technique of layout for BEM in rail projects. I have not yet seen such manuals (except, perhaps, for this , but it is not very suitable as a guide and I will tell more about it further), so I decided to write this article. In addition, I created a gem that will simplify the integration of BEM and the rail, about it and how to use it, I will write further.

Training


First you need to install the actual chop and rails. I prefer rvm . Follow the rvm installation instructions, and then install the rails via the command:

gem install rails 


Well, or you can install rails from here if you have Windows.
')
Then we create a new project through the command:

 rails new some_cool_project 


Next, add the bem gem to the Gemfile file, which is located in the root of the newly created project. I also recommend that you add high_voltage and slim-rails gems. The first will allow you to create typical pages for the typesetter without any special knowledge of rail and cut, the second - a great template engine that can significantly speed up the layout, as well as minimize the output html.

Now we install the necessary files for the bem heme with the command:

 rails g bem:install 


The config / initializers / bem.rb config will be installed, in which you can change technologies (initially scss and js) and templates for generating files for each technology lib / bem / templates / scss.tt and lib / bem / templates / js.tt . Suppose we want to use less in our project, then this technology should be entered into config / initializers / bem.rb config instead of scss:

 BEM.configure do |config| config.technologies = [ { :group => 'stylesheets', :extension => '.less', :name => 'less', :css_directive => '@import', :css_prefix => "'", :css_postfix => "';" }, { :group => 'javascripts', :extension => '.js', :name => 'js' } ] end 


I also highly recommend installing the config for spring through the command:

 rails g bem:spring 


This library will allow you to load the environment in the background, which allows you to quickly generate blocks.

If you set the config for spring, then run the following command:

 spring stop 


This command is necessary for the subsequent reboot spring.

Now you can begin to layout.

Layout


As an example for the layout, I chose the layout from this article.

Blocks, levels and manifests are created using the bem create command. This command accepts the following flags as input (the value of the flags must be indicated with a space after them):



You can also read information about flags and their use by running the command:

 bem help create 


The create command will create the same file structure (as here ).

Next, create our future level in which our blocks and manifest will be connected via the command:

 spring bem create -l shared -a application 


It is possible and without spring:

 bem create -l shared -a application 


But, as I said, spring will keep Wednesday in the background, which will speed up the execution of subsequent commands.

After executing this command, you will see messages in the terminal that levels and manifestos have been created for each of the technologies used. In this case, shared is the level in which our blocks will be located, and application is the manifest.

If you look in the manifest file, you will see that the shared level is connected to it by the string
 @import 'shared/shared'; 

There is a simple rule - levels are connected in manifests, blocks are connected in levels.

Delete the last app / assets / application.css manifest, since we will now use the app / assets / application.less manifest

Next, we create the blocks we need | elements | modifiers through similar commands:

 spring bem create -l shared -b clear --no-js spring bem create -l shared -b page --no-js spring bem create -l shared -b page -e head-line --no-js spring bem create -l shared -b page -e line --no-js spring bem create -l shared -b link -m menu -v active --no-js ... 


As you can see, I indicate the level of shared, in which the blocks will be located and the - no-js flag, since js files will not be used for these blocks.

After executing these commands, templates will be created in which the css class we need is already registered and you just need to fill it with suitable properties.

If you made a mistake and wrote the wrong class or included the block in the wrong level / manifest, you can always roll back by executing the reverse command to remove the block of the | modifier level element | via the bem destroy command. It accepts all the same flags except --js and --css.

Next, when we create the necessary modifiers | elements | we go to the html layout. If you installed the high_voltage gem about which I already wrote, then it will be enough just to create a folder:

 mkdir app/views/pages 


In which will be located to us the view. If you have read the documentation for this gem, then you will surely like the ease of connecting and displaying views. For example, you need a layout for the “welcome” page. Create the app / views / pages / welcome.html.slim view and set up the html we need there. After launching the web server via the command

 rails s 


You can see the result at http: // localhost: 3000 / pages / welcome

We put all the pictures in the app / assets / images folder and replace all tags with rail helper image_tag. We replace image addresses in less files with image-url (helper, which is provided by less-rails gems).

Unfortunately, in the given example js is not used. Nevertheless, the templates that are provided for it, make it easy to write the desired function and run it:

 function your_function_name_initializer() { // some code } $(function() { your_function_name_initializer(); }); $(window).bind('page:load', function() { your_function_name_initializer(); }) 


Why is that? The fact is that starting with version 4 of the rail, the turbolinks gem is used, which significantly speeds up the page display, but adds some features to the js initialization, so you have to arrange such initializations as functions and then call them on these two events.

The final version of the transferred layout and the rail project itself can be viewed on the githaba .

Alternatives


There are also bem-on-rails gems , about an article I spoke about at the beginning. I already wanted to use it, but it has a lot of minuses at the moment, which forced me to write my gem. Among the minuses - the inability to work normally with levels and manifests (I never managed to create two manifestos with my levels and scatter blocks on them), poorly readable code (about 4 spaces as a tab, somewhere two) and generally low quality code (there is not a single test, ugly architecture, it feels like the gem was done quite in a hurry and the code was simply thrown in there and I couldn’t run it on the rails of version 4.1 - I had to send a patch ), bad documentation, and also helper of this heme then ozhet receive such example (a simple footer):

 = b 'footer', content: [{ elem: 'el', elemMods: ['left'], content: [' «»'] }, { elem: 'el', elemMods: ['center'], content: [{ elem: 'nav-link', tag: 'a', content: [''] }, { elem: 'nav-link', tag: 'a', content: [' ']}, { elem: 'nav-link', tag: 'a', content: ['  '] }] }, { elem: 'el', elemMods: ['right'], content: ['<a href="http://ya.ru/"> </a>'.html_safe] }] 


What clearly does not benefit readability and can confuse the typesetter.

Nevertheless, I think that in general it is a good attempt to adapt the bem-tools to the rails.

There are some other exotic options for embedding a node in the rails to use bem-tools natively via grunt, for example half-pipe . But I considered this option very cumbersome and difficult, so I didn’t consider it seriously.

And yet, you can, of course, use the bem-tools themselves in some separate repository, but the process of layout and transfer will be very complicated - you will need to write some (bash) script to automatically transfer and replace URLs, for example, constantly chasing the layout hither and thither. Well, it's okay. But worst of all, switching from branch to branch in these two repositories takes place - you need to make sure that you use the correct branch in the repository with the rails and in the repository with the layout, and then also watch which branch is running and merging its in another repository too. Therefore, the solution is not the best.

Conclusion


So, the coder will simply need to rivet views and blocks with css | js without necessarily knowing what's going on inside. And the backend developer will insert the necessary logic. That is, the layout process is greatly simplified.

The library (gem) bem, which I wrote, is completely open and uses the most democratic MIT license. I wrote the library quite recently and I will be glad to receive your feedback and suggestions, as well as pullrequest to github.

I wrote quite briefly about everything, for each item you can still write a lot of explanations and arguments, so if you have any questions, I will be happy to answer them in the comments.

Links


https://github.com/gkopylov/bem
https://github.com/gkopylov/bem_with_rails_and_less_example_app

PS

At the time of this writing, the bem gem version 1.0.0 was used. At the moment, the version of this gem is 1.1.0 - it adds the ability to connect blocks of | elements of modifiers directly to the manifest. This was done so that the coder could change the order of connecting styles directly in the manifest, instead of connecting levels there.

To use this option, it is enough to add the -i flag to the generation command. Thus, the created styles will be connected immediately to the manifest without creating styles for the level.

I wanted to write a little more about the use of the import and require directives. Both directives have their pros and cons. Among the advantages of import:
- you can connect mixins and variables
- everything merges into one file and is faster given to the browser, instead of the many files that generate require (but this is a minus, see below)
among the cons:
- it is difficult to debug css - if a preprocessor error occurs, it will be difficult to find the place of this error
- styles are not updated when changing embedded css files (in order to update styles you need to run the command rm -rf tmp / assets / * and restart the rails)
Among the benefits include:
- easier to debug, since for each require it compiles a separate file (in the development environment)
- possibility of livereload injection (theoretically it is easier to do than with import)
among the cons:
- inability to use mixins or variables
- compiled style files can be given to the browser for a long time if there are a lot of

So the decision to use this or that directive should be taken deliberately and depending on the project.

I wanted to write a little more why, in default, I decided to use scss. The fact is that in the community the sass rail preprocessor is more popular and even by default when creating a new application, the heme is enabled with this preprocessor. And also there (as, incidentally, rightly noticed faost and in less http://lesscss.org/features/#parent-selectors-feature ) there is an excellent feature that is just suitable for BEM - this is the use of ampersand . Already, many in the BEM community move away from writing a separate file under the modifier (if it is small) and write the modifier directly in the file with the block, and with this sass ampersand you can just do such things right in the styles for the block.

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


All Articles