<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Maksim Dolgih</title>
    <description>The latest articles on DEV Community by Maksim Dolgih (@misterion96).</description>
    <link>https://dev.to/misterion96</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1074096%2F42b41365-01a6-4750-8e09-b1e79ae199d9.png</url>
      <title>DEV Community: Maksim Dolgih</title>
      <link>https://dev.to/misterion96</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/misterion96"/>
    <language>en</language>
    <item>
      <title>Fear of AI made me create my own product</title>
      <dc:creator>Maksim Dolgih</dc:creator>
      <pubDate>Thu, 12 Mar 2026 11:19:55 +0000</pubDate>
      <link>https://dev.to/misterion96/fear-of-ai-made-me-create-my-own-product-47gh</link>
      <guid>https://dev.to/misterion96/fear-of-ai-made-me-create-my-own-product-47gh</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;After losing my job, I encountered problems and questions that had always been there, but I hadn't paid much attention to them. But that's what defined the new me.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Where should I begin my story…
&lt;/h2&gt;

&lt;p&gt;I am a front-end developer with eight years of experience. Since September 2025, I have been looking for a job. And no, this is not another article about broken hiring or something else. This is my story of how losing meaning in the moment helps me understand and reflect on my entire professional experience. And that, sooner or later, everything I have done will mean nothing.&lt;/p&gt;

&lt;p&gt;After losing my job through no fault of my own, I was confronted with problems and questions that had always been there, but which I had never paid much attention to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Apathy and the trap of being a developer: "Why learn anything new about technology if AI will be able to do it in a month anyway?" "What's the point of learning if a library or framework only lasts 2–3 years on average?"&lt;/li&gt;
&lt;li&gt;With the realization that after 2020, there is no such thing as "stability." But what can I do if I'm not a developer? Where is my concept of "anti-fragility"?&lt;/li&gt;
&lt;li&gt;All my skills in processes and automation apply only once per team/employer. Once done, auto-process works without any problems. My skills served as a means to smoothly replace people, whether they were resources or not.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And the conclusion was simple: "I am a capable performer and creator, but I am still dependent on others."&lt;/p&gt;

&lt;p&gt;&lt;em&gt;I am a product of the current education system, where my skills are needed by those who are changing the world, but I myself am not.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The more I read about AI, the more useless I felt
&lt;/h2&gt;

&lt;p&gt;We all live in the same information field. Yes, the availability of Claude Opus 4.5 or other models has gradually and slowly made my experience and learning from mistakes a waste of time in the past. Everything I used to do for each project is now sometimes just "prompt + generation."&lt;/p&gt;

&lt;p&gt;I built processes where "SOLID" and "DRY" concepts were important. I built Zero Error Policy development and secure releases. I was meticulous about every possible bug, and I fiercely argued that writing strict and correct code was essential. But none of this fits under the concept of "business development." In fact, all my processes slow down feature delivery, but I forced people to write code for people.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Business thinks about how to make money now, while developers think about how not to spend money later.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This phrase can be used to describe any development, and every debate about what is more important: "refactoring" or "quick results."&lt;/p&gt;

&lt;h2&gt;
  
  
  AI has changed the code development paradigm
&lt;/h2&gt;

&lt;p&gt;In the past, people wrote code for people, so it was important to follow development principles. It was important to understand the context of the code over time and to ease the cognitive load on the developer in the future.&lt;/p&gt;

&lt;p&gt;With AI, there are no such problems. It can easily find bugs in the most obscure code, rewrite it, or adapt it to a new library or architecture. Tech debt has become conditionally free.&lt;/p&gt;

&lt;p&gt;Everything I tried to prevent became unimportant. Because now you can do this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Write preliminary tests and benchmarks for the application&lt;/li&gt;
&lt;li&gt;Write down the instructions for the result&lt;/li&gt;
&lt;li&gt;Run the model for 5–6 hours&lt;/li&gt;
&lt;li&gt;???&lt;/li&gt;
&lt;li&gt;Profit&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The only thing that concerns you now is how to optimize tokens and avoid quotas.&lt;/p&gt;

&lt;p&gt;Now, it doesn't matter how the code is written or by whom, because it can always be changed if you know how to verify it. Previously, a business couldn't grow without a development team, but now a business can consist of just one person with a smart idea.&lt;/p&gt;

&lt;p&gt;We now have ready-made website builders and AI-driven site generation from plain descriptions. Where front-end development by a human being was important, it has become automated and reproducible. We have moved from "code by people for people" to "code by machines for machines."&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Technology is not important, syntax is not important, patterns are meaningless; what matters is the idea.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The wrong question
&lt;/h2&gt;

&lt;p&gt;For a while, I was asking myself: "How do I stay relevant?" — It's the wrong question.&lt;/p&gt;

&lt;p&gt;It is assumed that relevance is something you develop within yourself by staying up to date with developments:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;learning a new framework&lt;/li&gt;
&lt;li&gt;mastering a new model&lt;/li&gt;
&lt;li&gt;learning a new language&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's a treadmill. And the speed only increases.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I'm going to say something that might hurt developers' feelings, but you will need to keep learning throughout your life to remain "marketable" to businesses. Relevant development skills last 3–5 years; then they become obsolete. Even your 3,000 tasks on LeetCode are just a set of numbers in your profile; AI is better than you at applying algorithms for working with arrays, hash tables, and other types of data.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The more I read about AI, the more I framed the problem as a competition. &lt;strong&gt;Me versus the model.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;My 8 years of experience versus a prompt that produces the same output in thirty seconds. Framed that way, I lose. Everyone loses. That's not an interesting problem to solve.&lt;/p&gt;

&lt;h3&gt;
  
  
  I stopped asking "how do I compete?"
&lt;/h3&gt;

&lt;p&gt;I started asking, &lt;em&gt;"What actually goes wrong when nobody with my knowledge is in the room?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Because something does go wrong. AI generates code, but it doesn't audit the result. It produces sites that look correct, pass basic checks, and ship broken in ways nobody noticed.&lt;/p&gt;

&lt;p&gt;That's not a gap that more AI fills. That's a gap that requires a different kind of thinking — not generation, but judgment. And judgment, unlike syntax, doesn't depreciate on a three-year cycle.&lt;/p&gt;

&lt;h2&gt;
  
  
  Capitalizing on your own skills
&lt;/h2&gt;

&lt;p&gt;The standard playbook for a developer who feels obsolete is predictable: pivot to mentoring, launch a course, rebrand as a consultant.&lt;/p&gt;

&lt;p&gt;And I rejected it immediately.&lt;/p&gt;

&lt;p&gt;All of these are the same dependency, just repackaged. You're still selling time. You're still replaceable. And the next model update will commoditize that too.&lt;/p&gt;

&lt;p&gt;The real question isn't "how do I stay marketable?" It's "what do I know that neither AI nor current automated tools will catch for you."&lt;/p&gt;

&lt;p&gt;These aren't exotic edge cases. They're the ordinary output of agencies, freelancers, and AI-generated sites that nobody audited with actual front-end knowledge. The people who commissioned the work don't know what to check. The tools they have access to don't surface these issues. And the developers who built it have already moved on.&lt;/p&gt;

&lt;p&gt;This is the gap. Not "I know more than AI." But: AI generates, Lighthouse measures performance, and nobody is looking at the output the way a senior front-end developer would.&lt;/p&gt;

&lt;h2&gt;
  
  
  Expertise as a service
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Assessment based on external characteristics
&lt;/h3&gt;

&lt;p&gt;As a front-end developer, I always look at the website of the company I am interviewing with.&lt;/p&gt;

&lt;p&gt;They may tell you about excellent conditions, a professional team, and other benefits, but these are just words.&lt;/p&gt;

&lt;p&gt;And the public website is the result of their work. If the public website is bad, what can be said about the rest of the internal product development?&lt;/p&gt;

&lt;p&gt;But checking every company website using several different tools is difficult and tedious. On the plus side, there are many checks that Lighthouse and other static analyzers don't highlight, and only developers are aware of them.&lt;/p&gt;

&lt;p&gt;That's how the idea to create a service for "auditing" public websites came about. To combine all the best practices and immediately perform a comprehensive analysis with one click: "What are the problems and how can they be solved?"&lt;/p&gt;

&lt;p&gt;But don't just say "the problem is bad"; explain to the user why it's a problem, what needs to be done, and how the solution will help.&lt;/p&gt;

&lt;h3&gt;
  
  
  First steps
&lt;/h3&gt;

&lt;p&gt;I knew for sure that I didn't want to do something like a "wrapper project over AI." Not because I'm bad at understanding AI, but because it creates obvious vendor lock-in.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Our project is not working due to an OpenAI malfunction. We apologize for the inconvenience.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Also, it won't be a startup that requires investment rounds, development hustle, and so on. &lt;strong&gt;I need to develop something at my own pace that reflects me and the knowledge I have, but also protects me from copying.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;What was the first thing that came to mind? Take the Lighthouse API, add a few static checks, and generate a large report by category with error categorization.&lt;/p&gt;

&lt;p&gt;What happened in the first iteration:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Lighthouse API&lt;/li&gt;
&lt;li&gt;W3C Validator API&lt;/li&gt;
&lt;li&gt;Basic rules for OpenGraph validation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh6jltgqf3y8unvs2spqs.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh6jltgqf3y8unvs2spqs.jpg" alt="First version"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;No designer, no development team, no business analyst, no Customer Journey Map — just pure enthusiasm and a desire to prove to myself that my knowledge is not useless.&lt;/p&gt;

&lt;p&gt;As you can see, at that point I had already created a "Dashboard" for storing history, a "Profile" for managing your data, and, of course, a "Subscription" for managing other people's money.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Yes, he was a businessman.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;But at that stage, I didn't even explain what the mistake was, why it was bad, or how to fix it.&lt;/p&gt;

&lt;p&gt;Obviously, simply creating a UI over standard free checks for the purpose of making money is not a great idea.&lt;/p&gt;

&lt;p&gt;The initial motivation was enough to make a prototype, and the plan in my head worked, but it cannot be called a full-fledged product, because anyone can copy or vibe-code something similar.&lt;/p&gt;

&lt;p&gt;The checks should primarily be based on my knowledge, which reinforces or supplements the usual code validators.&lt;/p&gt;

&lt;h2&gt;
  
  
  Development based on real needs, and almost the first customer
&lt;/h2&gt;

&lt;p&gt;It so happened that my friend and ex-colleague was creating a personal website at the same time. He wasn't a developer; he was a QA engineer. He had minimal front-end knowledge, just his idea, a few design sketches on paper, and Gemini 3 and Claude Opus 4.5 to generate the site.&lt;/p&gt;

&lt;p&gt;A distinctive feature of his website was that it was written entirely in native HTML, CSS, and JS. No trendy tools, builders, or optimizers. It's hard to imagine a more difficult way to build a website from scratch without any front-end knowledge.&lt;/p&gt;

&lt;p&gt;Coincidence? Luck? Fate? — I don't know.&lt;/p&gt;

&lt;p&gt;It so happened that I needed to automate the expert assessment process, and there was a person who needed help with the development, without asking AI, but getting an accurate answer about where the problem lies and what to do about it.&lt;/p&gt;

&lt;p&gt;If we disregard SEO validations, which should be 100% in the product, several audits are always found in separate tools, but never together.&lt;/p&gt;

&lt;h3&gt;
  
  
  OpenGraph
&lt;/h3&gt;

&lt;p&gt;The first problem that needed to be solved was, "How will the website look if it is shared on social media?"&lt;/p&gt;

&lt;p&gt;Obviously, a preview was needed, and something similar to &lt;a href="http://opengraph.xyz" rel="noopener noreferrer"&gt;opengraph.xyz&lt;/a&gt;, with the distinctive feature of "we don't just talk about mistakes, we also make decisions right away in one place."&lt;/p&gt;

&lt;p&gt;The standard solution is a parser, verification, output of failed checks, a little context, and providing fallback elements. It was simple.&lt;/p&gt;

&lt;p&gt;The number of checks increased, and it was impossible to simply place them in one long list, especially with previews.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1itgbh165vrl9gtix9xj.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1itgbh165vrl9gtix9xj.jpg" alt="webvalid.dev opengraph preview"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This is how the first draft for the Summary Preview came about.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Thanks to Apple for the tip
&lt;/h3&gt;

&lt;p&gt;In November 2025, a critical problem was discovered for the App Store web client. All of its source code maps were found together with the code. Anyone could see how Apple works, what methods it uses, and how it organizes its code base.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fthroc6nva8q4j1zvzsvq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fthroc6nva8q4j1zvzsvq.png" alt="webvalid.dev security module intro"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.reddit.com/r/webdev/comments/1onnzlj/app_store_web_has_exposed_all_its_source_code/" rel="noopener noreferrer"&gt;App Store web has exposed all its source code&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Naturally, for an engineer like me, who is used to nitpicking every minor bug, this was a gold mine for analysis.&lt;/p&gt;

&lt;p&gt;That's how the idea to add a "Security" module came about — but not just to search for &lt;code&gt;source.map&lt;/code&gt;, but to search for all possible "forgotten" tokens. What GitHub parsers do to search for committed API keys, I started doing for public sites.&lt;/p&gt;

&lt;p&gt;There are more details now, and new entities in the form of "files" have appeared. This is not just a review of an HTML document; it is a complete analysis of the build that users receive.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkitkljv1w1zsalysemxg.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkitkljv1w1zsalysemxg.jpg" alt="webvalid.dev - security hex-secret"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Example of detecting a suspicious string&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;It became clear that the old format of "here's the whole long list" wasn't really suitable for a quick overview of the issues. We needed a new visual representation that showed what we were working with and where the problem came from.&lt;/p&gt;

&lt;p&gt;Updated interface for working with security audits&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frds7lpkzdnwf0ojn49kx.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frds7lpkzdnwf0ojn49kx.jpg" alt="WebValid.dev — Example of detecting a JWT token in a build on one of the real websites"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Style validation
&lt;/h3&gt;

&lt;p&gt;The main problem with using AI in front-end development is that it cannot "see" the results it generates. AI is used to develop based on structural approaches such as FSD and Tailwind. Without them, AI becomes blind. The context of elements, their styles, and future sizes can easily be lost on it.&lt;/p&gt;

&lt;p&gt;Just as an example, this is what the adaptive looked like according to Claude Opus 4.5.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdldo0n6c53aq7sgad508.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdldo0n6c53aq7sgad508.png" alt="webvalid.dev - AI styles generation"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For a developer, this code is terrifying. For the average person, it's incomprehensible — but perhaps that's how it should be? This is just a few kilobytes added to the final size of the application, with no consequences, unless we consider the development of the site over the next 3–6 months.&lt;/p&gt;

&lt;p&gt;Did this fit the needs of a profile-website? Not really. The profile-website is a one-time event: "made, published, and forgotten."&lt;/p&gt;

&lt;p&gt;But &lt;code&gt;!important&lt;/code&gt; is something that can be caught immediately as a starting point for style validation. Of course, auditing &lt;code&gt;!important&lt;/code&gt; or &lt;code&gt;z-index&lt;/code&gt; alone does not carry the same weight as "fix it or lose money," but if you add more meaningful checks — such as Unsupported syntax, Coverage, or SRI — then style auditing becomes just as important as searching for forgotten tokens.&lt;/p&gt;

&lt;h2&gt;
  
  
  Closed demo
&lt;/h2&gt;

&lt;p&gt;Once the technical part was ready, I thought, "What if I bring the development out of the shadows and finally tell everyone what I've been doing for the past month?"&lt;/p&gt;

&lt;p&gt;What was available at that time:&lt;/p&gt;

&lt;p&gt;Modules: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Performance&lt;/li&gt;
&lt;li&gt;OpenGraph&lt;/li&gt;
&lt;li&gt;Network&lt;/li&gt;
&lt;li&gt;Security&lt;/li&gt;
&lt;li&gt;CSS Styles&lt;/li&gt;
&lt;li&gt;HTML + A11Y validation&lt;/li&gt;
&lt;li&gt;Technical SEO&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Plus a range of basic functionality: launch history, localization into 2 languages, audit statistics for a website or domain, authentication, subscription management, and RBAC.&lt;/p&gt;

&lt;p&gt;As a developer, you try to make the code and application as good as possible, even in your own project. The more you work on a project in focus, the harder it is to detach yourself from your own "I" and look at what you are doing from the outside.&lt;/p&gt;

&lt;p&gt;This is a real problem if you don't have an outside perspective.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg9j325ox3sb5mshpa46n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg9j325ox3sb5mshpa46n.png" alt="webvalid.dev - product history demo perspective"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Focus group
&lt;/h3&gt;

&lt;p&gt;The developer's environment consists mainly of other developers. And every developer understands how things work in browsers and on the internet.&lt;/p&gt;

&lt;p&gt;Ten 1-hour calls. No hints, just observation and answering questions. As soon as we went through the first scenarios and everything was relatively clear, I added context about "what works, how, and why."&lt;/p&gt;

&lt;p&gt;What did I learn?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A list of more than 50 errors is just "noise" to a person. Problems need to be prioritized.&lt;/li&gt;
&lt;li&gt;An "audit score" is just a number. A value of 0 (out of 100) is not perceived as a problem.&lt;/li&gt;
&lt;li&gt;Security — interesting to many.&lt;/li&gt;
&lt;li&gt;I missed cases where a public website is an iframe widget or a Telegram mini-app.&lt;/li&gt;
&lt;li&gt;Large websites cannot be checked because they are under re-captcha.&lt;/li&gt;
&lt;li&gt;The developer wants auto-checking, which means integration with CI/CD is needed.&lt;/li&gt;
&lt;li&gt;There was an "Ask AI" button that helped narrow the problem and solution when general recommendations were insufficient, but it was used only once.&lt;/li&gt;
&lt;li&gt;My product is disposable, and the release cycle for websites is limited to 2–3 launches. Once it's fixed, it's forgotten.&lt;/li&gt;
&lt;li&gt;UX and UI matter more than the number of features or product quality. If the interface doesn't tell you where to click, be prepared to do onboarding and tooltips.&lt;/li&gt;
&lt;li&gt;Dividing into sections is not ideal. Some individuals require a comprehensive list of issues, ranging from critical to insignificant.&lt;/li&gt;
&lt;li&gt;Technical descriptions and terms. Yes, the developers understood this, but QA engineers and others did not.&lt;/li&gt;
&lt;li&gt;Developers looked at errors, leads looked at graphs, and managers only looked at what affects SEO.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;"What difference does it make that it's a mistake if the company gets potential customers?"&lt;/p&gt;

&lt;p&gt;"There's already a Lighthouse, what's new?"&lt;/p&gt;

&lt;p&gt;"I don't understand what the correction will achieve?!"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  And at this stage, it is possible to cancel everything
&lt;/h2&gt;

&lt;p&gt;Because I have created something unnecessary.&lt;/p&gt;

&lt;p&gt;The knowledge and context I provided were obvious to the developers. Most people work in closed systems, and access to the internal system involves security policies and raw code processing.&lt;/p&gt;

&lt;h3&gt;
  
  
  I asked the wrong people
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;What problem was I initially trying to solve?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You trust designers, agencies, or AI to create your website without understanding the technology, fully confident that everything is correct because you were told so. But what if I showed you that this is not the case? What if I showed you in detail how agencies/AI/designers are "deceiving" you?&lt;/p&gt;

&lt;p&gt;And how do developers and commercial SPA development intersect with this problem? — Not at all.&lt;/p&gt;

&lt;p&gt;I solved some people's problems while asking others for their opinions. People who were like me, but remained part of the system of executors, rather than decision-makers.&lt;/p&gt;

&lt;h2&gt;
  
  
  The same vector, but meaningful
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Who am I trying to help?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;People who develop websites themselves with or without AI&lt;/li&gt;
&lt;li&gt;Agents to verify their work&lt;/li&gt;
&lt;li&gt;Freelance developers&lt;/li&gt;
&lt;li&gt;Customers who want to independently verify the result&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;What should I include in the product?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Clear context of the problem, as well as corrective measures&lt;/li&gt;
&lt;li&gt;Description of the problem for non-technical specialists, classification of problems, and the impact of each problem&lt;/li&gt;
&lt;li&gt;Seamless fix option for vibe-coders&lt;/li&gt;
&lt;li&gt;Tracking issues remotely to support websites after delivery&lt;/li&gt;
&lt;li&gt;Prevent problems before pages are indexed by Google&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;What did I do?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Each issue contains a description of the problem, a preview of the location of the problem, and the impact of the fix&lt;/li&gt;
&lt;li&gt;Division of technical and product reports into "by audit" and "by category"&lt;/li&gt;
&lt;li&gt;MCP server for local development that works with the build without interfering with the source code&lt;/li&gt;
&lt;li&gt;Generate prompt for AI — a set of ready-made adaptive prompts for AI. For when you don't want to install an MCP server&lt;/li&gt;
&lt;li&gt;Schedule of checks and thresholds by severity of problems&lt;/li&gt;
&lt;li&gt;User notifications by email&lt;/li&gt;
&lt;li&gt;Sharing the audit for review by other participants&lt;/li&gt;
&lt;li&gt;PDF reports for users and customers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I have separated the product from general access and am identifying the real needs of users in private conversations, rather than through metrics.&lt;/p&gt;

&lt;p&gt;Lighthouse is a solid foundation, but I go further: I discuss which errors matter and how to prioritize them to resolve them.&lt;/p&gt;

&lt;p&gt;This is how the closed beta test of my product for my circle of friends and a publicly accessible page appeared: anyone can try a part of the product and, of course, sign up for beta testing.&lt;/p&gt;

&lt;p&gt;

&lt;/p&gt;
&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://webvalid.dev/" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwebvalid.dev%2Fog%2Fen%2Findex.png" height="auto" class="m-0"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://webvalid.dev/" rel="noopener noreferrer" class="c-link"&gt;
            
      Give Your AI Editor Perfect Context
    
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            Stop guessing why AI code broke. Get 10-second scans and structured Markdown prompts for Cursor or Copilot to fix HTML, SEO, and Security issues instantly
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwebvalid.dev%2Ffavicon.svg"&gt;
          webvalid.dev
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;




&lt;p&gt;Keys are released gradually after major updates to avoid confusing the main tasks and issues. But you can already try part of the product for free.&lt;/p&gt;

&lt;h2&gt;
  
  
  This is not a conclusion, this is an opening
&lt;/h2&gt;

&lt;p&gt;I didn't write this to prove anything, not to myself, not to you.&lt;/p&gt;

&lt;p&gt;I wrote it because somewhere in this story — in the apathy, in the wrong questions, in the focus group that told me I was solving the wrong problem — you might recognize something familiar. A moment where you looked at what you built and weren't sure it mattered. Or a moment where you looked at what someone else built for you, and quietly suspected something was wrong, but didn't know what to call it.&lt;/p&gt;

&lt;p&gt;That recognition is exactly what I'm looking for.&lt;/p&gt;

&lt;p&gt;Not investors. Not users who will silently churn after a free trial. People who read this far — which means you're either a developer who's asked the same uncomfortable questions, or someone who commissions or ships websites and knows the gap between "it looks fine" and "it actually works" better than you'd like to admit. Either way, I want to hear from you.&lt;/p&gt;

&lt;p&gt;Not "great idea, keep going" — that's noise.&lt;/p&gt;

&lt;p&gt;Tell me:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Where does the logic break?&lt;/li&gt;
&lt;li&gt;What problem have I described that you've actually felt?&lt;/li&gt;
&lt;li&gt;What am I still getting wrong?&lt;/li&gt;
&lt;li&gt;Does the product sound useful — or like something you'd close after thirty seconds?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;WebValid is still being shaped. The person who shapes it is me — and, if you're willing, the next person is you.&lt;/p&gt;

&lt;p&gt;If anything in this resonated — reach out. One message. No commitment. Just a conversation between people who care about whether things are built correctly.&lt;/p&gt;

&lt;p&gt;I will leave it as an example&lt;/p&gt;

&lt;p&gt;

&lt;/p&gt;
&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://webvalid.dev/scan?url=https://examai.lovable.app" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwebvalid.dev%2Fog%2Fen%2Fscan.png" height="auto" class="m-0"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://webvalid.dev/scan?url=https://examai.lovable.app" rel="noopener noreferrer" class="c-link"&gt;
            
      Full Website Audit | WebValid
    
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            Comprehensive scan of SEO, Security, Markup, and Performance examai.lovable.app
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwebvalid.dev%2Ffavicon.svg"&gt;
          webvalid.dev
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;




</description>
      <category>webdev</category>
      <category>ai</category>
      <category>career</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Creating Envless Angular-application</title>
      <dc:creator>Maksim Dolgih</dc:creator>
      <pubDate>Mon, 12 Aug 2024 17:19:49 +0000</pubDate>
      <link>https://dev.to/misterion96/creating-envless-angular-application-5223</link>
      <guid>https://dev.to/misterion96/creating-envless-angular-application-5223</guid>
      <description>&lt;p&gt;&lt;em&gt;Ways to move from hard-coded code for each environment to a universal build that can be used anywhere&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;As you all know, Angular has its own tools for building an application for different environments&lt;/p&gt;

&lt;p&gt;&lt;a href="https://angular.dev/tools/cli/environments#angular-cli-configurations" rel="noopener noreferrer"&gt;Configuring application environments&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is accomplished by creating and using the &lt;code&gt;environment.&amp;lt;env&amp;gt;.ts&lt;/code&gt; file for the appropriate environment in the build. These allow you to switch between settings for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Development (&lt;code&gt;environment.ts&lt;/code&gt;)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Testing (&lt;code&gt;environment.test.ts&lt;/code&gt;)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Production (&lt;code&gt;environment.prod.ts&lt;/code&gt;)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The main tasks of &lt;code&gt;environment.ts&lt;/code&gt; files are:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;API settings.&lt;/strong&gt; Each file can contain different URLs for API servers depending on the environment.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Optimization.&lt;/strong&gt; The production file disables debugging features and enables optimization to improve performance.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Environment variables.&lt;/strong&gt; Easily manage environment variables such as API keys and flags to activate or deactivate functions.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And everything seems to be fine — a different file for each environment&lt;/p&gt;

&lt;h2&gt;
  
  
  Problem
&lt;/h2&gt;

&lt;p&gt;Imagine, as the number of environments grows, you need to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Create a separate &lt;code&gt;environment.&amp;lt;env&amp;gt;.ts file&lt;/code&gt; each time.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create a separate build-configuration and specify &lt;code&gt;fileReplacements&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Add this build-configuration to serve-build&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Add the command &lt;code&gt;"my-app.build.&amp;lt;env&amp;gt;": "ng build — configuration &amp;lt;env&amp;gt;”&lt;/code&gt; to &lt;code&gt;package.json&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;So every time&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmn52a9dlb96b4zfc1232.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmn52a9dlb96b4zfc1232.gif" alt="another one meme" width="480" height="270"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I’m not speaking about e2e-tests in pre-prod-environment or dedicated builds for feature-branch.&lt;/p&gt;

&lt;p&gt;And for what? — To use a template command in CI&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;- run: npm run my-app:build:&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;{ SOME_VAR.ENV &lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The notional pipelines of such an application can be depicted as follows&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3200%2F0%2AWs7vR3kt6ZxqHiSN" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3200%2F0%2AWs7vR3kt6ZxqHiSN" alt="Typical pipeline build and deploy workflow" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And you can say — “&lt;em&gt;this is basic scaling and CI independence from env. If we want to use TEST1, just pass ENV=TEST1&lt;/em&gt;”.&lt;/p&gt;

&lt;p&gt;No, my young architect, this is &lt;strong&gt;&lt;code&gt;wrong&lt;/code&gt;&lt;/strong&gt;. Why? — Because your application knows about all the environments in which it is used, and keeping track of every configuration is a problem:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Do you want to add 1 new parameter to the config? — you need to update each file, plus you need to know what value is needed for each env.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Want to change a parameter for an application in some environment? — Be kind enough to go to the repositories, update the file and run it&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are so many examples of this, and every time there are scalability and support issues&lt;/p&gt;

&lt;h3&gt;
  
  
  Disadvantages of using environments.ts files
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Support for all &lt;code&gt;environments.&amp;lt;env&amp;gt;.ts&lt;/code&gt; files is required&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Creating alternative builds for each env in &lt;code&gt;angular.json&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Creating duplicate docker images with only a few parameters, resulting inefficient registry space utilization&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Necessity to run a full pipeline for each &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Tests are performed on an assembly that will not be provided to the user&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Lack of flexibility to change a parameter for an individual environment&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Inability to share the application as a HeadLess solution&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Task Statement
&lt;/h2&gt;

&lt;p&gt;Main points to achieve:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Ensure that the application and docker image are built only 1 time.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Our application should be able to be configured for different ENVs, and define only the interface of the variables it needs&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;To separate the development space and work with the application build, we need to keep the source files &lt;code&gt;environment.ts&lt;/code&gt; and &lt;code&gt;environment.prod.ts&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As a result, we should get the following scheme for using and deploying the application&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2492%2F0%2AQll0E45YdqPs6g8U" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2492%2F0%2AQll0E45YdqPs6g8U" alt="Build and deploy workflow" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Envless Build pipeline is a pipeline that runs only once, builds the production build of the application, and saves it as a docker image in the registry&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt; Deploy pipeline is a release pipeline that already knows for which ENV the application should be deployed.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The application configuration is pulled back until the last moment closer to the release part&lt;/p&gt;




&lt;h2&gt;
  
  
  Solution 1 — Get config from the server
&lt;/h2&gt;

&lt;p&gt;To implement this solution, it is necessary to have an API-endpoint server within which all the necessary config can be obtained&lt;/p&gt;

&lt;h3&gt;
  
  
  Scheme of work
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2530%2F0%2A4nkrs6VfKbuDbMS5" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2530%2F0%2A4nkrs6VfKbuDbMS5" alt="Deploy workflow with configuration by server" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Implementation
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Let’s declare a configure interface and a token for its provisioning within the application. Also, we’ll create a default value for the initial state
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;IAppConfig&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;apiHost&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;imageHost&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
  &lt;span class="nx"&gt;titleApp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;APP_CONFIG_DEFAULT&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;IAppConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;apiHost&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://my-backend.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;imageHost&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://image-service.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;titleApp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Production Angular EnvLess App&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;APP_CONFIG_TOKEN&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;InjectionToken&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IAppConfig&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;InjectionToken&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IAppConfig&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;APP_CONFIG_TOKEN&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Create functions that will request the config and provide it. In case of server error, provide the application with default settings for valid operation
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;  &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;loadConfig&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IAppConfig&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// or relative path /app/config&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://localhost:3000/app/config&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
          &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;APP_CONFIG_DEFAULT&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;bootstrapApplicationWithConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;rootComponent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Type&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;unknown&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;appConfig&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;ApplicationConfig&lt;/span&gt;
  &lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ApplicationRef&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;bootstrapApplication&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rootComponent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="na"&gt;providers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
           &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;appConfig&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;providers&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
           &lt;span class="p"&gt;{&lt;/span&gt;
               &lt;span class="na"&gt;provide&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;APP_CONFIG_TOKEN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
               &lt;span class="na"&gt;useValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;loadConfig&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
           &lt;span class="p"&gt;},&lt;/span&gt;
       &lt;span class="p"&gt;]&lt;/span&gt;
   &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Replace the native &lt;code&gt;bootstrapApplication&lt;/code&gt; function with a new &lt;code&gt;bootstrapApplicationWithConfig&lt;/code&gt; function
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;  &lt;span class="c1"&gt;// bootstrapApplication(AppComponent, appConfig)&lt;/span&gt;
  &lt;span class="nf"&gt;bootstrapApplicationWithConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;AppComponent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;appConfig&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;The application configuration server will be a simple configuration on &lt;code&gt;express&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/app/config&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
          &lt;span class="na"&gt;apiHost&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://my-backend.&amp;lt;ENV&amp;gt;.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;imageHost&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://image-service.&amp;lt;ENV&amp;gt;.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;titleApp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;Env&amp;gt; - Angular EnvLess App&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Run-time verification
&lt;/h3&gt;

&lt;p&gt;Since the application is configured in run-time, it is not a problem to check its operation even in a local environment, knowing the required URL.&lt;/p&gt;

&lt;p&gt;At the moment of application startup, we get the config on request without any problems. We can use this config for other application services that use other API URLs for requests&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3200%2F0%2Ar5BtRPjUp5uvH-Zc" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3200%2F0%2Ar5BtRPjUp5uvH-Zc" alt="Successful request config.json" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In case of a response error from the server, the default value will be used and the application will continue working&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3200%2F0%2Am8vvceUKD4RxhGwr" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3200%2F0%2Am8vvceUKD4RxhGwr" alt="Rejected or failed request" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Advantages and disadvantages
&lt;/h3&gt;

&lt;p&gt;In addition to fulfilled task conditions, there is other advantages of using this approach:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The application is configured by runtime and does not require redeployment&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The configuration is loaded before the application starts, so you can use parallel requests via &lt;code&gt;APP_INITIALIZER&lt;/code&gt; tokens without worrying about the order in which the config is received&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In e2e-tests, it is easy to intercept the request and give the configuration file for the test&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;But there is a downside:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;You need to know the URL to get the config or have the same host for both front- and back-end application&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The response from the server can be long, which can affect the user’s expectation&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It is necessary to have a FALLBACK value in case of a request error&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It is necessary to have a dedicated database with config for each ENV&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It is necessary to have an API for reading and modifying the config by an administrator with dedicated access rights&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Due to run-time configuration, there is an increased chance of errors and the config needs to be validated in the front-end application&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Configuration support is provided by backend developers and DevOps&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If we don’t touch the basic build pipeline, is there any possibility to keep the scheme with getting the config, but no longer depend on the server considering its disadvantages? — &lt;strong&gt;Yes, you can configure a docker image&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Solution 2 — Configuring a docker image
&lt;/h2&gt;

&lt;p&gt;The essence of this solution is simple — instead of requesting a remote server to get the config, there will be a request to the file directory where the Frontend application is located&lt;/p&gt;

&lt;p&gt;The configuration file will be created during the source docker image retrieval stage, replacing the default &lt;code&gt;config.json&lt;/code&gt;. The default directory in which the front-end application executes requests is &lt;code&gt;assets&lt;/code&gt; or &lt;code&gt;public&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The configuration file will be created on the ENV variables that were specified when the deploy pipeline was started. If the ENV variable is not found — the default value will be used&lt;/p&gt;

&lt;h3&gt;
  
  
  Scheme of work
&lt;/h3&gt;

&lt;p&gt;The solution is elegant but will require skills not only in frontend, but also in DevOps and CI-scripts&lt;/p&gt;

&lt;p&gt;You will need to implement this scheme of work to “update” the &lt;code&gt;config.json&lt;/code&gt; file&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3200%2F0%2Ag_QN3tY9VRwYNnq7" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3200%2F0%2Ag_QN3tY9VRwYNnq7" alt="Workflow of “patch image” job" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Deploy Pipeline
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2226%2F0%2An3RbBGhxLSBaAxJv" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2226%2F0%2An3RbBGhxLSBaAxJv" alt="Deploy workflow with configuration by docker-image" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Implementation
&lt;/h3&gt;

&lt;p&gt;As opposed to getting config.json from the server. &lt;strong&gt;We need the keys in the config to match the ENV variable name when the config is updated&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Local &lt;code&gt;assets/config.json&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"APP_ENV_API_HOST"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://local.my-backend.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"APP_ENV_API_IMAGE_HOST"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://local.image-service.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"APP_ENV_TITLE_APP"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Local - Angular EnvLess App"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Config request function with updated URL
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;loadConfig&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IAppConfig&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// relative host&lt;/span&gt;
    &lt;span class="c1"&gt;// public or assets path&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/config.json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Example script to create a new &lt;code&gt;config.json&lt;/code&gt; and update docker-image
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  &lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;

  &lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-x&lt;/span&gt;
  &lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt;

  &lt;span class="c"&gt;# EXAMPLE - ENVS FOR CONFIG&lt;/span&gt;
  &lt;span class="nv"&gt;APP_ENV_API_HOST&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"https://&amp;lt;ENV&amp;gt;.my-backend.com"&lt;/span&gt;
  &lt;span class="nv"&gt;APP_ENV_API_IMAGE_HOST&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"https://&amp;lt;ENV&amp;gt;.image-service.com"&lt;/span&gt;

  &lt;span class="c"&gt;# SETTINGS&lt;/span&gt;
  &lt;span class="nv"&gt;PORT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;4110
  &lt;span class="nv"&gt;NGINX_PORT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;80
  &lt;span class="nv"&gt;CONTAINER_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"angular-envless-container"&lt;/span&gt;
  &lt;span class="nv"&gt;IMAGE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"angular-envless"&lt;/span&gt;
  &lt;span class="nv"&gt;NEW_IMAGE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"patched-angular-envless"&lt;/span&gt;
  &lt;span class="nv"&gt;CONFIG_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"config.json"&lt;/span&gt;
  &lt;span class="nv"&gt;APP_PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/usr/share/nginx/html"&lt;/span&gt;

  &lt;span class="c"&gt;#Step 1&lt;/span&gt;
  temp_container_run&lt;span class="o"&gt;(){&lt;/span&gt;
    docker run &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="nv"&gt;$PORT&lt;/span&gt;:&lt;span class="nv"&gt;$NGINX_PORT&lt;/span&gt; &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="nv"&gt;$CONTAINER_NAME&lt;/span&gt; &lt;span class="nv"&gt;$IMAGE&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="c"&gt;#Step 2&lt;/span&gt;
  temp_container_get_config&lt;span class="o"&gt;(){&lt;/span&gt;
    docker &lt;span class="nb"&gt;cp&lt;/span&gt; &lt;span class="nv"&gt;$CONTAINER_NAME&lt;/span&gt;:&lt;span class="nv"&gt;$APP_PATH&lt;/span&gt;/&lt;span class="nv"&gt;$CONFIG_NAME&lt;/span&gt; ./&lt;span class="nv"&gt;$CONFIG_NAME&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="c"&gt;#Step 3&lt;/span&gt;
  create_config_json&lt;span class="o"&gt;(){&lt;/span&gt;
    temp_container_get_config

      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="s2"&gt;"./&lt;/span&gt;&lt;span class="nv"&gt;$CONFIG_NAME&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
        &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Config file not found in the specified directory."&lt;/span&gt;
        temp_container_stop
        temp_container_rm
        &lt;span class="k"&gt;return &lt;/span&gt;1
      &lt;span class="k"&gt;fi&lt;/span&gt;

      &lt;span class="c"&gt;# Extracting keys and values from JSON&lt;/span&gt;
      &lt;span class="nv"&gt;KEY_VALUES&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;awk&lt;/span&gt; &lt;span class="nt"&gt;-F&lt;/span&gt; &lt;span class="s1"&gt;'[:,]'&lt;/span&gt; &lt;span class="s1"&gt;'/:/{gsub(/"| /,""); print $1 "=\"" $2 "\""}'&lt;/span&gt; &lt;span class="s2"&gt;"./&lt;/span&gt;&lt;span class="nv"&gt;$CONFIG_NAME&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;

      &lt;span class="c"&gt;# Creating a new JSON object&lt;/span&gt;
      &lt;span class="nv"&gt;PROD_CONFIG&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"{"&lt;/span&gt;

      &lt;span class="c"&gt;# Passing through keys and values&lt;/span&gt;
      &lt;span class="k"&gt;for &lt;/span&gt;PAIR &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nv"&gt;$KEY_VALUES&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="c"&gt;# Separating key and value&lt;/span&gt;
        &lt;span class="nv"&gt;KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$PAIR&lt;/span&gt; | &lt;span class="nb"&gt;cut&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'='&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; 1&lt;span class="si"&gt;)&lt;/span&gt;
        &lt;span class="nv"&gt;DEFAULT_VALUE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$PAIR&lt;/span&gt; | &lt;span class="nb"&gt;cut&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'='&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; 2 | &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="s1"&gt;'s/,$//'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt; 

        &lt;span class="c"&gt;# Check if there is a value in the environment variables&lt;/span&gt;
        &lt;span class="nv"&gt;VALUE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;!KEY&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;

        &lt;span class="c"&gt;# If there is no environment variable, we use the value from the source file&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nt"&gt;-z&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$VALUE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
          &lt;/span&gt;&lt;span class="nv"&gt;VALUE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$DEFAULT_VALUE&lt;/span&gt;
        &lt;span class="k"&gt;else
          &lt;/span&gt;&lt;span class="nv"&gt;VALUE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="nv"&gt;$VALUE&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
        &lt;span class="k"&gt;fi&lt;/span&gt;

        &lt;span class="c"&gt;# Add key and value to JSON object&lt;/span&gt;
        PROD_CONFIG+&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="nv"&gt;$KEY&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;$VALUE&lt;/span&gt;&lt;span class="s2"&gt;,"&lt;/span&gt;
      &lt;span class="k"&gt;done&lt;/span&gt;

      &lt;span class="c"&gt;# Remove the last comma and close the JSON object&lt;/span&gt;
      &lt;span class="nv"&gt;PROD_CONFIG&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PROD_CONFIG&lt;/span&gt;&lt;span class="p"&gt;%,&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
      PROD_CONFIG+&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"}"&lt;/span&gt;

      &lt;span class="c"&gt;# Saving the result to a file&lt;/span&gt;
      &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$PROD_CONFIG&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"./&lt;/span&gt;&lt;span class="nv"&gt;$CONFIG_NAME&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

      &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Config updated successfully and saved to ./&lt;/span&gt;&lt;span class="nv"&gt;$CONFIG_NAME&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="c"&gt;#Step 4&lt;/span&gt;
  temp_container_upsert_config&lt;span class="o"&gt;(){&lt;/span&gt;
    docker &lt;span class="nb"&gt;cp&lt;/span&gt; ./&lt;span class="nv"&gt;$CONFIG_NAME&lt;/span&gt; &lt;span class="nv"&gt;$CONTAINER_NAME&lt;/span&gt;:&lt;span class="nv"&gt;$APP_PATH&lt;/span&gt;/&lt;span class="nv"&gt;$CONFIG_NAME&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="c"&gt;#Step 5&lt;/span&gt;
  temp_container_commit&lt;span class="o"&gt;(){&lt;/span&gt;
    docker commit &lt;span class="nt"&gt;--pause&lt;/span&gt; &lt;span class="nv"&gt;$CONTAINER_NAME&lt;/span&gt; &lt;span class="nv"&gt;$NEW_IMAGE&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="c"&gt;#Step 6.1&lt;/span&gt;
  temp_container_stop&lt;span class="o"&gt;(){&lt;/span&gt;
    docker stop &lt;span class="nv"&gt;$CONTAINER_NAME&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="c"&gt;#Step 6.2&lt;/span&gt;
  temp_container_rm&lt;span class="o"&gt;(){&lt;/span&gt;
    docker &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nv"&gt;$CONTAINER_NAME&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  main&lt;span class="o"&gt;(){&lt;/span&gt;
      temp_container_run
      create_config_json
      temp_container_upsert_config
      temp_container_commit
      temp_container_stop
      temp_container_rm
  &lt;span class="o"&gt;}&lt;/span&gt;

  main

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Run-time verification
&lt;/h3&gt;

&lt;p&gt;After running this script, all you need to do is run the docker image in the container and make sure that the environment variables are applied to the config&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3200%2F0%2AoXeW3hzrQH6193YG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3200%2F0%2AoXeW3hzrQH6193YG" alt="Successful request config.json" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The code works fine, given that the &lt;code&gt;APP_ENV_TITLE_APP&lt;/code&gt; variable was not passed when the docker-image was configured&lt;/p&gt;

&lt;h3&gt;
  
  
  Advantages and disadvantages
&lt;/h3&gt;

&lt;p&gt;Thanks to this approach, the server’s influence on front-application configuration is reduced. In addition to the advantages of configuration through the server, we get:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The configuration is available immediately and delays in getting it are minimal&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;No FALLBACK value is required in case of a request error&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;No API or external administration over the config is required.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Reliability. The assembly cannot be broken in run-time&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;No need to create a separate database for each environment&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But if you look at it from the other side, there are some disadvantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Increased complexity of the application’s deployment infrastructure&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Separate Pipeline Deployment is required&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Need to be supported and validated by DevOps-engineers&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Need to know the right ENV-variables and set a pre-defined list to configure the application at the time the deployment starts&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  In conclusion
&lt;/h2&gt;

&lt;p&gt;The solutions I have presented are only suitable if you need flexibility and independent management of your Frontend application. If you realize that your current application does not require flexible configuration, your DevOps engineers effectively manage docker-registry memory or you do not plan to create a headless application — you can use &lt;code&gt;environment.ts&lt;/code&gt; files as before.&lt;/p&gt;

&lt;p&gt;In some cases, when you don’t know the possible implementations and uses of an application at the start of development, this approach can save a lot of time in the future, and give you full control over build management&lt;/p&gt;

</description>
      <category>angular</category>
      <category>cicd</category>
      <category>devops</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Angular 18 — Zoneless &amp; Change Detection</title>
      <dc:creator>Maksim Dolgih</dc:creator>
      <pubDate>Wed, 31 Jul 2024 08:27:29 +0000</pubDate>
      <link>https://dev.to/misterion96/angular-18-zoneless-change-detection-432e</link>
      <guid>https://dev.to/misterion96/angular-18-zoneless-change-detection-432e</guid>
      <description>&lt;p&gt;&lt;em&gt;Clear examples of change detection on different application triggers. Click, Input + NgModel, AsyncPipe, Signal, Web API — setInterval&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;After years of waiting and practicing “how to tame the dragon” skills, the Angular team has finally &lt;a href="https://angular.dev/api/core/provideExperimentalZonelessChangeDetection" rel="noopener noreferrer"&gt;released an update that allows you to test building applications without using ZoneJs&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this article I would like to show how change detection is performed across the entire component tree when using different triggers, namely:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Click event — button click event + handler&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;Input&lt;/code&gt; + &lt;code&gt;NgModel&lt;/code&gt; — processing of user input with saving to a variable via two-way data binding&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;AsyncPipe&lt;/code&gt; — output value into a template from &lt;code&gt;Observable&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;Signal&lt;/code&gt; — output value into a template from &lt;code&gt;toSignal(obs$)&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;setInterval&lt;/code&gt; — Web API&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These triggers will be tested in a few environments:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;NgZone&lt;/code&gt; + &lt;code&gt;ChangeDetection.Default&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;NgZone&lt;/code&gt; + &lt;code&gt;ChangeDetection.OnPush&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;Zoneless&lt;/code&gt; + &lt;code&gt;ChangeDetection.Default&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;Zoneless&lt;/code&gt; + &lt;code&gt;ChangeDetection.OnPush&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Environment
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Angular 18.0.7&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;zone.js 0.14.3&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Rxjs 7.8.0&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Click event
&lt;/h2&gt;

&lt;p&gt;Let’s start with a simple one. Button events are one of the most frequent events of any application. They are used for web page interactivity — navigation, form validation, animation triggering, etc.&lt;/p&gt;

&lt;h3&gt;
  
  
  NgZone + Default
&lt;/h3&gt;

&lt;p&gt;&lt;iframe src="https://player.vimeo.com/video/989342372" width="710" height="399"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  NgZone + OnPush
&lt;/h3&gt;

&lt;p&gt;&lt;iframe src="https://player.vimeo.com/video/989342453" width="710" height="399"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  Zoneless + Default
&lt;/h3&gt;

&lt;p&gt;&lt;iframe src="https://player.vimeo.com/video/989342597" width="710" height="399"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  Zoneless + OnPush
&lt;/h3&gt;

&lt;p&gt;&lt;iframe src="https://player.vimeo.com/video/989342765" width="710" height="399"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  Summary
&lt;/h3&gt;

&lt;p&gt;From these tests, we can see that the change detection behavior between &lt;code&gt;NgZone&lt;/code&gt; and &lt;code&gt;Zoneless&lt;/code&gt; is not different, and to reduce the number of checks it is necessary to use a detection strategy via &lt;code&gt;OnPush&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Input + NgModel
&lt;/h2&gt;

&lt;p&gt;Another one of the popular elements of any web application — search, login form, filtering data in a table. Listening and validating element values can be done in different ways from &lt;code&gt;addEventListener&lt;/code&gt; to &lt;code&gt;SubmitEvent&lt;/code&gt;, but nevertheless you should always listen. For these examples we use the &lt;code&gt;ngModel&lt;/code&gt; binding&lt;/p&gt;

&lt;h3&gt;
  
  
  NgZone + Default
&lt;/h3&gt;

&lt;p&gt;&lt;iframe src="https://player.vimeo.com/video/989342393" width="710" height="399"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  NgZone + OnPush
&lt;/h3&gt;

&lt;p&gt;&lt;iframe src="https://player.vimeo.com/video/989342481" width="710" height="399"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  Zoneless + Default
&lt;/h3&gt;

&lt;p&gt;&lt;iframe src="https://player.vimeo.com/video/989342628" width="710" height="399"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  Zoneless + OnPush
&lt;/h3&gt;

&lt;p&gt;&lt;iframe src="https://player.vimeo.com/video/989342795" width="710" height="399"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  Summary
&lt;/h3&gt;

&lt;p&gt;Similar to the button and click event tests, there is no difference between &lt;code&gt;NgZone&lt;/code&gt; and &lt;code&gt;Zoneless&lt;/code&gt; and &lt;code&gt;OnPush&lt;/code&gt; should be used to get a better and more optimized version of the application&lt;/p&gt;

&lt;h2&gt;
  
  
  AsyncPipe
&lt;/h2&gt;

&lt;p&gt;One of the older Angular APIs for handling asynchronous events and template updates. &lt;code&gt;RxJS&lt;/code&gt; and &lt;code&gt;AsyncPipe&lt;/code&gt; make it easier to handle asynchronous data flows, make code cleaner and more reactive, and improve the manageability of Angular applications.&lt;/p&gt;

&lt;p&gt;From a component update perspective, there is not much difference between subscribing inside a component with a call to &lt;code&gt;markForCheck()&lt;/code&gt; and using &lt;code&gt;AsyncPipe&lt;/code&gt;. We have a new value — we need to request an update.&lt;/p&gt;

&lt;p&gt;For this example we will use a simple &lt;code&gt;timer()&lt;/code&gt; counter with a period of 1 sec and display the value on the screen.&lt;/p&gt;

&lt;h3&gt;
  
  
  NgZone + Default
&lt;/h3&gt;

&lt;p&gt;&lt;iframe src="https://player.vimeo.com/video/989342326" width="710" height="399"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  NgZone + OnPush
&lt;/h3&gt;

&lt;p&gt;&lt;iframe src="https://player.vimeo.com/video/989342421" width="710" height="399"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  Zoneless + Default
&lt;/h3&gt;

&lt;p&gt;&lt;iframe src="https://player.vimeo.com/video/989342566" width="710" height="399"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  Zoneless + OnPush
&lt;/h3&gt;

&lt;p&gt;&lt;iframe src="https://player.vimeo.com/video/989342722" width="710" height="399"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  Summary
&lt;/h3&gt;

&lt;p&gt;Again no change between &lt;code&gt;Zoneless&lt;/code&gt; and &lt;code&gt;NgZone&lt;/code&gt;, still need to use &lt;code&gt;OnPush&lt;/code&gt; to reduce the number of component tree checks&lt;/p&gt;

&lt;h2&gt;
  
  
  Signal
&lt;/h2&gt;

&lt;p&gt;A new API for handling asynchronous values on a pub/sub basis.&lt;/p&gt;

&lt;blockquote&gt;
&lt;h1&gt;
  
  
  &lt;em&gt;Angular Signals is a system that keeps detailed track of how and where your state is used in the application, allowing the framework to optimize rendering updates.&lt;/em&gt;
&lt;/h1&gt;
&lt;/blockquote&gt;

&lt;p&gt;The familiar &lt;code&gt;timer()&lt;/code&gt; function will be used as the data source, with conversion to the Signal API via the &lt;code&gt;toSignal()&lt;/code&gt; function&lt;/p&gt;

&lt;h3&gt;
  
  
  NgZone + Default
&lt;/h3&gt;

&lt;p&gt;&lt;iframe src="https://player.vimeo.com/video/989362409" width="710" height="399"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  NgZone + OnPush
&lt;/h3&gt;

&lt;p&gt;&lt;iframe src="https://player.vimeo.com/video/989342537" width="710" height="399"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  Zoneless + Default
&lt;/h3&gt;

&lt;p&gt;&lt;iframe src="https://player.vimeo.com/video/989342690" width="710" height="399"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  Zoneless + OnPush
&lt;/h3&gt;

&lt;p&gt;&lt;iframe src="https://player.vimeo.com/video/989342859" width="710" height="399"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  Summary
&lt;/h3&gt;

&lt;p&gt;Finally we can evaluate and see the impact of signals on change detection checking for the whole application.&lt;/p&gt;

&lt;p&gt;The event detection cycle for the entire component tree only works in the &lt;code&gt;NgZone&lt;/code&gt; + &lt;code&gt;Default&lt;/code&gt; mapping. In all other cases, changes coming from signal are isolated for the component and do not require checking even the component itself. Wow 🔥&lt;/p&gt;

&lt;h2&gt;
  
  
  Web API — setInterval
&lt;/h2&gt;

&lt;p&gt;The basic idea behind &lt;code&gt;zone.js&lt;/code&gt; is to create an execution context, called a “zone”, that can intercept and handle all asynchronous operations occurring in that context. Zones can intercept and handle all asynchronous operations occurring in them. This is accomplished by overriding standard functions such as &lt;code&gt;setTimeout&lt;/code&gt;, &lt;code&gt;setInterval&lt;/code&gt;, &lt;code&gt;promises&lt;/code&gt;, etc.&lt;/p&gt;

&lt;p&gt;In simple language, “overriding” a function is monkey-patching. This is how &lt;code&gt;zone.js&lt;/code&gt; notifies Angular to check for a change.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;setInterval&lt;/code&gt; is one of the global functions available when code is executed in the browser. It is considered good practice to wrap the &lt;code&gt;setInterval&lt;/code&gt; call in &lt;code&gt;zone.runOutsideZone()&lt;/code&gt; to avoid unnecessary validation loops&lt;/p&gt;

&lt;h3&gt;
  
  
  NgZone + Default
&lt;/h3&gt;

&lt;p&gt;&lt;iframe src="https://player.vimeo.com/video/989362381" width="710" height="399"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  NgZone + OnPush
&lt;/h3&gt;

&lt;p&gt;&lt;iframe src="https://player.vimeo.com/video/989342513" width="710" height="399"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  Zoneless + Default
&lt;/h3&gt;

&lt;p&gt;&lt;iframe src="https://player.vimeo.com/video/989342659" width="710" height="399"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  Zoneless + OnPush
&lt;/h3&gt;

&lt;p&gt;&lt;iframe src="https://player.vimeo.com/video/989342823" width="710" height="399"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  Summary
&lt;/h3&gt;

&lt;p&gt;The tests give an unexpected picture, the use of &lt;code&gt;setInterval&lt;/code&gt; has a significant impact on component tree checking only when using the &lt;code&gt;NgZone&lt;/code&gt; + &lt;code&gt;Default&lt;/code&gt; mapping. In other cases, using &lt;code&gt;setInterval&lt;/code&gt; is safe without using &lt;code&gt;runOutsideZone&lt;/code&gt;, and does not affect component tree checking.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;It is relatively safe to use Zoneless in current applications when upgrading to version 18. All necessary component checks and trigger responses are similar between Zone.js and Zoneless&lt;/strong&gt;. If possible, you should always follow the event detection strategy via &lt;code&gt;OnPush&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Signal’s&lt;/code&gt; were a pleasant surprise. Template updates are isolated and do not affect the component tree, which will be extremely useful for partial hydration.&lt;/p&gt;

&lt;p&gt;There is no need to be afraid of using asynchronous global Web API. Even when using &lt;code&gt;Zoneless&lt;/code&gt; + &lt;code&gt;Default&lt;/code&gt; — it doesn’t cause component tree checking and all calculations happen in the background.&lt;/p&gt;

&lt;p&gt;I realize I have only checked a small part of possible scenarios and triggers, there are many more examples — using &lt;code&gt;Signal-input&lt;/code&gt; / &lt;code&gt;output&lt;/code&gt; / &lt;code&gt;model&lt;/code&gt;, &lt;code&gt;Signal Store&lt;/code&gt;, etc.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bonus
&lt;/h2&gt;

&lt;p&gt;One of the benefits of dropping &lt;code&gt;ZoneJs&lt;/code&gt; will be to lighten the current build.&lt;/p&gt;

&lt;p&gt;If your standard application with 0 logic at the start is &lt;code&gt;216kb&lt;/code&gt; in size, &lt;code&gt;ZoneJs&lt;/code&gt; takes up 15% of the total build, which is quite a large share&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3200%2F0%2ASJu1u_K1QHqiLm1c" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3200%2F0%2ASJu1u_K1QHqiLm1c"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After uninstalling &lt;code&gt;ZoneJs&lt;/code&gt; got rid of &lt;code&gt;33kb&lt;/code&gt; and made your build lighter, and the app continued to work as before.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3200%2F0%2A3P4NHxhnlatZr9Sf" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3200%2F0%2A3P4NHxhnlatZr9Sf"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>angular</category>
      <category>typescript</category>
      <category>webdev</category>
      <category>javascript</category>
    </item>
    <item>
      <title>“Eslint-Summary” — Hack your Eslint Config</title>
      <dc:creator>Maksim Dolgih</dc:creator>
      <pubDate>Wed, 31 Jul 2024 05:35:44 +0000</pubDate>
      <link>https://dev.to/misterion96/eslint-summary-hack-your-eslint-config-2bc2</link>
      <guid>https://dev.to/misterion96/eslint-summary-hack-your-eslint-config-2bc2</guid>
      <description>&lt;p&gt;&lt;em&gt;Get full information about used rules and plugins in the eslint-config on the project with just one console command&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Not very often, but we need to understand what rules are used in our eslint-config on a project. There could be several reasons for this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Control of third-party rules&lt;/strong&gt;. It’s more profitable for developers to use pre-built style guides from other teams. For example, Google or Airbnb. However, keeping track of other people’s rules is extremely inconvenient, especially if the rules are actively being added and changed.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/google/eslint-config-google" rel="noopener noreferrer"&gt;&lt;strong&gt;GitHub - google/eslint-config-google: ESLint shareable config for the Google JavaScript style guide&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.npmjs.com/package/eslint-config-airbnb" rel="noopener noreferrer"&gt;&lt;strong&gt;Airbnb's ESLint config, following our styleguide&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Familiarize team members with the current style guide&lt;/strong&gt;. If your configuration consists of many plugins, you hardly want to force a person to manually familiarize themselves with each plugin, rule, and area of responsibility from the config.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Collecting feedback&lt;/strong&gt;: Visual presentation and knowledge of the current rules help to collect and incorporate feedback from the team to further improve the ESLint configuration, making it more useful and convenient for everyone&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Avoiding redundant checks&lt;/strong&gt;: Understanding of the rules being used avoids redundant rules that can slow down development or complicate the current config&lt;/p&gt;&lt;/li&gt;

&lt;/ul&gt;




&lt;h2&gt;
  
  
  Example of problem
&lt;/h2&gt;

&lt;p&gt;Let’s say you’re a newbie and your first working week has started. You’ve got all the accesses, downloaded the repositories, see the familiar file &lt;code&gt;.eslintrc.json&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You open this file and see in it…&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="nl"&gt;"extends"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"next/core-web-vitals"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--pb9jWdrZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/0%2AQ9CYtpMglhZCWFuc" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--pb9jWdrZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/0%2AQ9CYtpMglhZCWFuc" alt="sally mem" width="480" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What information does this line give to you? — Nothing, except the name of the config. Ask yourself, “&lt;em&gt;Are you willing to waste the time to find a plugin and familiarize yourself with its rules?&lt;/em&gt;” — I think not.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;What’s the solution?&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;If &lt;code&gt;eslint&lt;/code&gt; is familiar to you, you can call the command &lt;code&gt;eslint --print-config ./.eslintrc.json&lt;/code&gt;. Calling the command will return a list of all the rules from the config as a long list in the console. But, unfortunately, you will have to search for each rule manually, understand its meaning and rationale, and correlate the current settings. This is extremely inconvenient if there are many rules.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You can try using the new solution “Eslint config inspector” — it is a visualization of the current config. The disadvantage of this solution is that it doesn’t support deep rule search along the inheritance chain. Also, it is not documentation, but an application.&lt;br&gt;
&lt;a href="https://github.com/eslint/config-inspector" rel="noopener noreferrer"&gt;&lt;strong&gt;GitHub - eslint/config-inspector: A visual tool for inspecting and understanding your ESLint flat…&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;My solution is npm package &lt;code&gt;@dolgikh-maks/eslint-summary&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  What is “Eslint-Summary”?
&lt;/h2&gt;

&lt;p&gt;This is an npm-package to generate rules documentation for the current project, custom plugins, sub-projects, and other possible scenarios where &lt;code&gt;eslint&lt;/code&gt; configs are used.&lt;/p&gt;

&lt;p&gt;Its task is simple — to generate a markdown file on the current configuration for each plugin and the rules involved in it.&lt;/p&gt;

&lt;p&gt;But not just to show that “there is such a rule”, but to provide all information about it, as if you were viewing the plugin’s page. You understand what the rule is for, whether it supports autofix, and what files it applies to.&lt;/p&gt;

&lt;h3&gt;
  
  
  Installation
&lt;/h3&gt;

&lt;p&gt;All you need to do is specify the familiar command to install npm-packages&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm i --save-dev @dolgikh-maks/eslint-summary
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  Launch
&lt;/h3&gt;

&lt;p&gt;If you are using the &lt;code&gt;.eslintrc.js&lt;/code&gt; file as the base config, then no additional configuration is needed, and it is enough to call the command&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;eslint-summary
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;After running the command, you will have an &lt;code&gt;eslint-summary-report&lt;/code&gt; directory with the &lt;code&gt;.eslintrc.md&lt;/code&gt; file.&lt;/p&gt;

&lt;h3&gt;
  
  
  Report file
&lt;/h3&gt;

&lt;p&gt;When you open the created &lt;code&gt;.eslintrc.md&lt;/code&gt; you will be given summary tables for each plugin involved in the &lt;code&gt;.eslintrc.js&lt;/code&gt; config.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6uLM5GU8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/3200/0%2AVDfk4SQ8VbDadbmz" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6uLM5GU8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/3200/0%2AVDfk4SQ8VbDadbmz" alt="Report for .eslintrc.js" width="800" height="364"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The table has reserved columns:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Rule — name of the rule of an &lt;code&gt;eslint&lt;/code&gt; plugin&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Extension &lt;code&gt;*.&amp;lt;extension&amp;gt;&lt;/code&gt; — column showing what settings the rule has for this or that extension file&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The remaining columns are columns that display meta data from the rule&lt;/p&gt;

&lt;p&gt;&lt;a href="https://eslint.org/docs/latest/extend/custom-rule-tutorial#step-3-add-rule-metadata" rel="noopener noreferrer"&gt;&lt;strong&gt;Custom Rule Tutorial - ESLint - Pluggable JavaScript Linter&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The main feature
&lt;/h3&gt;

&lt;p&gt;If you want to learn more about a rule, you don’t need to search for it manually through the search engine, just select the desired rule from the table.&lt;/p&gt;

&lt;p&gt;The name of a rule already contains a direct link to its documentation&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--betMj-I1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://cdn-images-1.medium.com/max/6048/1%2A7yEGrq20pZd8u5LouwvQuQ.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--betMj-I1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://cdn-images-1.medium.com/max/6048/1%2A7yEGrq20pZd8u5LouwvQuQ.gif" width="800" height="455"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuration
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;.eslint-summary.&amp;lt;js | json | ts | yaml&amp;gt;&lt;/code&gt; config file is used for easy configuration of the package. In it, you specify the necessary options for generating reports if you are not satisfied with the default settings of the package&lt;/p&gt;

&lt;h3&gt;
  
  
  extensions
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;default&lt;/strong&gt; — &lt;code&gt;['js']&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Specify the required file extensions to display the rule settings for each file type in the report.&lt;/p&gt;

&lt;p&gt;This is a very convenient option if your project contains different file types, such as &lt;code&gt;json&lt;/code&gt; or &lt;code&gt;spec.js&lt;/code&gt;, and you want to know how rules work with these file extensions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Important&lt;/strong&gt;. Specifying any value will overwrite the current &lt;code&gt;[js]&lt;/code&gt; setting. If you want to save the report for js-files, this extension must also be specified&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
 * @type {import('@dolgikh-maks/eslint-summary').IConfig}
 */&lt;/span&gt;
&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="na"&gt;extensions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
       &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;spec.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
   &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  output
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;default&lt;/strong&gt; — &lt;code&gt;eslint-summary-report&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Change the path of the report directory.&lt;/p&gt;

&lt;p&gt;Supports nested directories. If such a directory does not exist at the moment of generation start — it will be created.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
 * @type {import('@dolgikh-maks/eslint-summary').IConfig}
 */&lt;/span&gt;
&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="na"&gt;output&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./docs/eslint-summary&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  ignorePlugins
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;default&lt;/strong&gt; — &lt;code&gt;[]&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Exclude plugins from your report.&lt;/p&gt;

&lt;p&gt;Sometimes other people’s configs contain the use of third-party plugins, but they don’t work with our code and its analysis. For example, &lt;code&gt;eslint-config-prettier&lt;/code&gt;, which contains plugins for &lt;code&gt;react&lt;/code&gt;, &lt;code&gt;vue&lt;/code&gt; and &lt;code&gt;flowtype&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
 * @type {import('@dolgikh-maks/eslint-summary').IConfig}
 */&lt;/span&gt;
&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="na"&gt;ignorePlugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;eslint-plugin-vue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;eslint-plugin-flowtype&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  configs
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;default&lt;/strong&gt; — &lt;code&gt;['./.eslintrc.js']&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Specify eslint-configs for which you want to analyze and generate documentation.&lt;/p&gt;

&lt;p&gt;If your eslint config file name is different from the standard one (&lt;code&gt;.eslintrc.js&lt;/code&gt;), you can specify where and which file needs to be analyzed.&lt;/p&gt;

&lt;p&gt;If you have several files or sub-projects with their configs, it is not a problem to specify paths to them&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
 * @type {import('@dolgikh-maks/eslint-summary').IConfig}
 */&lt;/span&gt;
&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;configs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./example-apps/angular/.eslintrc.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./example-apps/next/.eslintrc.json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The generator will create a different report for each config, according to its name and location&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4d_4NmV3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2ACjkRI2AzJH_f9Mr8PoKfUw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4d_4NmV3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2ACjkRI2AzJH_f9Mr8PoKfUw.png" alt="example of reports" width="394" height="272"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Example of usage
&lt;/h2&gt;

&lt;p&gt;In my article on creating a team style guide, we got a way to create and scale &lt;code&gt;@my-team/eslint-plugin&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://medium.com/@maks-dolgikh/your-teams-style-guide-from-scratch-b9bb206845ac" rel="noopener noreferrer"&gt;&lt;strong&gt;Create your code style for the team from scratch. Eslint, Prettier, Commitlint and etc.&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qj9S4lSX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/3200/0%2ABcqBbg8E1V5pRopm" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qj9S4lSX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/3200/0%2ABcqBbg8E1V5pRopm" alt="scheme of eslint-plugin" width="800" height="531"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What if we want to allow users of our plugin to see settings and configurations as documentation, similar to this structure?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--W4N8_c0c--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/0%2A5_HGN5Nt-CguqqoK" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--W4N8_c0c--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/0%2A5_HGN5Nt-CguqqoK" alt="example of reports" width="444" height="604"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It’s pretty simple:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Install the package &lt;code&gt;@dolgikh-maks/eslint-summary&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Set the desired settings in &lt;code&gt;.eslint-summary.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
 * @type {import('@dolgikh-maks/eslint-summary').IConfig}
 */&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;extensions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;spec.ts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;ignorePlugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;eslint-plugin-vue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;eslint-plugin-react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;eslint-plugin-flowtype&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;configs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./configs/base.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./configs/recommended.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./configs/spec.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./configs/strict.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./plugins/rxjs/recommended.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./plugins/prettier/index.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="c1"&gt;// other paths  &lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;output&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./docs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Run the &lt;code&gt;eslint-summary&lt;/code&gt; command&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Get documentation for each configuration 🔥&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, some users of your plugin can go to the &lt;code&gt;/docs&lt;/code&gt; folder and see the current plugin settings.&lt;/p&gt;

&lt;p&gt;For example &lt;code&gt;plugins/prettier/index.md&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--sFqXDFUM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2848/0%2AGfnQaUPaXcGtUswy" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--sFqXDFUM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2848/0%2AGfnQaUPaXcGtUswy" alt="report for prettier/index.js" width="800" height="828"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You can find full example &lt;a href="https://github.com/Misterion96/frontend-style-guide-example/tree/master/packages/eslint-plugin/docs/configs" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  In conclusion
&lt;/h2&gt;

&lt;p&gt;At the moment, the npm package is under development and does not take into account many factors such as Eslint 9 and its flat configuration. But nothing stops you from trying to use it with Eslint 8 and older.&lt;/p&gt;

&lt;blockquote&gt;
&lt;h1&gt;
  
  
  If you think this tool would be useful — let me know. I’m happy for any feedback and help
&lt;/h1&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://medium.com/@maks-dolgikh/subscribe" rel="noopener noreferrer"&gt;&lt;strong&gt;Get an email whenever Maksim Dolgikh publishes.&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.npmjs.com/package/@dolgikh-maks/eslint-summary" rel="noopener noreferrer"&gt;&lt;strong&gt;@dolgikh-maks/eslint-summary&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>eslint</category>
      <category>webdev</category>
      <category>programming</category>
    </item>
    <item>
      <title>Bad questions for Senior Frontend Dev Interview</title>
      <dc:creator>Maksim Dolgih</dc:creator>
      <pubDate>Mon, 08 Apr 2024 06:11:51 +0000</pubDate>
      <link>https://dev.to/misterion96/bad-questions-for-senior-frontend-dev-interview-ee9</link>
      <guid>https://dev.to/misterion96/bad-questions-for-senior-frontend-dev-interview-ee9</guid>
      <description>&lt;h4&gt;
  
  
  How the interview process has turned into a generic ChatGPT template where your experience doesn’t matter because you’re just being run through a checklist of questions
&lt;/h4&gt;




&lt;h2&gt;
  
  
  Everything described below is my subjective opinion
&lt;/h2&gt;

&lt;p&gt;This story is not a direct guide for candidates and serves as a reflection on current technical interviews. It is up to you to decide what to do with this information&lt;/p&gt;

&lt;p&gt;I aim to tell how popular interview questions, which can be freely found in the search results, do not have any practical application, and for me, there are signs of the negligence of the company in the selection of candidates. By doing so, any team can lose all Senior developers because there won’t be any relevant questions asked&lt;/p&gt;

&lt;p&gt;I understand that the interview can be abstract if the hiring process is being held by a large company where the technical interviewer is not a part of the target team or project, and it’s just one step in a large selection process.&lt;/p&gt;

&lt;p&gt;These questions are more relevant to the hiring process for small to medium-sized companies on the employment scheme&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;HR Interview (0.5–1h) — Technical Interview (1.5–2h) — Manager Interview (Optional) — Offer&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I don’t rule out that the questions I’ve outlined have come across time and time again only to me and are my poor choice of company to interview with. I only mention  some of the questions, but not the interview itself or the approach, and also suggest alternative questions for a particular topic.&lt;/p&gt;




&lt;h2&gt;
  
  
  How does the Event Loop Work?
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;At this point you close the page, because everything is clear — the author is dumb.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is the most annoying question from any job interview for any level. But aren’t you tired of answering this question yourself every time?&lt;/p&gt;

&lt;p&gt;Yes, of course, you can memorize the answer like an article from the Bible and calmly answer — &lt;em&gt;There is some event, it is put into Call Queue, then into Call Stack and blah, blah, blah.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;You have successfully told about the Event Loop and received the coveted checkmark ✅. Next question.&lt;/p&gt;

&lt;h3&gt;
  
  
  Do you understand why JS needs this mechanism?
&lt;/h3&gt;

&lt;p&gt;The basic understanding of the Event loop is not to answer “&lt;em&gt;How is asynchrony provided in JS?&lt;/em&gt;” but “&lt;em&gt;Why is asynchrony provided in JS via the Event loop?&lt;/em&gt;”.&lt;/p&gt;

&lt;p&gt;These are two principally different questions. Do you feel the difference? The second question relies on your experience, perception and outlook in development, where the keyword will be “single-threadedness” in your answer. &lt;/p&gt;

&lt;p&gt;But basic interview guides from the internet and the popularization of Frontend development have led to the formalization of the main points, trying to pass off desired knowledge as actual knowledge&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--lLsnf7pN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2888/0%2AzSQSg078B_2i_-Gr" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lLsnf7pN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2888/0%2AzSQSg078B_2i_-Gr" alt="replacing " width="800" height="688"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Try asking, "&lt;em&gt;How to bypass the ‘single-threadedness’ limitation in JS and do computation in a separate thread?&lt;/em&gt;”&lt;/p&gt;

&lt;p&gt;Does knowing “Call Stack” or “Call Queue” help you? — No. I guess it’s something to think about&lt;/p&gt;




&lt;h2&gt;
  
  
  Microtask and Macrotask execution queue
&lt;/h2&gt;

&lt;p&gt;You have successfully answered the standard Event loop question and you are given a new task — “&lt;em&gt;In what order will the numbers be output to the console ?&lt;/em&gt;”&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)));&lt;/span&gt;

&lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--g2BIR4tE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/0%2Ac3PXF0UTJJa_1W8n" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--g2BIR4tE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/0%2Ac3PXF0UTJJa_1W8n" alt="Do you smell that? Unreal code, son. Nothing else in the world smells like that." width="500" height="211"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Do you smell that? Unreal code, son. Nothing else in the world smells like that.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Even if you’re a Node.js developer — How often does your code have an “execution race”? You don’t understand when your code is synchronous and asynchronous?&lt;/p&gt;

&lt;p&gt;The answer to this task is not even responsible for understanding &lt;code&gt;microtask&lt;/code&gt; and &lt;code&gt;macrotask&lt;/code&gt;, and their impact on rendering in the browser.&lt;/p&gt;

&lt;p&gt;With knowledge of the execution priority in &lt;code&gt;console.log&lt;/code&gt;, can you answer these questions?:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;How to ensure that the interface is fast and smooth even with multiple concurrent events in it&lt;/em&gt;?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;What is the point of using&lt;/em&gt; &lt;code&gt;requestAnimationFrame&lt;/code&gt;?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;How can you block the whole interface and further interaction with it when clicked, and how to avoid it&lt;/em&gt;?&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Arrow functions vs regular functions
&lt;/h2&gt;

&lt;p&gt;There is nothing wrong with this question, but it depends on who is asking it. If you answer “&lt;em&gt;about the accessibility of outer this context and accessibility of function for executing&lt;/em&gt;” — that’s enough for me. (Yes, you can also mention the use of arguments)&lt;/p&gt;

&lt;p&gt;But the question is being asked not by a simple interviewer, but by that “school nerd” who can’t get enough of your answer. You sit in awkward silence, and he is waiting for the difference between the two ways of declaring a function, and doesn’t give even a hint, because “&lt;strong&gt;the senior dev must know everything!&lt;/strong&gt;”.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--3yTYTVQX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2400/0%2AQjmAxE1F2G5rwN0_" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--3yTYTVQX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2400/0%2AQjmAxE1F2G5rwN0_" alt="Give me, give me more" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Give me, give me more&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;What’s he waiting for? — He’s waiting for you to talk about using &lt;code&gt;constructor&lt;/code&gt; in regular functions. Yes yes, it’s 2024 and we have to discuss ES5 syntax.&lt;/p&gt;

&lt;p&gt;Tell me, how often do you use this construction?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;    &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;RegularFuncBird&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;species&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;color&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;RegularFuncBird&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Parrot&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;blue&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Classes? — c’mon, who needs them ?! — FUNCTIONS.&lt;/p&gt;

&lt;p&gt;Yes, you can say that “&lt;em&gt;classes in JS are ‘syntactical sugar’ and it’s a way to pay homage to the old days&lt;/em&gt;”. &lt;/p&gt;

&lt;p&gt;But let’s be honest, this knowledge is not relevant today. If a candidate has told you the practical ways and the difference in usage — that’s enough for the work. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Don’t be a nerd, your historical knowledge is only for you. Progress does not stand still and new knowledge is replaced by others&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Var vs const &amp;amp; let
&lt;/h2&gt;

&lt;p&gt;Since I started the topic about ES5 syntax, I’ll continue.&lt;/p&gt;

&lt;p&gt;Another one of the popular interview questions. You are asked about it, and the discussion begins with which &lt;code&gt;var&lt;/code&gt; is bad — popping up, contexts and problems, and &lt;code&gt;const&lt;/code&gt; and &lt;code&gt;let&lt;/code&gt; are good ones&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0tmp-OkD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2048/0%2AFthI3KfKSDmyo4v1" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0tmp-OkD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2048/0%2AFthI3KfKSDmyo4v1" alt="You memorized a lot of mock interview answers and waited for this question." width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You memorized a lot of mock interview answers and waited for this question&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;What is the practical value of this question? — minimally&lt;/p&gt;

&lt;p&gt;Can I think that the company has projects with &lt;code&gt;var&lt;/code&gt;? — yes&lt;/p&gt;

&lt;p&gt;We can discuss for a long time how bad &lt;code&gt;var&lt;/code&gt; is, but if you really care about this question of variables, you’d better ask:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;About&lt;/em&gt; &lt;code&gt;const&lt;/code&gt; &lt;em&gt;working with objects and arrays&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;How the candidate understands the “const first” principle&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In my opinion, the candidate’s answers will cover a lot of use cases and will give a clear picture of the candidate’s understanding of how this syntax works.&lt;/p&gt;




&lt;h2&gt;
  
  
  Detecting Memory Leaks
&lt;/h2&gt;

&lt;p&gt;In one of my job interviews, I got an interesting question — “&lt;em&gt;You come on a project and immediately look for memory leaks in the application, but it’s not you who will do this task, it’s QA. How would you describe the process of finding memory leaks to him?&lt;/em&gt;”&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Wow. Unconventional wording of the question, because the interview usually indirectly describes the current problems of the project without telling you directly. But the funny thing is, my answer about “&lt;em&gt;analyzing application snapshots through the profiler&lt;/em&gt;” was wrong. I still don’t know what the person wanted to hear from me&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Anyway, if we abstract from the situation and try to understand the question, it appears that &lt;strong&gt;it describes the solution and the search for consequences, but not the prevention of causes&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--oEkXlpi8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2APgVMT2XSdsOaWJtAvrqGVQ.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--oEkXlpi8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2APgVMT2XSdsOaWJtAvrqGVQ.jpeg" alt="i like resolve problems" width="500" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Yes, you have found a memory fragment increasing with time, you have found a code area with a leak, and you don’t know what to do further, because you only know how to run the profiler.&lt;/p&gt;

&lt;p&gt;In my opinion, the better question is — “&lt;em&gt;how to write safe code that does not generate memory leaks ?&lt;/em&gt;”&lt;/p&gt;

&lt;p&gt;The main points to be covered:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;addEventListener('event', handler)&lt;/code&gt; -&amp;gt; &lt;code&gt;removeEventListener('event', handler)&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;const interval_Id = setInterval()&lt;/code&gt; -&amp;gt; &lt;code&gt;cleanInterval(interval_Id)&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Understanding of “garbage collector” and long-lived refs.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;You don’t need to know all about “how to find and fix consequences?” if you know “how not to cause problems?”&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Types in Javascript
&lt;/h2&gt;

&lt;p&gt;My favourite section for useless questions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;What are the main types of JS?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Why is &lt;code&gt;null&lt;/code&gt; the object?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;What is &lt;code&gt;Symbol&lt;/code&gt; and how to use it?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;What is &lt;code&gt;prototype&lt;/code&gt;?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;What is the difference between &lt;code&gt;Number(num)&lt;/code&gt; and &lt;code&gt;new Number(num)&lt;/code&gt;?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Why are there artefacts in the remainder when adding fractional numbers?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;How to make &lt;code&gt;a == 1 &amp;amp;&amp;amp; a == 2 &amp;amp;&amp;amp; a == 3&lt;/code&gt; ?&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You, as a Senior frontend developer, sit in an interview like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xyfFc2pY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/0%2AmAPB863gF_uI7LTw.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xyfFc2pY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/0%2AmAPB863gF_uI7LTw.jpg" alt="Yeah, dude. Not a single day goes by without me not using this syntax when developing web apps" width="589" height="521"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Yeah, dude. Not a single day goes by without me not using this syntax when developing web apps&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This list can go on and on, but the answers to these questions are not necessary for developing reliable and functional front-end applications. &lt;/p&gt;

&lt;p&gt;If you want to hear a candidate’s understanding of working with “types”, you should ask a list of questions like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;How do you make sure that a &lt;code&gt;value&lt;/code&gt; is an array?&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;What are some ways to cast the value to&lt;/em&gt; &lt;code&gt;boolean&lt;/code&gt; &lt;em&gt;type?&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Where do the&lt;/em&gt; &lt;code&gt;toString()&lt;/code&gt; &lt;em&gt;and&lt;/em&gt; &lt;code&gt;toJSON()&lt;/code&gt; &lt;em&gt;methods come from?&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Why is it better to use&lt;/em&gt; &lt;code&gt;obj.hasOwnProperty(key)&lt;/code&gt; &lt;em&gt;instead of&lt;/em&gt; &lt;code&gt;obj.key&lt;/code&gt; &lt;em&gt;?&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;What are the peculiarities of working with fractional numbers and displaying their result?&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Why should&lt;/em&gt; &lt;code&gt;NaN.isNaN()&lt;/code&gt; &lt;em&gt;be used?&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  CORS
&lt;/h2&gt;

&lt;p&gt;Anyone who has ever developed an application with integration to some service has gotten this error. All you need to know about the CORS mechanism is that the browser checks the correspondence between the allowed domains for calling the service and the current domain.&lt;/p&gt;

&lt;p&gt;You can find the historical part and the reasons for the appearance &lt;a href="https://aws.amazon.com/what-is/cross-origin-resource-sharing/?nc1=h_ls" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  What could go wrong here?
&lt;/h3&gt;

&lt;p&gt;You can get the question - “&lt;em&gt;Why is the HTTP OPTIONS request used ?&lt;/em&gt;”&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You don’t know? — It’s okay, don’t worry. You remain a good front-end developer. I give you answer&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Calling HTTP OPTIONS is browser logic for getting allow HTTP methods from the service for requests to it, &lt;strong&gt;which you cannot influence in the final build from the user, and do not organize in any way yourself&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The right question about CORS
&lt;/h3&gt;

&lt;p&gt;“&lt;em&gt;What are the ways to bypass CORS policies in the browser during development ?&lt;/em&gt;”&lt;/p&gt;

&lt;p&gt;This question can show that you are familiar with this error and you can suggest solutions to your colleagues. You can suggest your own variants:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Proxy config&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Special browser extension&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Disabling browser policies&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Knowing&lt;/strong&gt; “&lt;em&gt;Why is the HTTP OPTIONS request used?&lt;/em&gt;” &lt;strong&gt;won’t eliminate blocker problems when integrating a front app in development because you don’t develop the backend part&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  In conclusion
&lt;/h2&gt;

&lt;p&gt;The technical interview is a two-way process to understand how future tasks and your experience can be used for the best advantage of each other, rather than sitting for 2 hours taking a theoretical exam disconnected from reality.&lt;/p&gt;

&lt;p&gt;Checking the basic things that are required for Junior and Middle selection are not applicable for Senior developers. First and foremost, a Senior developer is about the experience with mistakes. &lt;/p&gt;

&lt;p&gt;Based on my suggested questions, ask yourself —  “&lt;em&gt;What kind of candidate would I like to get&lt;/em&gt;? &lt;em&gt;The one who answers the theory or the one who applies it?&lt;/em&gt;” All stakeholders will benefit from this decision because the project will really have people with experience, not just “sets of knowledge”.&lt;/p&gt;

&lt;p&gt;Still, &lt;strong&gt;my proposal will not cover the main problem — only one technical interview for the Senior Frontend Developer role&lt;/strong&gt;. In 2 hours of interviews, you won’t learn about the candidate’s skills in system design, and you won’t be able to devote much time to “live coding” and spend time on theory.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;But hopefully, it will help&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  P.S.
&lt;/h3&gt;

&lt;p&gt;I don’t exclude that I will make a second part about CSS questions if you like this article&lt;/p&gt;

</description>
      <category>career</category>
      <category>webdev</category>
      <category>interview</category>
    </item>
    <item>
      <title>Adding strict Eslint rules to the current code without problems</title>
      <dc:creator>Maksim Dolgih</dc:creator>
      <pubDate>Thu, 29 Feb 2024 17:28:33 +0000</pubDate>
      <link>https://dev.to/misterion96/make-your-code-great-again-1pm3</link>
      <guid>https://dev.to/misterion96/make-your-code-great-again-1pm3</guid>
      <description>&lt;h4&gt;
  
  
  A strategy for applying new or strict linting rules to existing code without loss of development
&lt;/h4&gt;




&lt;h2&gt;
  
  
  Problem statement
&lt;/h2&gt;

&lt;p&gt;In a previous story (&lt;a href="https://medium.com/@maks-dolgikh/your-teams-style-guide-from-scratch-b9bb206845ac" rel="noopener noreferrer"&gt;Create your code style for the team from scratch. Eslint, Prettier, Commitlint and etc.&lt;/a&gt;), I broke down a way for a team to create their rules, organize them into packages in the recommended format, and apply them to a repository&lt;/p&gt;

&lt;p&gt;Suppose you want to apply new &lt;code&gt;Eslint&lt;/code&gt; rules or configs to an existing repository. You run a check on your repository and get a message like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1271 problems (1076 errors, 195 warnings)
345 errors and 37 warnings potentially fixable with the  --fix option.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What does this message tell us? — It says that &lt;code&gt;Eslint&lt;/code&gt; rules found 1076 errors and 195 warnings. Of these, 345 errors and 37 warnings can be corrected automatically. We can fix only some parts of the code automatically, while the rest it requires manual correction. &lt;em&gt;It is an unpleasant situation.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;With &lt;code&gt;lint-staged&lt;/code&gt;, any commit will “crash” on validation, because of errors in existing code. If you have a built-in check on the Lint job in &lt;code&gt;CI/CD&lt;/code&gt;, it will also crash.&lt;/p&gt;

&lt;p&gt;If the project is large and involves several participants, it is unlikely that you will be able to fix all the problems at once, even with auto-fixing. Even if you manage to do that, the current pool of Pull Requests will become conflicting, which will also affect the speed of development and the usability of the others.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;We wanted the best, but we got a huge “blocker” of development&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Strategies for solving the problem
&lt;/h2&gt;

&lt;p&gt;Three main options can be identified:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Don’t apply new rules&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You realize that introducing new rules generates many problems and there is no time to adapt and correct the code. Your attempt to improve the code and standardize it has failed.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Disable checks&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Rules are needed, but they shouldn’t block work either, and perhaps you’ll look into fixing problems in the future. In this strategy, lint-staged checks do not include &lt;code&gt;Eslint&lt;/code&gt; startup, and &lt;code&gt;CI/CD&lt;/code&gt; jobs don’t block the pipeline process.&lt;/p&gt;

&lt;p&gt;This strategy has a significant downside — your code review has become passive. Every developer can use his own style,&lt;br&gt;
and your code review will be noticeably longer because you need to mark all the places to be fixed yourself when &lt;code&gt;Eslint&lt;/code&gt; did it for you.&lt;/p&gt;

&lt;p&gt;It is also not a fact that you will allocate time to fix problems in future and that the number of errors has not increased during this time.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Adapt rules to the current repository&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With this strategy, you disable or change the alert type to &lt;code&gt;WARN&lt;/code&gt; of “blocking” rules that don’t support auto-remediation. This will take some time to implement, but it’s a straightforward golden mean to get out of the situation. You don’t unilaterally fix the code to fit the rules, which will help not to affect your other colleagues.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Is it all?&lt;br&gt;
There is no more strategy to apply code inspection rules? — There are&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  Divide &amp;amp; Conquer
&lt;/h2&gt;

&lt;p&gt;This strategy is basically based on the “&lt;strong&gt;Adapt rules to the current repository&lt;/strong&gt;” strategy, with one difference — the old code is checked against the &lt;code&gt;Eslint&lt;/code&gt; config you adapted, but the new code is checked against the original &lt;code&gt;Eslint&lt;/code&gt; config you originally wanted to apply to the repository.&lt;/p&gt;

&lt;p&gt;For this purpose 2 &lt;code&gt;Eslint&lt;/code&gt; configs are created:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Source config.&lt;/strong&gt; Config containing code main lint rules to be used for development.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Adapted config.&lt;/strong&gt; It inherits from the source config, but it also inherits from the “temporary rules config”. “Temporary rules” are “blocking” rules of the source config in the &lt;code&gt;ERROR&lt;/code&gt; state, but which have no auto-remediation capability. These rules must be obtained imperatively the first time you run the code checker and their status is set to &lt;code&gt;WARN&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Main advantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The approach ensures that new changes within the current repository will already be styled according to the new rules, but leaves the old code checked in. Over time, the new code will supersede the old code, and your repository will follow the current code style without exception.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;To speed up the process, you can build into the work cycle switch from &lt;code&gt;WARN&lt;/code&gt; to &lt;code&gt;ERROR&lt;/code&gt; 1 rule per sprint&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The approach can be applied to existing repositories with static analytic tools of code if you need to increase code rigour with a new plugin or rules&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;An abstract scheme for making changes and validating them would look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F5324%2F1%2ACy7ywsSb5Nf7np8In1Mj6A.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F5324%2F1%2ACy7ywsSb5Nf7np8In1Mj6A.png" alt="scheme of committing changes"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Implementation
&lt;/h2&gt;

&lt;p&gt;As an example, let’s see how to use the configuration &lt;code&gt;strict&lt;/code&gt; from &lt;code&gt;@my-team/eslint-plugin&lt;/code&gt; to the repository&lt;/p&gt;
&lt;h3&gt;
  
  
  Creating adapter eslint config
&lt;/h3&gt;

&lt;p&gt;If we run the lint now, we will get the following log&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2076%2F0%2AUt54CgT2JNVNed9N" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2076%2F0%2AUt54CgT2JNVNed9N" alt="log"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There are 4 “blocking” rules that do not have autofix. Let’s put them in “temporary rules config” c &lt;code&gt;WARN&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;configs/temp-rules.eslint-config.js&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;overrides&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;files&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;*.ts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="na"&gt;rules&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular-eslint/no-output-native&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;warn&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@typescript-eslint/explicit-member-accessibility&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;warn&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;files&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;*.html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="na"&gt;rules&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular-eslint/template/no-any&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;warn&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular-eslint/template/no-call-expression&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;warn&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;


            &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Also, create an adapted config that inherits from the &lt;code&gt;.eslintrc.js&lt;/code&gt; and our &lt;code&gt;temp-rules.eslint-config.js&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;.eslintrc.adapted.js&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;root&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;extends&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./.eslintrc.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./configs/temp-rules.eslint-config.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;If we run the check now, we should have no errors left behind&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2072%2F0%2ADRNkQfQ0VcmjofJh" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2072%2F0%2ADRNkQfQ0VcmjofJh" alt="log without ERROR"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Files splitting for validation
&lt;/h3&gt;

&lt;p&gt;Most implementations of &lt;code&gt;lint-staged&lt;/code&gt; and &lt;code&gt;husky&lt;/code&gt; are as follows starting call &lt;code&gt;lint-staged&lt;/code&gt; on the &lt;code&gt;pre-commit&lt;/code&gt; hook&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/usr/bin/env sh&lt;/span&gt;
&lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;dirname&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;/_/husky.sh"&lt;/span&gt;

npx lint-staged &lt;span class="nt"&gt;--quiet&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Config &lt;code&gt;.lintstagedrc.js&lt;/code&gt; from the root of the repository&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;*.{js,ts,html}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;eslint --quiet --fix&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;*.{json,scss,md}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;prettier --write&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;So how can we achieve separate checking of our change with two &lt;code&gt;Eslint&lt;/code&gt; configs?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To do this, we can refer to the &lt;code&gt;lint-staged&lt;/code&gt; documentation and find the &lt;code&gt;--diff-filter&lt;/code&gt; parameter. This is a Git parameter that allows you to separate files by how they are type of change (learn more &lt;a href="https://git-scm.com/docs/git-diff#Documentation/git-diff.txt---diff-filterACDMRTUXB82308203" rel="noopener noreferrer"&gt;here&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;We should only be interested in two parameters — &lt;code&gt;A&lt;/code&gt; (added) and &lt;code&gt;M&lt;/code&gt; (modified). We will use them to call separate checks. So simple 🔥&lt;/p&gt;

&lt;p&gt;Now our file for the &lt;code&gt;pre-commit&lt;/code&gt; hook looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/sh&lt;/span&gt;
&lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;dirname&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;/_/husky.sh"&lt;/span&gt;

npx lint-staged &lt;span class="nt"&gt;--diff-filter&lt;/span&gt; M &lt;span class="nt"&gt;-c&lt;/span&gt; ./.lintstagedrc.adapted.js &lt;span class="nt"&gt;--quiet&lt;/span&gt;
npx lint-staged &lt;span class="nt"&gt;--diff-filter&lt;/span&gt; A &lt;span class="nt"&gt;-c&lt;/span&gt; ./.lintstagedrc.js &lt;span class="nt"&gt;--quiet&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In addition to the main &lt;code&gt;.lintstagedrc.js&lt;/code&gt; config, we also need to create &lt;code&gt;.lintstaged.adapted.js&lt;/code&gt;, which will call our &lt;code&gt;.eslintrc.adapted.js&lt;/code&gt; config&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;*.{js,ts,html}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;eslint --quiet --fix --config ./.eslintrc.adapted.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;*.{json,scss,md}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;prettier --write&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This completes the configuration&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing
&lt;/h2&gt;

&lt;p&gt;As a check, let’s perform some changes, namely:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;create a component new-test-app-component identical to &lt;code&gt;app.component&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;in the original &lt;code&gt;app.component&lt;/code&gt;, add a few simple changes.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;What for? The code of these files is almost identical, but different checks will be applied to them because of the type of change. In the first case, we’ve created conditionally new files that have problems and we don’t want to push them to the repository. In the second case, we changed the old files, but since we need non-blocking validation, we should just get warnings.&lt;/p&gt;

&lt;p&gt;If we call &lt;code&gt;git commit&lt;/code&gt; such changes, we should only get an error on the new code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[STARTED] .lintstagedrc.adapted.js — 2 files
[STARTED] *.{js,ts,html} — 2 files
[STARTED] *.{json,scss,md} — 0 files
[SKIPPED] *.{json,scss,md} — no files
[STARTED] eslint --fix --config ./.eslintrc.adapted.js
[COMPLETED] eslint --fix --config ./.eslintrc.adapted.js
[COMPLETED] *.{js,ts,html} — 2 files
[COMPLETED] .lintstagedrc.adapted.js — 2 files

→ eslint --fix --config ./.eslintrc.adapted.js:
/Users/maksim/WebstormProjects/playground/example-styleguide/example-angular-app/src/app/app.component.html
   2:12  warning  Avoid calling expressions in templates  @angular-eslint/template/no-call-expression
  15:17  warning  Avoid using "$any" in templates         @angular-eslint/template/no-any
/Users/maksim/WebstormProjects/playground/example-styleguide/example-angular-app/src/app/app.component.ts
  12:13  warning  Output bindings, including aliases, should not be named as standard DOM events  @angular-eslint/no-output-native
  15:5   warning  Missing accessibility modifier on method definition test                        @typescript-eslint/explicit-member-accessibility
  15:13  warning  Unexpected any. Specify a different type                                        @typescript-eslint/no-explicit-any
✖ 5 problems (0 errors, 5 warnings) ✅

[STARTED] Preparing lint-staged...
[COMPLETED] Preparing lint-staged...
[STARTED] Running tasks for staged files...
[STARTED] .lintstagedrc.js — 3 files
[STARTED] *.{js,ts,html} — 3 files
[STARTED] *.{json,scss,md} — 0 files
[FAILED] eslint --fix --config ./.eslintrc.js [FAILED].

✖ eslint --fix --config ./.eslintrc.js:
/Users/maksim/WebstormProjects/playground/example-styleguide/example-angular-app/src/new-test-app-component/app.component.html
   2:12  error  Avoid calling expressions in templates  @angular-eslint/template/no-call-expression
  15:17  error  Avoid using "$any" in templates         @angular-eslint/template/no-any
/Users/maksim/WebstormProjects/playground/example-styleguide/example-angular-app/src/new-test-app-component/app.component.ts
  12:13  error    Output bindings, including aliases, should not be named as standard DOM events  @angular-eslint/no-output-native
  15:5   error    Missing accessibility modifier on method definition test                        @typescript-eslint/explicit-member-accessibility
  15:13  warning  Unexpected any. Specify a different type                                        @typescript-eslint/no-explicit-any
✖ 5 problems (4 errors, 1 warning) ❌

husky - pre-commit hook exited with code 1 (error)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, everything worked as intended, and now we can be confident in our style guide, and that new files will follow it without exception.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/Misterion96/frontend-style-guide-example" rel="noopener noreferrer"&gt;GitHub - Misterion96/frontend-style-guide-example: test repository to demo style-guide operation&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;I'm expanding my network of contacts on &lt;a href="https://www.linkedin.com/in/max-dolgikh/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;. I will be glad to meet new people&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>productivity</category>
      <category>javascript</category>
      <category>development</category>
    </item>
    <item>
      <title>The Front-End Development we’re used to is dying</title>
      <dc:creator>Maksim Dolgih</dc:creator>
      <pubDate>Fri, 09 Feb 2024 07:47:44 +0000</pubDate>
      <link>https://dev.to/misterion96/the-front-end-development-were-used-to-is-dying-4e19</link>
      <guid>https://dev.to/misterion96/the-front-end-development-were-used-to-is-dying-4e19</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Why I think we’ll soon be back to where we started.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Before the advent of SPA, web applications were typically multi-page. This meant that every time a user interacted with the application, the server sent a new page in its entirety and a browser loaded it again. Each time the user navigated between pages, a complete page reload occurred, and it could slow things down and create a less-than-smooth user experience. Similar applications were often built using server-side technologies such as PHP, Ruby on Rails, ASP.NET, etc., which generated HTML code on the server side and sent it to the browser.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F0%2AIcdswn5CFRcaw39d" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F0%2AIcdswn5CFRcaw39d" alt="how a PHP web application works"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Web developers were universal specialists, they were responsible for front-end and back-end parts at the same time. After the development of web technology and the demand of users, new solutions, which would allow them to work with an interactive interface without any problems or waiting were required.&lt;/p&gt;

&lt;p&gt;This is how the first solutions for SPA using BackboneJs or AngularJs appeared. They allowed us to reduce the load on the server, whose resources were limited at that time, and to provide interactivity when working with a web page via JS because there was no need to wait for a new page with updates from the server.&lt;/p&gt;

&lt;p&gt;That’s how the division into front-end and back-end parts appeared. The role of purely front-end developers has become more demanded and diverse. They began to specialize in creating user interfaces, working with HTML, CSS and JavaScript, as well as interacting with APIs and the server. On the other hand, back-end developers became more focused on data processing, application business logic, working with databases, and creating server APIs.&lt;/p&gt;

&lt;p&gt;And that’s how we entered the era of React, Angular2, Vue and other web application development tools. Instead of creating simple forms and lists, now we have js-routing, state management, browser API, binding authorization tokens to requests, data mappings, etc.&lt;/p&gt;

&lt;blockquote&gt;
&lt;h3&gt;
  
  
  We started to complicate things which were simple.
&lt;/h3&gt;
&lt;/blockquote&gt;

&lt;p&gt;As a result of this approach, the problems were obtained:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Difficulties in communication and coordination&lt;/strong&gt;. Api Contracts and communication method — HTTP 1.1, Websocket, GraphQL. JSON parsing and validation.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Divergence in understanding and knowledge&lt;/strong&gt;. For example, you could develop a front-end application that creates many queries and consider it a normal and optimized SPA. But for the back-end, this is a very dangerous situation, because it now needs a lot of database accesses and proper aggregation of this data, which will affect its performance and maintenance.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Duplication of work&lt;/strong&gt;. Most CRUD operations on the back-end had similar behaviour on the front-end. We didn’t just get the list from the server, now we put it in the store(), each user action is processed via dispatch() and waits for the request to be executed, after that we update the store via reducer() depending on the result — &lt;strong&gt;everything the back-end does to the database, we repeat on the front-end&lt;/strong&gt;. (page reloading and restoring SPA to the current state from the server are also worth mentioning — a separate pain for the moment)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Difficulties in debugging and testing&lt;/strong&gt;. You now need to consider possible integration issues and test them in the context of both sides of the application. Yes, you can create isolated e2e-tests for the front-end application, but they cannot guarantee reliability in Production. Yes, there is ZoD for validating server responses, but what percentage of its usage?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Increased development time and cost&lt;/strong&gt;. Any change to an API contract requires two people at the same time. You can’t directly change a template to a server like you used to. You need rallies, split into separate tasks, business-analytic specialists and so on to make the change smoothly.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;SEO&lt;/strong&gt;. Since our app is entirely formed through JS, search engines could not get the app content and its navigation to index it properly, thus SSR and SSG solutions were required.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Security&lt;/strong&gt;. Any critical data entered on the page needs to be hidden before being passed to the server. Also, a lot of personal information needs to be requested from the server for the application, revealing access tokens.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  So, why is the usual front-end dying?
&lt;/h2&gt;

&lt;p&gt;Just go to any resource and you’ll see how many job vacancies are open:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Python + Django&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;PHP + Laravel&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;NextJs + React&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Nuxt + Vue&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are all bundles for server-based web application development. Thanks to the Hydration and Resumability approaches, the server can only render the modified part of the interface, without reloading the page.&lt;/p&gt;

&lt;p&gt;What they provide:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The server application now does not need complex HTTP or WS contracts and support them on both sides, it can use better methods to exchange information with other services like gRPC.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The process of making changes is faster due to the lack of intermediate approvals, for 1 person the result the user sees immediately changes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Tests can check the application holistically, eliminating integration tests and reducing errors.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You exchange only HTML markup, all “request-response” logic is hidden for a user&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Why pass a lot of data in JSON to restore SPA to the right state when you can pass a ready template?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You don’t need to worry about browser compatibility and use babel and other tools, because JS code on the page is minimal.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With the advent of No-Code solutions, template generation via AI, huge server resources, and SEO requirements — the current number of front-end developers as well as tools are not needed to develop only the front-end part.&lt;/p&gt;

&lt;p&gt;Business owners have a valid question — “&lt;em&gt;Why do I need to hire a pure front-end developer and a pure back-end developer to do a simple application?”&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Full-stack developer is not a management fad, in terms of saving on staffing, now it’s a mainstay. You don’t need a pure front-end developer, you need a developer who can make a whole application, performing simple operations with the database directly or other services and displaying the result.&lt;/p&gt;

&lt;p&gt;Yes, there will undoubtedly remain a complex or "headless" applications that require front-end and back-end separation but most of the applications will move away from SPA and go down the way that was already there, but now we have a solution to those problems. With the advent of HTMX, any back-end developer with basic knowledge can create a web application. You don’t even need to know JS to create a single-page app with little logic now.&lt;/p&gt;

&lt;p&gt;You may ask, “&lt;em&gt;The front-end developer was responsible, not only for JS logic but for CSS and proper selectors, HTML and its semantics, does the backend developer have to know that now ?&lt;/em&gt;” — No, now an AI or “HTML layout designer” can do template generation based on layouts from Figma. The logic and interactivity of the HTML-template are now defined on the server.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Now is a good time to think whether you really need all these sophisticated front-end development tools and whether you should remain a pure front-end developer.&lt;/p&gt;

&lt;p&gt;I expect current front-end developers to move to Fullstack qualification with a 60%-front-end, and 40%-back-end split to stay relevant specialists. HTMX is just the beginning, the vector towards NextJs or Nuxt tools will grow, and Angular-type frameworks will die if they can’t adapt to new implementations, although the Angular ecosystem already has prototypes on AnalogJs as well&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://htmx.org/" rel="noopener noreferrer"&gt;&lt;strong&gt;htmx - high power tools for html&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://analogjs.org/" rel="noopener noreferrer"&gt;&lt;strong&gt;Analog&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.indeed.com/jobs?q=front+end+developer&amp;amp;l=Remote" rel="noopener noreferrer"&gt;Search jobs by “Front End developer” role&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.indeed.com/jobs?q=full+stack+developer&amp;amp;l=Remote" rel="noopener noreferrer"&gt;Search jobs by “Full stack developer” role&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nextjs.org/" rel="noopener noreferrer"&gt;&lt;strong&gt;Next.js by Vercel - The React Framework&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nuxt.com/" rel="noopener noreferrer"&gt;&lt;strong&gt;Nuxt: The Intuitive Vue Framework&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>discuss</category>
      <category>career</category>
      <category>development</category>
    </item>
    <item>
      <title>Angular is not for everyone, and probably not for you</title>
      <dc:creator>Maksim Dolgih</dc:creator>
      <pubDate>Thu, 11 Jan 2024 08:27:40 +0000</pubDate>
      <link>https://dev.to/misterion96/angular-is-not-for-everyone-and-probably-not-for-you-404n</link>
      <guid>https://dev.to/misterion96/angular-is-not-for-everyone-and-probably-not-for-you-404n</guid>
      <description>&lt;p&gt;For 2023, Team Angular has made a lot of important changes which were asked for by the community, and that’s insanely awesome. But it wasn’t always like this.&lt;/p&gt;

&lt;p&gt;In this story, I’d like to tell you about my 4 years experience of using Angular. First of all, I think Angular &lt;strong&gt;should not be your first technology&lt;/strong&gt; to develop applications.&lt;/p&gt;

&lt;p&gt;I want to highlight the problems which Angular creates and how they affect developers and team building. I will also try to give solutions to the problems I have identified if you already use Angular or want to use it.&lt;/p&gt;

&lt;p&gt;Unfortunately, some teams or even companies are slow to upgrade for one reason or another, and you may find applications on &lt;code&gt;Angular 8, 9 or 12&lt;/code&gt;. Therefore some of the issues outlined here can still be relevant.&lt;/p&gt;

&lt;p&gt;If you are a junior developer, this article may also be useful for you and will help you with choosing your first development stack.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;At the one moment, i may seem criticizing declarative approaches implemented by the Angular team — not at all. I don’t question that over time any &lt;code&gt;low-level&lt;/code&gt; code becomes &lt;code&gt;high-level&lt;/code&gt; code via abstraction and new features, making our work easier. Each new UI library tries to solve the problems of current libraries and offers improvements, providing growth and quality tools from year to year&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The convenience trap
&lt;/h2&gt;

&lt;p&gt;As we know, Angular is a UI framework, not a library. It positions itself as a self-contained solution for front-end application development. You don’t have a “zoo of technology” from app to app, everything is uniform and monotonous, but there is a downside to this. It’s easy to get used to the conveniences that Angular provides, and it gets more difficult to give them up later on.&lt;/p&gt;

&lt;h3&gt;
  
  
  ReactiveForms
&lt;/h3&gt;

&lt;p&gt;At one time, the approach proposed by the Angular team, the form and its control are separated into an &lt;code&gt;HTML-template&lt;/code&gt; and a &lt;code&gt;JS-controller&lt;/code&gt;, really proved to be handy for form development.&lt;/p&gt;

&lt;p&gt;The problem is different, we are so used to relying on validation from &lt;code&gt;ReactiveForms&lt;/code&gt; that we forget that &lt;code&gt;HTML&lt;/code&gt; natively provides us with all the attributes we need to validate input fields — &lt;code&gt;min&lt;/code&gt;, &lt;code&gt;max&lt;/code&gt;, &lt;code&gt;pattern&lt;/code&gt;, &lt;code&gt;required&lt;/code&gt;, &lt;code&gt;readonly&lt;/code&gt;, etc.&lt;/p&gt;

&lt;p&gt;What is this problem? — Once you get beyond Angular, it turns out that ReactiveForms doesn’t exist as a standalone library. &lt;strong&gt;You’ll have to re-learn how to develop forms&lt;/strong&gt; — events (&lt;code&gt;submit&lt;/code&gt;,&lt;code&gt;change&lt;/code&gt;) and input field attributes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Building an application
&lt;/h3&gt;

&lt;p&gt;You don’t need to customize the application build, just run the “build” or “serve” commands to get started. You do not see the &lt;code&gt;webpack.config.js&lt;/code&gt; or &lt;code&gt;vite.config.js&lt;/code&gt; configuration files of the builder.&lt;/p&gt;

&lt;p&gt;Can you say:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;How is your application built?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Which file is the entry point?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Which tool builds your application?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;How do your &lt;code&gt;SCSS files&lt;/code&gt; become &lt;code&gt;CSS&lt;/code&gt;?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;How does &lt;code&gt;HRM&lt;/code&gt; work?&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you work only with Angular, you missed the growth stage of gaining the skill to build an application. Webpack, Gulp, Rollup, Vite, Esbuild — you just don’t know it. If you’re asked to create a simple web page in HTML and SCSS without Angular — probably you can’t.&lt;/p&gt;

&lt;h3&gt;
  
  
  HTTP client
&lt;/h3&gt;

&lt;p&gt;This is a convenient wrapper over &lt;code&gt;XHR&lt;/code&gt; using the &lt;code&gt;Observable&lt;/code&gt; pattern, given the recent &lt;code&gt;XHR2&lt;/code&gt; feature for &lt;code&gt;SSR&lt;/code&gt;. It allows us to make queries with multiple parameters, track the progress of the query, and be able to convert the response to the desired data type with just a single parameter.&lt;/p&gt;

&lt;p&gt;But as an angular developer, would you be able to say:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;When was the last time you used native methods to handle HTTP — &lt;code&gt;fetch&lt;/code&gt; or &lt;code&gt;XHR&lt;/code&gt;?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Can you handle requests and errors globally without using an &lt;code&gt;Interceptor&lt;/code&gt;?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Can you name ways to undo an HTTP-request without using &lt;code&gt;switchMap&lt;/code&gt;?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Do you know of &lt;code&gt;axios&lt;/code&gt; or &lt;code&gt;node-fetch&lt;/code&gt; libraries?&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Despite the convenience, we should know how to make queries without Angular. It surprises me when even Senior developers don’t know how to make a request before bootstrap application or about the existence of &lt;a href="https://rxjs.dev/api/ajax/ajax" rel="noopener noreferrer"&gt;RxJS.Ajax&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We must have an understanding of the essence of the request and response to be able to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Handle errors&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Parse the response&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Track the progress of the request&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Work with FormData&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://medium.com/@maks-dolgikh/angular-is-not-for-everyone-and-probably-not-for-you-72e4766fff20" rel="noopener noreferrer"&gt;read more...&lt;/a&gt;&lt;/p&gt;

</description>
      <category>angular</category>
      <category>webdev</category>
      <category>programming</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Charts and CSS-variables in Angular</title>
      <dc:creator>Maksim Dolgih</dc:creator>
      <pubDate>Mon, 08 Jan 2024 19:47:35 +0000</pubDate>
      <link>https://dev.to/misterion96/charts-and-css-variables-in-angular-5hal</link>
      <guid>https://dev.to/misterion96/charts-and-css-variables-in-angular-5hal</guid>
      <description>&lt;h2&gt;
  
  
  Chart styling as we know it
&lt;/h2&gt;

&lt;p&gt;Styling charts is another area where you need to use colors. There are a lot of color palettes for charts on the internet, but not every color palette can fit our brandbook and we have to apply “our” colors to maintain the overall style.&lt;/p&gt;

&lt;p&gt;Often, it is a regular preset with hardcoded colors. This approach completely covers most graph styling issues if only 1 interface color scheme is used.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;But what about supporting more than one color scheme?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--FRmpZ5dC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/0%2A4rjR2E6vHbH4zjiC" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--FRmpZ5dC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/0%2A4rjR2E6vHbH4zjiC" alt="Switching themes does not affect charts" width="800" height="333"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Adapting charts for each theme is a challenge for developers. And if experience is not enough, you can even meet such implementations&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;backgroundColor = theme === 'dark' ? 'white' : 'black'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;It’s scary to imagine if detailed stylization of each type of chart would be required.&lt;/em&gt; 😱&lt;/p&gt;

&lt;p&gt;Let’s suppose developers have solved the problem of this approach and made a ColorsService that provides the desired color by &lt;code&gt;colorName&lt;/code&gt;, hiding the actual value.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;    &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ColorsService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;themeMap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;TThemes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;TColorName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
           &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;default&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;TColorName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
               &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;primary&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#d75894&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
               &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;secondary&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#9b3dca&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
               &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;chart-color-1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#526ed3&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
               &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;chart-color-2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#ea97c4&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
               &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;chart-color-3&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#fee797&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
               &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;base-1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#808080&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
               &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;base-2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#bebebe&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
           &lt;span class="p"&gt;])],&lt;/span&gt;
           &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dark&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;TColorName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
               &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;primary&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#5e84ff&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
               &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;secondary&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#0dd0ff&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
               &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;chart-color-1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#ffce56&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
               &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;chart-color-2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#36a2eb&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
               &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;chart-color-3&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#ff6384&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
               &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;base-1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#c7c7c7&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
               &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;base-2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#bcbcbc&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
           &lt;span class="p"&gt;])],&lt;/span&gt;
       &lt;span class="p"&gt;])&lt;/span&gt;


       &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;paletteMap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;TColorName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;themeMap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;default&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;


       &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
           &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;themeSwitcher&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ThemeSwitcherService&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
           &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;themeSwitcher&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;eventBus$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
               &lt;span class="nf"&gt;takeUntilDestroyed&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
           &lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;theme&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
               &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;paletteMap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;themeMap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
           &lt;span class="p"&gt;})&lt;/span&gt;
       &lt;span class="p"&gt;}&lt;/span&gt;


       &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;getColor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;colorName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TColorName&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
           &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;paletteMap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;colorName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
       &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The service installs a new color map every time the theme changes. And the &lt;code&gt;eventBus$&lt;/code&gt; bus will notify the charts that they need to be refreshed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--vU6K3GqZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/0%2AFxBYs7KFyTPCdJDs" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vU6K3GqZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/0%2AFxBYs7KFyTPCdJDs" alt="Switching themes affects charts, and they are styled via ColorsService" width="800" height="336"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;By introducing the &lt;code&gt;ColorsService&lt;/code&gt; abstraction, we have solved the potential problem of hardcoding colors in each component of the graph.&lt;/p&gt;

&lt;p&gt;But we didn’t get rid of another problem — SCSS color variables and &lt;code&gt;ColorsService&lt;/code&gt; are not related in any way, and therefore support for current and new themes will also be done by hardcoded colors. If the color scheme on SCSS changes, we’ll need to make changes here as well.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Can we make this ColorsService even more abstract, and not do any more theme support in it ?&lt;/em&gt; &lt;a href="https://medium.com/@maks-dolgikh/css-variables-in-angular-charts-part-3-2bcdb63c556c" rel="noopener noreferrer"&gt;read more...&lt;/a&gt;&lt;/p&gt;

</description>
      <category>angular</category>
      <category>ui</category>
      <category>css</category>
      <category>webdev</category>
    </item>
    <item>
      <title>ng-deep is no longer needed</title>
      <dc:creator>Maksim Dolgih</dc:creator>
      <pubDate>Mon, 08 Jan 2024 19:38:55 +0000</pubDate>
      <link>https://dev.to/misterion96/css-variables-in-angular-part-2-ng-deep-is-no-longer-needed-1dc9</link>
      <guid>https://dev.to/misterion96/css-variables-in-angular-part-2-ng-deep-is-no-longer-needed-1dc9</guid>
      <description>&lt;h2&gt;
  
  
  External library component
&lt;/h2&gt;

&lt;p&gt;Let’s imagine that we are developing an &lt;strong&gt;Angular library&lt;/strong&gt; of UI components for the rest of the teams.&lt;/p&gt;

&lt;p&gt;We have a simple component that displays a header and a description&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;    &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
     &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;lib-external-component&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="na"&gt;standalone&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="na"&gt;imports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
     &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`
       &amp;lt;h2 class="header"&amp;gt;{{header}}&amp;lt;/h2&amp;gt;
       &amp;lt;span class="description"&amp;gt;{{description}}&amp;lt;/span&amp;gt;
     `&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="na"&gt;styleUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./external-component.component.scss&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ExternalComponentComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Input&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
     &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nx"&gt;header&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;External component header&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;


     &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Input&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
     &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;External component description&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;    &lt;span class="nd"&gt;:host&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;block&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
     &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8px&lt;/span&gt; &lt;span class="m"&gt;12px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
     &lt;span class="nl"&gt;outline&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1px&lt;/span&gt; &lt;span class="nb"&gt;solid&lt;/span&gt; &lt;span class="m"&gt;#b7b7b7&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


     &lt;span class="err"&gt;.header&lt;/span&gt; &lt;span class="err"&gt;{&lt;/span&gt;
       &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;18px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
       &lt;span class="nl"&gt;font-weight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bold&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
       &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;red&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
     &lt;span class="p"&gt;}&lt;/span&gt;


     &lt;span class="nc"&gt;.description&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;14px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
       &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;blue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
     &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="err"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flb2j8rttt8cqfpscxg1s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flb2j8rttt8cqfpscxg1s.png" alt="Сomponent visualization" width="755" height="169"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Currently, when we change the theme, the component does not pick up our styles and remains unchanged&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_JP6vVEh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/0%2A37GxY77_0iP2MeS_" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_JP6vVEh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/0%2A37GxY77_0iP2MeS_" alt="Switching themes does not affect the component" width="800" height="319"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;How can we style .header and .description?&lt;/p&gt;

&lt;p&gt;There are three options:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Customize globally via a generic &lt;code&gt;styles.scss&lt;/code&gt; file&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Customize the style of the component in the parent component style with &lt;code&gt;ViewEncapsulation.None&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Customize the style of the component in the parent component by wrapping that in &lt;code&gt;::ng-deep&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The first two options may be used depending on the situation and if they do not break the overall styling logic.&lt;/p&gt;

&lt;p&gt;But &lt;code&gt;ng-deep&lt;/code&gt; is a &lt;strong&gt;deprecated&lt;/strong&gt; selector, and developers continue to use it as a “&lt;em&gt;magic pill&lt;/em&gt;” for accessing styles of a child component.&lt;/p&gt;

&lt;p&gt;Overriding styles in a parent component with theme support may look like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scss"&gt;&lt;code&gt;    &lt;span class="k"&gt;@each&lt;/span&gt; &lt;span class="nv"&gt;$theme-key&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;variables&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;$themes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="nv"&gt;$theme&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;variables&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;$themes&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$theme-key&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;


     &lt;span class="nd"&gt;:host-context&lt;/span&gt;&lt;span class="o"&gt;([&lt;/span&gt;&lt;span class="nt"&gt;data-theme&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nv"&gt;$theme-key&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="o"&gt;])&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="nd"&gt;::ng-deep&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
         &lt;span class="nt"&gt;app-external-component&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
           &lt;span class="nc"&gt;.header&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
             &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$theme&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"primary"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
           &lt;span class="p"&gt;}&lt;/span&gt;


           &lt;span class="nc"&gt;.description&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
             &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$theme&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"secondary"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
           &lt;span class="p"&gt;}&lt;/span&gt;
         &lt;span class="p"&gt;}&lt;/span&gt;
       &lt;span class="p"&gt;}&lt;/span&gt;
     &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s check the support of our themes for the external component&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--gnEtHxQK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/0%2ATtTeeDGs_cSouF2G" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gnEtHxQK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/0%2ATtTeeDGs_cSouF2G" alt="Switching themes affects the component via ng-deep" width="800" height="378"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We got the result we wanted but created a lot of complex code to style the component, which inherited all the &lt;a href="https://maks-dolgikh.medium.com/67e727cf317b" rel="noopener noreferrer"&gt;styling issues&lt;/a&gt; for generic styling&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Is it possible to simplify all this and even get rid of using &lt;code&gt;::ng-deep&lt;/code&gt;?&lt;/em&gt; &lt;a href="https://medium.com/@maks-dolgikh/css-variables-in-angular-ng-deep-is-no-longer-needed-part-2-3ac60f8a4abc" rel="noopener noreferrer"&gt;read more...&lt;/a&gt;&lt;/p&gt;

</description>
      <category>css</category>
      <category>angular</category>
      <category>development</category>
      <category>designpatterns</category>
    </item>
    <item>
      <title>Forget about SCSS variables</title>
      <dc:creator>Maksim Dolgih</dc:creator>
      <pubDate>Mon, 08 Jan 2024 19:21:53 +0000</pubDate>
      <link>https://dev.to/misterion96/css-variables-in-angular-part-1-forget-about-scss-variables-2b6n</link>
      <guid>https://dev.to/misterion96/css-variables-in-angular-part-1-forget-about-scss-variables-2b6n</guid>
      <description>&lt;h2&gt;
  
  
  SCSS variables
&lt;/h2&gt;

&lt;p&gt;In my career, I’ve managed to work on a lot of projects that used styling via SCSS, LESS, or Stylus. One of the main advantages of favoring them over CSS, besides “cascading”, was “&lt;strong&gt;variables&lt;/strong&gt;”&lt;/p&gt;

&lt;p&gt;They enabled:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;To respect the DRY principle&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;To centralize shared variables for reuse via &lt;a class="mentioned-user" href="https://dev.to/import"&gt;@import&lt;/a&gt; or @use&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;To create more abstract styles without hardcoding&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;To synchronize variable names with Figma tokens&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;To perform simple arithmetic and complex operations on variables&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Variables did not go directly into the build, but were compiled into actual CSS values&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Example of implementation
&lt;/h3&gt;

&lt;p&gt;Let’s realize a basic example of &lt;code&gt;SCSS variables&lt;/code&gt; application&lt;/p&gt;

&lt;p&gt;Variables&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;    &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="nt"&gt;primary&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;#d75894&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="nt"&gt;secondary&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;#9&lt;/span&gt;&lt;span class="nt"&gt;b3dca&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="nt"&gt;background&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;#fafafa&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Styling of elements&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scss"&gt;&lt;code&gt;    &lt;span class="k"&gt;@use&lt;/span&gt; &lt;span class="s1"&gt;'variables'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


    &lt;span class="nt"&gt;body&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;variables&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;$background&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


     &lt;span class="nt"&gt;h1&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;variables&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;$primary&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
     &lt;span class="p"&gt;}&lt;/span&gt;


     &lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;variables&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;$secondary&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
     &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F0%2ATUh-JmLTywctXlQ1" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F0%2ATUh-JmLTywctXlQ1" alt="Styles applied to elements"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;It’s simple and intuitive *👍&lt;/em&gt;.*&lt;/p&gt;

&lt;h3&gt;
  
  
  New theme
&lt;/h3&gt;

&lt;p&gt;But let’s say we need to add support for a dark theme for the current style scheme due to business requirements. *How do we implement it? *🧐&lt;/p&gt;

&lt;p&gt;Experienced developers 🤓 will tell you that you should use mapping to substitute the correct value into the selector from each theme. In this way, we will provide extensibility for new themes.&lt;/p&gt;

&lt;p&gt;Let’s change our simple variable list to a color theme map&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scss"&gt;&lt;code&gt;    &lt;span class="nv"&gt;$themes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
     &lt;span class="s2"&gt;"default"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
       &lt;span class="n"&gt;primary&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mh"&gt;#d75894&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
       &lt;span class="n"&gt;secondary&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mh"&gt;#9b3dca&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
       &lt;span class="n"&gt;background&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mh"&gt;#fafafa&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
     &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
     &lt;span class="s2"&gt;"dark"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
       &lt;span class="n"&gt;primary&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mh"&gt;#5e84ff&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
       &lt;span class="n"&gt;secondary&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mh"&gt;#0dd0ff&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
       &lt;span class="n"&gt;background&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mh"&gt;#1b1918&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
     &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Themes applying&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scss"&gt;&lt;code&gt;    &lt;span class="k"&gt;@use&lt;/span&gt; &lt;span class="s2"&gt;"variables"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;@use&lt;/span&gt; &lt;span class="s2"&gt;"sass:map"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


    &lt;span class="k"&gt;@mixin&lt;/span&gt; &lt;span class="nf"&gt;setTheme&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$theme-map&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$theme-map&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"background"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;


     &lt;span class="nt"&gt;h1&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$theme-map&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"primary"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
     &lt;span class="p"&gt;}&lt;/span&gt;


     &lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$theme-map&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"secondary"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
     &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;


    &lt;span class="nt"&gt;body&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="k"&gt;@each&lt;/span&gt; &lt;span class="nv"&gt;$theme-key&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;variables&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;$themes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="k"&gt;&amp;amp;&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;data-theme&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nv"&gt;$theme-key&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
           &lt;span class="k"&gt;@include&lt;/span&gt; &lt;span class="nd"&gt;setTheme&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;variables&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;$themes&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$theme-key&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
       &lt;span class="p"&gt;}&lt;/span&gt;
     &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Result&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F0%2AgpyJsmoh0o_OG9RM" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F0%2AgpyJsmoh0o_OG9RM" alt="Applied the new dark theme"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Yay, we’ve achieved the requested behavior. &lt;strong&gt;But at what cost?&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Problems
&lt;/h3&gt;

&lt;p&gt;As you can see from this small example, the amount of code to support the new dark theme has &lt;strong&gt;increased&lt;/strong&gt;, and the old scheme had to be &lt;strong&gt;refactored&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Another disadvantage is obtained is the &lt;strong&gt;increase&lt;/strong&gt; in the resulting CSS file due to having multiple themes simultaneously.&lt;/p&gt;

&lt;p&gt;And hence its size, which takes time 📉 to download and parse.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;    &lt;span class="nt"&gt;body&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;data-theme&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nt"&gt;default&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#fafafa&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nt"&gt;body&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;data-theme&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nt"&gt;default&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="nt"&gt;h1&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#d75894&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nt"&gt;body&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;data-theme&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nt"&gt;default&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#9b3dca&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nt"&gt;body&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;data-theme&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nt"&gt;dark&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#1b1918&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nt"&gt;body&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;data-theme&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nt"&gt;dark&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="nt"&gt;h1&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#5e84ff&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nt"&gt;body&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;data-theme&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nt"&gt;dark&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#0dd0ff&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As a consequence, with the growth of the code base and the requirement for stylization, we will get:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Increasing complexity of style architecture in the development of individual components&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Maintenance and development of new features will be harder every time&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Constant refactoring and need for regression screen tests&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These problems will undoubtedly affect the speed of development, the quality of the result, and the convenience of developers.&lt;/p&gt;

&lt;p&gt;Unfortunately, many libraries developed using SCSS, such as &lt;code&gt;@angular/material&lt;/code&gt;, encourage this approach. Many developers are unaware of the recommended ways of styling via mixins, which leads to anti-pattern styling as well as the use of &lt;code&gt;::ng-deep&lt;/code&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Those who have ever upgraded Angular in conjunction with &lt;code&gt;@angular/material&lt;/code&gt; will understand UI problems in regression tests after upgrade if you don’t use the recommended way of component customization&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;So what’s the solution to this problem?&lt;/em&gt; &lt;a href="https://medium.com/@maks-dolgikh/css-variables-in-angular-forget-about-scss-variables-part-1-67e727cf317b" rel="noopener noreferrer"&gt;read more...&lt;/a&gt;&lt;/p&gt;

</description>
      <category>css</category>
      <category>scss</category>
      <category>angular</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Disable any animations in Angular by prefers-reduced-motion</title>
      <dc:creator>Maksim Dolgih</dc:creator>
      <pubDate>Mon, 08 Jan 2024 11:12:11 +0000</pubDate>
      <link>https://dev.to/misterion96/advanced-animation-in-angular-part-2-disable-any-animations-by-prefers-reduced-motion-5629</link>
      <guid>https://dev.to/misterion96/advanced-animation-in-angular-part-2-disable-any-animations-by-prefers-reduced-motion-5629</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Animations today are an integral part of modern web applications. Animations help us to improve the perception of our application to the users by giving them feedback about their actions, which helps to make the user experience pleasant and memorable.&lt;/p&gt;

&lt;p&gt;But there are cases when we should not use animations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Users with restrictions&lt;/strong&gt;. For them, animation is not an embellishment, but a distracting part that may be less accessible and interfere with the perception&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;E2E tests&lt;/strong&gt;. It takes time to wait for each animation and transition. The more tests there are, the more time is spent waiting for them to be completed&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For these 2 cases, you can’t build a separate application without animations, you need to have an opportunity to disable animations.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;And there is an easy way to do this.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Prefers-reduced-motion
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;The &lt;strong&gt;prefers-reduced-motion&lt;/strong&gt; CSS media feature is used to detect if a user has enabled a setting on their device to minimize the amount of non-essential motion. The setting is used to convey to the browser on the device that the user prefers an interface that &lt;strong&gt;removes, reduces, or replaces&lt;/strong&gt; motion-based animations. ( You can find ways to activate it &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-reduced-motion#user_preferences" rel="noopener noreferrer"&gt;here&lt;/a&gt; )&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Since this is an &lt;code&gt;@media&lt;/code&gt; setting, all code can be handled in the &lt;code&gt;@media&lt;/code&gt; block&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@media&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prefers-reduced-motion&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;transition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;all&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="n"&gt;linear&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="c"&gt;/* others styles */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Knowing about this customization, we just need to learn how to handle it properly in the Angular application &lt;a href="https://maks-dolgikh.medium.com/advanced-animation-in-angular-part-2-disable-any-animations-by-prefers-reduced-motion-8f9af185cd5d" rel="noopener noreferrer"&gt;read more...&lt;/a&gt;&lt;/p&gt;

</description>
      <category>angular</category>
      <category>css</category>
      <category>ui</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
