<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>molily</title>
    <description>HTML, CSS, JavaScript and web development</description>
    <link>https://molily.de/</link>
    <atom:link href="https://molily.de/feed.xml" rel="self" type="application/rss+xml"/>
    <pubDate>Thu, 23 Apr 2026 10:45:34 +0200</pubDate>
    <lastBuildDate>Thu, 23 Apr 2026 10:45:34 +0200</lastBuildDate>
    <generator>Jekyll v4.4.1</generator>
    
      
        <item>
          <title>The Power of Understanding</title>
          <description>&lt;p&gt;This post describes my personal approach to software development. It highlights different aspects that are not strongly connected but all affected by generative AI – a topic I’m not particularly keen on writing about, but here we are.&lt;/p&gt;

&lt;h2 id=&quot;the-power-of-understanding&quot;&gt;The Power of Understanding&lt;/h2&gt;

&lt;p&gt;Shortly after I got internet access, I came across a free documentation: “&lt;a href=&quot;https://wiki.selfhtml.org/wiki/SELFHTML&quot;&gt;SELFHTML&lt;/a&gt; – create your own HTML files”. Established in 1995, Selfhtml was one of the first German webauthoring tutorials. Its influence on the early German-speaking web cannot be overstated.&lt;/p&gt;

&lt;p&gt;Selfhtml was founded by Stefan Münz, who studied literature and philosophy and trained as an application developer. His fascination for Hypertext systems brought him to the web. Münz aimed to establish a welcoming, sustainable community that contrasts with the toxic sysadmin culture that still dominates technical discussions.&lt;/p&gt;

&lt;p&gt;Selfhtml not only explained web technologies, but always came with a critical commentary on common practices and the booming internet economy. This tutorial and its community planted ideas in my head that went far beyond technical skills.&lt;/p&gt;

&lt;p&gt;In the 90s, people with different social and professional backgrounds logged into the web for the first time. Almost no one was a programmer or computer scientist. Many were students, teachers, homemakers, retirees. The profession of a web developer was just forming.&lt;/p&gt;

&lt;p&gt;I realized that people hold different approaches to webauthoring: Some want to understand the underlying concepts, like the radical impact of Hypertext. Some value the personal expression and artistic freedom. Others appreciate the intellectual exchange in web communities that connect people from all over the world.&lt;/p&gt;

&lt;p&gt;By 1998, Selfhtml adopted the motto “The Power of Understanding” (“Die Energie des Verstehens”). This motto still resonates with me. In the community forums, I learned to grasp what learners are trying to achieve, to debug problems and to explain them with empathy.&lt;/p&gt;

&lt;p&gt;This allowed me to develop an important professional skill: Finding out how things work, getting to the bottom of things and communicating them clearly.&lt;/p&gt;

&lt;svg class=&quot;separator&quot; aria-hidden=&quot;true&quot;&gt;&lt;use xlink:href=&quot;#ornament&quot; /&gt;&lt;/svg&gt;

&lt;h2 id=&quot;caring-and-understanding&quot;&gt;Caring and understanding&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://matthiasott.com/notes/continvoucly-morged-value&quot;&gt;Matthias Ott recently wrote&lt;/a&gt; on using GenAI in the workplace:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;[Before] AI, organisations relied on the quiet labour of skilled professionals to compensate for weak process and poor decision-making. […] Care filled the gaps. […]&lt;/p&gt;

  &lt;p&gt;If we reduce professionals to reviewers of machine output, we don’t eliminate “the work”. We don’t make work more easy and efficient. And we also don’t increase the speed and quality of our work. We devaluate it. We displace it. […]&lt;/p&gt;

  &lt;p&gt;The care is the work. The care creates the value.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This made me think about what matters to me professionally: I strive for quality based on principles such as usability and accessibility.&lt;/p&gt;

&lt;p&gt;Making good software requires a broad and deep technical knowledge and understanding of the field. As you slowly build up experience, you get quicker and more efficient at acquiring knowledge, developing skills and making decisions.&lt;/p&gt;

&lt;p&gt;When applying my knowledge, I try to understand the use cases and weigh up the requirements. I pay attention to details. During implementation, I try to find a simple and robust solution using defensive programming, based on proven architecture.&lt;/p&gt;

&lt;p&gt;While this methodology values quality, it still allows you to design and implement features quickly. The velocity comes from mastering your craft, from a strong confidence in the system, from making quick and informed decisions.&lt;/p&gt;

&lt;p&gt;Once the software is deployed, my colleagues and I are responsible for distributing, scaling, maintaining and enhancing it. Without an accurate mental map, without a understanding the logic and the trade-offs behind it, I would be unable to reason about, debug and extend a piece of software.&lt;/p&gt;

&lt;p&gt;For me, software design and development is a &lt;a href=&quot;https://en.wikipedia.org/wiki/Hermeneutics&quot;&gt;hermeneutic process&lt;/a&gt;: I rely on deep understanding and the process that lets me question and refine my mental map – a &lt;a href=&quot;https://en.wikipedia.org/wiki/Hermeneutic_circle&quot;&gt;hermeneutic circle&lt;/a&gt;.&lt;/p&gt;

&lt;svg class=&quot;separator&quot; aria-hidden=&quot;true&quot;&gt;&lt;use xlink:href=&quot;#ornament&quot; /&gt;&lt;/svg&gt;

&lt;h2 id=&quot;goal-process-and-passion&quot;&gt;Goal, process and passion&lt;/h2&gt;

&lt;p&gt;While there are many valid approaches to software development, people try to pit them against each other. Some attribute support for and opposition to GenAI to personal traits:&lt;/p&gt;

&lt;p&gt;On the one end, there are supposedly goal-oriented developers. They want to get the work done. They see their tools as instrumental and interchangeable. They are excited about the final product and its impact on the user. They find pleasure in other forms of art, culture and community.&lt;/p&gt;

&lt;p&gt;On the other end, there are supposedly process-oriented developers. They want to achieve the goal with reliable, sustainable tools. They see software development as their craft and emphasise coding as a form of art. Programming is their passion, part of their identity, and they take pride in their work.&lt;/p&gt;

&lt;p&gt;According to this dichotomy, goal-oriented people are eager to adopt GenAI while process-oriented people oppose GenAI. The dichotomy is often part a rhetoric that tries to frame GenAI as “inevitable”. With condescension, proponents of GenAI tell the latter group to find other ways of creative expression since their craft is being destroyed “inevitably”.&lt;/p&gt;

&lt;p&gt;While a spectrum between goal- and process-oriented people may exist, I think this is a false dichotomy because &lt;em&gt;process and final product are inseparable&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://fediverse.zachleat.com/@zachleat/116088035613617236&quot;&gt;As Zach Leatherman sums it up&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;it’s important to keep caring about how things work and how they’re built&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;“How things work” and “how they are built” are interwoven. A good design process leads to good code using reliable tools and techniques, which leads to usable, performant and accessible software.&lt;/p&gt;

&lt;p&gt;Good software stems from diverse teams with proper resources and organizational support. A team where each member lifts up other members to produce better results within the given constraints. Where &lt;a href=&quot;https://matthiasott.com/notes/the-shape-of-friction&quot;&gt;friction&lt;/a&gt; inspires and encourages everyone.&lt;/p&gt;

&lt;p&gt;To recognize how process and goal are intertwined, programming does not have to be your passion or part of your identity. It does not matter whether programming is a job for you to get by or whether you take artistic pride in it.&lt;/p&gt;

&lt;p&gt;The field fell into this trap several times. In the past, privileged cis-male gatekeepers looked down on newcomers accusing them of “being in it only for the money” and lacking any deeper interest. With schadenfreude, GenAI proponents now invoke the same trope against the old guard who sees the act of writing code as a craft.&lt;/p&gt;

&lt;p&gt;For me, software development is wage work first and foremost. I am motivated by the goal: I want the software to serve the user. But each time, I work myself backwards from the goal to a certain process: thought-out architecture and meticulous programming practice.&lt;/p&gt;

&lt;svg class=&quot;separator&quot; aria-hidden=&quot;true&quot;&gt;&lt;use xlink:href=&quot;#ornament&quot; /&gt;&lt;/svg&gt;

&lt;h2 id=&quot;information-retrieval&quot;&gt;Information retrieval&lt;/h2&gt;

&lt;p&gt;In 1989/1990, Tim Berners Lee wrote his &lt;a href=&quot;https://www.w3.org/History/1989/proposal.html&quot;&gt;original proposal of the Web&lt;/a&gt; for the European Organization for Nuclear Research (CERN):&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;We should work toward a universal linked information system, in which generality and portability are more important than fancy graphics techniques and complex extra facilities.&lt;/p&gt;

  &lt;p&gt;The aim would be to allow a place to be found for any information or reference which one felt was important, and a way of finding it afterwards. The result should be sufficiently attractive to use that […] the information contained would grow past a critical threshold, so that the usefulness […] would in turn encourage its increased use.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;My “hermeneutic” approach requires research: posing questions, finding information, connecting observations to form a working hypothesis.&lt;/p&gt;

&lt;p&gt;In the past, finding information mostly meant searching the web. Reading documentation, API references, source code, forums. Then writing minimal demos with in plain HTML files, simple scripts. Probably using starter kits, boilerplates, CodePen.&lt;/p&gt;

&lt;p&gt;This practice is now foiled. GenAI thwarts finding information because it poisons the very well it draws from. Public programming forums like StackOverflow are winding down because programmers ask LLMs instead, among other reasons.&lt;/p&gt;

&lt;p&gt;Web crawlers are hammering all possible sources of information and code. &lt;a href=&quot;https://www.anildash.com/2026/03/27/endgame-open-web/&quot;&gt;The open web is dying&lt;/a&gt;. Publicly accessible knowledge decreases or is poisoned by slop while AI companies &lt;a href=&quot;https://en.wikipedia.org/wiki/Enclosure&quot;&gt;enclose&lt;/a&gt; information to sell it back to programmers.&lt;/p&gt;

&lt;p&gt;Searching effectively used to be a crucial programming skill. But search engines are almost unusable now for these purposes. There are noticeably fewer results for programming questions. The remaining results are generic and fuzzy even for very specific requests. Results are filled with spam and slop.&lt;/p&gt;

&lt;p&gt;I’ve been searching the web since 1998. With every search query today I realize that the big tech corporations have stopped funding semantic search and have diverted their investments to GenAI. The text corpus that used to be the search index is only valuable for training LLMs nowadays.&lt;/p&gt;

&lt;p&gt;AI companies keeping programming knowledge in their silos means that searching the open web becomes increasingly pointless. “Prompting” an LLM is the only way left to access this information. But then the output is so fuzzy, random, flawed and devoid of context that it does damage in ways you cannot foresee.&lt;/p&gt;

&lt;p&gt;Search engines have terminated the tacit agreement with publishers that once formed the basis of the web economy: Publishers created high-quality web content. Search engines rewarded this by listing these sites on result pages, directing traffic to them. Sites were able to monetize this traffic.&lt;/p&gt;

&lt;p&gt;Step by step, search engines implemented ways to keep users on their site. They integrated the helpful information directly into the search result page. For the publishers, inbound organic search traffic plummeted.&lt;/p&gt;

&lt;p&gt;LLM chatbots drove the final nail into the coffin of classic web search. At most, web pages are added as “sources” for the LLM output, which they often are not, making it impossible to assess the provenance and timeliness of the presented information.&lt;/p&gt;

&lt;p&gt;Years ago, I would have advised beginners to start a humble blog and publish their lessons learned regularly. Without much effort, people would find your writings through search engines, give feedback and blog about the topic as well. As Tim Berners Lee wrote, the usefulness would encourage its increased use.&lt;/p&gt;

&lt;p&gt;Today, GenAI is depriving us of the tools to share and acquire knowledge, to connect with each other, to contribute to this “universal linked information system”.&lt;/p&gt;

&lt;svg class=&quot;separator&quot; aria-hidden=&quot;true&quot;&gt;&lt;use xlink:href=&quot;#ornament&quot; /&gt;&lt;/svg&gt;

&lt;h2 id=&quot;learning-and-education&quot;&gt;Learning and education&lt;/h2&gt;

&lt;p&gt;When you learn to transform problems and requirements into computer programs and user interfaces, you not only amass facts in your brain. You grow as a person, you develop instincts, opinions and taste. You become an expert in fields of your choice. You learn how to critically assess different approaches. You connect with other practitioners, follow their work. Their views constantly shake your worldview.&lt;/p&gt;

&lt;p&gt;Especially junior developers need to have the freedom to dive deeply into technologies. They need be able to read and write code without haste and unnecessary pressure. They have to make mistakes themselves and learn from them. They become creative by experimenting and exploring.&lt;/p&gt;

&lt;p&gt;Carson Gross, who teaches computer science, &lt;a href=&quot;https://htmx.org/essays/yes-and/&quot;&gt;tells his students that they have to write the code&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;If a junior programmer does not learn to write code and simply generates it, they are robbing themselves of the opportunity to develop the visceral understanding of code that comes with being down in the trenches. […] If they don’t write the code, they will not be able to effectively read the code.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;More broadly, the astrophysicist &lt;a href=&quot;https://ergosphere.blog/posts/the-machines-are-fine/&quot;&gt;Minas Karamanis describes&lt;/a&gt; that no aspiring scientist can skip the “grunt work” and outsource it to AI.&lt;/p&gt;

&lt;p&gt;Karamanis describes two hypothetical PhD students named Alice and Bob. While Bob uses AI agents for the research, Alice does not. This enables Alice to &lt;q&gt;[build] a structure inside her own head, and that structure is hers now, permanently, portable, independent of any tool or subscription.&lt;/q&gt; Karamanis:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;What’s great about science is its people. The slow, stubborn, sometimes painful process by which a confused student becomes an independent thinker. If we use these [AI] tools to bypass that process in favor of faster output, we don’t just risk taking away what’s great about science. We take away the only part of it that wasn’t replaceable in the first place. […]&lt;/p&gt;

  &lt;p&gt;Every hour you spend confused is an hour you spend building the infrastructure inside your own head that will eventually let you do original work. There is no shortcut through that process that doesn’t leave you diminished on the other side.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;What is essential for the scientific method applies to software development as well: We need confusion to build the infrastructure inside your own head.&lt;/p&gt;

&lt;svg class=&quot;separator&quot; aria-hidden=&quot;true&quot;&gt;&lt;use xlink:href=&quot;#ornament&quot; /&gt;&lt;/svg&gt;

&lt;h2 id=&quot;mental-capacity&quot;&gt;Mental capacity&lt;/h2&gt;

&lt;p&gt;While self-directed learning is challenging and mentally taxing, there is a natural limit. If someone or something pushes you beyond that limit again and again, you burn out.&lt;/p&gt;

&lt;p&gt;Producing the code to implement an idea used to be a bottleneck in software development. Proponents of GenAI say that code is cheap now since it can be generated en masse. Code is cheap &lt;em&gt;if&lt;/em&gt; no one has to understand, maintain and support it. &lt;em&gt;If&lt;/em&gt; no one takes the responsibility for its consequences. &lt;em&gt;If&lt;/em&gt; you ignore all externalities that LLMs involve.&lt;/p&gt;

&lt;p&gt;Thus, code is never cheap. Long before code was LLM-generated, practitioners pointed out that the sheer amount of code is a liability.&lt;/p&gt;

&lt;p&gt;Junior software developers learned to read, write and change code. Senior developers assisted them with these tasks, but also identified code that should not be written or changed in the first place. After careful consideration, they politely said “no” to features and changes – to protect the stability, usability and performance of the software.&lt;/p&gt;

&lt;p&gt;With LLM-generated code, these checks and safeguards aren’t removed necessarily. But the burden of responsibility is imposed on individual developers.&lt;/p&gt;

&lt;p&gt;As the computer science professor Margaret-Anne Storey writes, generated code leads to &lt;a href=&quot;https://margaretstorey.com/blog/2026/02/09/cognitive-debt/&quot;&gt;cognitive debt&lt;/a&gt; &lt;q&gt;in the brains of the developers and affects their lived experiences and abilities to ‘go fast’ or to make changes.&lt;/q&gt; She states:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Cognitive debt is likely a much bigger threat than technical debt, as AI and agents are adopted. Peter Naur reminded us some decades ago that a program is more than its source code. Rather a program is a theory that lives in the minds of the developer(s) capturing what the program does, how developer intentions are implemented, and how the program can be changed over time. Usually this theory is not just in the minds of one developer but fragments of this theory are distributed across the minds of many, if not thousands, of other developers.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;GenAI does not require you to develop a theory in your mind. Since it tends to isolate each developer, it is less likely that a theory is distributed across minds. Storey experienced that &lt;q&gt;velocity without understanding is not sustainable&lt;/q&gt; and advises developers to &lt;q&gt;slow down&lt;/q&gt; and apply proven practices to build a &lt;q&gt;shared understanding&lt;/q&gt;.&lt;/p&gt;

&lt;p&gt;Experienced users of GenAI describe their work as “mentally exhausting”. GenAI churns out lines of code so fast that their brain is not able to keep up.&lt;/p&gt;

&lt;p&gt;The software engineer Marvin Hagemeister describes this experience as a &lt;a href=&quot;https://marvinh.dev/blog/ddosing-the-human-brain/&quot;&gt;Distributed Denial of Service (DDoS) attack on the brain&lt;/a&gt;. The sheer volume of code, the rapidly changing tasks and responsibilities require your brain to switch between contexts often and remain in a &lt;q&gt;hyper-vigilant state&lt;/q&gt;.&lt;/p&gt;

&lt;p&gt;A study by Aruna Ranganathan and Xingqi Maggie Ye, professor/student of Management of Organizations, showed that &lt;a href=&quot;https://hbr.org/2026/02/ai-doesnt-reduce-work-it-intensifies-it&quot;&gt;AI doesn’t reduce work, it intensifies it&lt;/a&gt;: &lt;q&gt;Employees worked at a faster pace, took on a broader scope of tasks, and extended work into more hours of the day, often without being asked to do so.&lt;/q&gt; The introduction of GenAI into the workplace widened the field of responsibility, &lt;q&gt;expanded the quantity and density of work&lt;/q&gt;. &lt;q&gt;That workload creep can in turn lead to cognitive fatigue, burnout, and weakened decision-making.&lt;/q&gt;&lt;/p&gt;

&lt;svg class=&quot;separator&quot; aria-hidden=&quot;true&quot;&gt;&lt;use xlink:href=&quot;#ornament&quot; /&gt;&lt;/svg&gt;

&lt;h2 id=&quot;the-conditions-of-possibility&quot;&gt;The Conditions of Possibility&lt;/h2&gt;

&lt;p&gt;When thinking about the future of software development, I am wondering about the &lt;a href=&quot;https://en.wikipedia.org/wiki/Condition_of_possibility&quot;&gt;Conditions of Possibility&lt;/a&gt;: What do software and web developers need …&lt;/p&gt;

&lt;ul class=&quot;compact-list&quot;&gt;
  &lt;li&gt;to be able to learn something,&lt;/li&gt;
  &lt;li&gt;to be able to apply these skills,&lt;/li&gt;
  &lt;li&gt;to be able to achieve something they want, something that benefits the users.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On all of these levels, the preconditions are being destroyed and taken away from us.&lt;/p&gt;

&lt;p&gt;GenAI is an onslaught on developer agency and independence, specifically on thorough understanding. Instead of thinking through a problem and editing few lines of code, GenAI encourages you to burn through millions of tokens – mostly &lt;a href=&quot;/ai-environment/&quot;&gt;a synonym for fossil fuels&lt;/a&gt; – to brute-force a solution that adds hundreds of lines of code. Such a workflow makes independent, self-directed learning with educators, mentors and coworkers less attractive and more and more impossible.&lt;/p&gt;

&lt;p&gt;My “hermeneutic” approach is one possible approach to software development. There are plenty of others, perhaps equally effective and important. I am not defending it for my own sake. I simply hold the opinion that pursuing this path should remain &lt;em&gt;possible&lt;/em&gt;.&lt;/p&gt;
</description>
          <pubDate>Wed, 08 Apr 2026 00:00:00 +0200</pubDate>
          <link>https://molily.de/understanding/</link>
          <guid isPermaLink="true">https://molily.de/understanding/</guid>
          
          
        </item>
      
    
      
        <item>
          <title>On the environmental impact of AI</title>
          <description>&lt;p&gt;Recently, two articles were published and widely shared:&lt;/p&gt;

&lt;div class=&quot;compact-list&quot;&gt;
  &lt;ul&gt;
    &lt;li&gt;&lt;a href=&quot;https://epoch.ai/gradient-updates/how-much-energy-does-chatgpt-use&quot;&gt;How much energy does ChatGPT use?&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;https://andymasley.substack.com/p/a-cheat-sheet-for-conversations-about&quot;&gt;Why using ChatGPT is not bad for the environment&lt;/a&gt;&lt;/li&gt;
  &lt;/ul&gt;
&lt;/div&gt;

&lt;p&gt;What these articles show is that the average personal usage of LLM-based chatbots like ChatGPT likely contributes a negligible share to the carbon footprint of a person living in a Western industrialized society.&lt;/p&gt;

&lt;p&gt;Compared to other mundane online activities like video streaming, using chatbots consumes relatively little electrical energy and water. Hence, the second article claims that &lt;em&gt;not&lt;/em&gt; using ChatGPT won’t measurably reduce your personal carbon footprint.&lt;/p&gt;

&lt;p&gt;I do not intend to disprove these calculations. Since the companies operating AI chatbots do not report energy usage in meaningful ways, we do not have reliable data anyway. More importantly, these articles demonstrate again how distracting and eventually harmful the idea of a personal environmental footprint connected with individual moral responsibility is.&lt;/p&gt;

&lt;p&gt;Considerate people in climate science and climate activism reason about states and economies, about decarbonization of whole sectors, about climate-neutral public infrastructure, about national policies and international treaties, about top-polluting industries, about holding corporations accountable to reach zero emissions, about installing gigawatts of photovoltaics, wind power and battery storage.&lt;/p&gt;

&lt;p&gt;When researchers and activists talk about end consumers and private households, they discuss consumer prices, adjusting taxes on certain goods to incorporate external costs, subsidies for energy-efficient construction and renovation, as well as incentives and nudging. They talk about citizen initiatives for distributed clean energy, about local circular economies.&lt;/p&gt;

&lt;p&gt;They do not shame consumers, say, for buying plastic when every available product is made of plastic, contains plastic or is wrapped in plastic. The reduction of global economic and ecological problems to individual lifestyle decisions is a well-known marketing ploy by top polluters to &lt;a href=&quot;https://en.wikipedia.org/wiki/Carbon_footprint#Shifting_responsibility_from_corporations_to_individuals&quot;&gt;shift the responsibility from corporations to individuals&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;While calculating the carbon footprint of certain activities might be valuable, it is not in the case of personal AI usage. You may endlessly dwell on the moral question what to do as a consumer. You might even gain some insights on how global economics work and where greenhouse gases are emitted. But in its societal function, the focus on individual carbon footprints is pure ideology.&lt;/p&gt;

&lt;p&gt;The second article claims that “environmental objections to ChatGPT often dilute other serious criticisms of the technology.” Let us turn this thinking upside down: Environmental objections are necessary, valid and well-founded provided they address ICT and AI as a whole, not just the personal use of a particular chatbot. No matter how you look at it, the latter is part of the former. It cannot be singled out but also cannot be exempted.&lt;/p&gt;

&lt;p&gt;The article acknowledges that “we should be focused on systematic change over individual lifestyles”, but utterly fails to do that. So let us examine the system that needs to be changed.&lt;/p&gt;

&lt;p&gt;Computing in general and AI specifically consumes large amounts of energy, water and other natural resources. One way we can quantify this is the electricity consumption of data centres, which amounted to around 415 terawatt hours (TWh), about 1.5% of global electricity consumption in 2024 (&lt;a href=&quot;https://www.iea.org/reports/energy-and-ai/energy-demand-from-ai&quot;&gt;International Energy Agency [IEA], Apr 2025&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;That demand is &lt;a href=&quot;https://www.iea.org/reports/electricity-2025&quot;&gt;growing rapidly&lt;/a&gt; (&lt;a href=&quot;https://iea.blob.core.windows.net/assets/0f028d5f-26b1-47ca-ad2a-5ca3103d070a/Electricity2025.pdf&quot;&gt;IEA, Feb 2025, PDF, p. 36&lt;/a&gt;). There are different estimates about the future absolute amount and relative share, and how the electricity will be generated (&lt;a href=&quot;https://www.iea.org/reports/energy-and-ai/energy-demand-from-ai&quot;&gt;IEA&lt;/a&gt;, &lt;a href=&quot;https://newscenter.lbl.gov/2025/01/15/berkeley-lab-report-evaluates-increase-in-electricity-demand-from-data-centers/&quot;&gt;Berkeley Lab for the US Department of Energy, Dec 2024&lt;/a&gt;, &lt;a href=&quot;https://www.goldmansachs.com/insights/articles/ai-to-drive-165-increase-in-data-center-power-demand-by-2030&quot;&gt;Goldman Sachs Research, Feb 2025&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;The IEA base scenario estimates a growth from 415 TWh to 945 TWh (× 2.28) by 2030, under 3% of total global electricity by 2030. The lowest scenario estimates around 700 TWh (× 1.69) by 2030, the highest 1,250 TWh (× 3.01). This surge is expected to be largely attributable to AI. The different scenarios take into account the projected growth of AI and how the power grid and efficiency progress can keep up with the demand.&lt;/p&gt;

&lt;p&gt;While we don’t know if data centers will consume 2% or rather 4.4% of the global electricity in 2030, it becomes clear that for the society, for the planet, this is significant.&lt;/p&gt;

&lt;p&gt;AI quickly gained economic and societal significance, as quickly as no technology in the last 25 years. Partly because consumers find AI tools useful. Partly because businesses integrate AI into their workflows. Partly because Big Tech is forcing AI on their customers without them being able to opt-out.&lt;/p&gt;

&lt;p&gt;Billions of dollars of capital are flowing into the sector. Partly because Big Tech wants to grab power from workers, creatives and other industries through “disruption”. Partly because AI firms deceive and promise the moon. Their leaders &lt;a href=&quot;https://firstmonday.org/ojs/index.php/fm/article/view/13636/11599&quot;&gt;subscribe to “utopian-apocalyptic” and fascist ideologies&lt;/a&gt; (“AGI”).&lt;/p&gt;

&lt;p&gt;The proliferation of AI is already affecting real people:&lt;/p&gt;

&lt;div class=&quot;compact-list&quot;&gt;
  &lt;ul&gt;
    &lt;li&gt;New data centers are being built in areas affected by water stress (&lt;a href=&quot;https://www.source-material.org/amazon-microsoft-google-trump-data-centres-water-use/&quot;&gt;Source Material, Apr 2025&lt;/a&gt;, &lt;a href=&quot;https://www.bloomberg.com/graphics/2025-ai-impacts-data-centers-water-data/&quot;&gt;Bloomberg, May 2025&lt;/a&gt;), for example in &lt;a href=&quot;https://www.theatlantic.com/technology/archive/2024/03/ai-water-climate-microsoft/677602/&quot;&gt;Arizona&lt;/a&gt;.&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;https://ieefa.org/resources/data-centers-drive-buildout-gas-power-plants-and-pipelines-southeast&quot;&gt;New gas power plants are being built&lt;/a&gt;.&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;https://www.selc.org/news/elon-musks-xai-facility-is-polluting-south-memphis/&quot;&gt;Gas turbines are being set up next to AI data centers&lt;/a&gt;.&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;https://www.cascadepbs.org/news/2024/11/amazon-offers-334m-nuclear-reactors-be-built-hanford&quot;&gt;New nuclear reactors are being built&lt;/a&gt;.&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;https://www.theverge.com/2024/9/20/24249770/microsoft-three-mile-island-nuclear-power-plant-deal-ai-data-centers&quot;&gt;Old, error-prone nuclear reactors are being switched on again&lt;/a&gt;.&lt;/li&gt;
  &lt;/ul&gt;
&lt;/div&gt;

&lt;p&gt;Data centers are highly concentrated and localized. Their expansion in the wake of AI causes struggles in many places around the world, for &lt;a href=&quot;https://www.eenews.net/articles/elon-musks-xai-in-memphis-35-gas-turbines-no-air-pollution-permits/&quot;&gt;real people and real communities&lt;/a&gt;, especially vulnerable and disadvantaged groups. Struggles about water, pollution and health, land grab, resource extraction and labor exploitation. There are many examples, from &lt;a href=&quot;https://www.theguardian.com/global-development/2024/sep/25/mexico-datacentre-amazon-google-queretaro-water-electricity&quot;&gt;Mexico&lt;/a&gt; to &lt;a href=&quot;https://www.source-material.org/amazon-microsoft-google-trump-data-centres-water-use/#:~:text=Amazon%E2%80%99s%20three%20proposed%20data%20centres%20in%20Aragon%2C%20northern%20Spain&quot;&gt;Spain&lt;/a&gt; to &lt;a href=&quot;https://www-bund--nrw-de.translate.goog/themen/braunkohle/strukturwandel-im-revier/stoppt-den-flaechenfrass-im-rheinischen-revier/?_x_tr_sl=auto&amp;amp;_x_tr_tl=en&quot;&gt;Germany&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In the last 25 years, there has been no technology or economic activity for which politicians have been willing to sacrifice so much. AI companies are violating environmental regulations while &lt;a href=&quot;https://www.forbes.com/sites/garthfriesen/2025/01/23/trumps-ai-push-understanding-the-500-billion-stargate-initiative/&quot;&gt;governments are laxing safety standards&lt;/a&gt;.
This deregulation at the expense of local communities and global climate is sugarcoated as “&lt;a href=&quot;https://www.eenews.net/articles/elon-musks-xai-in-memphis-35-gas-turbines-no-air-pollution-permits/&quot;&gt;[streamlining] permitting and regulations&lt;/a&gt;”.&lt;/p&gt;

&lt;p&gt;Local administrations and city councils attract AI companies to the detriment of their citizens. National governments are using &lt;a href=&quot;https://www.reuters.com/technology/artificial-intelligence/trump-revokes-biden-executive-order-addressing-ai-risks-2025-01-21/&quot;&gt;authoritarian measures&lt;/a&gt; to allow their local tech firms to prevail in the global AI arms race.&lt;/p&gt;

&lt;p&gt;The most glaring evidence of AI’s climate impact comes from technology companies themselves. It is not just critics who point out the energy demand of AI. Big Tech reports that it does not meet its own climate targets – and explains it with the skyrocketing electricity needs of AI. Instead of emitting less, these companies are emitting even more because of AI.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;“Google falling short of important climate target, cites electricity needs of AI” (&lt;a href=&quot;https://apnews.com/article/climate-google-environmental-report-greenhouse-gases-emissions-3ccf95b9125831d66e676e811ece8a18&quot;&gt;AP&lt;/a&gt;). “In 2023, our total GHG emissions increased 13% year-over-year, primarily driven by increased data center energy consumption and supply chain emissions” (&lt;a href=&quot;https://sustainability.google/reports/google-2024-environmental-report/&quot;&gt;Google 2024 Environmental Report&lt;/a&gt;)&lt;/li&gt;
  &lt;li&gt;“Meta emitted 14,067,104 metric tons of carbon dioxide equivalent in 2023, up slightly from 2022 and more than double what it reported in 2019, according to &lt;a href=&quot;https://sustainability.atmeta.com/2024-sustainability-report/&quot;&gt;Meta’s 2024 sustainability report&lt;/a&gt;.” (&lt;a href=&quot;https://trellis.net/article/the-meta-dilemma-invest-billions-in-ai-but-find-ways-to-cut-emissions-too/&quot;&gt;Trellis&lt;/a&gt;)&lt;/li&gt;
  &lt;li&gt;“The hype surrounding artificial intelligence is causing Microsoft’s emissions of climate-damaging gases to skyrocket.” (&lt;a href=&quot;https://www.heise.de/en/news/Microsoft-KI-laesst-Emissionen-um-bis-zu-40-Prozent-steigen-9723155.html&quot;&gt;Heise&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These figures illustrate the catastrophic environmental impact of AI. These are the numbers we should be talking about. We need to hold Big Tech accountable and demand a quick turnaround.&lt;/p&gt;

&lt;p&gt;These companies plan to operate climate-neutral, “net zero” by 2030. But the actual increase shows that we cannot believe their promises. They fancy climate neutrality, but they care more about keeping pace in the AI arms race.&lt;/p&gt;

&lt;p&gt;Many companies investing in AI argue that AI will improve energy efficiency in such a dramatic way that it will offset all extra emissions, allowing them to meet their net zero goals. “First we will emit more, but soon, when all savings take effect, we will emit even less than before!”&lt;/p&gt;

&lt;p&gt;We know this “techno-solutionist” ploy already: The magic technology that will “offset” our greenhouse gas emissions is just around the corner. For some players in the fossil industry, it is called Carbon Capture and Storage (CCS). For the transport sector, the magic technology is called electric vehicles or even green hydrogen. For some politicians and tech nerds, it’s called small modular reactors or even fusion reactors. For Big Tech, &lt;a href=&quot;https://greenscreen.network/en/blog/within-bounds-limiting-ai-environmental-impact/#ii-computing-within-limits&quot;&gt;the smoke screen is called AI&lt;/a&gt;. Soon, AI will make up for all the emissions of AI and the rest as well!&lt;/p&gt;

&lt;p&gt;Yes, non-generative AI will likely help to optimise production processes and save energy in many industries (&lt;a href=&quot;https://www.iea.org/reports/energy-and-ai/ai-for-energy-optimisation-and-innovation&quot;&gt;IEA, Apr 2025&lt;/a&gt;). Yes, &lt;a href=&quot;https://www.sustainabilitybynumbers.com/p/ai-energy-demand#%C2%A7weve-been-here-before-with-fears-around-data-centres&quot;&gt;energy demand does not grow linearly with computing power&lt;/a&gt;, thanks to efficiency advancements. But what we observe so far is a &lt;a href=&quot;https://en.wikipedia.org/wiki/Rebound_effect_(conservation)&quot;&gt;rebound effect&lt;/a&gt;: The performance and efficiency gain is eaten by capitalist growth. Energy demand and carbon emissions are growing, not shrinking.&lt;/p&gt;

&lt;p&gt;The recent AI race is a prime example of capitalism wasting resources. In the current global AI competition, every company trains and operates their models in private, closed source, on content scraped without permission, &lt;a href=&quot;https://adactio.com/journal/21831&quot;&gt;exploiting and attacking shared, public infrastructure&lt;/a&gt;. The tremendous advancements render models trained months ago almost useless. The improvements do not bring more efficiency and less resource use for the whole industry, they merely fuel the race. So far, the AI bubble has not built anything that lasts – not even a return for investors.&lt;/p&gt;

&lt;p&gt;It becomes evident that AI’s energy and water hunger is bad for the environment and thus bad for many people. How bad is it compared to fossil capitalism as a whole, which undermines the foundations of human life? What is the relative contribution to the climate catastrophe? Is is 1%, 2% or 3%? In any case, the amount is sizeable. A 1% difference matters just as a 0.1°C global temperature rise matters. We must not let IT companies get away with this.&lt;/p&gt;

&lt;p&gt;Apart from the quantity, the specific quality of AI’s environmental impact matters: Due to the global competition between nation states, policymakers let AI firms break energy and environmental rules. These regulations, which were hard fought for, keep people healthy, keep clean water available and critical infrastructure running.&lt;/p&gt;

&lt;p&gt;“Individual use of AI is not bad for the environment”, says the mentioned article. If you treat this topic merely as a question of personal consumer responsibility, you twist it beyond recognition. If you recognize it as a societal problem, yes, AI in its current form is bad for the environment. So let us ask:&lt;/p&gt;

&lt;div class=&quot;compact-list&quot;&gt;
  &lt;ul&gt;
    &lt;li&gt;&lt;a href=&quot;https://greenscreen.network/en/blog/within-bounds-limiting-ai-environmental-impact/&quot;&gt;How do we limit AI’s environmental impact?&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;https://www.anildash.com/2025/05/01/what-would-good-ai-look-like/&quot;&gt;What would “good” AI look like?&lt;/a&gt;&lt;/li&gt;
  &lt;/ul&gt;
&lt;/div&gt;

&lt;svg class=&quot;separator&quot; aria-hidden=&quot;true&quot;&gt;&lt;use xlink:href=&quot;#ornament&quot; /&gt;&lt;/svg&gt;

&lt;h2 style=&quot;margin: 1rem 0; font-size: inherit&quot;&gt;Sources&lt;/h2&gt;

&lt;div class=&quot;compact-list&quot;&gt;
  &lt;ul&gt;
    &lt;li&gt;&lt;a href=&quot;https://about.bnef.com/blog/liebreich-generative-ai-the-power-and-the-glory/&quot;&gt;Generative AI – The Power and the Glory – BloombergNEF&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;https://www.iea.org/reports/energy-and-ai&quot;&gt;IEA Report: Energy and AI&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;https://www.iea.org/reports/electricity-2025&quot;&gt;IEA Report: Electricity 2025&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;https://www.sustainabilitybynumbers.com/p/ai-energy-demand&quot;&gt;Hannah Ritchie: What’s the impact of artificial intelligence on energy demand?&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;https://arxiv.org/abs/2304.03271&quot;&gt;Pengfei Li et al.: Making AI Less “Thirsty”: Uncovering and Addressing the Secret Water Footprint of AI Models&lt;/a&gt;&lt;/li&gt;
  &lt;/ul&gt;
&lt;/div&gt;
</description>
          <pubDate>Sat, 10 May 2025 00:00:00 +0200</pubDate>
          <link>https://molily.de/ai-environment/</link>
          <guid isPermaLink="true">https://molily.de/ai-environment/</guid>
          
          
        </item>
      
    
      
        <item>
          <title>Something went wrong</title>
          <description>&lt;style&gt;
.something-went-wrong-toc {
  font-size: 85%;
}

.something-went-wrong-toc ol {
  list-style-type: &apos;&apos;;
  margin-left: 0;
}

.something-went-wrong-toc li {
  list-style-type: &apos;▾ &apos;;
  margin-bottom: 0;
}
.something-went-wrong-toc li::marker {
  font-size: 130%;
  line-height: 1;
  color: #666;
}
&lt;/style&gt;

&lt;nav class=&quot;something-went-wrong-toc&quot;&gt;
  &lt;h2&gt;Table of contents&lt;/h2&gt;
  &lt;ol class=&quot;something-went-wrong-toc-list&quot;&gt;
    &lt;li&gt;&lt;a href=&quot;#smashing-things-against-each-other&quot;&gt;Smashing things against each other&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;#next-nextjs&quot;&gt;Next: Next.js&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;#the-javascript-crisis&quot;&gt;The JavaScript crisis&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;#the-community-crisis&quot;&gt;The community crisis&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;#camp-mentality&quot;&gt;Camp mentality&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;#poor-analysis-and-conspiracy-theories&quot;&gt;Poor analysis and conspiracy theories&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;#the-big-rewrite&quot;&gt;The Big Rewrite&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;#simplicity-and-complexity&quot;&gt;Simplicity and complexity&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;#the-dichotomy-between-user-experience-ux-and-developer-experience-dx&quot;&gt;The dichotomy between User Experience (UX) and Developer Experience (DX)&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;#the-obsession-with-developer-experience&quot;&gt;The obsession with developer experience&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;#react-and-derailed-frontends&quot;&gt;React and derailed frontends&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;#common-goals&quot;&gt;Common goals&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;#primitives-and-apis&quot;&gt;Primitives and APIs&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;#closing-words&quot;&gt;Closing words&lt;/a&gt;&lt;/li&gt;
  &lt;/ol&gt;
&lt;/nav&gt;

&lt;h2 id=&quot;smashing-things-against-each-other&quot;&gt;Smashing things against each other&lt;/h2&gt;

&lt;p&gt;There is much to learn when things break. Think about the &lt;a href=&quot;https://en.wikipedia.org/wiki/Large_Hadron_Collider&quot;&gt;Large Hadron Collider&lt;/a&gt; (LHS) at the CERN in Switzerland. Scientists accelerate particles like protons and lead ions with much energy and &lt;span style=&quot;font-family: comic sans ms, fantasy, sans-serif; color: #7ebc57; font-weight: bold; -webkit-text-stroke: 1px black; text-shadow: 1px 1px 1px black; letter-spacing: 0.1ex&quot;&gt;SMASH&lt;/span&gt; them into each other. They make a huge mess, sift through the debris in order to find something valueable. Like the Higgs field and the Higgs boson (the “Goddamn particle”) that happen to give all other particles their mass. It is no coincidence that the CERN also invented the World Wide Web, which is the LHC’s precursor experiment (just kidding).&lt;/p&gt;

&lt;p&gt;In the spirit of moving fast (99.9999991% the speed of light) and breaking things, my Firefox browser is configured to block all cookies, ads, tracking and other privacy invasions. Firefox will warn you that it “will cause websites to break”. This somehow reverses cause and effect, but indeed, some web sites self-destruct when the browser rejects cookies. As a web dev, I can handle that, for example by opening the site in a browser instance that allows cookies.&lt;/p&gt;

&lt;p&gt;When the browser blocks cookies, it not only ignores the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Cookie&lt;/code&gt; HTTP header and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;document.cookie&lt;/code&gt;, it also blocks access to the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API&quot;&gt;JavaScript storage APIs &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;localStorage&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sessionStorage&lt;/code&gt;&lt;/a&gt;. When a script merely accesses these objects, the script is terminated with an &lt;a href=&quot;https://molily.de/robust-javascript/#exceptions&quot;&gt;exception&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;A script should prepare for the fact that access to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;localStorage&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sessionStorage&lt;/code&gt; may throw an error. The precaution is to &lt;a href=&quot;https://molily.de/robust-javascript/#handling-exceptions-with-trycatch&quot;&gt;wrap the access in a try-catch&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For example, if you want to store the user’s theme preference, you can use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sessionStorage&lt;/code&gt; in a fault-tolerant way:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;theme&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;dark&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// Whatever the user has chosen&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;sessionStorage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;setItem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;theme&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;theme&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;catch &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Could not access sessionStorage&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;When reading the preference, you can query the system theme and override it with the user choice:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;systemTheme&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;matchMedia&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;(prefers-color-scheme: dark)&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;matches&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;dark&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;light&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;userTheme&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;userTheme&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;sessionStorage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getItem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;theme&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;catch &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Could not access sessionStorage&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;finalTheme&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;userTheme&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;systemTheme&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// Do something with finalTheme&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Most browsers allow storing values using these APIs, so very few sites guard the access. While I do encourage you to program defensively, I reckon my browser configuration to be an outlier.&lt;/p&gt;

&lt;p&gt;Unchecked storage access alone does not cause havoc. The exception blows up the current stack, stopping the particular script task. In the debris of this explosion, nothing interesting can be found. Typically, most of the site features continue to work.&lt;/p&gt;

&lt;h2 id=&quot;next-nextjs&quot;&gt;Next: Next.js&lt;/h2&gt;

&lt;p&gt;There is a class of web sites where such an innocuous JavaScript exception causes havoc: Sites build with Next.js, a framework based on React.js. (In theory, this is not specific to Next.js. In practice, it is.)&lt;/p&gt;

&lt;p&gt;Let us smash browsers and sites together and record the debris! Take two sites you visit every day (or not): &lt;a href=&quot;https://www.tiktok.com&quot;&gt;TikTok&lt;/a&gt; and &lt;a href=&quot;https://nodejs.org&quot;&gt;Node.js&lt;/a&gt;. If your browser blocks storage access, nodejs.org is empty. Simple as that. Tiktok.com shows a sad robot that says: “Page not available. Sorry about that! Please try again later.”&lt;/p&gt;

&lt;p&gt;What’s happening here? Next.js renders the HTML page and sends it to the browser. A significant amount of client-side JavaScript is loaded which “hydrates” the HTML DOM. In the most naive way, this means that React.js re-renders the whole page and updates the DOM if necessary.&lt;/p&gt;

&lt;p&gt;If an exception occurs during this process, React &lt;em&gt;will remove the server-rendered HTML from the document&lt;/em&gt;. This can be observed on nodejs.org.&lt;/p&gt;

&lt;p&gt;But fear not. React allows you to catch errors using an &lt;a href=&quot;https://react.dev/reference/react/Component#catching-rendering-errors-with-an-error-boundary&quot;&gt;error boundary&lt;/a&gt;. Like a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;try-catch&lt;/code&gt;, but for the React component tree. An error bubbles up to the nearest error boundary.&lt;/p&gt;

&lt;p&gt;In the spirit of &lt;a href=&quot;https://molily.de/robust-javascript/#graceful-degradation&quot;&gt;Graceful Degradation&lt;/a&gt;, you can render a meaningful fallback if an error happens in a certain component branch. You can take action to recover from that error. (The popular &lt;a href=&quot;https://github.com/bvaughn/react-error-boundary&quot;&gt;react-error-boundary&lt;/a&gt; package is actually quite powerful.)&lt;/p&gt;

&lt;p&gt;In practice, React error boundaries are misused. In almost all cases, there is one (1) error boundary at the top of the React render tree. And the only thing it does is to show a pointless error message like “Something went wrong”. This can be observed on tiktok.com.&lt;/p&gt;

&lt;p&gt;On vercel.com, the site of the company that makes Next.js, you get a more nerdy “Application error: a client-side exception has occurred (see the browser console for more information).”&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://indieweb.social/@stoyan/113097869836565348&quot;&gt;Stoyan has a catchy name for this behavior&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote cite=&quot;https://indieweb.social/@stoyan/113097869836565348&quot;&gt;
&lt;p&gt;You&apos;ve heard of FOUC, FOUT, FOIT, FOFT... now say hello to FORC - Flash Of Readable Content. This phenomenon occurs when a perfectly readable web page is &quot;hydrated&quot; by JavaScript and an error in said hydration takes over the otherwise usable experience. FORC is pronounced &quot;fork&quot; as in &quot;I&apos;d like to stick a fork in my eye&quot;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I haven’t mentioned blocked cookies because of its relevance. It’s merely one way to trigger errors in JavaScript-heavy web sites. It allows you to observe how the site handles &lt;em&gt;any&lt;/em&gt; JavaScript error. It’s the LHC way of examining JavaScript apps.&lt;/p&gt;

&lt;svg class=&quot;separator&quot; aria-hidden=&quot;true&quot;&gt;&lt;use xlink:href=&quot;#ornament&quot; /&gt;&lt;/svg&gt;

&lt;h2 id=&quot;the-javascript-crisis&quot;&gt;The JavaScript crisis&lt;/h2&gt;

&lt;p&gt;I’ve opened this article with an anecdote to illustrate the abysmal state of client-side JavaScript usage.&lt;/p&gt;

&lt;p&gt;For some reason, in some case, &lt;a href=&quot;https://piccalil.li/blog/a-handful-of-reasons-javascript-wont-be-available/&quot;&gt;client-side JavaScript will inevitably fail&lt;/a&gt;. There are &lt;a href=&quot;https://molily.de/robust-javascript/#how-to-prevent-failure&quot;&gt;plenty intricate, piecemeal solutions how to prevent this&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Even more problematic than error-prone JavaScript is the sheer amount of client-side JavaScript. Browsers have to download, parse, compile and execute the code. This blocks the rendering of the page. For mobile internet users in particular, the transmission of JavaScript cost money and the execution drains the battery.&lt;/p&gt;

&lt;p&gt;As a result, web pages are unreliable, slow and unusable for many people. Writing more robust JavaScript and saving a few kilobytes are stopgap solutions. The overall solution are web architectures that minimize the reliance on client-side JavaScript.&lt;/p&gt;

&lt;p&gt;This problem is well-known across the industry, with many people and companies working on improved architectures. Google, for example, has identified the performance problem and tries to address it with their metrics, the Core Web Vitals.&lt;/p&gt;

&lt;p&gt;Despite these efforts, the situation is not improving, as shown by the &lt;a href=&quot;https://httparchive.org/reports/state-of-javascript&quot;&gt;HTTP Archive&lt;/a&gt; with its &lt;a href=&quot;https://almanac.httparchive.org/en/2022/javascript&quot;&gt;Web Almanac&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;the-community-crisis&quot;&gt;The community crisis&lt;/h2&gt;

&lt;p&gt;To stretch the metaphor even further, at the LHC, there are in fact two beams of particles accelerated and shot at each other.&lt;/p&gt;

&lt;p&gt;Similarly, the &lt;a href=&quot;https://molily.de/javascript-criticism/&quot;&gt;web development community is divided into two camps&lt;/a&gt; on the issue of client-side JavaScript. They do not talk to each other, but ridicule each other.&lt;/p&gt;

&lt;p&gt;The technical discord is superimposed by layers of social discord, effectively preventing the community from solving the crisis. As &lt;a href=&quot;https://jakelazaroff.com/words/pathetic/&quot;&gt;Jake Lazaroff described&lt;/a&gt;, prominent voices in the community are injecting toxicity into the discourse. This hurts web development, discourages beginners and prevents us from building better web sites.&lt;/p&gt;

&lt;p&gt;In my opinion, the current state of client-side JavaScript usage on the web is so abysmal &lt;em&gt;in part&lt;/em&gt; because the criticism of that state is so abysmal. As someone who is trying to improve the state, I don’t exempt myself from this verdict. If we want to make any progress, we need to start with this confession.&lt;/p&gt;

&lt;p&gt;I’d like to discuss what I’m pretty sure doesn’t work and what I hope might work.&lt;/p&gt;

&lt;h2 id=&quot;camp-mentality&quot;&gt;Camp mentality&lt;/h2&gt;

&lt;p&gt;I do acknowledge the frustration and anger on both sides, in particular on the side of JavaScript critics. They have been ignored, insulted and abused. I do understand how the two groups became estranged.&lt;/p&gt;

&lt;p&gt;At the same time, I see righteousness, condescension and vilification. I see an “us vs. them” mentality. The camps are not talking to each other in any constructive way. This has to stop.&lt;/p&gt;

&lt;p&gt;Given the deadlock, the web community &lt;a href=&quot;https://molily.de/update-on-robust-javascript/&quot;&gt;needs to convene in a respectful and productive way&lt;/a&gt;, take criticism seriously and make radical changes.&lt;/p&gt;

&lt;h2 id=&quot;poor-analysis-and-conspiracy-theories&quot;&gt;Poor analysis and conspiracy theories&lt;/h2&gt;

&lt;p&gt;There are manifold reasons why error-prone, low-performing JavaScript-heavy architectures have prevailed. It is important to understand why managers and developers choose certain web technology so we can help them make better choices or improve the technology they choose.&lt;/p&gt;

&lt;p&gt;There is a simplistic and lazy explanation: A small cabal of JavaScript framework vendors, “&lt;a href=&quot;https://thenewstack.io/developers-rail-against-javascript-merchants-of-complexity/&quot;&gt;merchants of complexity&lt;/a&gt;”, “fraudsters”, “grifters”, have conspired to sell us inferior architectures. Meta with React.js and Vercel with Next.js are named as the culprits.&lt;/p&gt;

&lt;p&gt;Indeed, there are powerful economic actors who want to sell their goods and paint them in the best possible light. Of course, we need to &lt;del&gt;eat&lt;/del&gt; &lt;ins&gt;hold&lt;/ins&gt; the billionaires behind frameworks &lt;ins&gt;accountable&lt;/ins&gt; for poor performance, accessibility and usability. The mistakes of the framework makers and the shortcomings of their products are &lt;em&gt;also&lt;/em&gt; responsible for the JavaScript crisis. They did not listen to criticism, they did too little, too late. They even tried to silence critics.&lt;/p&gt;

&lt;p&gt;Nonetheless, the conspiracy theory is as simple as it is insufficient. It is downright dangerous since it spreads nothing but hate and actively prevents better analysis that is able to solve the crisis.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://tomdale.net/2015/11/javascript-frameworks-and-mobile-performance/&quot;&gt;Tom Dale wrote in 2015&lt;/a&gt; that “developers aren’t getting tricked by framework authors; they find the benefits worth it.” In 2023, Laurie Voss &lt;a href=&quot;https://seldo.com/posts/the_case_for_frameworks&quot;&gt;rejected the conspiracy theory and pointed out economic and social reasons&lt;/a&gt; assuming managers and developers are rational economic actors instead of mere fraud victims.&lt;/p&gt;

&lt;p&gt;In 2019, &lt;a href=&quot;http://web.archive.org/web/20210805020051/https://whalecoiner.com/articles/react&quot;&gt;Charlie Owen described React&lt;/a&gt; in terms of &lt;a href=&quot;https://en.wikipedia.org/wiki/Fordism&quot;&gt;Fordism&lt;/a&gt;. React fueled the commodification of the web. With React, Facebook introduced an assembly line that standardized the unit of labor, treating developers as factory workers instead of craft professionals.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.baldurbjarnason.com/2024/react-electron-llms-labour-arbitrage/&quot;&gt;Baldur Bjarnason followed the same line in his 2024 article&lt;/a&gt;. React and similar technologies allow capital to “play employees in different regions and fields against each other”. These technologies replace expensive specialists with more commodified generalists. “React and the component model standardises the software developer and reduces their individual bargaining power […] It helps [management and executives to] erase the various specialities – CSS, accessibility, standard JavaScript in the browser, to name a few – from the job market.”&lt;/p&gt;

&lt;p&gt;All these profound critiques do completely without conspiracy theories.&lt;/p&gt;

&lt;h2 id=&quot;the-big-rewrite&quot;&gt;The Big Rewrite&lt;/h2&gt;

&lt;p&gt;New architectures are popping up that try to solve the shortcomings of the existing ones. They often focus on server-side rendering (SSR), Progressive Enhancement, web components or compilers to generate less JavaScript.&lt;/p&gt;

&lt;p&gt;While this research is valuable, it typically creates new islands in the framework archipelago. The new techniques are often sold with the same zeal, marketing and superficiality as the previous JavaScript framework.&lt;/p&gt;

&lt;p&gt;Marco Rogers described the industry’s situation as a &lt;a href=&quot;https://polotek.net/posts/the-frontend-treadmill/&quot;&gt;Frontend Treadmill&lt;/a&gt;: whatever framework you choose, it will be obsolete in five years. If it still exists, it will have changed fundamentally. Developers are forced to keep up with this unhealthy pace.&lt;/p&gt;

&lt;p&gt;Rewriting your frontend will not lead to the promised land, Rogers says. Instead, he advises to dive deep into the framework you’re already using. Also, learn fundamental web technologies that will outlive any framework.&lt;/p&gt;

&lt;h2 id=&quot;simplicity-and-complexity&quot;&gt;Simplicity and complexity&lt;/h2&gt;

&lt;p&gt;The most common argument against client-side JavaScript solutions is that they bring unnecessary technical complexity. It’s a commonplace that everyone agrees with right away, no further explanation or analysis necessary. Just show &lt;a href=&quot;https://i.redd.it/tfugj4n3l6ez.png&quot;&gt;the meme that depicts node_modules as the heaviest object in the universe&lt;/a&gt; and everyone in the audience will lol-sob.&lt;/p&gt;

&lt;p&gt;I find the debate around complexity detached at best and harmful at worst. In almost all cases, the person who cries over-engineering has no insight into the process and the requirements. They claim they could solve the problem with a tenth of the code. Often they want to sell their own framework and want you to rewrite your frontend with it – see the previous section.&lt;/p&gt;

&lt;p&gt;Debating complexity is pointless because it’s a subjective metric. Every developer has a different gut feeling about simplicity, complexity and the appropriate amount of complexity for a given task. When people try to find an objective definition, they come to wildly different results. And that’s okay.&lt;/p&gt;

&lt;p&gt;Instead, we should focus on hard metrics from a user perspective. Performance, efficiency, compatibility, accessibility and fault-tolerance can be measured, tested and evaluated, automatically and manually.&lt;/p&gt;

&lt;p&gt;Any amount of complexity is fine as long as these goals are met. This typically involves moving the complexity to the server, including the edge, where all forms of optimization and scaling are possible.&lt;/p&gt;

&lt;h2 id=&quot;the-dichotomy-between-user-experience-ux-and-developer-experience-dx&quot;&gt;The dichotomy between User Experience (UX) and Developer Experience (DX)&lt;/h2&gt;

&lt;p&gt;Another cliché of JavaScript criticism is that modern web development favors developer experience (DX) to the disadvantage of user experience (UX). Instead of rolling up their sleeves, lazy developers allegedly choose technologies (frameworks in particular) that make their life easy but are detrimental for their users. Modern development tools are accused of creating heaven for developers and hell for users.&lt;/p&gt;

&lt;p&gt;In my opinion, UX vs. DX is a false dichotomy. Some people say there is an inherent inverse relationship between the two. More DX, less UX. I’d argue there is no necessary connection between the two.&lt;/p&gt;

&lt;p&gt;Claiming that developers have put their convenience first is an implausible explanation for the current crisis. I don’t think established stacks like React and Next.js provide a good developer experience, let alone a superior one. I don’t think they still offer a productivity benefit.&lt;/p&gt;

&lt;p&gt;Frameworks, dev servers, bundlers, transpilers/compilers, compile-to-JS languages, linters, testing tools and editors are hard to learn, hard to configure and perform poorly. We can’t complain about “tooling fatigue” and at the same time allege that developers favor DX over UX.&lt;/p&gt;

&lt;p&gt;Much innovation is happening regarding developer experience. For better or worse, &lt;a href=&quot;https://nolanlawson.com/2024/10/20/why-im-skeptical-of-rewriting-javascript-tools-in-faster-languages/&quot;&gt;every tool in the frontend toolchain is being rewritten in Rust&lt;/a&gt; to make it faster. Each framework has spawned multiple meta-frameworks. Each framework has its own transpiler or compiler. (React recently introduced a compiler. Svelte 5 gets a new compiler. The Angular compiler was recently rewritten.)&lt;/p&gt;

&lt;p&gt;I suppose these DX innovations have a mixed impact on UX. The new tools optimize and minimize the code, resulting in less, faster JavaScript. But improved DX may cause a &lt;a href=&quot;https://en.wikipedia.org/wiki/Rebound_effect_(conservation)&quot;&gt;rebound effect&lt;/a&gt;. Faster tools make it easier to deploy more and more client-side JavaScript, worsening the overall situation.&lt;/p&gt;

&lt;p&gt;When your Rust-based build tool churns out 20 MB of client-side JavaScript in milliseconds and your dev server hot-reloads those 20 MB in milliseconds, you don’t feel the devastation this causes for your users.&lt;/p&gt;

&lt;p&gt;This is the point where criticism needs to chime in. We need tools that make it easy to do the right thing and hard to impair the UX. Tools that inform the developer about the impact of a decision on performance and reliability.&lt;/p&gt;

&lt;p&gt;Critics often dismiss the significance of developer experience for achieving the values they advocate. Developer experience as pure convenience is indeed worthless. But it’s probably the most effective way to guide and influence developer decisions. Frameworks in particular can bake in accessibility rules and principles like Progressive Enhancement. The default choices should be the right choices. The default, easy way should lead to a robust, fast site.&lt;/p&gt;

&lt;p&gt;As Tom Dale noted in 2015, we need to &lt;a href=&quot;https://tomdale.net/2015/11/javascript-frameworks-and-mobile-performance/&quot;&gt;reduce the cost of code&lt;/a&gt;. Frameworks should provide zero-cost abstractions.&lt;/p&gt;

&lt;h2 id=&quot;the-obsession-with-developer-experience&quot;&gt;The obsession with developer experience&lt;/h2&gt;

&lt;p&gt;While I reject the DX vs. UX dichotomy, I acknowledge that developers and their managers chase good developer experience. Sometimes obsessively and selfishly. That is why DX is a huge market, with millions of venture capital flowing into dev tooling that promises a small productivity benefit. DX is a major driving force in our industry.&lt;/p&gt;

&lt;p&gt;Developers rather identify with their tools than with values regarding their craft such as usability, accessibility, or business goals such as trust, excellent service and friendliness towards customers. Not to mention elegance, creativity and beauty.&lt;/p&gt;

&lt;p&gt;Developers look for an integrated development environment: One language for everything (JavaScript/TypeScript), one server software for everything (Next.js, for example). This deceptive integration bulldozes important architectural distinctions: backend vs. frontend, HTML vs. JS, CSS vs. JS. JavaScript-heavy architectures have pulled HTML and CSS into their vortex. Now they are coming for every other aspect as well.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://seldo.com/posts/the_case_for_frameworks/&quot;&gt;As Laurie Voss described&lt;/a&gt;, developers are hawks “greedily sucking up browser resources to save themselves time”, while the users are doves “meekly trying to load a website and hoping it will run”. But Voss argues that a stable equilibrium between hawks and doves is established and we need to shift the equilibrium.&lt;/p&gt;

&lt;h2 id=&quot;react-and-derailed-frontends&quot;&gt;React and derailed frontends&lt;/h2&gt;

&lt;p&gt;Mocking React is yet another cliché. React has become a code word for everything that is wrong with JavaScript. In some circles you don’t have to provide any facts or arguments, you just have to mention that a site uses React to get laughs and sighs.&lt;/p&gt;

&lt;p&gt;In fact, there is well-informed fundamental criticism of React. Josh Collinsworth wrote the seminal articles &lt;a href=&quot;https://joshcollinsworth.com/blog/self-fulfilling-prophecy-of-react&quot;&gt;The self-fulfilling prophecy of React&lt;/a&gt; in 2022 and &lt;a href=&quot;https://joshcollinsworth.com/blog/antiquated-react&quot;&gt;Things you forgot (or never knew) because of React&lt;/a&gt; in 2023.&lt;/p&gt;

&lt;p&gt;In summary, React is sub-par by any measure and everyone in the industry should acknowledge that. Since React is the dominant JavaScript framework marketed by one of the most powerful IT corporations, it deserves its fair amount of criticism.&lt;/p&gt;

&lt;p&gt;But React is not the single adversary, the end boss. It’s unfounded to blame “React” for JavaScript atrocities. The mere use of React does not explain why frontends derail and become slow, inaccessible and unusable.&lt;/p&gt;

&lt;p&gt;For example, people found the new GitHub frontend, which is build with heavy client-side JavaScript, to be slow and buggy. Some quickly attributed it to the use of React. But &lt;a href=&quot;https://mastodon.social/@molily/111609317057394382&quot;&gt;as I wrote&lt;/a&gt;, the React library is not the sole cause of bad performance. It is comparably slow and huge. With client-only components, it promotes a development model that is known to be slow and fragile.&lt;/p&gt;

&lt;p&gt;But React’s performance is usually covered by many architectural layers that multiply the problem. In the case of GitHub, React accounts for 67 of 675 KB of JavaScript on pages like Pull Requests.&lt;/p&gt;

&lt;p&gt;For historical reasons, Github uses a wild mix of &lt;a href=&quot;https://github.com/primer/react&quot;&gt;Primer React&lt;/a&gt;, &lt;a href=&quot;https://reactrouter.com&quot;&gt;React Router&lt;/a&gt;, &lt;a href=&quot;https://catalyst.rocks/&quot;&gt;Catalyst web components&lt;/a&gt;, &lt;a href=&quot;https://lit.dev/docs/libraries/standalone-templates/&quot;&gt;lit-html&lt;/a&gt;, &lt;a href=&quot;https://github.com/patrick-steele-idem/morphdom&quot;&gt;morphdom&lt;/a&gt; and &lt;a href=&quot;https://github.com/hotwired/turbo-rails&quot;&gt;Rails Turbo&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Several competing technologies and frontend architectures coexist on one page. I would identify this as the main problem. These pages perform horribly not because React is one cornerstone, but because inconsistent engineering decisions lead to a half-baked single-page application.&lt;/p&gt;

&lt;p&gt;The GitHub case is a good example of how frontend projects deteriorate over time. According to &lt;a href=&quot;https://en.wikipedia.org/wiki/Conway%27s_law&quot;&gt;Conway’s law&lt;/a&gt;, software projects mirror the organizational and communication structure of the design team – &lt;a href=&quot;https://www.youtube.com/watch?v=5IUj1EZwpJY&amp;amp;t=1792s&quot;&gt;and all previous teams&lt;/a&gt;. Over the course of years, every real-world software project becomes a monument of shifts in product direction, power struggles, management and organizational restructuring, conflicting programming patterns and incomplete migrations.&lt;/p&gt;

&lt;p&gt;Every industry hype, every JavaScript trend leaves its mark in the codebase at the expense of user experience. For every line of code written and vetted by well-meaning developers, there are ten lines of third-party code from component libraries, tracking scripts and advertisement.&lt;/p&gt;

&lt;p&gt;A web framework is neither responsible for nor capable of preventing this dynamic. But it can provide a rigid architecture that mitigates the harm when developers (are forced to) go wild. Choosing boring, robust, fast, minimal, modular, replaceable, standardized technologies as the basis reduces the likelihood of frontend derailment.&lt;/p&gt;

&lt;h3 id=&quot;common-goals&quot;&gt;Common goals&lt;/h3&gt;

&lt;p&gt;Almost 25 years ago, PHP provided one of the first affordable development environments for web applications. Symfony, Laravel, Django and Rails later established best practices for web applications.&lt;/p&gt;

&lt;p&gt;The JavaScript community initially ignored these practices when single-page apps conquered the client. When Node.js became popular, Node-based frameworks adopted the practices, but also reinvented the wheel. Many Node “full-stack” frameworks today still leave out the frontend (“use React or Angular or whatever”).&lt;/p&gt;

&lt;p&gt;After a decade of criticism, JavaScript folks realized that server-side rendering and logic was useful, after all. In recent years, “meta-frameworks” have rediscovered the distinction between server and client logic – JavaScript that runs on the server vs. JavaScript that runs on the client vs. JavaScript that runs on the server and client (“universal” JavaScript). They have rediscovered semantic markup, CSS-in-CSS (also known as CSS), forms and links.&lt;/p&gt;

&lt;p&gt;The JavaScript community is roughly where PHP was in 2000. Which is a good thing. We have just scratched the surface of what a sensible use of JavaScript might look like. This involves rendering some pages statically, rendering some pages dynamically on the server, and rendering &lt;a href=&quot;https://jasonformat.com/islands-architecture/&quot;&gt;interactive “islands”&lt;/a&gt; on the client.&lt;/p&gt;

&lt;p&gt;What I am missing and what could improve the situation are common goals across JavaScript frameworks:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Every starter project should meet certain performance metrics. General-purpose frameworks should be measured on common tasks. In addition to miniscule examples like &lt;a href=&quot;https://todomvc.com/&quot;&gt;TodoMVC&lt;/a&gt;, we need examples for typical tasks like Create, Read, Update, Delete (CRUD), complex forms with validation as well as loading and streaming content.&lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;The performance impact of developer decisions should be transparent. We already have the tools to quickly assess performance, from bundle size warnings to Lighthouse &lt;abbr title=&quot;command line interface&quot;&gt;CLI&lt;/abbr&gt; and &lt;abbr title=&quot;continuous integration&quot;&gt;CI&lt;/abbr&gt;.&lt;/p&gt;

    &lt;p&gt;Of course, a build tool alone cannot predict the final page performance. But the &lt;a href=&quot;https://infrequently.org/2024/01/performance-inequality-gap-2024/#the-budget%2C-2024&quot;&gt;performance budget&lt;/a&gt; – the amount of HTML, critical CSS and initial JavaScript – is pretty fixed if you are targeting an acceptable load time for common internet connections on common devices.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;There should be a visible separation between server and client code. Server-run JavaScript has a categorically different footprint than client-side JavaScript. At the same time, we need a smooth and safe transition between server-only components, client-only components and universal components.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://dev.to/this-is-learning/is-0kb-of-javascript-in-your-future-48og&quot;&gt;Not literally zero kilobytes of client-side JavaScript&lt;/a&gt;, but the minimal feasible amount. Coding abstractions should come at negligible cost to the end users.&lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Frameworks should “magically disappear” in client code thanks to compilers. The remaining runtime shipped to the client should be minimal.
Modern frameworks like Preact, Svelte and Solid have demonstrated that capable, high-level abstractions only require a few kilobytes of JavaScript.&lt;/p&gt;

    &lt;p&gt;I understand that some frameworks today do not aggressively optimize for the first page view or for the size of a Hello World page. Many JavaScript-heavy sites never see light of the World Wide Web, but run on intranets or even locally.&lt;/p&gt;

    &lt;p&gt;Still, almost all frameworks have responded to criticism and made good progress on initial load performance. Angular, for example, now integrates server-side rendering (SSR) and static site generation (SSG). (According to my test, a standalone Hello World app amounts to 26.42 KB of client-side JavaScript. Angular 19.0.0-next.3, zoneless, without routing.)&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;primitives-and-apis&quot;&gt;Primitives and APIs&lt;/h2&gt;

&lt;p&gt;After 25 years, we finally have a clue how to share and connect server logic and client-side interactivity in a meaningful way. Unfortunately, everyone is still working in silos.&lt;/p&gt;

&lt;p&gt;There are many complementary and competing patterns, such as server-side rendering (SSR), static site generation (SSG), Islands, Hydration and &lt;a href=&quot;https://qwik.dev/docs/concepts/resumable/&quot;&gt;Resumability&lt;/a&gt;. This Cambrian explosion is exciting. But we should also strive for convergence. These ideas should be translated into primitives and APIs shared between frameworks.&lt;/p&gt;

&lt;p&gt;Each framework provides similar capabilities. Each framework now features a component model where “Lego bricks” structure the UI. Still, if you want to use two widgets from different vendors on one page, each one ships with its own version of React.&lt;/p&gt;

&lt;p&gt;Build tools need to apply similar optimizations. Even though they are built on similar foundations (Webpack/Rspack, Rollup/Rolldown, esbuild, SWC etc.), there is zero interoperability.&lt;/p&gt;

&lt;p&gt;There is some hope. Recently, the Vue.js community has become the steward of the entire JavaScript ecosystem. Vue is always-neutral Switzerland. Vue land is common land. Its tools have proven useful across all stacks, including &lt;a href=&quot;https://vitejs.dev/&quot;&gt;Vite&lt;/a&gt;, &lt;a href=&quot;https://nitro.unjs.io/&quot;&gt;Nitro&lt;/a&gt;, &lt;a href=&quot;https://github.com/nksaraf/vinxi&quot;&gt;Vinxi&lt;/a&gt;, &lt;a href=&quot;https://vitest.dev/&quot;&gt;Vitest&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Having shared fundamental tools is nice, but standardized APIs are better. We need a high-level, interoperable, portable component model that supports server, client and universal rendering.&lt;/p&gt;

&lt;p&gt;Your JavaScript code should be interoperable across runtimes and frameworks. There should be no vendor or framework lock-in. We should be able to copy components into any web project and they should play by the same rules.&lt;/p&gt;

&lt;p&gt;To be useful, a component model would need to cover declarative HTML templates, content projection (think of slots and portals), CSS scoping and encapsulation, attaching JavaScript behavior, value and form binding, attribute/property type definitions and public JavaScript APIs. It should feature good defaults plus generic programmable APIs.&lt;/p&gt;

&lt;p&gt;With &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements&quot;&gt;HTML custom elements&lt;/a&gt;, we have a standardized API that allows to &lt;a href=&quot;https://custom-elements-everywhere.com/&quot;&gt;integrate client-side DOM logic of different provenance&lt;/a&gt;. This is a great achievement without question. Many people are so excited about web components that they already proclaim “ditch your framework, just #UseThePlatform”.&lt;/p&gt;

&lt;p&gt;In my opinion, the current web component APIs provide 1% of what we technically need to overcome the JavaScript crisis. I’m afraid web-component-based frameworks currently add to the fragmentation. I’m skeptical whether techniques like the Shadow DOM and &lt;a href=&quot;https://web.dev/articles/declarative-shadow-dom&quot;&gt;Declarative Shadow DOM&lt;/a&gt; will even be part of a broad solution, and &lt;a href=&quot;https://meyerweb.com/eric/thoughts/2023/11/01/blinded-by-the-light-dom/&quot;&gt;so are proponents of web components&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Mayank pointed out that &lt;a href=&quot;https://www.mayank.co/blog/web-components-are-not-components&quot;&gt;web components are not components&lt;/a&gt; and went on to explain &lt;a href=&quot;https://www.mayank.co/blog/what-is-a-component-anyway&quot;&gt;what a component is anyway&lt;/a&gt;. Components in the sense of frameworks like React “&lt;a href=&quot;https://www.mayank.co/blog/web-components-considered-harmful&quot;&gt;exist in a different plane&lt;/a&gt;” than web components. “Web component APIs can be useful when creating components, but they are not the complete answer. Components should be able to do a lot more than what web component APIs are capable of today.”&lt;/p&gt;

&lt;p&gt;To my knowledge, there are only a few projects like &lt;a href=&quot;https://enhance.dev&quot;&gt;Enhance&lt;/a&gt; and &lt;a href=&quot;https://github.com/11ty/webc&quot;&gt;WebC&lt;/a&gt; that are currently exploring this problem space. They are groundbreaking, but still fringe. I guess agnostic and inclusive tools like &lt;a href=&quot;https://astro.build/&quot;&gt;Astro&lt;/a&gt; and &lt;a href=&quot;https://www.11ty.dev/&quot;&gt;11ty&lt;/a&gt; are having the biggest impact right now. They break up framework silos, start with plain HTML and demonstrate how frameworks can work together.&lt;/p&gt;

&lt;p&gt;After assessing &lt;a href=&quot;https://www.spicyweb.dev/web-components-ssr-node/&quot;&gt;server-side rendering of web components&lt;/a&gt;, including Enhance and WebC, &lt;a href=&quot;https://www.spicyweb.dev/web-components-ssr-node/#webc-an-enchanting-path-forward&quot;&gt;Jared White concludes&lt;/a&gt; that “we [need] a sense of &lt;em&gt;server-side interop&lt;/em&gt;, a vision of a component format where you could squint and see how server components could be authored in one environment and ported over to another environment without too much hassle”. He adds, “we desperately need a common language around thinking of web components as fullstack components”.&lt;/p&gt;

&lt;svg class=&quot;separator&quot; aria-hidden=&quot;true&quot;&gt;&lt;use xlink:href=&quot;#ornament&quot; /&gt;&lt;/svg&gt;

&lt;h2 id=&quot;closing-words&quot;&gt;Closing words&lt;/h2&gt;

&lt;p&gt;I don’t think I’m saying anything new in this post. People much smarter than me have said these things before in a more sensible and eloquent way. I’ve tried to give them due credit. Also I’m merely repeating what I have already written in my last five blog posts on the topic. In this post, I wanted to compile the aspects I find noteworthy for reference – mostly my own – and for posterity.&lt;/p&gt;

&lt;p&gt;I’ve talked about various possible technical solutions, but I think the most pressing issue is the discourse that needs to be fixed. We need to recognize that clichés, sermons, insults and righteousness have failed. We need to reconcile with mutual respect sharing the common goal of &lt;a href=&quot;https://www.w3.org/TR/ethical-web-principles/&quot;&gt;making the web usable, accessible, secure and safe for everyone&lt;/a&gt;.&lt;/p&gt;
</description>
          <pubDate>Wed, 11 Sep 2024 00:00:00 +0200</pubDate>
          <link>https://molily.de/something-went-wrong/</link>
          <guid isPermaLink="true">https://molily.de/something-went-wrong/</guid>
          
          
        </item>
      
    
      
        <item>
          <title>Full circle development</title>
          <description>&lt;p&gt;Around 1996 or 1997, I started writing HTML. My family did not have internet access yet. But we owned a computer with a CD-ROM drive. On a CD-ROM that came with a video gaming magazine, I found some .HTM files. The magazine had shipped its website as HTML files on this CD-ROM because few people had internet access. I opened the files in Internet Explorer, then in Notepad. I changed the code and immediately realized the creative power of Hypertext. I created my first HTML pages and I distributed them via floppy disks.&lt;/p&gt;

&lt;p&gt;A few years later, we got internet access at home. I immediately uploaded a personal website to a free webhoster. I became involved with the German &lt;a href=&quot;https://wiki.selfhtml.org/&quot;&gt;SELFHTML documentation&lt;/a&gt;, which was to German web developers what the Mozilla Developer Network is today: the definitive guide and reference for web technologies.&lt;/p&gt;

&lt;p&gt;Many years later, I have become a professional web developer.&lt;/p&gt;

&lt;svg class=&quot;separator&quot; aria-hidden=&quot;true&quot;&gt;&lt;use xlink:href=&quot;#ornament&quot; /&gt;&lt;/svg&gt;

&lt;p&gt;Fast-forward to 2010. Something new was brewing in web development. The JavaScript programming language became more mature and powerful. With ECMAScript 5 and HTML5 (later named “HTML Living Standard”), the browser APIs became stable and reliable. With Chrome, a brand-new standards-compliant browser with a fast JavaScript engine became popular.&lt;/p&gt;

&lt;p&gt;Web developers started to take JavaScript seriously. They pondered about the role JavaScript could play in web development in the future. And people started to use more and more client-side JavaScript for interactive web applications.&lt;/p&gt;

&lt;p&gt;There have been Flash and Ajax applications before, but they were mostly gates to other dimensions where the rules of the web did not apply. (The first thing people did with Flash and Ajax was to reinvent the desktop and window metaphors, within the browser, within a web page.)&lt;/p&gt;

&lt;p&gt;Around the same time, mobile computing got popular and affordable. Smartphones became powerful web clients. And Steve Jobs foretold that Flash has no future on mobile devices (&lt;a href=&quot;https://en.wikipedia.org/wiki/Thoughts_on_Flash&quot;&gt;“Thoughts on Flash”&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Steps followed to reconcile a document-centric web with an application-centric web. For example, the JavaScript API &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;history.pushState&lt;/code&gt; was introduced to reflect the application state in the URL.&lt;/p&gt;

&lt;p&gt;A Cambrian explosion of JavaScript libraries and tools happened: Require.js, CoffeeScript, Backbone.js, Knockout.js, Angular.js, jQuery Mobile, Mustache, Handlebars.&lt;/p&gt;

&lt;p&gt;People wrote more and more client-side JavaScript, so they needed ways to structure the code. “Application architectures” with patterns like MVC or MVVM sprouted like mushrooms. &lt;a href=&quot;https://todomvc.com&quot;&gt;TodoMVC&lt;/a&gt; guided developers through the jungle.&lt;/p&gt;

&lt;p&gt;During that time, nothing was set in stone, everything was in flux. There weren’t two or three architectures that had been agreed upon. There was no standard solution in the industry. Controversy erupted over how to use these new capabilities and patterns for the user’s benefit.&lt;/p&gt;

&lt;svg class=&quot;separator&quot; aria-hidden=&quot;true&quot;&gt;&lt;use xlink:href=&quot;#ornament&quot; /&gt;&lt;/svg&gt;

&lt;p&gt;JavaScript made a difference in 2010 because user experience of websites lagged way behind that of native apps. Every interaction meant an interruption instead of a meaningful transition. Every web navigation led to a blank white page, confusing and erratic loading behavior. The browser caching was horrible. There was no back/forward cache, no multiprocess data fetching, processing and rendering. No caching of CSS and JavaScript parse trees, no JavaScript bytecode cache. There were no cross-page transitions (outside of Internet Explorer).&lt;/p&gt;

&lt;p&gt;At the web agency I work for, we used the new methods and tools to demonstrate our clients how smooth interactions on websites could work: Easy and quick browsing through content. Smooth transition between list and item and back. Animating dialogs. Loading new content automatically, live updates. Integrating interaction widgets and social media seamlessly. Authentication with single-sign on.&lt;/p&gt;

&lt;p&gt;These design ideas were anything but new. They were already described in 2005. &lt;a href=&quot;http://web.archive.org/web/20050227021921/http://www.adaptivepath.com/publications/essays/archives/000385print.php&quot;&gt;Ajax&lt;/a&gt; promised to “eliminate the start-stop-start-stop nature of interaction on the Web”. Moreover: “The user is never staring at a blank browser window and an hourglass icon, waiting around for the server to do something.”&lt;/p&gt;

&lt;p&gt;After having used these new possibilities, we wanted to share our experience and discuss possible architectures with other developers.&lt;/p&gt;

&lt;p&gt;In May 2012, folks from &lt;a href=&quot;https://en.wikipedia.org/wiki/Moviepilot&quot;&gt;Moviepilot&lt;/a&gt; and &lt;a href=&quot;https://9elements.com/&quot;&gt;9elements&lt;/a&gt; started a meet-up in Berlin, Germany: &lt;a href=&quot;http://web.archive.org/web/20120825043249/http://berlinjs.org/apps&quot;&gt;apps.berlin.js&lt;/a&gt;. It was a spin-off from &lt;a href=&quot;https://berlinjs.org/&quot;&gt;Berlin.js&lt;/a&gt;, an already successful JavaScript user group, started by &lt;a href=&quot;https://coding-robin.de/&quot;&gt;Robin Mehner&lt;/a&gt; and &lt;a href=&quot;https://writing.jan.io/&quot;&gt;Jan Lehnardt&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The spin-off ran until February 2014, as far as I remember, and merged again with Berlin.js. JavaScript client-side apps became mainstream. Also, JavaScript frameworks like Angular.js and React emerged. The crowd started to split into framework user groups and the overarching discussions abated.&lt;/p&gt;

&lt;svg class=&quot;separator&quot; aria-hidden=&quot;true&quot;&gt;&lt;use xlink:href=&quot;#ornament&quot; /&gt;&lt;/svg&gt;

&lt;p&gt;Recently, I was reminded of a talk at apps.berlin.js. &lt;a href=&quot;http://tif.ca/&quot;&gt;Tiffany Conroy&lt;/a&gt;, who worked at SoundCloud at the time, spoke about why the SoundCloud website heavily relied on client-side rendering. Why perform all the routing and state management on the client? Why not use an old-fashioned, traditional server-side web application? The answer was: the site allows playing music while the user continues to browse the site.&lt;/p&gt;

&lt;p&gt;Ten years later, we are debating the same questions we discussed from 2013 onwards. During the last decade, JavaScript web applications exploded. Many new web developers are only taught this way of building websites. Many websites are JavaScript apps for no particular reason or benefit. The resulting sites are slow, fragile and inaccessible. Megabytes of JavaScript are shipped for what could have been a simple and fast application with boring but solid PHP.&lt;/p&gt;

&lt;p&gt;Today, we experience a backlash against this practice. At the same time, developers express a “tooling fatigue”. There is a strong sentiment against frameworks. People want to get rid of the “struggle stack” and “use the platform” with “zero dependencies”. So people advertise “vanilla JavaScript” solutions “built with web standards” to set them apart from frameworks.&lt;/p&gt;

&lt;p&gt;Questioning the predominant use of JavaScript makes perfectly sense – always has, always will. The backlash today however tends to swing to the other extreme. Critical analysis of existing designs, refactoring of existing tech stacks is hard to market. It does not make for viral content. It’s easier to start from scratch and to throw out the baby with the bath water.&lt;/p&gt;

&lt;p&gt;JavaScript critics call the last decade a lost decade. In contrast, I have seen diverse and meaningful discussion around the usage of HTML, CSS and particularly JavaScript. Also, remarkable critiques on web design and web economics. What do we want to do with the web? How should we use the technologies we have? Which communities and interactions do we want to build? Which principles should we bake into web technologies, tools and our code?&lt;/p&gt;

&lt;p&gt;The last decade seems lost because we failed to carry the knowledge gained in these lively discussions into the present. This means we are doomed to repeat history. &lt;a href=&quot;https://en.wikipedia.org/wiki/The_Eighteenth_Brumaire_of_Louis_Bonaparte#First_as_tragedy,_then_as_farce&quot;&gt;The first time was a tragedy, now it’s a farce&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;What is said in 2023 about interactive web applications, JavaScript usage and frameworks falls short of what we discussed years ago. The discourse has fallen back behind the nuances we had achieved.&lt;/p&gt;

&lt;p&gt;I don’t exempt myself from that at all. This affects my thinking and writing as well. For example, someone writes an article on frameworks. I’m thinking: Let me pick up these great thoughts! Later I realize this very discussion happened in 2015. There were respectful, fruitful, nuanced blog posts. Today? Rather not. People are shouting over each other.&lt;/p&gt;

&lt;svg class=&quot;separator&quot; aria-hidden=&quot;true&quot;&gt;&lt;use xlink:href=&quot;#ornament&quot; /&gt;&lt;/svg&gt;

&lt;p&gt;Much of the web development discourse today is ruined. The community became divided, scattered, and driven by animosity. The different camps rant about others in their echo chambers.&lt;/p&gt;

&lt;p&gt;There are humble, friendly, far-sighted and compassionate voices on all sides. But they simply don’t succeed building bridges between the estranged groups. Any nuanced take falls on toxic soil.&lt;/p&gt;

&lt;p&gt;What led to a community this divided? I think it is normal that tech communities grow apart. People first have a civil discourse about different approaches. They respectfully disagree, then pursue their ways. They move further and further apart and become estranged over the years. If they happen to run into each other, they just throw snarky remarks at each other.&lt;/p&gt;

&lt;p&gt;Fragmentation by tools and frameworks played its part. The complexity of software ecosystems requires a certain specialization. For example, people do not simply use a Shiny Library as an isolated tool. A person is educated as a “Shiny Library developer”, gets hired as a “Shiny Library developer”, sooner or later identifies as a “Shiny Library developer” and exchanges with fellow “Shiny Library developers”.&lt;/p&gt;

&lt;p&gt;To make matters worse, corporations with hundreds of millions of capital use “developer evangelism” and “open source” to market their products, cloud services and the underlying idea of the web. As &lt;a href=&quot;https://blog.testdouble.com/posts/2023-10-16-must-have-10-years-experience-with-lineman-js/&quot;&gt;Justin Searls describes&lt;/a&gt;, this crushed innovative, independent tools that evolved from the daily work of small agencies and professionals.&lt;/p&gt;

&lt;p&gt;Also, Twitter broke apart. On Twitter, web authors with different affiliations and fundamentally different views lived right next to each other. Despite all horrors, the global townsquare allowed diverse voices to chime in.&lt;/p&gt;

&lt;p&gt;Today, the web community is fragmented into sealed echo chambers on Twitter, Bluesky, Mastodon, Threads, Discord, YouTube, Twitch etc. In fact many web developers love smaller, tight-knit communities in which no one fundamentally questions your stance of the web.&lt;/p&gt;

&lt;svg class=&quot;separator&quot; aria-hidden=&quot;true&quot;&gt;&lt;use xlink:href=&quot;#ornament&quot; /&gt;&lt;/svg&gt;

&lt;p&gt;&lt;a href=&quot;https://molily.de/javascript-criticism/&quot;&gt;In March, I asked&lt;/a&gt;: “How do we reconcile? First of all, do we want to reconcile? Or are we fine with the divide? Are we fine with bridges burning? Are we fine with smart people on both sides ridicule and insult each other? Is this the new normal?” The answers are pretty clear by now.&lt;/p&gt;

&lt;p&gt;This post does not have a message or resolution. I do not have any suggestions. There are enough web developers who take their narrow perspective on the web as absolute. They have a fixed opinion how you should use the web and how you should build websites. They have clear friends and foes.&lt;/p&gt;

&lt;p&gt;I have seen many circles in 25 years and all I can say is that the most recent circle is a farce.&lt;/p&gt;

&lt;p&gt;That said, I love web development and web publishing since 1996. HTML is radical, disturbing, chaotic, wicked, powerful and beautiful.&lt;/p&gt;

&lt;svg class=&quot;separator&quot; aria-hidden=&quot;true&quot;&gt;&lt;use xlink:href=&quot;#ornament&quot; /&gt;&lt;/svg&gt;

&lt;p&gt;Last but not least, let me save some knowledge from the far and recent past into the present.&lt;/p&gt;

&lt;p&gt;Pamela Fox wrote on &lt;a href=&quot;http://blog.pamelafox.org/2013/05/frontend-architectures-server-side-html.html&quot;&gt;Server-side HTML vs. JS Widgets vs. Single-Page Web Apps&lt;/a&gt; summarizing her talk &lt;a href=&quot;https://web.archive.org/web/20130428114412/http://frontend-architectures.appspot.com/&quot;&gt;Frontend Architectures: from the prehistoric to the Post-modern&lt;/a&gt; in 2013.&lt;/p&gt;

&lt;p&gt;Tom Dale wrote &lt;a href=&quot;https://tomdale.net/archive/&quot;&gt;fundamental blog posts&lt;/a&gt; on frameworks around 2015, like &lt;a href=&quot;https://tomdale.net/2015/02/youre-missing-the-point-of-server-side-rendered-javascript-apps/&quot;&gt;You’re Missing the Point of Server-Side Rendered JavaScript Apps&lt;/a&gt; and &lt;a href=&quot;https://tomdale.net/2015/11/javascript-frameworks-and-mobile-performance/&quot;&gt;JavaScript Frameworks and Mobile Performance&lt;/a&gt;. He also gave a fun talk: &lt;a href=&quot;https://www.youtube.com/watch?v=puOrC7cfjRI&amp;amp;list=PLkJyefyZTdnFyzdh70LWuzhFTBOgMBnmJ&amp;amp;index=6&quot;&gt;Progressive Enhancement is Dead, Long Live Progressive Enhancement&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Nolan Lawson wrote a &lt;a href=&quot;https://nolanlawson.com/tag/spas/&quot;&gt;series of thoughtful blog posts on Single-Page Apps&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Josh Collinsworth wrote on &lt;a href=&quot;https://joshcollinsworth.com/blog/self-fulfilling-prophecy-of-react&quot;&gt;The self-fulfilling prophecy of React&lt;/a&gt; and &lt;a href=&quot;https://joshcollinsworth.com/blog/antiquated-react&quot;&gt;Things you forgot (or never knew) because of React&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Laurie Voss made &lt;a href=&quot;https://seldo.com/posts/the_case_for_frameworks/&quot;&gt;the case for frameworks&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Rich Harris asked “Have Single-Page Apps Ruined the Web?” (“kinda”) and advocates for &lt;a href=&quot;https://www.youtube.com/watch?v=860d8usGC0o&quot;&gt;transitional web apps&lt;/a&gt; to break the dichotomy of single-page versus multi-page apps.&lt;/p&gt;
</description>
          <pubDate>Sat, 11 Nov 2023 00:00:00 +0100</pubDate>
          <link>https://molily.de/full-circle-development/</link>
          <guid isPermaLink="true">https://molily.de/full-circle-development/</guid>
          
          
        </item>
      
    
      
        <item>
          <title>Planet of the Beavers</title>
          <description>&lt;p&gt;&lt;small&gt;Content note: Mention of fictional death in a video game&lt;/small&gt;&lt;/p&gt;

&lt;p&gt;Almost three years ago, &lt;a href=&quot;/antagonism-human-nature/&quot;&gt;I wrote about Factorio&lt;/a&gt;, a factory simulation game. I lamented on the distorted relationship between human and nature and how the game negates the principles of human and non-human life.&lt;/p&gt;

&lt;p&gt;On Twitter, &lt;a href=&quot;https://twitter.com/anniecburman/status/1326860189748834305&quot;&gt;Dr Annie Burman followed up with a thread&lt;/a&gt; I recommend reading as a whole. Burman notes that the player character, simply called engineer, is human – but all that is human is foreign to them:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;I have been playing #Factorio for a while now. It is fun, and easy to get very into, but I think it falls short in a few ways. This thread is going to be about the engineer character and how it is under-utilised. […]&lt;/p&gt;

  &lt;p&gt;The thing where the game really fails, in my opinion, is in addressing the absolute loneliness of this world. You crash on a planet devoid of sentient lives. All your crew-mates are dead – their bodies are scattered just like the rubble of your ship.&lt;/p&gt;

  &lt;p&gt;You are stuck in this vast world, and you start building, taming the wilderness. But that sense of loneliness still remains. You are still the only person there, now stuck in a vast industrial landscape.&lt;/p&gt;

  &lt;p&gt;The character we play is never given much in the way of emotions or fear or needs. They do not need to eat or sleep. They are a non-entity in many ways, to the extent that on occasion, I’ve wondered why there is a sprite at all (except to get killed by the biters).&lt;/p&gt;

  &lt;p&gt;I think that the game could explore the horror of this plight and of your own actions in a few subtle ways. […]&lt;/p&gt;

  &lt;p&gt;So it is a failing, definitely, to have a character on screen, but not allow it any of the things that make us human, a theme that feels like it could have been central to this game.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This sums it up brilliantly. These glaring aspects of Factorio were brought back to my mind recently while playing another video game. That game resembles Factorio in many ways yet distinctly differs in the points Burman mentioned.&lt;/p&gt;

&lt;p&gt;I am talking about &lt;a href=&quot;https://mechanistry.com/&quot;&gt;Timberborn&lt;/a&gt;. With regard to the mentioned aspects, Timberborn can be viewed as the antithesis to Factorio.&lt;/p&gt;

&lt;p&gt;Timberborn is a rather traditional city economy simulation. The player builds a beaver colony. Each beaver inhabits a house, works in a production building where it extracts raw materials or processes them further. Products are consumed, like food for example, or used as building material.&lt;/p&gt;

&lt;p&gt;Compared to Factorio’s countless buildings, resources, products and processing steps, Timberborn is rather simple. The game is also down-to-earth in the sense that you need to build a sustainable economy that works with the limited natural resources the habitat provides. The most basic ones are water, irrigated and fertile soil, timber and other forest products. They remain the limiting factors even later in the game.&lt;/p&gt;

&lt;p&gt;The goal of the game is to satisfy the needs of all beavers: From eating, drinking and sleeping over health and pleasure to community and spirituality. The goal is not to maximize production and consumption endlessly, but to grant the beavers &lt;a href=&quot;https://en.wikipedia.org/wiki/The_Right_to_Be_Lazy&quot;&gt;The Right to Be Lazy&lt;/a&gt;. The beavers want to work as little and enjoy as much leisure time as possible.&lt;/p&gt;

&lt;p&gt;The beavers want to sip coffee, eat maple pastry, read books. Chill on a rooftop terrace during sundown. Swim in a lido, or enjoy the bubbles in a mud bath. Meet friends and potential partners at a fireplace. Find community and spiritual contemplation in shrines and temples. Experience beauty and awe when marvelling at statues and monuments.&lt;/p&gt;

&lt;p&gt;The things that make us human, the things that Factorio lacks, are central to this game. Timberborn’s anthropomorphic beavers are more human than all humans in Factorio.&lt;/p&gt;

&lt;p&gt;While switching between Factorio and Timberborn, it came to my mind that Factorio is a game from programmers for programmers – or more broadly, for people with an obsession on automation and efficiency. With all the interlocking production logic, with circuits and combinators, Factorio itself forms a visual programming environment. This also explains the popularity of the game in the programming community. (Disclosure: I am a programmer myself.)&lt;/p&gt;

&lt;p&gt;In Factorio, there is a unity of efficiency in the game world and the game controls. The game screams “Do Not Repeat Yourself” all over – a common, yet misleading programming principle. The keyboard and mouse controls are optimized as programmers would optimize their code editor. There are a dozen of options to configure the interface for maximum input efficiency. As the game progresses, there is a positive feedback loop between faster/less input and faster/more production.&lt;/p&gt;

&lt;p&gt;Let us recap that this &lt;a href=&quot;https://en.wikipedia.org/wiki/Great_Acceleration&quot;&gt;Great Acceleration&lt;/a&gt; does not reflect on &lt;em&gt;what&lt;/em&gt; it accelerates and &lt;em&gt;why&lt;/em&gt;. Factorio’s automation for the sake of automation establishes dominance over nature and exterminates other creatures.&lt;/p&gt;

&lt;p&gt;In Timberborn, there is also a unity of efficiency: There is little efficiency in the game. And the game controls are inefficient as well.&lt;/p&gt;

&lt;p&gt;Timberborn revolves around manual labor and repetition. Every day, the beavers wake up and carry out their arduous stint. The ways to increase the productivity are very limited: Well-rested, well-fed, satisfied beavers are slightly more productive.&lt;/p&gt;

&lt;p&gt;Once there is enough food for everyone, the player is supposed to reduce the beaver’s working hours, increase their leisure time, so they can thrive and prosper. This slows down the whole economy until it reaches an equilibrium of workload and leisure, production and consumption.&lt;/p&gt;

&lt;p&gt;The only significant productivity leap comes with the invention of robots, formerly known as golems. While beavers are sensitive and demanding creatures, the tenacious robots work day and night with a little maintenance. Still, it is manual work to sustain a steady robot workforce. And while robots are an interesting addition to the game, there is no immediate need or substantial gain to let robots do all the work.&lt;/p&gt;

&lt;p&gt;Similarly, the game controls are manual and tedious and remain so over the course of the game. Configurable keyboard shortcuts were introduced just recently in Timberborn Update 5, two years after the initial Early Access release. For important actions, there is still no keyboard shortcut.&lt;/p&gt;

&lt;p&gt;Maybe the game controls will become more efficient in future updates. But it goes against the grain of this game to have shortcuts, copy &amp;amp; paste blueprints, productivity updates or even programmable logic.&lt;/p&gt;

&lt;p&gt;There is no electronic circuit that automatically closes the floodgates when a tide of toxic water threatens to contaminate the soil, destroy your crops and make your beavers sick. You have to be on the watch and manage the gates manually. Nature has no mercy and this is the beaver condition.&lt;/p&gt;

&lt;p&gt;I would like to close with a thought that puts both games, their fictional worlds and the real world into perspective. You may call it far-fetched or just fanfic: I can make sense of these games when I regard them as sequels. Of course, they are from different game studios and superficially, their story lines do not cross. But let me explain.&lt;/p&gt;

&lt;p&gt;The Factorio player character is a lonely astronaut. I imagine that they have left the poisoned, barren earth. They are doomed to wander in space and scrape raw materials from the crust of hostile planets without ever finding community or peace.&lt;/p&gt;

&lt;p&gt;The shipwrecked engineer surrounded by automated mining drills and gun turrets reminds me of the &lt;a href=&quot;https://thenewinquiry.com/manifesto-of-the-committee-to-abolish-outer-space/&quot;&gt;Manifesto of the Committee to Abolish Outer Space&lt;/a&gt;, a satirical critique of the colonial “frontier” narratives in space flight.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;What will Mars look like in ten years, fifty, a hundred, five hundred? It’s a question that breeds monsters. Maybe domed cities, maybe tidy spa resorts on the shores of the Hellas basin. Or there could be dark and vast robots there, colossi wreathed in smoke and fire striding across the planet’s surface, digging deep scars into the rock with metal jaws, stripping out the useful minerals and burning the rest in an atomic blaze. We might see the streaming furrows of a dust storm on the horizon, while the last colonist gnaws at the bones of her fellow adventurers, driven mad by that tiny dot in the night sky that was once her home.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This last colonist resembles the engineer in Factorio, who is not even able to grieve their dead friends.&lt;/p&gt;

&lt;p&gt;While not immediately obvious, the world the cute beavers of Timberborn inhabit is our very own planet Earth long after the “hoomans” disappeared. The beavers find and use the human relics and have to cope with their remains. Like having to deal with rivers polluted by toxic waste:&lt;/p&gt;

&lt;blockquote cite=&quot;https://store.steampowered.com/news/app/1062090/view/7034115464063354887&quot;&gt;
  &lt;p&gt;In Timberborn’s world, humanity disappeared and left ruin behind. As of Update 5, that legacy also includes toxic pollution, colloquially known as badwater. Accumulated in the Earth’s crust in mankind’s final days, these deadly chemicals flow down the rivers and erupt from the ground, threatening all life and making restoration of the planet even more challenging.&lt;/p&gt;

  &lt;p&gt;– &lt;a href=&quot;https://store.steampowered.com/news/app/1062090/view/7034115464063354887&quot;&gt;Timberborn Update 5 release notes&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So allow me this fanfic: Timberborn and Factorio play in the same universe, at the same time. The former on Earth and the latter on a distant planet.&lt;/p&gt;

&lt;p&gt;This allows me to see the games not as antithetical, but as two sides of the same coin. Humanity managed to wipe itself off the face of the Earth. Isolated individuals of Homo Sapiens – like the engineer – are wandering around in space. This explains why Factorio’s economy serves no human need, why the game has no concept of ecology and does not try to grasp the essence of life.&lt;/p&gt;

&lt;p&gt;The hoomans &lt;a href=&quot;https://www.youtube.com/watch?v=mDLS12_a-fk&amp;amp;t=86s&quot;&gt;blew it up&lt;/a&gt;, and the post-apocalyptic Earth is now the Planet of the Beavers.&lt;/p&gt;

</description>
          <pubDate>Sat, 07 Oct 2023 00:00:00 +0200</pubDate>
          <link>https://molily.de/planet-of-the-beavers/</link>
          <guid isPermaLink="true">https://molily.de/planet-of-the-beavers/</guid>
          
          
        </item>
      
    
      
        <item>
          <title>On browser compatibility and support baselines</title>
          <description>&lt;h2 id=&quot;preface-on-asynchrony&quot;&gt;Preface on asynchrony&lt;/h2&gt;

&lt;p&gt;One of the defining features of the web is technical asynchrony. Web standards, web clients – like browsers – and web pages are never fully aligned in time. They meet &lt;em&gt;sometimes&lt;/em&gt; but &lt;em&gt;most of the time&lt;/em&gt; one is ahead or lags behind.&lt;/p&gt;

&lt;p&gt;Web standards are usually ahead of browsers and websites. They are designed, then browsers start implementing them. Once a web standard is stable, the implementations are finished and shipped. Then web authors use them on their sites.&lt;/p&gt;

&lt;p&gt;But since browser behavior is not fully standardized, web standards may also lag behind browsers.&lt;/p&gt;

&lt;p&gt;Browsers are usually ahead of websites. Most websites are developed at one point in time whereas browsers are updated frequently. Today, Firefox and Chromium-based browsers are evergreen, meaning they auto-update to a new major version every four weeks. Safari receives major updates roughly every year.&lt;/p&gt;

&lt;p&gt;Browsers allow a glimpse into the past. They need to support all websites ever written since the beginning of the web. Only a few web technologies have been deprecated and removed from browsers. Old sites mostly work in newer browsers, only some features are broken.&lt;/p&gt;

&lt;p&gt;But browsers may also lag behind websites. When web authors use web technologies just released in evergreen browsers, most browser versions in use do not support them yet. This was and is a huge problem because some browsers update infrequently or manually. A significant number of people are stuck with old devices, old operating systems and old browsers that cannot be updated.&lt;/p&gt;

&lt;p&gt;For web authors, this is daily business. A large part of a web author’s work is dealing with browser compatibility and website interoperability. The situation improved thanks to evergreen browsers. But fundamentally, this is the essence of authoring for the web.&lt;/p&gt;

&lt;p&gt;When using an HTML, CSS or JavaScript feature, web authors need to check for its browser support. &lt;a href=&quot;https://caniuse.com/&quot;&gt;Can I Use&lt;/a&gt; and &lt;a href=&quot;https://developer.mozilla.org/en-US/&quot;&gt;MDN&lt;/a&gt; are the most comprehensive databases. There is an ecosystem of tools that builds on Can I Use data: &lt;a href=&quot;https://github.com/browserslist/browserslist&quot;&gt;browserslist&lt;/a&gt; is a way to list browser versions a website aims to support. &lt;a href=&quot;https://github.com/postcss/autoprefixer&quot;&gt;Autoprefixer&lt;/a&gt; and &lt;a href=&quot;https://babeljs.io/docs/babel-preset-env&quot;&gt;@babel/preset-env&lt;/a&gt; use browserslist to generate interoperable code.&lt;/p&gt;

&lt;h1 id=&quot;how-to-deal-with-old-browsers&quot;&gt;How to deal with old browsers&lt;/h1&gt;

&lt;p&gt;The crucial recurring question since the beginning of the web is: How to deal with browsers that do not support a certain web technology feature? The answer is always: It depends! It depends on how the HTML, CSS, JavaScript feature works, on the browser market partition in the target audience, on the importance of the feature for the site, and much more.&lt;/p&gt;

&lt;p&gt;Progressive Enhancement and Graceful Degradation are best practices for dealing with old browsers and building interoperable sites. Based on support data, web authors decide whether to use the feature at all. They can test with browser versions that do not support the feature. How do old browsers deal with the new code? How does it affect the user experience?&lt;/p&gt;

&lt;p&gt;Web authors can directly use the feature if it enhances the site in newer browsers and does not break anything in older browsers. If it does, web authors can detect the feature and activate it safely. They can add a polyfill or fallback if applicable.&lt;/p&gt;

&lt;p&gt;Unfortunately, this is tedious, manual work. A website uses hundreds, if not thousands of distinct web features across HTML, CSS, SVG, JavaScript, DOM, WebGL, images, audio, video, etc. Web authors need to investigate and group the features to make pragmatic browser support decisions.&lt;/p&gt;

&lt;p&gt;That is to say, I can fully understand that web authors want to make this task easier and less time-consuming.&lt;/p&gt;

&lt;h1 id=&quot;googles-baseline-initiative&quot;&gt;Google’s Baseline initiative&lt;/h1&gt;

&lt;p&gt;At Google’s developer conference, Google recently announced the &lt;a href=&quot;https://web.dev/baseline/&quot;&gt;Baseline initiative&lt;/a&gt;. See also &lt;a href=&quot;https://web.dev/introducing-baseline/&quot;&gt;Introducing Baseline&lt;/a&gt; and &lt;a href=&quot;https://www.youtube.com/watch?v=eZa3BgGaAeA&amp;amp;t=616s&quot;&gt;Rachel Andrew’s YouTube video&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Google Baseline aims to make it easier for web authors and web publishers to think and talk about browser support. Baseline is &lt;q&gt;a line in the sand indicating which web platform features are safe to use. Features in Baseline have cross-browser support, they are interoperable, with no major issues in any browser engine.&lt;/q&gt; As Rachel Andrew explains in the video, &lt;q&gt;if a feature is part of Baseline, our aim is that most web teams should feel confident to just use it.&lt;/q&gt;&lt;/p&gt;

&lt;p&gt;The &lt;a href=&quot;https://web.dev/baseline/&quot;&gt;blog post lists the pursued benefits&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;When planning a project, rather than needing to list specific browser versions, you can set a requirement to use features that are part of Baseline.&lt;/li&gt;
&lt;li&gt;When publishing a library, you can help potential users understand support of features used (and therefore whether it is safe to use on their site) by declaring support for Baseline.&lt;/li&gt;
&lt;li&gt;When writing a tutorial, you can tell readers that everything described is in Baseline. Your reader then knows this is a solution they can incorporate into a project.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;The crucial technical definition of the Google Baseline is: &lt;q&gt;Features become part of Baseline when they are supported in the current and previous version of all major browsers—Chrome, Edge, Firefox, and Safari.&lt;/q&gt;&lt;/p&gt;

&lt;h2 id=&quot;widely-supported-cascade-layers&quot;&gt;“Widely supported” Cascade Layers&lt;/h2&gt;

&lt;p&gt;While I value Google’s manifold efforts to improve web interoperability, I don’t think that Google Baseline clears things up and delivers on its promises. It is a simplification of the reality. It gives web authors a false impression of how browser compatibility works.&lt;/p&gt;

&lt;p&gt;Let me pick an example to explain how Google Baseline fails on its promises: &lt;strong&gt;CSS Cascade Layers&lt;/strong&gt;.&lt;/p&gt;

&lt;aside style=&quot;font-size: 80%&quot;&gt;&lt;p&gt;In this post, I will not explain how Cascade Layers work. Please refer to the &lt;a href=&quot;https://css-tricks.com/css-cascade-layers/&quot;&gt;Complete Guide to CSS Cascade Layers&lt;/a&gt; by Miriam Suzanne and the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Cascade_layers&quot;&gt;Cascade Layers guide on MDN&lt;/a&gt; by Estelle Weyl et al.
For this article, you just need to know that Cascade Layers is a new CSS feature that introduces new syntax.&lt;/p&gt;&lt;/aside&gt;

&lt;p&gt;Cascade Layers are part of Google Baseline. According to the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/@layer&quot;&gt;new browser support box on MDN&lt;/a&gt;, this feature is “widely supported” with the note added: &lt;q&gt;Baseline is determined by this web feature being supported on the current and the previous major versions of major browsers.&lt;/q&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/browser-support-layer-mdn.png&quot; alt=&quot;Screenshot: Browser support box for @layer on MDN. It reads: Baseline: Widely supported. Icons with green checkmarks for Chrome, Edge, Firefox and Safari.&quot; class=&quot;image-max-full&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The link “See full compatibility” brings you to the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/@layer#browser_compatibility&quot;&gt;browser compatibility table&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/browser-support-layer-mdn-compat-table.png&quot; alt=&quot;Screenshot: Browser support table for @layer. Checkmarks for all listed browsers each with the version that started support: Chrome 99, Edge 99, Firefox 97, Opera 85, Safari 15.4, Chrome Android 99, Firefox for Android 97, Opera Android 68, Safari on iOS 15.4, Samsung Internet 18.0, WebView Android 99. Samsung Internet is selected so the release date is shown: 2022-08-08.&quot; class=&quot;image-max-full&quot; /&gt;&lt;/p&gt;

&lt;p&gt;This table is very informative. It tells you that Cascade Layers were shipped in the listed browsers &lt;em&gt;last year&lt;/em&gt;. Firefox was the first (of the listed browsers) to ship support on 2022-02-08. Samsung Internet was the last (of the listed browsers) to ship support on 2022-08-08.&lt;/p&gt;

&lt;p&gt;We have learned that all major browser engines and evergreen browsers support it since August 2022. That is &lt;em&gt;nine months ago&lt;/em&gt;.&lt;/p&gt;

&lt;h2 id=&quot;reality-check-usage-relative-browser-support&quot;&gt;Reality check: Usage-relative browser support&lt;/h2&gt;

&lt;p&gt;Unfortunately, MDN does not tell you the &lt;strong&gt;market share of these browsers&lt;/strong&gt;. And MDN does not tell you about &lt;strong&gt;other browsers&lt;/strong&gt; that are actually used.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://caniuse.com/mdn-css_at-rules_layer&quot;&gt;The entry for @layer on Can I Use&lt;/a&gt; shows the same browser support data but puts them into perspective. If you select “Usage relative”, you get a stacked column chart with browser versions that support and do not support the feature.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/browser-support-layer-caniuse.png&quot; alt=&quot;Screenshot: Browser support box for @layer on Can I Use. It lists 14 browsers, including Chrome, Edge, Safari, Firefox, Opera, IE and their mobile counterparts. Red bars visualize browser versions that do not support @layer, sized by their market share. Green bar visualize browser versions that support @layer.&quot; class=&quot;image-max-full&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Can I Use also calculates a total percent based on the global browser market share. That percent value is a staggering 90.19%. That means Cascade Layers work for 9 out of 10 of your website visitors. They do not work for one visitor out of 10. This important fact is hidden behind the “widely supported” verdict of Baseline.&lt;/p&gt;

&lt;aside style=&quot;font-size: 80%&quot;&gt;&lt;p&gt;Disclaimer: Measuring browser market share is &lt;a href=&quot;https://en.wikipedia.org/wiki/Usage_share_of_web_browsers#Accuracy&quot;&gt;no exact science&lt;/a&gt;, but heuristics and estimation. There is no statistical survey on browser usage with a representative sample using robust measuring and reporting methods. Can I Use uses data from &lt;a href=&quot;https://gs.statcounter.com/browser-market-share&quot;&gt;StatCounter GlobalStats&lt;/a&gt; but allows you to import your own browser usage statistics from Google Analytics or Simple Analytics.&lt;/p&gt;&lt;/aside&gt;

&lt;p&gt;Where does this discrepancy stem from?&lt;/p&gt;

&lt;p&gt;MDN only states which browser versions started supporting the feature and when. It does not show market shares of the versions that do support and those that do not. This is unique to the “Usage relative” view of Can I Use.&lt;/p&gt;

&lt;p&gt;Evergreen browsers auto-update every month, but some people are still stuck on old versions that do not support Cascade Layers. Three examples:&lt;/p&gt;

&lt;ul class=&quot;compact-list&quot;&gt;
&lt;li&gt;2.11% of all web users are using Chrome &amp;lt; 99.&lt;/li&gt;
&lt;li&gt;0.95% are using desktop Safari &amp;lt; 15.4 and 1.74% are using mobile Safari &amp;lt; 15.4.&lt;/li&gt;
&lt;li&gt;0.65% are using Firefox &amp;lt; 97.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There is another reason why the MDN support table suggests 100% support while the actual global support is rather 90.19%: The MDN table &lt;strong&gt;omits browsers with a small market share&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;One of these is &lt;a href=&quot;https://en.wikipedia.org/wiki/UC_Browser&quot;&gt;UC Browser for Android&lt;/a&gt; published by the Chinese Alibaba Group. This browser has a global market share of 0.95%. It is based on a fork of Chromium 78. You heard right, in May 2023, UC Browser is stuck on a browser engine that was released in October 2019! Web developers in the Western world mostly ignore UC Browser, but it is still popular in India, Indonesia and China. These countries have a combined population of almost 3.1 billion people.&lt;/p&gt;

&lt;p&gt;While the individual percent values are rather small, they add up to 9.81%.&lt;/p&gt;

&lt;p&gt;This example illustrates that web authors need to check browser support for a feature and join it with browser market share data to get a clear impression. Can I Use is still the best tool for that. The simplistic “widely supported” claim of Baseline is not accurate.&lt;/p&gt;

&lt;h2 id=&quot;assessing-practical-backward-compatibility&quot;&gt;Assessing practical backward compatibility&lt;/h2&gt;

&lt;p&gt;The most important question is not how many browsers support the feature but &lt;strong&gt;what happens in browsers that do not support it&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This is where we need to examine the feature itself, Cascade Layers. Here is a simple but common example (see also Chris Coyier’s &lt;a href=&quot;https://chriscoyier.net/2023/04/10/whats-a-basic-use-case-for-cascade-layers-in-css/&quot;&gt;basic use case for Cascade Layers&lt;/a&gt;):&lt;/p&gt;

&lt;div class=&quot;language-html highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;html&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;lang=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;en&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;meta&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;charset=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;utf-8&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Cascade Layers example&lt;span class=&quot;nt&quot;&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;style&amp;gt;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;@layer&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bootstrap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;my-own-styles&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;@import&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&quot;https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;layer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bootstrap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;@layer&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;my-own-styles&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;button&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nl&quot;&gt;font-size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;2rem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;p&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;button&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;btn btn-primary&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;Activate me!&lt;span class=&quot;nt&quot;&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This document imports the Bootstrap library and assigns it to the layer &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bootstrap&lt;/code&gt;. We want to make sure that our own code always overwrites Bootstrap, without waging specificity wars against Bootstrap selectors.&lt;/p&gt;

&lt;p&gt;So we assign our code to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;my-own-styles&lt;/code&gt; layer and set the layer order so that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;my-own-styles&lt;/code&gt; is more important than &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bootstrap&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Voilà, the button has a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;font-size&lt;/code&gt; of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;2rem&lt;/code&gt; even though Bootstrap sets a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;font-size&lt;/code&gt; for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.btn&lt;/code&gt;, which has a higher specificity than &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;button&lt;/code&gt;. Without Cascade Layers, Bootstrap would win the specificity conflict. (We could use the same selector as Bootstrap in our code, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.btn&lt;/code&gt;. But this is what Cascade Layers make obsolete.)&lt;/p&gt;

&lt;p&gt;Now for the interesting part: &lt;strong&gt;How do older browsers without Cascade Layers support deal with this code?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The answer is, these browsers do not recognize &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@layer&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@import&lt;/code&gt; with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;layer()&lt;/code&gt; and therefore &lt;strong&gt;ignore the code&lt;/strong&gt;. They do not download Bootstrap either.&lt;/p&gt;

&lt;p&gt;Is this good or bad? It is rather good! They do not understand this newer syntax and continue parsing un-layered styles, if any.&lt;/p&gt;

&lt;p&gt;When using Cascade Layers, it makes sense to assign most of your styles to a layer. If you do so, these styles are not applied in 9.81% of the browsers.&lt;/p&gt;

&lt;p&gt;Unfortunately, it hard to use Cascade Layers in a backward-compatible way. &lt;a href=&quot;https://css-tricks.com/css-cascade-layers/#aa-browser-support-and-fallbacks&quot;&gt;As Miriam Suzanne wrote&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Since layers are intended as foundational building blocks of an entire CSS architecture, it is difficult to imagine building manual fallbacks in the same way you might for other CSS features. The fallbacks would likely involve duplicating large sections of code, with different selectors to manage cascade layering — or providing a much simpler fallback stylesheet.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href=&quot;https://www.smashingmagazine.com/2022/01/introduction-css-cascade-layers/#can-we-start-using-cascade-Layers&quot;&gt;Stephanie Eckles wrote&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;With new CSS features, we can often begin using them as a progressive enhancement. For example, with properties like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;aspect-ratio&lt;/code&gt; or selectors like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:is()&lt;/code&gt;, we can use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@supports&lt;/code&gt; to include new features while supporting fallbacks. Or, sometimes features can be added, and graceful degradation is acceptable without a comparable fallback.&lt;/p&gt;
&lt;p&gt;However, cascade layers are such an all-encompassing change that it will be difficult to start moving to use them until a polyfill is available. Unfortunately, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@supports&lt;/code&gt; doesn’t currently work with at-rules, and even if it did, it would not be entirely sufficient for cascade layers since unlayered styles always win over layered ones.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To recap:&lt;/p&gt;

&lt;ul class=&quot;compact-list&quot;&gt;
&lt;li&gt;We cannot use Cascade Layers as an enhancement step (Progressive Enhancement).&lt;/li&gt;
&lt;li&gt;There is no practical fallback possible without rewriting all layered styles (Graceful Degradation).&lt;/li&gt;
&lt;li&gt;&lt;span&gt;It is not possible to detect support for Cascade Layers in old browsers using HTML or CSS alone. It is possible to &lt;a href=&quot;https://supportscss.dev/&quot;&gt;detect support for Cascade Layers using JavaScript&lt;/a&gt; by checking for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;window.CSSLayerBlockRule&lt;/code&gt;.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;There is no easy way to serve Cascade Layer code to new browsers and legacy code to old browsers.&lt;/li&gt;
&lt;li&gt;&lt;span&gt;The good news is, there is a PostCSS-based &lt;a href=&quot;https://www.oddbird.net/2022/06/21/cascade-layers-polyfill/&quot;&gt;Cascade Layers polyfill&lt;/a&gt; that transforms &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@layer&lt;/code&gt; code into backward-compatible code. As you might expect, the polyfill has several limitations.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After having investigated the specific feature and the behavior of old browsers, we can ask the questions that Baseline tries to answer:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is it okay to start using the feature?&lt;/strong&gt; – It depends on the site you are building, your users and how you use the feature. If you are building a site for the global audience and find Cascade Layers useful, you should try whether the polyfill works on your code. If you are building for a limited audience with newer browsers, like for a corporate intranet, you can start using Cascade Layers without safeguards in place.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is it safe to use?&lt;/strong&gt; – Technically yes, since old browsers will ignore the new syntax because their CSS parsers are forwards-compatible. But you should not serve a site without styles to almost 10% of the users. Many sites are still readable without styles. But styles are not just decoration and veneer, they facilitate readability, usability, accessibility and interactivity. You should provide at least some basic styles to all browsers.&lt;/p&gt;

&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;/h2&gt;

&lt;p&gt;Google Baseline does not answer crucial browser compatibility questions. Baseline merely states that the latest version and the last but one version of certain evergreen browsers support a feature interoperably. This is good to know, but not enough to use the feature on your site in a safe manner.&lt;/p&gt;

&lt;p&gt;My fear is that Google’s Baseline initiative oversimplifies the discourse on browser support. Web authors will see “widely supported”, all-green checkmarks and alleged 100% browser support and use the feature without further examination. Web publishers will say “we require Baseline” without realizing that it means they only support two-month-old evergreen browsers plus the latest Safari.&lt;/p&gt;

&lt;p&gt;Coming back to the &lt;a href=&quot;https://web.dev/baseline/&quot;&gt;pursued benefits&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;When planning a project, rather than needing to list specific browser versions, you can set a requirement to use features that are part of Baseline.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;That is not enough. Please perform a market analysis to find out the browser usage in your audience. Then decide which browsers you want to support and find out how. Use Progressive Enhancement when planning a project.&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;When publishing a library, you can help potential users understand support of features used (and therefore whether it is safe to use on their site) by declaring support for Baseline.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;That is not enough. Please make deliberate browser support decisions and document them. Please state the individual browser versions the library requires. Please state how the library behaves in older browsers. Please use feature detection in your library. Please define your own baseline and state it in a machine-readable way using &lt;a href=&quot;https://browsersl.ist/&quot;&gt;Browserslist&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;When writing a tutorial, you can tell readers that everything described is in Baseline. Your reader then knows this is a solution they can incorporate into a project.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;That is not enough. Please explain how old browsers deal with the new code. Please explain how to use the feature as an enhancement or in a backward-compatible way.&lt;/p&gt;

&lt;p&gt;With new web technology features being shipped every four weeks, web authors need better practical guidance. I agree we need to unify and simplify browser support information.&lt;/p&gt;

&lt;p&gt;A better browser support box should center on practical and safe usage. A concise text should answer these questions: What is the percentage of users with browsers supporting the feature? How do old browsers deal with the feature? Can it be used as an enhancement? How to detect the feature? How to develop a fallback? Do polyfills exist?&lt;/p&gt;

&lt;p&gt;I believe this will enable web authors to develop modern sites using the latest browser features without impairing compatibility.&lt;/p&gt;
</description>
          <pubDate>Sat, 13 May 2023 00:00:00 +0200</pubDate>
          <link>https://molily.de/browser-compatibility-baseline/</link>
          <guid isPermaLink="true">https://molily.de/browser-compatibility-baseline/</guid>
          
          
        </item>
      
    
      
        <item>
          <title>ECMAScript modules and browser compatibility</title>
          <description>&lt;p&gt;One of the biggest changes in JavaScript in the last decade was the switch from loosely-connected scripts to ECMAScript modules (ESM). This affected both client-side and server-side JavaScript code.&lt;/p&gt;

&lt;p&gt;JavaScript programmers today take it for granted that they can pull a library dependency into client-side or server-side JavaScript code with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;npm install&lt;/code&gt; or other package managers that build on the npm registry. A decade ago, this crucial infrastructure was still in its infancy.&lt;/p&gt;

&lt;p&gt;In client-side JavaScript, an early module format was Asynchronous Module Definition (AMD). It was used together with pioneer loaders like RequireJS or &lt;a href=&quot;https://github.com/systemjs/systemjs&quot;&gt;SystemJS&lt;/a&gt; and bundlers like r.js. In server-side JavaScript runtimes, the CommonJS module specification predated Node.js but Node.js made it made popular from 2009 on.&lt;/p&gt;

&lt;h2 id=&quot;ecmascript-modules&quot;&gt;ECMAScript modules&lt;/h2&gt;

&lt;p&gt;In 2015, ECMAScript 6 standardized a declarative syntax for JavaScript files to import and export values.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;index.js:&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;helloWorld&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;./helloWorld.js&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;nf&quot;&gt;helloWorld&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;helloWorld.js:&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;helloWorld&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Hello world!&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Node.js experimentally supported ECMAScript modules in version 8.5.0 (September 2017). Since version 14 (April 2020), the implementation is no longer experimental. Since version 15.3.0 (November 2020), it is considered stable.&lt;/p&gt;

&lt;p&gt;It took fierce discussions to agree on &lt;a href=&quot;https://nodejs.org/api/packages.html#determining-module-system&quot;&gt;how Node handles ECMAScript modules&lt;/a&gt;, like specifying &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;type&quot;: &quot;module&quot;&lt;/code&gt; in package.json, handling .js, .mjs and .cjs files. The ecosystem-wide migration from CommonJS to ECMAScript modules is far from finished. It still keeps Node authors busy and causes headaches.&lt;/p&gt;

&lt;h1 id=&quot;ecmascript-modules-in-the-browsers&quot;&gt;ECMAScript modules in the browsers&lt;/h1&gt;

&lt;p&gt;For client-side JavaScript, authors quickly adopted ECMAScript modules when writing their code. Transpilers like &lt;a href=&quot;https://babeljs.io/&quot;&gt;Babel&lt;/a&gt; and bundlers like &lt;a href=&quot;https://rollupjs.org/&quot;&gt;Rollup&lt;/a&gt; and &lt;a href=&quot;https://webpack.js.org/&quot;&gt;Webpack&lt;/a&gt; understood ECMAScript modules early. The bundlers used the declarative imports and exports to understand the module dependency tree and to optimize the output bundles (“tree shaking”).&lt;/p&gt;

&lt;p&gt;However, browsers did not support ECMAScript modules natively yet. They did not understand the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;import&lt;/code&gt;/&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;export&lt;/code&gt; syntax yet. So the bundlers produced JavaScript files without ECMAScript module syntax.&lt;/p&gt;

&lt;p&gt;Webpack used its own mechanism for splitting code into &lt;em&gt;chunks&lt;/em&gt; and loading them dynamically. Rollup relies on the module loaders RequireJS or SystemJS to be present at runtime.&lt;/p&gt;

&lt;p&gt;In January 2016, &lt;a href=&quot;https://github.com/whatwg/html/pull/443&quot;&gt;the HTML specification was extended&lt;/a&gt; to introduce a new script type – module scripts. In these scripts, the familiar &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;import&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;export&lt;/code&gt; syntax can be used.&lt;/p&gt;

&lt;div class=&quot;language-html highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;script &lt;/span&gt;&lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;module&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// This is ECMAScript module code and module rules apply.&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// This code is evaluated in Strict Mode.&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// import and export may be used here.&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;helloWorld&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;./helloWorld.js&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nf&quot;&gt;helloWorld&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;&amp;lt;!--
The execution of the external module script is deferred.
That is, it is executed when the document is ready.
--&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;script &lt;/span&gt;&lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;module&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;src=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;externalModuleScript.js&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;For backwards-compatibility, &lt;a href=&quot;https://github.com/whatwg/html/pull/2261&quot;&gt;the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nomodule&lt;/code&gt; attribute for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;script&lt;/code&gt; was introduced&lt;/a&gt; in January 2017. Browsers with module support ignore these scripts. Old browser do not recognize the attribute, simply ignore it and execute the script as usual.&lt;/p&gt;

&lt;div class=&quot;language-html highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;script &lt;/span&gt;&lt;span class=&quot;na&quot;&gt;nomodule&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;src=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;scriptForOldBrowsers.js&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This allows web developers to ship two different versions of their code:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;One &lt;strong&gt;modern build&lt;/strong&gt; with native ECMAScript modules for new browsers.&lt;/li&gt;
  &lt;li&gt;One &lt;strong&gt;legacy build&lt;/strong&gt;, backwards-compatible with old browsers that lack support for ECMAScript modules.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Since May 2018, all major browser engines – Chrome 61 / Edge 79, Safari 11, Firefox 60 – &lt;a href=&quot;https://caniuse.com/es6-module&quot;&gt;support native ECMAScript modules&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Today, 95.69 % of all browsers worldwide fully support &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;script type=&quot;module&quot;&amp;gt;&lt;/code&gt;, according to Can I Use. The remaining 4.31 % have no support. Bear in mind that these values are global means. In your user base, in your audiences, the values may be lower or higher.&lt;/p&gt;

&lt;h2 id=&quot;ecmascript-modules-as-a-baseline&quot;&gt;ECMAScript modules as a baseline&lt;/h2&gt;

&lt;p&gt;The switch to ECMAScript modules for client-side code seems small at first sight. We do not need a module loader like SystemJS any longer and the shipped production code is more closer to the written code. This is it, or not?&lt;/p&gt;

&lt;p&gt;The crucial point is that ECMAScript module support may serve as a litmus test for several ECMAScript features and JavaScript APIs. The ECMAScript modules build is only downloaded and executed by the mentioned browsers. &lt;a href=&quot;https://philipwalton.com/articles/deploying-es2015-code-in-production-today/&quot;&gt;We know what they are capable of&lt;/a&gt; and may treat them as a baseline for the modern browser build.&lt;/p&gt;

&lt;p&gt;To support older browsers, transpiling ECMAScript 6+ code to ECMAScript 5 using Babel is a common practice. For our modern browser build, there is no need to. The targeted browsers fully support ECMAScript 6 and even some features of ECMAScript 7 (2016) and 8 (2017). We can skip the transpilation completely if we stick to supported syntax features. We can also skip certain feature detection and omit polyfills for supported APIs.&lt;/p&gt;

&lt;p&gt;The resulting modern build is smaller and faster. It is a clear win to ship ECMAScript module code to browsers that support it. But it requires developers to compile and embed two builds: the ECMAScript modules build and the legacy build for browsers without ECMAScript module support. Since the code of the two builds may differ considerably, developers need to test and debug both.&lt;/p&gt;

&lt;h2 id=&quot;dynamic-imports&quot;&gt;Dynamic imports&lt;/h2&gt;

&lt;p&gt;There is one missing piece in the puzzle: We still want to split the bundle into smaller chunks and load them lazily when the page actually needs the JavaScript code. Static imports load code eagerly. Bundlers like Webpack and Rollup would emit one gigantic JavaScript file even when an individual page just needs a tiny fraction of JavaScript.&lt;/p&gt;

&lt;p&gt;Enter dynamic imports. In addition to static, declarative import statements, ECMAScript 11 (2020) introduces &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import&quot;&gt;dynamic, programmatic import calls&lt;/a&gt;. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;import()&lt;/code&gt; is a function that expects the URL of the script and returns a promise:&lt;/p&gt;

&lt;div class=&quot;language-html highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;button&amp;gt;&lt;/span&gt;Say hello!&lt;span class=&quot;nt&quot;&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;script &lt;/span&gt;&lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;module&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;button&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;click&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;async &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// Load code dynamically when the user interacts&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;helloWorld&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;./helloWorld.js&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;helloWorld&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Dynamic imports are supported by all major browser engines since Chrome 63 (December 2017), Safari 11.1 (April 2018) and Firefox 67 (May 2019). Edge 79 (January 2020) was the last browser to support them, when Microsoft switched from EdgeHTML to Chromium and the Blink engine.&lt;/p&gt;

&lt;p&gt;Compare this to the support for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;script type=&quot;module&quot;&amp;gt;&lt;/code&gt;: Chrome 61 (September 2017) / Edge 79 (January 2020), Safari 11 (September 2017) and Firefox 60 (May 2018).&lt;/p&gt;

&lt;h2 id=&quot;intermediate-browsers&quot;&gt;Intermediate browsers&lt;/h2&gt;

&lt;p&gt;There is a small range of browser versions that do support ECMAScript modules but not dynamic imports: Chrome 61 to 62, Firefox 60 to 66, Edge 16 to 78 and Safari 10.3 to 11.0.&lt;/p&gt;

&lt;p&gt;Luckily, these browser versions are hardly relevant in 2023. Only few users are stuck on old versions of Chrome, new Edge and Firefox. These “evergreen” browsers are updated automatically to a new major version every month. Safari does not update that often, but the version range 11 (September 2017) to 11.1 (April 2018) is tiny.&lt;/p&gt;

&lt;p&gt;How should we deal with these intermediate browsers? We have two options:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Serve them the modern build, but do not use native dynamic imports. Use a module loader like SystemJS for importing code dynamically.&lt;/li&gt;
  &lt;li&gt;Serve them the legacy build without ECMAScript module code and without dynamic imports. Use a module loader like SystemJS for dynamic imports.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Because of the small market share of intermediate browsers, most projects use native dynamic imports and put intermediate browsers into one bucket with old browsers.&lt;/p&gt;

&lt;p&gt;Shifting the baseline to browsers that support dynamic imports gives us even more freedom for what is possible in the modern build.&lt;/p&gt;

&lt;h2 id=&quot;detecting-support-for-dynamic-imports&quot;&gt;Detecting support for dynamic imports&lt;/h2&gt;

&lt;p&gt;But how do we serve the legacy build to intermediate browser? The combination of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;script type=&quot;module&quot;&amp;gt;&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;script nomodule&amp;gt;&lt;/code&gt; allows us to create a conditional loader: If the browser supports ECMAScript modules, load the modern build, otherwise load the legacy build.&lt;/p&gt;

&lt;p&gt;Unfortunately, there is no simple conditional loader for scripts using dynamic imports. This feature cannot be detected easily. The reason is that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;import&lt;/code&gt; is a reserved word in ECMAScript. Reserved words cannot be used in expressions where an identifier is expected.&lt;/p&gt;

&lt;p&gt;If an intermediate browser parses a script with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;import(&apos;…&apos;)&lt;/code&gt;, it fails with a syntax error. When the parsing fails, the browser cannot execute the code.&lt;/p&gt;

&lt;div class=&quot;language-html highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;script &lt;/span&gt;&lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;module&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// Wrap code in a function to prevent a top-level await.&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;async &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// The next line raises a SyntaxError in intermediate browsers.&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;helloWorld&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;./helloWorld.js&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// The next line in only executed if the browser supports&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// dynamic imports. It is never executed in intermediate browsers.&lt;/span&gt;
  &lt;span class=&quot;nf&quot;&gt;helloWorld&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;})();&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

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

&lt;p&gt;Luckily, the syntax error that prevents execution already hints at a possible solution. To detect support for dynamic imports – we perform a dynamic import! If the browser executes the imported code and the code after the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;import()&lt;/code&gt; call, it is a new browser. If the browser does not execute the code, it is an intermediate browser.&lt;/p&gt;

&lt;p&gt;We use dynamic imports to load the bundle that in turn uses dynamic imports. This guarantees us that only capable browsers execute the code. All other browsers are served the legacy bundle.&lt;/p&gt;

&lt;div class=&quot;language-html highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;script &lt;/span&gt;&lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;module&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// Try to load bundle for modern browsers.&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;./bundle-with-dynamic-imports.js&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// Set a global flag that the browser supports dynamic imports.&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;window&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;__browserSupportsDynamicImports&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;script &lt;/span&gt;&lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;module&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// This script is executed in browsers with ECMAScript module support.&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// If we cannot find the flag, the browser must be intermediate!&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;window&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;__browserSupportsDynamicImports&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// Load the legacy build.&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;script&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;createElement&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;script&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;script&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;src&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;./legacy-build.js&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;head&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;appendChild&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;script&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;&amp;lt;!-- Legacy build for browsers without ECMAScript module support. --&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;script &lt;/span&gt;&lt;span class=&quot;na&quot;&gt;nomodule&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;src=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;./legacy-build.js&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;vites-legacy-plugin&quot;&gt;Vite’s legacy plugin&lt;/h2&gt;

&lt;p&gt;This structure of the snippet above is adapted from the &lt;a href=&quot;https://github.com/vitejs/vite/tree/main/packages/plugin-legacy&quot;&gt;legacy plugin for the Vite build tool&lt;/a&gt;. With &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@vitejs/plugin-legacy&lt;/code&gt;, Vite compiles two builds:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;The &lt;em&gt;modern build&lt;/em&gt; with an entry script and chunks for modern browsers that support ECMAScript module and dynamic imports.&lt;/li&gt;
  &lt;li&gt;The &lt;em&gt;legacy build&lt;/em&gt; with an entry script and chunks for legacy browsers. The code is transpiled with Babel.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The actual cross-browser Vite embed code is much more sophisticated: Vite detects support for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;import.meta.url&lt;/code&gt;, dynamic imports and async generators in one script. If these three features are supported, it sets the flag &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;__vite_is_modern_browser&lt;/code&gt;. If this flag is &lt;em&gt;not&lt;/em&gt; set, it first loads the &lt;em&gt;legacy polyfill&lt;/em&gt; which contains SystemJS and, well, polyfills. Using SystemJS, it then loads the &lt;em&gt;legacy entry&lt;/em&gt;. (This is the equivalent to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;legacy-build.js&lt;/code&gt; in the example above.)&lt;/p&gt;

&lt;p&gt;Vite also deals with a nasty problem of Safari 10.1, released in March 2017. This browser has impartial support for ECMAScript modules. It supports &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;script type=&quot;module&quot;&amp;gt;&lt;/code&gt; but not &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;script nomodule&amp;gt;&lt;/code&gt; and therefore executes both code. Vite includes a &lt;a href=&quot;https://gist.github.com/samthor/64b114e4a4f539915a95b91ffd340acc&quot;&gt;workaround that prevents Safari 10.1 from executing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nomodule&lt;/code&gt; scripts&lt;/a&gt;. Fortunately, this problem has been fixed in Safari 11.&lt;/p&gt;

&lt;h2 id=&quot;module-preload&quot;&gt;Module preload&lt;/h2&gt;

&lt;p&gt;If you use dynamic imports frequently in your code base or have several entry points that share library code, bundlers like Rollup will create many small chunks. An individual page will load numerous small JavaScript files even if there is little JavaScript interactivity.&lt;/p&gt;

&lt;p&gt;This is not necessarily a performance penalty since HTTP/2 multiplexing can request and receive many resources in parallel. Once these small chunks with reused library code are cached in the browser, subsequent pages have an excellent loading performance.&lt;/p&gt;

&lt;p&gt;But often the dependency graph is a chain: a.js imports b.js, b.js imports c.js, for example. If there are other lazy-loaded modules pointing to b.js and c.js, the code does not end up in one chunk, but in three chunks.&lt;/p&gt;

&lt;p&gt;When a page embeds a.js, a request waterfall happens. The browser downloads a.js, b.js and c.js subsequently, not in parallel. It downloads a.js, finds the import of b.js, downloads b.js, finds the import of c.js, downloads c.js. Finally, the browser is able to execute a.js after all dependencies have been loaded in sequence.&lt;/p&gt;

&lt;p&gt;Depending on the network bandwidth and latency (round-trip time), this is a performance nightmare. To mitigate this problem, Vite analyzes the module graph and adds &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/rel/modulepreload&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;link rel=&quot;modulepreload&quot;&amp;gt;&lt;/code&gt;&lt;/a&gt; elements to the page. So when the page embeds a.js with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;script type=&quot;module&quot; src=&quot;a.js&quot;&amp;gt;&lt;/code&gt;, Vite will add &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;link rel=&quot;modulepreload&quot;&amp;gt;&lt;/code&gt; for b.js and c.js. The browser then requests and downloads a.js, b.js and c.js in parallel, utilizing the full available bandwidth.&lt;/p&gt;

&lt;p&gt;This improves the cold boot performance while using many small chunks with the minimal amount of JavaScript necessary for a certain page.&lt;/p&gt;

&lt;h2 id=&quot;pragmatic-compatibility-with-old-browsers&quot;&gt;Pragmatic compatibility with old browsers&lt;/h2&gt;

&lt;p&gt;Vite is an example for a mature build tool that helps you ship ECMAScript modules. It supports old as well as intermediate browsers and optimizes the performance for modern browsers. This blog post cannot get into all details of Vite’s strategy.&lt;/p&gt;

&lt;p&gt;For your project, you need to decide which browser capabilities are required and which browsers you can support easily.&lt;/p&gt;

&lt;p&gt;For example, I am currently working on a JavaScript library for a client. The library does not actively support old browsers without ECMAScript module support, it does so passively. With little effort, old browsers get a basic functionality. We have a pragmatic approach:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;There is ECMAScript syntax that can be transpiled easily and there are browser APIs that can be polyfilled easily. We make sure to include these polyfills and configure Babel to &lt;a href=&quot;https://babeljs.io/docs/babel-preset-env&quot;&gt;perform the right transformations to support a certain list of browsers&lt;/a&gt;. See also the &lt;a href=&quot;https://github.com/vitejs/vite/tree/main/packages/plugin-legacy#targets&quot;&gt;Vite legacy plugin options&lt;/a&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;targets&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;polyfills&lt;/code&gt;.&lt;/p&gt;

    &lt;p&gt;These polyfills and transformations typically affect the legacy bundle only since the baseline for the modern build is already quite high.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;There is ECMAScript syntax that cannot be transpiled and there are browser APIs that cannot be polyfilled with reasonable effort.&lt;/p&gt;
    &lt;ul&gt;
      &lt;li&gt;If we do not strictly need these capabilities, we do not use them. We check browser support before using a JavaScript feature to avoid raising the bar for no important reason.&lt;/li&gt;
      &lt;li&gt;If these capabilities are highly beneficial, we use them in browsers which support them, guarded by feature detection. We make sure that older browsers do not throw parsing or runtime errors. We write &lt;a href=&quot;https://molily.de/robust-javascript/&quot;&gt;robust JavaScript&lt;/a&gt;.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;how-frameworks-employ-ecmascript-modules&quot;&gt;How frameworks employ ECMAScript modules&lt;/h2&gt;

&lt;p&gt;When all major browser engines implemented support for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;script type=&quot;module&quot;&amp;gt;&lt;/code&gt; in 2018, JavaScript programmers and projects started to switch.&lt;/p&gt;

&lt;p&gt;How is the situation today? What is the strategy of popular build tools and frameworks?&lt;/p&gt;

&lt;p&gt;Here is a quick survey:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Vite&lt;/strong&gt;: ECMAScript modules per default. Option to support older browsers with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@vitejs/plugin-legacy&lt;/code&gt; (see above).&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;create-vue@3&lt;/strong&gt;: Uses Vite and has the same defaults, supports &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@vitejs/plugin-legacy&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;create-react-app&lt;/strong&gt;: Does not use ECMAScript modules. Uses Babel and supports polyfills.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Astro&lt;/strong&gt;: Does not use ECMAScript modules. But the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;astro-island&lt;/code&gt; custom element uses dynamic imports without feature detection or fallback. So the minimal required browser needs to support both &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;customElements.define()&lt;/code&gt; and dynamic imports.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Angular CLI&lt;/strong&gt;: ECMAScript module build only. &lt;a href=&quot;https://angular.io/guide/browser-support&quot;&gt;Angular only supports most recent browsers&lt;/a&gt;. Angular uses dynamic imports for route-level code splitting. (Angular 16 allows to use Vite as dev server, but the production build works the same.)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Next.js&lt;/strong&gt;: Does not use ECMAScript modules. Uses &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nomodule&lt;/code&gt; to load polyfills though. Allows to &lt;a href=&quot;https://nextjs.org/docs/basic-features/supported-browsers-features&quot;&gt;configure Babel and load polyfills&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Nuxt.js&lt;/strong&gt;: Does not use ECMAScript modules. One build per default. Allows to &lt;a href=&quot;https://nuxtjs.org/docs/configuration-glossary/configuration-modern/&quot;&gt;build and serve a modern and a legacy build&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Sveltekit&lt;/strong&gt;: Uses dynamic imports without feature detection or fallback. Sveltekit uses Vite under the hood, but &lt;a href=&quot;https://github.com/sveltejs/kit/issues/12&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@vitejs/plugin-legacy&lt;/code&gt; currently does not work with Sveltekit&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Remix&lt;/strong&gt;: ECMAScript modules and dynamic imports only. On purpose, &lt;a href=&quot;https://remix.run/docs/en/main/guides/browser-support&quot;&gt;Remix runs in browsers that support ECMAScript modules&lt;/a&gt;. Remix supports older browser by not serving them JavaScript, falling back to server-side logic.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This overview merely describes, but does not judge the different approaches. While backwards compatibility is a virtue, each framework and site author need to decide on the minimum browser requirements and how to support browsers that do not meet them.&lt;/p&gt;

&lt;h2 id=&quot;cutting-the-mustard-with-ecmascript-modules&quot;&gt;Cutting the mustard with ECMAScript modules&lt;/h2&gt;

&lt;p&gt;Back in 2012, developers at the BBC used Progressive Enhancement to deliver a robust site to all browsers. The core experience in plain HTML worked without JavaScript. The developers guarded the JavaScript with feature detects so it only executed in browsers that “&lt;a href=&quot;http://web.archive.org/web/20201209062357/http://responsivenews.co.uk/post/18948466399/cutting-the-mustard&quot;&gt;cut the mustard&lt;/a&gt;”, that is, meet a certain mark.&lt;/p&gt;

&lt;p&gt;This technique absolved developers from writing convoluted, backwards-compatible JavaScript. It made the JavaScript simpler and more robust since it did not have to deal with every eventuality.&lt;/p&gt;

&lt;p&gt;Since 2018, several &lt;a href=&quot;https://fettblog.eu/cutting-the-mustard-2018/&quot;&gt;developers have been proposing ECMAScript modules as a new way to cut the mustard&lt;/a&gt;. As you can see in the list above, several frameworks are applying this approach.&lt;/p&gt;

&lt;p&gt;Not all frameworks use Progressive Enhancement or Graceful Degradation. Not all frameworks have a strategy for browsers that do not meet the minimum requirements. For some frameworks, the site is just empty or broken in these browsers.&lt;/p&gt;

&lt;p&gt;It is hard to even find out the minimum requirements of popular frameworks today. Only few state them explicitly. Most tacitly use JavaScript APIs or ECMAScript features introduced recently without realizing that this raises the bar of entry.&lt;/p&gt;

&lt;h2 id=&quot;using-new-ecmascript-syntax-safely-the-optional-chaining-operator&quot;&gt;Using new ECMAScript syntax safely: The optional chaining operator&lt;/h2&gt;

&lt;p&gt;Unfortunately, developers often raise the bar unintentionally. For example, I like the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining&quot;&gt;optional chaining operator&lt;/a&gt;. It helps to write more robust code.&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;user&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Robin&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// The user might have an address or not&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;address&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;street&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Technically, optional chaining is “syntactic sugar”: a shorter, more readable way to write a logic that was already possible before. Syntactic sugar can easily be transpiled into older syntax with broader support:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;user&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Robin&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// The user might have an address or not&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;street&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;address&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;address&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;street&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;undefined&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;street&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Historically, optional chaining is a relatively new addition to ECMAScript. It was introduced in ECMAScript 11, published in June 2020. The major browser engines already shipped support in February or March 2020 when the corresponding proposal was finished.&lt;/p&gt;

&lt;p&gt;By the way – ECMAScript 11 is the same edition that introduced &lt;a href=&quot;dynamic-imports&quot;&gt;dynamic imports described above&lt;/a&gt;. But browsers started to support dynamic imports much earlier than optional chaining.&lt;/p&gt;

&lt;p&gt;Today, optional chaining &lt;a href=&quot;https://caniuse.com/mdn-javascript_operators_optional_chaining&quot;&gt;is supported by 93.33 % browsers worldwide, according to Can I Use&lt;/a&gt;. 6.67 % of all used browsers do not support it. Some of them will execute the modern build but will not support optional chaining.&lt;/p&gt;

&lt;p&gt;Recently, Jim Nielsen described in his blog post &lt;a href=&quot;https://blog.jim-nielsen.com/2022/a-web-for-all/&quot;&gt;The Optional Chaining Operator, “Modern” Browsers, and My Mom&lt;/a&gt; what happens when new JavaScript syntax is used without caution:&lt;/p&gt;

&lt;blockquote cite=&quot;https://blog.jim-nielsen.com/2022/a-web-for-all/&quot;&gt;

  &lt;p&gt;The real-life impact of our technical decisions really hit home to me once again: my Mom had trouble volunteering and participating in her local community because somebody shipped the optional chaining operator in their production JavaScript.&lt;/p&gt;

&lt;/blockquote&gt;

&lt;p&gt;If you use new syntax features, do so consciously and mind the consequences. New syntax raises the bar and may thwart previous efforts to support older browsers.&lt;/p&gt;

&lt;p&gt;To use the optional chaining operator safely, we can apply the knowledge from &lt;a href=&quot;#detecting-support-for-dynamic-imports&quot;&gt;detecting support for dynamic imports&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We can either &lt;a href=&quot;https://babeljs.io/docs/babel-plugin-proposal-optional-chaining&quot;&gt;transpile it to more robust syntax using Babel with @babel/preset-env&lt;/a&gt; – both in the modern and the legacy build.&lt;/p&gt;

&lt;p&gt;Or we detect the browser support by using optional chaining and setting a flag. If the browser parses the code and sets the flag, we load the modern build that may use optional chaining right away.&lt;/p&gt;

&lt;p&gt;We did similar with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;window.__browserSupportsDynamicImports&lt;/code&gt; above. As we have learned, Vite checks for multiple syntax features and sets &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;__vite_is_modern_browser&lt;/code&gt;. Let us integrate two syntax checks into one script that sets &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;window.__isModernBrowser&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-html highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;&amp;lt;!-- Litmus test that uses modern syntax and sets a flag. --&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;script &lt;/span&gt;&lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;module&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// Try to use optional chaining. This code does nothing on&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// new browsers and causes a syntax error on old browsers.&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;window&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;__testingOptionalChaining&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// Load modern build with dynamic import. It is safe to use&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// dynamic imports and optional chaining in the build.&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;./modern-build.js&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// Set a global flag that the browser passed the litmus test.&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;window&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;__isModernBrowser&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;script &lt;/span&gt;&lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;module&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// This script is executed in browsers with ECMAScript module&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// support. If the flag is not set, the browser did not pass&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// the litmus test.&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;window&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;__isModernBrowser&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// Load the legacy build.&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;script&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;createElement&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;script&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;script&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;src&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;./legacy-build.js&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;head&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;appendChild&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;script&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;&amp;lt;!-- Legacy build for browsers without ECMAScript module support. --&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;script &lt;/span&gt;&lt;span class=&quot;na&quot;&gt;nomodule&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;src=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;./legacy-build.js&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;the-future&quot;&gt;The future&lt;/h2&gt;

&lt;p&gt;The ECMAScript standard and browser APIs keep evolving. Many innovations make it easier to deliver small, fast, custom-fit JavaScript to the browser.&lt;/p&gt;

&lt;p&gt;There are several upcoming features that will make ECMAScript modules in the browser more powerful. &lt;a href=&quot;https://github.com/WICG/import-maps&quot;&gt;Import maps&lt;/a&gt; is one of them. Since March 2023, all major browser engine support import maps. With imports maps, you do not necessarily need a traditional package manager and a module bundler to import third-party dependencies.&lt;/p&gt;

&lt;p&gt;Luckily, there is a &lt;a href=&quot;https://github.com/guybedford/es-module-shims&quot;&gt;shim for import maps&lt;/a&gt;. Note that it is highly complex since it fetches, parses and rewrites the module code right in the browser before executing it.&lt;/p&gt;

&lt;p&gt;Even if we take ECMAScript modules, dynamic imports and potentially more features as a baseline for our JavaScript, we constantly need to think about browser compatibility. The nature of the web has not changed. We always have to deal with diverse browsers with hugely different capabilities.&lt;/p&gt;

&lt;p&gt;Therefore we still need Progressive Enhancement and Graceful Degradation. If we use the latest JavaScript features and want to support slightly older browsers, we still need two builds. We will still need transpilation, feature detects and polyfills in the future.&lt;/p&gt;
</description>
          <pubDate>Fri, 21 Apr 2023 00:00:00 +0200</pubDate>
          <link>https://molily.de/ecmascript-modules/</link>
          <guid isPermaLink="true">https://molily.de/ecmascript-modules/</guid>
          
          
        </item>
      
    
      
        <item>
          <title>Client-side JavaScript and React criticism: What comes next?</title>
          <description>&lt;p&gt;&lt;em&gt;A continuation of &lt;a href=&quot;/update-on-robust-javascript/&quot;&gt;An update on Robust Client-Side JavaScript – Where is client-side JavaScript heading?&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;the-great-divide-is-now-a-great-war&quot;&gt;The Great Divide is now a Great War&lt;/h2&gt;

&lt;p&gt;JavaScript critics are effing mad right now. For well-documented reasons. And they do not mince matters any longer. The web development community has never been so divided. The &lt;a href=&quot;https://css-tricks.com/the-great-divide/&quot;&gt;Great Divide&lt;/a&gt; is now a Great War.&lt;/p&gt;

&lt;p&gt;Critics mostly talk to their kind on Mastodon while most of the client-side JavaScript authors still converse on Twitter. Both groups rant and rave in their respective echo chambers.&lt;/p&gt;

&lt;p&gt;I acknowledge the frustration and anger of JavaScript critics. It accumulated over years. Their articles, talks and Twitter posts are records on struggling with client-side JavaScript practices and intervening into discussions.&lt;/p&gt;

&lt;p&gt;My question is: Given the dire situation we have, the divided web development community we have, where do we go now and what comes next? How do we cut the Gordian knot? How do we reconcile?&lt;/p&gt;

&lt;p&gt;First of all, do we want to reconcile? Or are we fine with the divide? Are we fine with bridges burning? Are we fine with smart people on both sides ridicule and insult each other? Is this the new normal?&lt;/p&gt;

&lt;h2 id=&quot;sermons-and-insults&quot;&gt;Sermons and insults&lt;/h2&gt;

&lt;p&gt;I hear JavaScript critics yelling: “Just use Progressive Enhancement! Sprinkle some JavaScript on your static HTML! Don’t believe those fraudsters, grifters, bastards, idiots that lied to you!”&lt;/p&gt;

&lt;p&gt;Again, I understand the frustration. Nonetheless, I don’t think the current situation can be explained in terms of fraud, lies, gaslighting et cetera. While there are powerful actors with certain economic interests, &lt;a href=&quot;https://seldo.com/posts/the_case_for_frameworks&quot;&gt;there is no “Big JavaScript” conspiracy, no JavaScript framework cabal&lt;/a&gt; that has lied to us to sell us their sub-par products.&lt;/p&gt;

&lt;p&gt;Even if certain individuals would be to blame – critics personally blame JavaScript framework maintainers and the giant tech corporations they work for –, I don’t see much value in doing so.&lt;/p&gt;

&lt;p&gt;I don’t have a grande theory that explains how we got into the current mess. I have a rather technical explanation: &lt;a href=&quot;https://en.wikipedia.org/wiki/Path_dependence&quot;&gt;Path dependence&lt;/a&gt; and technology lock-in. We didn’t start with the React single-page apps we have today. It was a series of small steps where each step seemed rational and logical at the time but lead to a poor outcome.&lt;/p&gt;

&lt;p&gt;We started with DOM Scripting during the Browser Wars, then came Ajax and client-side JavaScript exploded. Libraries like Backbone.js helped to structure client-side JavaScript in order to implement dynamic interfaces. Then came React and solved a specific problem, more on that later. React brought up new problems one obviously doesn’t face without React, but React users had to deal with them.&lt;/p&gt;

&lt;p&gt;There are also several economic explanations for React’s rise to power and continued dominance. For example, in 2019, &lt;a href=&quot;http://web.archive.org/web/20210805020051/https://whalecoiner.com/articles/react&quot;&gt;Charlie O’Hara described React&lt;/a&gt; as the Fordism moment that commodified the web further. With React, Facebook introduced an assembly line that standardized the work for developers, turning them from artisans into factory workers.&lt;/p&gt;

&lt;h2 id=&quot;shifting-the-ecosystem&quot;&gt;Shifting the ecosystem&lt;/h2&gt;

&lt;p&gt;Back to the message that JavaScript critics are sending right now. I don’t think that we can convince anyone with a sermon that is half truism and half insult. We have been shouting “use Progressive Enhancement, duh!” for almost two decades – just like Sisyphus is sentenced to roll up a boulder ad infinitum after evading and outsmarting death many times. The recent addition – the insults – doesn’t make the message more convincing.&lt;/p&gt;

&lt;p&gt;Given the mess web developers are stuck in right now, I don’t expect them to act accordingly. There is no easy way out for organizations that have invested in heavy client-side JavaScript architectures. Especially React doesn’t provide escape hatches. That is the core problem that critics describe so well. &lt;a href=&quot;https://joshcollinsworth.com/blog/self-fulfilling-prophecy-of-react&quot;&gt;React is a one-way road&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;So I see no other option than to shift the JavaScript ecosystem gradually, which ironically is what some critics refuse. In particular, I don’t understand why they refuse “transitional” concepts like the &lt;a href=&quot;https://jasonformat.com/islands-architecture/&quot;&gt;Island Architecture&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;“Islands” is the rebranding that progressive enhancement never should have needed.&lt;/p&gt;

  &lt;p&gt;The problem with progressive enhancement is by nature, it means you have to care about users, whereas “Islands” means developers can continue pretending users don’t exist.&lt;/p&gt;

  &lt;p&gt;– &lt;a href=&quot;https://bell.bz/@andy/109919510521244054&quot;&gt;Andy Bell&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Granted, “islands” aren’t the user-centric breakthrough that we might have wished for. But it’s useful to explain the concept of Progressive Enhancement to someone who is stuck knee-deep in a certain thinking, programming practice, tooling and legacy code. If we want to improve their JavaScript usage, we have to pull them out of that bog. We need to give them better tools that enable them to do the right thing.&lt;/p&gt;

&lt;h2 id=&quot;sprinkling-javascript&quot;&gt;Sprinkling JavaScript&lt;/h2&gt;

&lt;p&gt;At the same time, we should be honest that a web site doesn’t magically get more robust and performant if web developers ditch React or whatever megabyte-heavy JavaScript stack they are using right now.&lt;/p&gt;

&lt;p&gt;For more than 20 years, I’ve sprinkled JavaScript on HTML, I’ve built with Progressive Enhancement in mind, I’ve helped people fixing their JavaScript, with and without frameworks.&lt;/p&gt;

&lt;p&gt;One thing I have learned and do not get tired mentioning is that “vanilla” JavaScript is a clusterfuck as well. I don’t recommend writing client-side JavaScript without a proper concept, without proven patterns and tools. Without guidance and guardrails, you’ll end up with a buggy, slow, incoherent, insecure and unmaintainable site.&lt;/p&gt;

&lt;p&gt;The beauty and joy of client-side JavaScript is that there is no inherent purpose or limit. That means that Thou Shalt set up rules and restrain yourself to make your JavaScript benefit the user.&lt;/p&gt;

&lt;p&gt;Progressive Enhancement provides guardrails, but so do frameworks. To illustrate that, let me tell you from the Golden Age of jQuery and Ajax, before component libraries like React took over. What did “sprinkle JavaScript on top of HTML” mean back then?&lt;/p&gt;

&lt;p&gt;Two-thirds of your front-end logic was server-delivered, declarative HTML and CSS. The other two-thirds was imperative, low-level jQuery DOM manipulation, event handling, setting classes and inline styles.&lt;/p&gt;

&lt;p&gt;The user session and the user interface state was two-thirds on the server, two-thirds on the client. Again, the client state was two-thirds in the DOM – as element presence, classes, data attributes, JSON etc. The other two-thirds was in JavaScript variables, most of them global.&lt;/p&gt;

&lt;p&gt;Yes, there was roughly one third overlap and duplication, but no proper connection or binding. There was no easy state change and automatic DOM update. This was a developing nightmare.&lt;/p&gt;

&lt;p&gt;More importantly, such interfaces were error-prone and brittle. They failed their users. A user could easily get into a &lt;i&gt;kaput&lt;/i&gt; state.&lt;/p&gt;

&lt;p&gt;It was React that introduced the concept that &lt;a href=&quot;https://www.kn8.lt/blog/ui-is-a-function-of-data/&quot;&gt;the user interface is a function of the application state&lt;/a&gt;. The page DOM should always reflect the application state properly and consistently. This concept is not a fancy legitimation for single-page apps, it addresses problems every tiny JavaScript widget deals with.&lt;/p&gt;

&lt;p&gt;React came at the expense of sucking HTML (JSX) and later CSS (CSS-in-JS) into its dysfunctional vortex. Better frameworks let you write plain HTML with non-invasive template logic and plain CSS or Sass that is component-scoped per default. They allow to define the intersections of HTML, CSS and JavaScript more clearly so they can render static pages, mangle and optimize the JavaScript code on compile time, then “hydrate partially” or “resume” what is left on the client.&lt;/p&gt;

&lt;p&gt;These frameworks are still the opposite of sprinkling JavaScript onto your HTML. And I think this is totally fine as long as the outcome is an accessible, performant and robust web site.&lt;/p&gt;

&lt;h2 id=&quot;enhancing-progressively-with-javascript&quot;&gt;Enhancing progressively with JavaScript&lt;/h2&gt;

&lt;p&gt;Last but not least, if we tell web developers to “use Progressive Enhancement, duh!”, especially developers bogged down in React single-page apps, we need to bring along a bouquet of tutorials, best practices and case studies that reflect their needs.&lt;/p&gt;

&lt;p&gt;Enhancing progressively with JavaScript means that many practical questions pop up. How do users access and use my site? What are the common points of failure? What is my technical baseline, what is the core functionality? Which enhancement steps do I pick assuming that every step needs a user? How do I bundle enhancements? How do I implement the enhancement steps? What can I achieve with server-side logic, HTML, CSS; which interactions are more user-friendly and even more robust in client-side JavaScript? Can the enhancement steps and different experiences incrementally build on each other? If not, how does the switch from one step to the next look and feel for the user? How do I keep steps in sync and reduce duplication? How to fight fragmentation? How do I guarantee that enhancements are as robust as possible? How do I prevent failure? How do I deal with failure? How do I measure and verify that my Progressive Enhancement approach improved the experience for the different users and situations? […]&lt;/p&gt;

&lt;p&gt;I’ll stop here, you get the idea. These are questions me and my colleagues are dealing with every day.&lt;/p&gt;

&lt;p&gt;By nature, Progressive Enhancement means deep research and learning by doing. Most advocates though tell you that building web sites with Progressive Enhancement is easier and the resulting site gets simpler. They argue that a “minimal viable product” approach will do away with unnecessary complexity of JavaScript-heavy front-ends.&lt;/p&gt;

&lt;p&gt;There are certainly sites whose core functionality can be implemented with server-rendered forms and minimal JavaScript logic. Even then, how are the enhancement steps implemented that enable users to achieve their tasks faster? Web developers will not – and in my opinion should not – keep their hands off highly dynamic client-side interactivity and associated frameworks.&lt;/p&gt;

&lt;p&gt;For many years, I’ve lamented that only a few people discuss and explore practical Progressive Enhancement with JavaScript on complex sites and web applications that currently default to React monoliths. Seriously, I cannot read another tutorial on Progressive Enhancement that operates on trivial examples that allow straight-forward enhancements or require little client-side JavaScript at all. I wouldn’t even recommend them to my colleagues since they don’t address their practical problems.&lt;/p&gt;

&lt;p&gt;I’ve created technical demos myself to research and teach certain Progressive Enhancement and robust JavaScript techniques. That is totally fine, but in practice we have highly dynamic web applications that solve complex problems. They are slow, brittle, buggy and inaccessible. Progressive Enhancement can help, among other practices. We need to empower web developers to enhance progressively with JavaScript. Again, that means giving them a bouquet of approachable and adoptable best practices.&lt;/p&gt;
</description>
          <pubDate>Fri, 03 Mar 2023 00:00:00 +0100</pubDate>
          <link>https://molily.de/javascript-criticism/</link>
          <guid isPermaLink="true">https://molily.de/javascript-criticism/</guid>
          
          
        </item>
      
    
      
        <item>
          <title>An update on Robust Client-Side JavaScript</title>
          <description>&lt;p&gt;In 2017, I published the online book &lt;strong&gt;&lt;a href=&quot;/robust-javascript/&quot;&gt;Robust Client-Side JavaScript – A Developer’s Guide&lt;/a&gt;&lt;/strong&gt;. More than five years later, I think my advice is still valuable. JavaScript as a language has not changed much when it come to techniques for writing robust code.&lt;/p&gt;

&lt;p&gt;At the moment I do not have the time for a substantial book update. In this post, I would like to describe how I regard the whole issue today and how I would restructure the book today.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Update from the future:&lt;/em&gt; In March 2023, I’ve published the continuation &lt;a href=&quot;/javascript-criticism/&quot;&gt;Client-side JavaScript and React criticism: What comes next?&lt;/a&gt;.&lt;/p&gt;

&lt;svg class=&quot;separator&quot; aria-hidden=&quot;true&quot;&gt;&lt;use xlink:href=&quot;#ornament&quot; /&gt;&lt;/svg&gt;

&lt;p&gt;Recently, yet another debate sparked over single-page apps, client-side frameworks like &lt;a href=&quot;https://www.zachleat.com/web/react-criticism/&quot;&gt;React&lt;/a&gt; and client-side versus server-side rendering. The arguments are not new. During the last decade, I found criticism of the dominant client-side JavaScript usage necessary and worthwhile. Especially proponents of progressive enhancement challenged the JavaScript ecosystem. Yet the mainstream did not adapt patterns for robustness and performance. Web sites became slower, more fragile, error-prone, inaccessible and exclusive largely due to client-side JavaScript misuse.&lt;/p&gt;

&lt;p&gt;There always has been a class of full-stack, “universal” JavaScript frameworks with a focus on speed and simplicity – think of &lt;a href=&quot;https://markojs.com/&quot;&gt;Marko&lt;/a&gt;, &lt;a href=&quot;https://astro.build/&quot;&gt;Astro&lt;/a&gt;, &lt;a href=&quot;https://fresh.deno.dev/&quot;&gt;Fresh&lt;/a&gt; or &lt;a href=&quot;https://qwik.builder.io/&quot;&gt;Qwik&lt;/a&gt;. They render HTML on the server and aim to ship the minimal necessary amount of JavaScript to the client. The client-side JavaScript then picks up where the server-side JavaScript left off, ideally without duplicating the server-side logic. More and more frameworks adapt such a workflow. But the mainstream is still dominated by React monoliths that comprises megabytes of client-side JavaScript.&lt;/p&gt;

&lt;svg class=&quot;separator&quot; aria-hidden=&quot;true&quot;&gt;&lt;use xlink:href=&quot;#ornament&quot; /&gt;&lt;/svg&gt;

&lt;p&gt;Unfortunately, the chasm between the opposite sides of the debate grew wider. The groups are no longer listening and talking to each other, but mock and ridicule each other while talking to their in-group. Echo chambers in social media amplify this divisive discourse.&lt;/p&gt;

&lt;p&gt;Certain posts from prominent JavaScript critics are filled with scathing polemic. They personally attack JavaScript project maintainers, calling them &lt;a href=&quot;https://infrequently.org/2023/02/the-market-for-lemons/&quot;&gt;liars, fraudsters and grifters&lt;/a&gt; because they only recently have “discovered” the downsides of single-page apps.&lt;/p&gt;

&lt;p&gt;I am all for radical criticism, especially targeted at billion-dollar tech corporations and powerful project leaders who &lt;a href=&quot;https://hachyderm.io/@zachleat@zachleat.com/109830049815165514&quot;&gt;try to silence critics&lt;/a&gt;. We need to hold them accountable for tech that produces harmful, subpar web experiences. They deserve their decent share of “told you so”.&lt;/p&gt;

&lt;p&gt;It is frustrating that influential people did not listen to the facts or did not deliver on their own promises. Will it help to call them fraudsters in the moment they start to acknowledge the facts? I believe vitriol makes the situation even more dire. I am disappointed that smart people who made valueable contributions to the web engage in mudslinging.&lt;/p&gt;

&lt;p&gt;Only a few note that such a behavior may harm the developer community that is already toxic and exclusive:&lt;/p&gt;

&lt;blockquote cite=&quot;https://hachyderm.io/@hbuchel/109830004886148541&quot;&gt;

  &lt;p&gt;I’ve been wailing on about &lt;abbr title=&quot;single-page apps&quot;&gt;SPA&lt;/abbr&gt; frameworks recently (like a lot of us have, probably because we’ve found more of our people over here) but just to be clear:&lt;/p&gt;

  &lt;p&gt;The world sucks right now. Get a job where you can. If React or Vue or Angular or Next or whatever gets you a job, then that is absolutely fantastic. If you are new in web dev and it introduces you to a love for the web, that is also fantastic.&lt;/p&gt;

  &lt;p&gt;You’re going to spend a lot  of time as a web developer figuring out where web experiences are broken for humans and how your platform or tech choices affect that. That always has been and is always going to be true.&lt;/p&gt;

  &lt;p&gt;Sometimes this conversation can veer into the “sounding self righteous” lane which gives me the ick.&lt;/p&gt;

  &lt;p&gt;– &lt;a href=&quot;https://hachyderm.io/@hbuchel/109830004886148541&quot;&gt;Heather Buchel&lt;/a&gt;&lt;/p&gt;

&lt;/blockquote&gt;

&lt;blockquote cite=&quot;https://social.lol/@sophie/109836319615664190&quot;&gt;

  &lt;p&gt;There’s a lot of fair criticism of React floating around at the mo. My one request is that people take care to separate “The React Community” from the people who just get paid to build things in React. I build stuff in React for money, but I do it as accessibly and consciously as I can. I know it’s far from ideal but that’s what we use. Switching to Not React isn’t really an option in an org of our size.
So please avoid mud-slinging and name-calling, and keep the discussion civil.&lt;/p&gt;

  &lt;p&gt;I think the biggest takeaway is that you probably don’t need React; and if you really do, and you’re sure, make sure you’re aware of the drawbacks and have plans to mitigate them.&lt;/p&gt;

  &lt;p&gt;– &lt;a href=&quot;https://social.lol/@sophie/109836319615664190&quot;&gt;Sophie Koonin&lt;/a&gt;&lt;/p&gt;

&lt;/blockquote&gt;

&lt;svg class=&quot;separator&quot; aria-hidden=&quot;true&quot;&gt;&lt;use xlink:href=&quot;#ornament&quot; /&gt;&lt;/svg&gt;

&lt;p&gt;What a year, huh? – Captain, it’s February!&lt;/p&gt;

&lt;p&gt;Anyway, where were we?&lt;/p&gt;

&lt;p&gt;My 2017 book was an attempt to mediate between the different camps of the debate on client-side JavaScript usage. Much advice from JavaScript critics was and is abstract for the sole reason that you need a robust site architecture in the first place before writing any robust client-side JavaScript code. With my book, I wanted to teach patterns any developer who writes client-side JavaScript can apply in their daily work regardless of the framework used.&lt;/p&gt;

&lt;p&gt;Around 2015 and 2016, several front-end developers wondered how to properly address JavaScript failure. &lt;a href=&quot;https://molily.de/javascript-failure/&quot;&gt;What happens when a JavaScript enhancement fails?&lt;/a&gt; These essential and much needed discussions urged me to write a book on robust JavaScript.&lt;/p&gt;

&lt;p&gt;Unfortunately, only a few developers and projects picked up the ideas and integrated them into their work. Preventing and dealing with failing JavaScript is still an afterthought for many projects, frameworks and libraries. We need to continuously explore how practical progressive enhancement in JavaScript looks like.&lt;/p&gt;

&lt;p&gt;In 2017, I also wanted to emphasize that progressive enhancement is much more than server-side rendering. The discussion on progressive enhancement regarding JavaScript still revolves around server-side rendering versus client-side rendering. For good reason, but this is where progressive enhancement starts.&lt;/p&gt;

&lt;p&gt;It is a first step to use a framework that renders fully-functional HTML documents on the server. A frameworks that understands your code, identifies client-side interactivity and figures out the least amount of JavaScript that needs to be shipped to the client.&lt;/p&gt;

&lt;p&gt;It does not mean you are done with it. Adding client-side JavaScript should not be one monolithic enhancement step from 0 to 100, but many small deliberate and considerate steps. That is why it is called progressive enhancement.&lt;/p&gt;

&lt;svg class=&quot;separator&quot; aria-hidden=&quot;true&quot;&gt;&lt;use xlink:href=&quot;#ornament&quot; /&gt;&lt;/svg&gt;

&lt;p&gt;So, where are we today? I welcome the new discussions on better web site architectures and sensible JavaScript usage. The industry is already shifting and new universal JavaScript frameworks are pushing the existing ecosystems.&lt;/p&gt;

&lt;p&gt;My 2017 book concluded with &lt;a href=&quot;/robust-javascript/#writing-less-javascript&quot;&gt;Writing less JavaScript&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;

  &lt;p&gt;An important skill of a front-end developer is to know when not to solve a problem with client-side JavaScript. It is always more robust to solve a problem further down in the stack.&lt;/p&gt;

  &lt;p&gt;If all techniques and tools did not help you to write robust JavaScript, consider reducing the code complexity and the amount of code. In the last resort, reduce the usage of client-side JavaScript. Find simpler solutions that rely on HTML, CSS and server-side logic alone.&lt;/p&gt;

&lt;/blockquote&gt;

&lt;p&gt;Today I would turn the reasoning upside down. Reducing client-side JavaScript is the most effective technique to prevent JavaScript failure. The most robust client-side JavaScript is the JavaScript that is never written, never shipped to the client and never executed. (&lt;a href=&quot;https://knowyourmeme.com/memes/roll-safe&quot;&gt;Clever, huh?&lt;/a&gt;)&lt;/p&gt;

&lt;svg class=&quot;separator&quot; aria-hidden=&quot;true&quot;&gt;&lt;use xlink:href=&quot;#ornament&quot; /&gt;&lt;/svg&gt;

&lt;p&gt;Apart from that, what techniques are essential today to write robust JavaScript?&lt;/p&gt;

&lt;p&gt;I’ve mentioned &lt;strong&gt;TypeScript&lt;/strong&gt; as a compile-to-JavaScript language in the book. Since 2017, TypeScript conquered the JavaScript world, superseded other compile-to-JavaScript languages and became a de-facto standard for a great share of libraries and frameworks.&lt;/p&gt;

&lt;p&gt;TypeScript is the single tool that made my JavaScript significantly more robust in the last couple of years. It helps me to design cascades of operations that may fail and helps me to implement the success and error handling. Strict typing forces me to think twice and write cautious code.&lt;/p&gt;

&lt;p&gt;With the goal of writing robust JavaScript in mind, we should utilize TypeScript as a static code checker for JavaScript – like ESLint.&lt;/p&gt;

&lt;p&gt;TypeScript is also a language that is a superset of JavaScript. It is also a program that compiles (transpiles) this language to JavaScript. But you do not have to use these parts to get most benefits.&lt;/p&gt;

&lt;p&gt;You can check plain JavaScript files with the TypeScript type checker. It understands plain JavaScript well enough to spot my lapses and lazy thinking. You can &lt;a href=&quot;https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html&quot;&gt;define types and add type annotations with JSDoc&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;While there are benefits to write &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.ts&lt;/code&gt; files with TypeScript syntax, this is not necessary to get started. In several projects, I have hardly written any &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.ts&lt;/code&gt; file, but TypeScript is an essential development tool.&lt;/p&gt;

&lt;p&gt;My advice is to install an editor like Visual Studio Code and start using TypeScript in your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.js&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.jsx&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.vue&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.svelte&lt;/code&gt; files today.&lt;/p&gt;

&lt;p&gt;I understand that TypeScript adds a heavy burden for web developers who already struggle with JavaScript and its toolchains. (I guess that is, ehm, everyone here?) Fortunately, editors, libraries and frameworks make it easy to integrate typed code gradually so you can learn as you go.&lt;/p&gt;

&lt;svg class=&quot;separator&quot; aria-hidden=&quot;true&quot;&gt;&lt;use xlink:href=&quot;#ornament&quot; /&gt;&lt;/svg&gt;

&lt;p&gt;My 2017 book featured several chapters on &lt;strong&gt;automated testing&lt;/strong&gt; from a high-level perspective. Since then, I gained more experience on automatic testing of web sites in general and client-side JavaScript in particular.&lt;/p&gt;

&lt;p&gt;In 2021, I published an extensive book on &lt;strong&gt;&lt;a href=&quot;https://testing-angular.com/&quot;&gt;Testing Angular&lt;/a&gt;&lt;/strong&gt;. It is the spiritual successor of &lt;cite&gt;Robust JavaScript&lt;/cite&gt;.&lt;/p&gt;

&lt;p&gt;The fact that the book deals with Angular is partly consequence, partly coincidence. I had been working on large Angular projects for clients who demanded (and could afford) technical robustness and understood test automation. Plus, Angular is built with testability in mind and the community values well-tested, robust code.&lt;/p&gt;

&lt;p&gt;While the second book goes into all necessary details and Angular specifics, it was the big picture that inspired me. How can testing help us to make better web sites that do not let the user down, but empower them? How can we write better, more robust JavaScript through testing?&lt;/p&gt;

&lt;p&gt;So eventually I wrote &lt;cite&gt;Testing Angular&lt;/cite&gt; for the same reason I wrote &lt;cite&gt;Robust JavaScript&lt;/cite&gt;: I wanted to explore and teach writing better web experiences. Preventing JavaScript failure is still my white whale.&lt;/p&gt;

&lt;p&gt;Fortunately, testing tools improved since 2017 and both end-to-end testing as well as JavaScript unit and integration testing got more approachable and reliable. Today I put much more emphasis on automated testing to make JavaScript robust.&lt;/p&gt;

&lt;svg class=&quot;separator&quot; aria-hidden=&quot;true&quot;&gt;&lt;use xlink:href=&quot;#ornament&quot; /&gt;&lt;/svg&gt;

&lt;p&gt;Angular is the “special occasion” framework in the JavaScript world. While &lt;a href=&quot;https://almanac.httparchive.org/en/2022/javascript#libraries-and-frameworks&quot;&gt;jQuery is used on 81% and React is used on 8% of the web sites analyzed&lt;/a&gt;, Angular is suitable for heavy-weight corporate intranet applications with a restricted audience using desktop computers.&lt;/p&gt;

&lt;p&gt;Especially JavaScript critics shake their head when Angular is mentioned. It ships larger amounts of client-side JavaScript than other frameworks. While it has rudimentary server-side rendering, it is not a practically viable default yet. Nonetheless, I think the Angular community listens to criticism and innovates.&lt;/p&gt;

&lt;p&gt;Angular has some architectural advantages that allows it to evolve in order to improve the site’s robustness and thereby the user experience. The core of Angular is a compiler. Like the Svelte compiler, it transforms your high-level, declarative and human-readable code into low-level, imperative and concise code that is shipped to the browser.&lt;/p&gt;

&lt;p&gt;The Angular team can optimize the compiler to produce more efficient and less code. In fact, the team recently rewrote the whole compiler and rendering engine. Thanks to the ahead-of-time compilation, there is dormant potential in Angular.&lt;/p&gt;

&lt;p&gt;I am excited that the Angular ecosystem catches up with projects like &lt;a href=&quot;https://github.com/analogjs/analog&quot;&gt;Analog.js&lt;/a&gt;, a full-stack framework that compares itself to SvelteKit, Nuxt and Next.js. Although Angular will most likely stick with the single-page application architecture, folks from the Angular community are building next-generation frameworks. For example, Miško Hevery, the creator of the original AngularJS framework and co-creator of Angular, now works on Qwik.&lt;/p&gt;

&lt;svg class=&quot;separator&quot; aria-hidden=&quot;true&quot;&gt;&lt;use xlink:href=&quot;#ornament&quot; /&gt;&lt;/svg&gt;

&lt;p&gt;While I still deem it necessary to teach basic defensive coding techniques, one cannot talk about robust client-side JavaScript without discussing the whole web site architecture. I have done so in several blog posts, but not prominently in &lt;cite&gt;Robust JavaScript&lt;/cite&gt;.&lt;/p&gt;

&lt;p&gt;Client-side JavaScript affects performance and accessibility, and I have realized that these are essential aspects of robustness as well. If JavaScript is freezing a mobile browser for 20 seconds, the site is not usable, let alone robust. If a single-page application breaks browser navigation features that users of assistive technologies rely on in particular, the site is not robust. And so on.&lt;/p&gt;

&lt;p&gt;All things considered, I think we are in a crucial phase of turmoil. My hope is that the JavaScript community convenes in a respectful and productive way, takes criticism seriously and makes radical technical and social changes.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Read the continuation:&lt;/em&gt; &lt;a href=&quot;/javascript-criticism/&quot;&gt;Client-side JavaScript and React criticism: What comes next?&lt;/a&gt;&lt;/p&gt;

</description>
          <pubDate>Fri, 10 Feb 2023 00:00:00 +0100</pubDate>
          <link>https://molily.de/update-on-robust-javascript/</link>
          <guid isPermaLink="true">https://molily.de/update-on-robust-javascript/</guid>
          
          
        </item>
      
    
      
        <item>
          <title>The Antagonism of Human and Nature in Factorio</title>
          <description>&lt;p&gt;
  &lt;video autoplay=&quot;&quot; muted=&quot;&quot; loop=&quot;&quot; playsinline=&quot;&quot; controls=&quot;&quot; style=&quot;display: block; margin; auto; max-width: 100%&quot;&gt;
    &lt;source type=&quot;video/mp4; codecs=&amp;quot;av01.0.05M.08&amp;quot;&quot; src=&quot;/assets/factorio-av1.mp4&quot; /&gt;
  	&lt;source type=&quot;video/mp4; codecs=&amp;quot;avc1.42E01E&amp;quot;&quot; src=&quot;/assets/factorio.mp4&quot; /&gt;
	&lt;/video&gt;
&lt;/p&gt;

&lt;p&gt;The video game Factorio got me hooked and I have played it longer than any other single-player game. While it is still in the early access phase and scheduled to be released in August, more than two million copies of the game have been sold.&lt;/p&gt;

&lt;p&gt;Video games today are multifaceted. As video games gained in depth and complexity in the last decade, video game criticism started taking them seriously as cultural and artistic works, as a diverse medium. Every game tells you something about the world – the in-game fictional world but also the world their creators and players inhabit. It is worth examining what games tell about the world – and what not. I find it noteworthy how Factorio depicts the natural world and human interaction with it.&lt;/p&gt;

&lt;p&gt;On its surface, Factorio is a simulation of a factory. The factory uses machines to mine raw materials and process them. More machines transform products into other products, and so forth. The goal of the game is to automate the production further and produce more complex artifacts.&lt;/p&gt;

&lt;p&gt;Instead of asking what the game is about, it gives more insight to ask what Factorio is &lt;em&gt;not&lt;/em&gt; about. It is surprising what the game omits, what the game does &lt;em&gt;not&lt;/em&gt; tell.&lt;/p&gt;

&lt;p&gt;First, the game is not about building an economy. In an economy, there are humans and human labor transforming natural substances. There is demand on the consumer side and supply on the producer side. In the capitalist mode of production, someone owns the means of production, employs workers, pays wages and earns profit in order to reinvest it. Products are sold on a market, exchanged as commodities. There are technical, societal and juridical conditions.&lt;/p&gt;

&lt;p&gt;Second, the game is not about ecology, broadly defined as “relationship of organisms with each other and the environment”. Such organisms span from microbes to animals, including humans. They transform matter in biochemical processes. In ecology, there are few one-way streets. Substances are transformed in food webs, but matter and energy is never lost. A species cannot survive for long if it is not part of biogeochemical cycles and energy flows.&lt;/p&gt;

&lt;p&gt;From a human perspective, ecology could mean exchange of matter between human and nature. Clearly, humans depend on and are entangled with the nature around them. For lack of a better description, science uses an economic term: nature provides “ecosystem services”, like drinking water, breathable air, fertile soil, renewable resources, decomposition of poisonous substances etc. Today, as the climate crisis, the Anthropocene extinction and plastic pollution are among the most pressing problems of humankind, we are reminded of these essential “services”.&lt;/p&gt;

&lt;p&gt;Third, on its surface, the game does not tell anything. There is a thin story, but it can be summarized in one sentence: The player avatar, simply called engineer, crash-lands on an alien planet and needs to build a rocket to launch a satellite into orbit. (It is not that the engineer wants to be rescued.) You “win” the game by launching the satellite. But it’s not the end of the technology tree, you can continue playing the game.&lt;/p&gt;

&lt;p&gt;There is, however, a story being told casually. When game designers do this on purpose, it is called environmental storytelling. Factorio features environmental storytelling in the sense that it tells about the natural environment and how human interacts with it.&lt;/p&gt;

&lt;p&gt;The factory simulation is a mathematical model, a function over time. Goods are produced, transformed and consumed. Yet the variables of this simulation are familiar to the player: trees, water, ores, oil and derivatives, conveyor belts, machines, cars, trains, electricity, power plants. They appeal to what the player knows. In terms of technical progress, the game world is a mix of mid and late 20th century innovations. The industry relies heavily on fossil resources and fossil fuels.&lt;/p&gt;

&lt;p&gt;There is the distant goal of building a rocket. But instead, a near goal drives the gameplay forward: the alien threat. The aliens are insect-like swarm creatures. They live in nests and occasionally expand by building new nests. They attack everything that comes near them. They run straight into the player’s defenses. These enemies are an important outer limiting factor, an additional challenge the player needs to tackle when planning and expanding the factory.&lt;/p&gt;

&lt;p&gt;As a game device, the aliens force the player to build a machinery of war. If one would take out the products, the buildings, the technology research etc. directly or indirectly connected to military, there is only a fraction left. (To be specific here, I have counted 129 civil &lt;a href=&quot;https://wiki.factorio.com/Items&quot;&gt;items&lt;/a&gt;, 10 dual use items and 44 military items. That means almost a quarter of the items are clearly military.) So for a great deal, this game is a war game, with little strategic value I might add.&lt;/p&gt;

&lt;p&gt;Defending your civilization against the natives is a notorious colonial narrative. To expand your factory, you constantly need to push the “frontier” forward, eliminating the native population.&lt;/p&gt;

&lt;p&gt;In the huge mathematical simulation, there is one formula reminiscent of ecology: Some parts of your factory cause pollution. The pollution is one factor that makes aliens attack your factory. They seek to eliminate the source of the pollution. The environment is somehow resilient against pollution: Trees absorb pollution, but may also die from it. Soil and water absorb and neutralize pollution.&lt;/p&gt;

&lt;p&gt;In essence, this is an ecological idea. Reduce pollution to improve your life, to stop antagonizing the native life. There is one drawback: I found the whole pollution mechanic to be obscure, insignificant and ultimately pointless. You can almost ignore it during gameplay. It is not thought-out, it seems unsound and unfinished.&lt;/p&gt;

&lt;p&gt;Reducing pollution could have been an important aspect of the game, but it is not. There is little incentive not to clear a forest. (You cannot reforest. Trees do not regrow either.) There is little motivation not to pave the ground and seal the soil. To defend against alien attacks attracted by pollution, it is much easier and more obvious to build up arms, to optimize your war machinery, to achieve superior firepower.&lt;/p&gt;

&lt;p&gt;Early in the game, when you burn massive amounts of fossil fuels, there are little ways to reduce pollution. So you need to invest in military to counter the inevitable attacks. Later in the game, you can reduce pollution easily, but mostly as a byproduct of energy efficiency. At that stage, you have already built a powerful military industry and do not have to care about pollution.&lt;/p&gt;

&lt;p&gt;Upgrading your weapons is the natural way of handling the negative impact of pollution. The game offers plenty of strategies how to decimate aliens or keep them at bay. Funnily enough, pollution does not harm yourself directly. Only the aliens are bothered. This does not make sense given the player seems to be a living organism as well.&lt;/p&gt;

&lt;p&gt;In addition to static defense structures, there is offensive combat. Again, with a huge complexity and variety. There are plenty of guns, ammunition, armed vehicles, combat robots, armed trains and respective upgrades. Whole industries are connected to these weapons.&lt;/p&gt;

&lt;p&gt;The purpose of offensive combat is to conquer new territories. It is necessary that your factory grows steadily to open up new resources. This is due to the fact that in the game world, conservation of mass and energy does not apply. Especially for technology upgrades, matter is consumed and vanishes into thin air. Most resources are finite. Once raw materials have been processed, you cannot disassemble and recycle the products. (You can only throw them away or blow them up.)&lt;/p&gt;

&lt;p&gt;Since there is no recycling, you cannot set up a circular economy. Therefore, expansion, growth and colonization are imperatives of the game. Sustainability and peace are no options.&lt;/p&gt;

&lt;p&gt;Challenging the game for its focus on war means putting the cart before the horse. Rather, the question is why the alien creatures are designed like they are: lacking intelligence, always hostile, no intelligible motives or needs. This is a particular cheap way of conceiving adversaries.&lt;/p&gt;

&lt;p&gt;How do these creatures sustain their life? Like every organism, they must exchange matter with nature. They need a habitat. They are interconnected with other organisms. The fact that the aliens look like insects and live in huge groups suggests they have a &lt;a href=&quot;https://en.wikipedia.org/wiki/Eusociality&quot;&gt;eusocial structure&lt;/a&gt;, like ants and bees.&lt;/p&gt;

&lt;p&gt;If the game had explored how these organisms live and survive, coexistence would be possible. Both species could interact, exchange and support each other. This could be as complex and manifold as building a sophisticated war industry, without denying that there are different interests and that the player is an intruder.&lt;/p&gt;

&lt;p&gt;All this seems like a missed opportunity for me. The game designers opted for the “safe” way by raking up colonial narratives. As a consequence, the simulation actively ignores the basics of human-nature interaction and ultimately the basics of life.&lt;/p&gt;

&lt;p&gt;Every fictional work is free to do so, it does not have to be realistic. Also, a game is not a lecture in economy or ecology. Still, works of fiction deal with issues from the real world, find fictional answers and shape how we reason about them. The game antagonizes human and nature, especially human and non-human animals. This is nothing but a story, a harmful story.&lt;/p&gt;

&lt;p&gt;&lt;small&gt;Postscriptum: In this article, I describe the “vanilla” gameplay and the standard configuration. The game has many options, like peaceful mode, that change the gameplay significantly. Also Factorio has a vibrant modding community that changes and extends almost every aspect of the game. Several mods change the mechanics mentioned here. Taking mods into account, it is impossible to say what the game is in essence and what not. That is why I examine the vanilla gameplay. Even without mods, Factorio is an open framework. While military plays an important role in standard gameplay, there are plenty of ways to play this sandbox game. One can spend twenty hours optimizing the war machinery or trying to minimize armed conflicts.&lt;/small&gt;&lt;/p&gt;
</description>
          <pubDate>Sun, 21 Jun 2020 00:00:00 +0200</pubDate>
          <link>https://molily.de/antagonism-human-nature/</link>
          <guid isPermaLink="true">https://molily.de/antagonism-human-nature/</guid>
          
          
        </item>
      
    
  </channel>
</rss>
