Example @@ include


Modern front-end frameworks provide amazing opportunities. React, Vue, Angular and others are made to do what was previously impossible - web applications. In 2020, downloading and installing applications is no longer necessary. Why, if everything can be done on the site?


However, with a lot of power comes a large number of dependencies. And there are enthusiasts who decide that raising a large framework for their small project is not such a bad idea. Even if it's just a landing page.


In this matter, I support the Conservatives. No need to write landing pages and multi-pages on Create-React-App, for this, normal statics will work.


However, I also perfectly understand those who do otherwise. Modern front-end frameworks not only provide a lot of new functionality, they are very convenient to use. And if I need to make a simple site with a couple of pages, I don’t have much choice.


What to do? Write a sheet of HTML markup in a single file? Store data in view? It doesn’t take a step back, it is torn and fall into the abyss. This is not just inconvenient, it runs counter to the modern front-end development paradigm.


Firstly, data-driven. The data is at the forefront, and the appearance is just their display. The user takes an action, the data changes, after the display changes. This is how all modern frameworks work.


Another element of the modern approach is componentization. We divide the application into small self-sufficient reusable pieces. More reusability - less code. Less code means fewer bugs.


Before that, we already discussed how to implement data-driven with minimal effort. My choice is Alpine.js . What to do with componentization? For simple static sites, I suggest the simplest option - gulp-file-include .


Talked so much about modernity and paradigms, but ended up with a library that is already 100 years old? Well, actually, she's not that old. 4 years from version 1.0.0, as much as the first stable version of React (15). Yes, and why reinvent the wheel, if everything is ready.


The library has only six hundred stars on Github and 6.5 thousand downloads per week on npm, but it gives us everything we need to quickly divide the HTML sheet into small convenient components. And without adding a byte of additional code to the final result.


The only obstacle is getting to know Gulp. Well, in fact, writing even a simple landing without such a tool today is not very correct. Therefore, if you do not know Gulp, find out. For this article on Habr , here is a link to translate the documentation . We will not stop here.


If you want not to interrupt, but continue with me, here is a link to my preset on Github with whom we will work, in the same place you can find my gulpfile .


So, what are we going to do? This is it


What we will do


It looks simple. Let's see how it looks in HTML.


How it looks in HTML
<section class="text-gray-700 body-font"> <div class="container px-5 py-24 mx-auto"> <h1 class="mb-20 text-2xl font-medium text-center text-gray-900 sm:text-3xl title-font"> Проблемы, которые я решаю </h1> <div class="flex flex-wrap -mx-4 -mt-4 -mb-10 sm:-m-4 md:mb-10"> <div class="flex flex-col items-center p-4 mb-6 sm:flex-row lg:w-1/3 md:mb-0 sm:items-stretch" > <div class="inline-flex items-center justify-center flex-shrink-0 w-12 h-12 mb-4 text-indigo-500 bg-indigo-100 rounded-full" > <svg class="w-6 h-6" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" viewBox="0 0 24 24" > <path d="M22 12h-4l-3 9L9 3l-3 9H2"></path> </svg> </div> <div class="flex-grow pl-6"> <h2 class="mb-2 text-xl font-medium text-gray-900 title-font">Оптимизация скорости</h2> <p class="text-lg leading-relaxed"> Увеличим быстродействие системы при загрузке, уменьшим нагрузку на процессор и оперативную память, исключим из автозагрузки требовательные к ресурсам устройства программы. </p> </div> </div> <div class="flex flex-col items-center p-4 mb-6 lg:w-1/3 md:mb-0 sm:flex-row sm:items-stretch" > <div class="inline-flex items-center justify-center flex-shrink-0 w-12 h-12 mb-4 text-indigo-500 bg-indigo-100 rounded-full" > <svg class="w-6 h-6" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" viewBox="0 0 24 24" > <circle cx="6" cy="6" r="3"></circle> <circle cx="6" cy="18" r="3"></circle> <path d="M20 4L8.12 15.88M14.47 14.48L20 20M8.12 8.12L12 12"></path> </svg> </div> <div class="flex-grow pl-6"> <h2 class="mb-2 text-xl font-medium text-gray-900 title-font"> Восстановление системных файлов </h2> <p class="text-lg leading-relaxed"> В случае некорректной работы системы и устройств, проведём анализ системных файлов и восстановим их, если они повреждены. </p> </div> </div> <div class="flex flex-col items-center p-4 mb-6 lg:w-1/3 md:mb-0 sm:flex-row sm:items-stretch" > <div class="inline-flex items-center justify-center flex-shrink-0 w-12 h-12 mb-4 text-indigo-500 bg-indigo-100 rounded-full" > <svg class="w-6 h-6" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" viewBox="0 0 24 24" > <path d="M20 21v-2a4 4 0 00-4-4H8a4 4 0 00-4 4v2"></path> <circle cx="12" cy="7" r="4"></circle> </svg> </div> <div class="flex-grow pl-6"> <h2 class="mb-2 text-xl font-medium text-gray-900 title-font"> Установка и обновление драйверов устройств </h2> <p class="text-lg leading-relaxed"> При неработоспособности какого-либо из устройств или проблемах, связанных с их некорректной работой, произведём установку, обновление или откат драйверов. </p> </div> </div> </div> </div> </section> 

Wow! Not as easy as we would like. Of course, TailwindCSS, which is used here, also makes itself felt. If I had to understand this code, I would be the first to dislike an article stating that TailwindCSS is a new evolutionary step . But no, I wrote it.And all because this code can be beautifully divided into components, where this mountain of classes will turn into a meaningful picture that will not only worsen, but even improve our developer-experience.


But back to the plugin. Let's start with a little theory. To use gulp-file-include to insert one HTML into another, we need to write the command CDMY0CDMY.


At the same time, you can configure a lot for gulpfile for yourself. My setup is something like this:


function html() { return src('src/*.html') .pipe(fileinclude({ basepath: './src/partials' })) .pipe(dest('dist')); } 

We take all the HTML files from CDMY1CDMY, run it through our plugin and put it in the CDMY2CDMY folder. At the same time, a number of options can be passed to the plugin settings. Let's go over them quickly.


  • CDMY3CDMY - you can change the prefix from CDMY4CDMY to any other.
  • CDMY5CDMY - you can add a suffix.
  • CDMY6CDMY - you can configure how paths are calculated in directives. By default, CDMY7CDMY is from an HTML file. There is CDMY8CDMY - from the root, or any other way. In our case, I created a special folder in CDMY9CDMY CDMY10CDMY, where all our components will lie. It is important to configure Gulp correctly so that these components do not get into the final build. In the example above, Gulp takes only files from the root of CDMY11CDMY, without looking at the folders. This is what we need.
  • CDMY12CDMY - allows you to specify functions that can then be launched from the markup. See examples in the documentation .
  • CDMY13CDMY - "global" variables for conditions CDMY14CDMY.

There are also a number of directives:


  • CDMY15CDMY - embed an HTML file in another HTML.
  • CDMY16CDMY - conditions; variables are taken from the "global" CDMY17CDMY and/or from the variable object used by CDMY18CDMY.
  • CDMY19CDMY - a regular loop through an array of CDMY20CDMY/variables CDMY21CDMY.
  • CDMY22CDMY - we go through an array of objects, using the data from them as variables, and insert for each component. May use JSON.

It would be possible to parse each of them individually, but this is redundant. It’s easier to just go to the documentation and see examples for each case. Everything is more or less clear there.


In our case, we are most interested in CDMY23CDMY. We will transfer all the data from the cards to the JSON file, create a component and pass it its data as props.


What do we have in the data? Correct answer: card title, text and SVG. In variables we can pass both plain text and HTML as a string. He will simply substitute her where we say.


This is what JSON (data.json) looks like.


[ { "title": "Оптимизация скорости", "text": "Увеличим быстродействие системы при загрузке, уменьшим нагрузку на процессор и оперативную память, исключим из автозагрузки требовательные к ресурсам устройства программы.", "svg": "<path d=\"M22 12h-4l-3 9L9 3l-3 9H2\"></path>" }, { "title": "Восстановление системных файлов", "text": "В случае некорректной работы системы и устройств, проведём анализ системных файлов и восстановим их, если они повреждены.", "svg": "<circle cx=\"6\" cy=\"6\" r=\"3\"></circle><circle cx=\"6\" cy=\"18\" r=\"3\"></circle><path d=\"M20 4L8.12 15.88M14.47 14.48L20 20M8.12 8.12L12 12\"></path>" }, { "title": "Установка и обновление драйверов устройств", "text": "При неработоспособности какого-либо из устройств или проблемах, связанных с их некорректной работой, произведём установку, обновление или откат драйверов.", "svg": "<path d=\"M20 21v-2a4 4 0 00-4-4H8a4 4 0 00-4 4v2\"></path><circle cx=\"12\" cy=\"7\" r=\"4\"></circle>" } ] 

Now we will create a component of one card (card.html). We insert the variables as CDMY24CDMY.


<div class="flex flex-col items-center p-4 mb-6 sm:flex-row lg:w-1/3 md:mb-10 sm:items-stretch" > <div class="inline-flex items-center justify-center flex-shrink-0 w-12 h-12 mb-4 text-indigo-500 bg-indigo-100 rounded-full" > <svg class="w-6 h-6" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" viewBox="0 0 24 24" > @@svg </svg> </div> <div class="flex-grow pl-6"> <h2 class="mb-2 text-xl font-medium text-gray-900 title-font">@@title</h2> <p class="text-lg leading-relaxed">@@text</p> </div> </div> 

All that remains is to create the section file (index.html).


<section class="text-gray-700 body-font"> <div class="container px-5 py-24 mx-auto"> <h1 class="mb-20 text-2xl font-medium text-center text-gray-900 sm:text-3xl title-font"> Проблемы, которые я решаю </h1> <div class="flex flex-wrap -mx-4 -mt-4 -mb-10 sm:-m-4"> @@loop('problems/card.html', 'partials/problems/data.json') </div> </div> </section> 

The first parameter in CDMY25CDMY is the path to the component (from the previously configured CDMY26CDMY), the second is the path to the JSON file (from CDMY27CDMY).


The file structure looks like this:


src │ index.html │ main.css │ └───partials │ │ │ └───problems │ │ index.html │ │ card.html │ │ data.json... 

Now I can insert index.html myself using CDMY28CDMY into the main page file.


<!DOCTYPE html> <html lang="ru"> <head> ... </head> <body> ... @@include('problems/index.html') ... </body> </html> 

With minimal effort, we got full component division. At the same time, this will not affect the result, the HTML will be the same as before. Of course, I cannot help but notice that this also reinforces the thesis about TailwindCSS - it no longer seems as uncomfortable as before, does it? Then it’s small, to repeat all of the above for all sections of the site.


This concludes our introduction to this plugin. The purpose of this article was to show how easy it is to avoid the use of modern heavyweight frameworks in small projects, while preserving the ideas that they bring with them. Of course, this is not the only way to do this. Perhaps you know other alternatives, it will be interesting to hear about them in the comments.


UPD: The comments pointed to the lack of extend functionality. It is true and it is bad. Perhaps it makes sense for a push request. I'll think about it.

At the same time, with a simple hack, you can easily implement this functionality using the usual @@ include.
  • We create a layout-file into which we insert the @@ data variable (the name is arbitrary, but not "content", it is reserved)

<!DOCTYPE html> <html lang="ru"> <head>...</head> <body>... @@data... </body> </html> 

  • Create the root CDMY29CDMY file, into which we insert our layout, and transfer the CDMY30CDMY CDMY31CDMY file with markup to the CDMY32CDMY variable

@@include('layouts/app.html', { "data": "@@include('main.html')" }) 

Finally, please answer the question:

.

Source