<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Jonas Liljegren</title>
    <description>The latest articles on DEV Community by Jonas Liljegren (@aigan).</description>
    <link>https://dev.to/aigan</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F170812%2Fcc888a58-17af-466c-98c3-8a93fb438b7d.jpeg</url>
      <title>DEV Community: Jonas Liljegren</title>
      <link>https://dev.to/aigan</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/aigan"/>
    <language>en</language>
    <item>
      <title>Getting started with web development in 2024</title>
      <dc:creator>Jonas Liljegren</dc:creator>
      <pubDate>Wed, 20 Dec 2023 11:56:04 +0000</pubDate>
      <link>https://dev.to/aigan/getting-started-with-web-development-in-2024-2b9n</link>
      <guid>https://dev.to/aigan/getting-started-with-web-development-in-2024-2b9n</guid>
      <description>&lt;h2&gt;
  
  
  Short history
&lt;/h2&gt;

&lt;p&gt;1994: &lt;a href="https://winworldpc.com/product/netscape-navigator/0x"&gt;Netscape Navigator&lt;/a&gt; made the web popular.&lt;/p&gt;

&lt;p&gt;2004: &lt;a href="https://winworldpc.com/product/internet-explorer/10"&gt;Internet Explorer&lt;/a&gt; by Microsoft destroyed Netscape, dominating with 94% market share.&lt;/p&gt;

&lt;p&gt;Then started the browser war, with Firefox, Chrome and Safari. It became a real pain trying to create websites that would look and work as intended in all popular browsers. All the browsers had numerous differences in implementation and bugs. Libraries like jQuery were created for helping building sites that would work on most versions of most browsers. Many features could not be used since they would not work the same on all browsers. New features could not be used since you would still need to support all the older browsers used by people.&lt;/p&gt;

&lt;p&gt;All this changed in 2014. HTML5 would revitalize the web after many years of XHTML. &lt;a href="https://en.wikipedia.org/wiki/ECMAScript_version_history#5th_Edition_%E2%80%93_ECMAScript_2009"&gt;ES5&lt;/a&gt; would finally get full support in all the browsers. But more important than this was the introduction of &lt;a href="https://babeljs.io/"&gt;Babel&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://nodejs.org/en/about"&gt;NodeJS&lt;/a&gt; is a javascript engine that lets you run programs outside the browser. Babel was one such program that can rewrite other javascript programs so that they can run on older versions of browsers. That would let you write javascript using the latest version ES6, and still having it work on older versions of all the popular browsers. ES6 introduced a lot of new things including class declarations.&lt;/p&gt;

&lt;p&gt;The power of Babel allowed for programs to use packages from the NodeJS ecosystem. Babel would transform them for compatibility with the web and tools like &lt;a href="https://webpack.js.org/"&gt;Webpack&lt;/a&gt; would optimize them by minimizing the size and bundle all the files together for faster load times. This led to an explosion in popularity and the rise of &lt;a href="https://react.dev/"&gt;React&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The evolution of the web platform
&lt;/h2&gt;

&lt;p&gt;Around the same time in 2014, all the major browsers would start to use automatic updates. Instead of many browsers being 5 or more years old, most users would have the latest browser while using the web. This was the rise of the evergreen browsers, that would eventually shorten the time for new features being available for almost all of the users.&lt;/p&gt;

&lt;p&gt;Every year there would be lots of new functionality introduced. The last couple of years would see major improvements every single month. Popular libraries and frameworks would serve as inspiration for new features added to the browser.&lt;/p&gt;

&lt;p&gt;This means that popular libraries with much needed features bit by bit would be made obsolete by similar features being built into the language and web api in the browser. Popular frameworks like React, Angular and Vue have evolved but their core architecture is based on the capabilities of the web at the time of their creation. They are still using build tools with transpilation and bundling even though this is no longer necessary and makes the whole framework much more complicated than it has to be.&lt;/p&gt;

&lt;p&gt;Every added library &lt;a href="https://www.spicyweb.dev/"&gt;comes with a cost&lt;/a&gt;. Updates in one part can force an upgrade of other parts. There may be security vulnerabilities or bugs. Every added interdependent component makes it harder to replace or fix functions that don't do what you want. The framework will &lt;a href="https://surma.dev/things/cost-of-convenience/"&gt;limit what you can do&lt;/a&gt;, making many custom solutions complicated and suboptimal. More time will go to adapting what you want to do to the capabilities and architecture of the chosen framework. Every library and every part of the toolchain and build process is another potential point of failure. Installing the example project with create-react-app will download 1500 package dependencies totaling over 2 million lines of javascript code. At the time of writing, they include 6 high level vulnerabilities. How long will it take you to understand what's happening across all those lines of code?&lt;/p&gt;

&lt;p&gt;Since frameworks like React and Angular have cemented its position as a de facto webstandard, there is a huge ecosystem of existing sites, apps, libraries and people. Mastery in these prevailing toolchains are required by more than 95% of existing jobs. But this article is not about culture or popularity. It’s about how to do better. And regardless of what framework you end up using, you should still learn the foundation and capabilities of the modern web. And be prepared to re-learn every year.&lt;/p&gt;

&lt;h2&gt;
  
  
  The modern web
&lt;/h2&gt;

&lt;p&gt;There are three main browser engines today. These are the ones used by &lt;a href="https://www.chromium.org/Home/"&gt;Chrome&lt;/a&gt;, &lt;a href="https://webkit.org/"&gt;Safari&lt;/a&gt; and &lt;a href="https://www.mozilla.org/"&gt;Firefox&lt;/a&gt;. Most other browsers are using Chromium, which is the engine known for Chrome. About 95% of all users have a browser version that is less than two months old.&lt;/p&gt;

&lt;p&gt;The core features of the modern web includes &lt;a href="https://en.wikipedia.org/wiki/ECMAScript_version_history#6th_Edition_%E2%80%93_ECMAScript_2015"&gt;ES6&lt;/a&gt; (2017), &lt;a href="https://en.wikipedia.org/wiki/HTTP/2"&gt;HTTP/2&lt;/a&gt; (2017), &lt;a href="https://css-tricks.com/snippets/css/complete-guide-grid/"&gt;CSS Grid&lt;/a&gt; (2017), &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_shadow_DOM"&gt;Shadow DOM&lt;/a&gt; (2018), &lt;a href="https://web.dev/blog/cq-stable"&gt;CSS Container Query&lt;/a&gt; (2023), &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script/type/importmap"&gt;importmap&lt;/a&gt; (2023), &lt;a href="https://developer.chrome.com/docs/css-ui/declarative-shadow-dom"&gt;Declarative Shadow DOM&lt;/a&gt; (2024) among many other Web APIs, javascript features and CSS modules. Many of these features have conditional polyfills that is javascript code that will make the feature work even in older browsers. The years given is the time it was supported in all three engines.&lt;/p&gt;

&lt;p&gt;This article will start from the beginning for how to develop web applications that use &lt;a href="https://www.npmjs.com/"&gt;npm packages&lt;/a&gt;. I may continue in later articles with more considerations often covered by popular frameworks, like routing, user sessions, database access, state management with reactivity, Server Side rendering, testing, documentation and deployment.&lt;/p&gt;

&lt;h2&gt;
  
  
  VS Code
&lt;/h2&gt;

&lt;p&gt;I started out with &lt;a href="https://www.gnu.org/software/emacs/"&gt;Emacs&lt;/a&gt; and still use it daily. You can use whatever text editor you like. But it should include syntax highlighting, indentation and some sort of integrated documentation like code autocompletion. Microsoft &lt;a href="https://code.visualstudio.com/"&gt;Visual Studio Code&lt;/a&gt; is very popular, especially for web development.&lt;/p&gt;

&lt;p&gt;You will need a web server for serving the website. The easiest to start with might be the &lt;a href="https://marketplace.visualstudio.com/items?itemName=ritwickdey.LiveServer"&gt;ritwickdey.LiveServer&lt;/a&gt; extension for VS Code. Open your project folder, create a html file and then &lt;em&gt;Go Live&lt;/em&gt; using the button at the bottom right.&lt;/p&gt;

&lt;p&gt;I hate all distracting elements including all the helpful popups that VS Code throws at you. The editor has thousands of things to configure to your liking. I disabled most things related to quickSuggestions, suggestOnTriggerCharacters, cursorBlinking, inlineSuggest, parameterHints, suggest, snippetSuggestions, closeEmptyGroups, autoClosingQuotes, autoClosingBrackets, autoClosingTags and lightbulb. I also removed some of the columns in the editor like minimap, glyphMargin and showFoldingControls. I’m also using the extension garaemon.vscode-emacs-tab and bound it to shift enter for indenting the current line.&lt;br&gt;
I also have &lt;a href="https://blog.jonas.liljegren.org/vs-code-keyboard-shortcuts/"&gt;a personal “Cheat sheet” for VS Code&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  ES modules
&lt;/h2&gt;

&lt;p&gt;NodeJS introduced &lt;a href="https://nodejs.org/api/modules.html"&gt;CommonJS modules&lt;/a&gt; (cjs), but those only work on the server. You will recognize them by their use of &lt;code&gt;require&lt;/code&gt; for importing libraries. ES6 introduced platform support for &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules"&gt;modules&lt;/a&gt; (mjs) using &lt;code&gt;import&lt;/code&gt; and &lt;code&gt;export&lt;/code&gt; syntax, which will also work in the browser.&lt;/p&gt;

&lt;p&gt;Most examples of importing libraries are using &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules"&gt;bare module specifiers&lt;/a&gt;. Those assume you are using nodeJS or that you are transpiling the code before running them on the browser. You don’t need a compilation step. Just provide the actual path to the module you want to require, using a relative or absolute path. The mjs file extension may not be associated with the mime type text/javascript in older web servers. You could use js instead, but I prefer mjs since that is suggested by NodeJS and I use it as a way to declare them as real modules and not something that has to be transpiled. You can add the mime type to the web server if needed.&lt;/p&gt;

&lt;p&gt;Here is a complete example of module use for remembering form input, in case the user accidentally closes the page before submitting. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;index.html&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;style&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;textarea&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;min-height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;box-sizing&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;border-box&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;textarea&lt;/span&gt; &lt;span class="na"&gt;disabled&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"notes"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/textarea&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"module"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;persist_input&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/utils.mjs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nf"&gt;persist_input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;notes&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;utils.mjs&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;persist_input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;$el&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
  &lt;span class="nx"&gt;$el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;$el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;$el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;disabled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;$el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;input&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;on_input&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;on_input&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;$el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;$el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A larger project will usually use several layers of nested folders. For those projects, it’s usually easier to use absolute paths. But while using absolute paths, you must keep track of what folder to use as the web root. It’s usually named &lt;code&gt;public&lt;/code&gt;. You can tell the Live Server extension to use that folder by creating a file &lt;code&gt;.vscode/settings.json&lt;/code&gt; with the content&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"liveServer.settings.root"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/public"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Web components
&lt;/h2&gt;

&lt;p&gt;Web components are the standard for reusable encapsulated components. Not to be confused with the non-standard framework-specific component systems such as react components and the like. Components lets you create your own html tags with any functionality you like. Here we encapsulate the persist_input function as a component:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;persist-input.mjs&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;persist_input&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/utils.mjs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;El&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;HTMLElement&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;connectedCallback&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;$inputs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelectorAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;input,textarea&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;$inp&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;$inputs&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nf"&gt;persist_input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;$inp&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;customElements&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;define&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;persist-input&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;El&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And now we can use it for persisting all input elements inside the tag:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;style&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;textarea&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;min-height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;box-sizing&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;border-box&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;persist-input&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;textarea&lt;/span&gt; &lt;span class="na"&gt;disabled&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"notes"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/textarea&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/persist-input&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"module"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/persist-input.mjs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  NodeJS
&lt;/h2&gt;

&lt;p&gt;NodeJS is the server side javascript engine used by most frontend frameworks. It can run under Windows, but will work better on a unix-like system like MacOS or Linux or the &lt;a href="https://learn.microsoft.com/en-us/windows/wsl/tutorials/wsl-vscode"&gt;Windows Subsystem for Linux&lt;/a&gt; (WSL). You will be using a terminal with the &lt;a href="https://www.gnu.org/software/bash/"&gt;Bash&lt;/a&gt; shell for command line interface (CLI) tools. Start by installing the &lt;a href="https://github.com/nvm-sh/nvm?tab=readme-ov-file#table-of-contents"&gt;Node Version Manager&lt;/a&gt; (nvm). With that, you can install the latest stable version of node.&lt;/p&gt;

&lt;p&gt;Each project can have its own installed CLI tools, located in &lt;code&gt;./node_modules/bin&lt;/code&gt;. Those can be run by using &lt;a href="https://docs.npmjs.com/cli/v10/commands/npx"&gt;npx&lt;/a&gt;, the relative path, or with a tool that checks the project bin dir using bash &lt;a href="https://www.linuxjournal.com/content/bash-command-not-found"&gt;command_not_found_handle()&lt;/a&gt;. Keeping the tools with the project makes it easier to share the code and make sure that the project works with the version of the tool installed.&lt;/p&gt;

&lt;p&gt;The modules we created don't need to be compiled. But many modules from &lt;a href="https://www.npmjs.com/"&gt;npm&lt;/a&gt; do need a compilation step. We often need to change the module paths used inside the imported modules so that they can work in the browser. We can use &lt;a href="https://rollupjs.org/"&gt;rollup&lt;/a&gt; for repairing the paths in the module. We will have to tell rollup to not bundle or mangle the files. We only need &lt;a href="https://www.npmjs.com/package/@rollup/plugin-node-resolve"&gt;the path translation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;An alternative to repairing the import paths is to use the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script/type/importmap"&gt;&lt;code&gt;&amp;lt;script type="importmap"&amp;gt;&lt;/code&gt;&lt;/a&gt; feature for mapping directories or bare module specifiers to their actual location. For this, you can use a tool that finds all the module paths and places them in an importmap.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://lit.dev/"&gt;Lit&lt;/a&gt; is a library that can simplify writing web components. During rollup, we can tell it to use the uncompressed &lt;em&gt;development&lt;/em&gt; version of the files. In most cases, there is no need to use minified files. I believe in giving every user the freedom of seeing what's happening in the pages they visit. We can always optimize later if it's truly needed.&lt;/p&gt;

&lt;p&gt;Standing in your project directory, install lit and rollup with &lt;code&gt;npm i -D lit rollup @rollup/plugin-node-resolve&lt;/code&gt;. This will create a manifest in &lt;code&gt;package.json&lt;/code&gt; and install the modules in node_modules.&lt;/p&gt;

&lt;p&gt;Here is the rollup.config.mjs I use for repairing the files. Use the config by running &lt;code&gt;npx rollup -c&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;resolve&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@rollup/plugin-node-resolve&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="na"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
   &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;lit&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;lit/decorators.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="p"&gt;],&lt;/span&gt;
 &lt;span class="na"&gt;output&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="na"&gt;dir&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;public/x&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;es&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="na"&gt;preserveModules&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="na"&gt;minifyInternalExports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="na"&gt;entryFileNames&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;chunkInfo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
       &lt;span class="nx"&gt;chunkInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;
         &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;node_modules&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
         &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/index&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
       &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;.mjs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
     &lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="p"&gt;},&lt;/span&gt;
 &lt;span class="p"&gt;},&lt;/span&gt;
 &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
   &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;exportConditions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;development&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
 &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The result is put in the folder &lt;code&gt;x&lt;/code&gt;. I like short names, but you may want to call it &lt;code&gt;external&lt;/code&gt; or &lt;code&gt;vendor&lt;/code&gt; to show that it is an external dependency. &lt;/p&gt;

&lt;p&gt;Now we can use the library for creating components, like this minimal&lt;/p&gt;

&lt;p&gt;&lt;code&gt;say-hello.mjs&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;LitElement&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/x/lit.mjs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;El&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;LitElement&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="s2"&gt;`&amp;lt;p&amp;gt;Hello&amp;lt;/p&amp;gt;`&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;customElements&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;define&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;say-hello&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;El&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And now it can be used as a component with&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
 &lt;span class="nt"&gt;&amp;lt;say-hello&amp;gt;&amp;lt;/say-hello&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"module"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
 &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/say-hello.mjs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;npmjs.com has millions of packages. And this is how you can use them for building web applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  Optimized delivery
&lt;/h2&gt;

&lt;p&gt;Once upon a time we used HTTP/1 for delivering files. That protocol had an overhead for each file, so we used bundlers to minimize the number of files the browser needed to fetch. This is no longer the case with HTTP/2 and HTTP/3. It doesn’t make a difference if the content resides in one large file or 1000 small ones. In fact, it’s much better to keep them as many small files, since the browser will only fetch the files that are needed for the current page, and only if the files have updated since the last fetch.&lt;/p&gt;

&lt;p&gt;For a tree of dependencies where module 1 imports module 2 that imports module 3, the browser will only start to download the dependent modules after the previous ones have been loaded and parsed. This is called the network waterfall. For optimizing the load, you can just declare what modules to load directly from the html page. One way to do that is to use &lt;code&gt;&amp;lt;link rel="modulepreload" href="/my-module.mjs"&amp;gt;&lt;/code&gt; tags at the beginning of the page. You can use the &lt;a href="https://www.npmjs.com/package/modulepreload"&gt;modulepreload&lt;/a&gt; tool from npmjs to automatically look up all nested dependencies of the page and inject the modulepreload tags that will eliminate the network waterfall. In our example, this will add&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"modulepreload"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/x/lit.mjs"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"modulepreload"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/x/@lit/reactive-element/development/reactive-element.mjs"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"modulepreload"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/x/@lit/reactive-element/development/css-tag.mjs"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"modulepreload"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/x/lit-html/development/lit-html.mjs"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"modulepreload"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/x/lit-element/development/lit-element.mjs"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"modulepreload"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/x/lit-html/development/is-server.mjs"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I did my own tool for generating preloads before found this newly published tool.&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>javascript</category>
      <category>buildless</category>
      <category>webcomponents</category>
    </item>
    <item>
      <title>30 years dreaming of the semantic web</title>
      <dc:creator>Jonas Liljegren</dc:creator>
      <pubDate>Fri, 01 Dec 2023 07:11:13 +0000</pubDate>
      <link>https://dev.to/aigan/30-years-dreaming-of-the-semantic-web-411b</link>
      <guid>https://dev.to/aigan/30-years-dreaming-of-the-semantic-web-411b</guid>
      <description>&lt;p&gt;I started writing HTML in 1995 after enrolling at the university informatics department. That was the year when Netscape just started adding new capabilities to the web, like background images, colors, tables, javascript and animated gifs.&lt;/p&gt;

&lt;p&gt;The first parts of what would become paranormal.se were created at that time. In those days, a homepage was your home on the web. It was a place for your notes, bookmarks and contact information. I have basically kept my homepage from that time, with just some minor updates to keep it usable and somewhat up to date over the years.&lt;/p&gt;

&lt;p&gt;I soon found my home at the student computer club. Spending all nights learning programming in Perl on the Solaris, while listening on MP3s of &lt;a href="https://youtu.be/j2F4INQFjEI"&gt;Belinda Carlisle&lt;/a&gt;, &lt;a href="https://youtu.be/AIOAlaACuv4"&gt;Tracy Chapman&lt;/a&gt; or anything else I found on the server. Installing qtest1 on all the lab computers for checking it out.&lt;/p&gt;

&lt;p&gt;I used Perl for creating the first online facebook for the students at the informatics department. Also created the student newspaper CMS (Snutten), and the computer club website (SKIP) along with the growing paranormal site.&lt;/p&gt;

&lt;p&gt;I have always preferred dynamic languages that cover the space between low level functionality and high level concepts, from ARexx to Perl to Javascript. Living on the edge, submitting bug reports and patches to the language or libraries since around 1996.&lt;/p&gt;

&lt;p&gt;Paranormal.se was a project to create a semantic knowledge base with a hypertext frontend. The idea was to discover and surface new knowledge by integrating a large body of research and existing theories. I was hoping to create a sort of discussion forum where each new discussion would help to organize all existing information, making the whole continually more connected and refined. So many algorithms today work by surfacing the most popular and generally understood thinking. I had an idea of how to nurture ideas and perspectives and let them grow until more people understand them. Unlocking the secrets of the universe.&lt;/p&gt;

&lt;p&gt;Dreaming of Xanadu. I love the original vision of Ted Nelson, who coined the terms hypertext and hypermedia. This would later inspire Tim Berners-Lee creation of the Web. I was deeply involved in the semantic web during the introduction of RDF in 1999. The dream of connecting all the world's knowledge with machine-readable semantic markup and a universal API for all public databases. The ontologies would  allow for artificial intelligence to answer any question using deduction with symbolic logic. This is still very much a central part of knowledge representation today and used in combination with machine learning and large language models.&lt;/p&gt;

&lt;p&gt;Changing workplace, I picked up my personal GNU/Linux server with all my sites and mail, to find a new home at the next company. This would be the place where I fully developed my hypertext dream, using the technology both for the company and the personal project.&lt;/p&gt;

&lt;p&gt;Paranormal.se &lt;a href="https://paranormal.se/"&gt;version 3&lt;/a&gt; (P3) consists of about 30.000 topics and 16.000 users. It was a very active community around 1998 - 2008. This was before Wikipedia and Facebook. In 2007, I started developing version 4 (P4) with a much better system for version management, graph database flexibility and deduction capabilities. By 2009, I was burned out.&lt;/p&gt;

&lt;p&gt;P4 was supposed to use my semantic database library &lt;a href="https://blog.jonas.liljegren.org/rdf-base/"&gt;RDF::Base&lt;/a&gt; (RB), which was created to run on my application framework &lt;a href="https://blog.jonas.liljegren.org/para-frame/"&gt;Para::Frame&lt;/a&gt; (PF), built with Perl. PF and RB have been continually developed and refined since 2003. It's powerful and versatile, including multisite frontends, content management, request tracker, email handing, translations, external API and load balancing. All of it built on a &lt;a href="https://blog.jonas.liljegren.org/semantic-databases/"&gt;semantic database&lt;/a&gt; inspired by RDF with typed literals, reified statements, class schemas and syllogism inference. Since it's a temporal database, parts or whole of queries can be constrained to a selected date.&lt;/p&gt;

&lt;p&gt;PF and RB was the foundation for Hotellguiden.se from 2003 to 2009. After that, the system would continue to serve as the main customer management database, handling bookings and statistics, newsletters and even the internal call center administration, integrating all the business systems.&lt;/p&gt;

&lt;p&gt;GOV, a web voting system for liquid democracy, was built in 2009 by my brother, for Aktiv Demokrati. It was built using RDF::Base and included ranked pair condorcet method for voting on lists. The liquid democracy was implemented by letting users delegate voting to other users. If you did not vote, the vote of your delegate would be counted. This also handled prioritized lists of delegates, voting jurisdiction and the temporal information of membership and voting history. I took over the development in 2010 and continued its development until 2017.&lt;/p&gt;

&lt;p&gt;I have administered a lot of sites for forums, blogs or facebook pages related to groups I participated in. This includes Perl Mongers, Aktiv Demokrati, Occupy Göteborg, Zeitgeist Movement Sweden, Direktdemokraterna, in addition to many more personal sites. I also produced a lot of IRL events for Zeitgeist and Direktdemokraterna, including several Z-day conferences and election campaigns. This included a lot of marketing on the streets, public speaking and also online campaigns using ads, facebook and emails. Also did a lot of printing material, recording and editing of audio and video.&lt;/p&gt;

&lt;p&gt;All of this ended in 2015. Burned out again, but now with &lt;a href="https://blog.jonas.liljegren.org/tag/health/"&gt;health problems&lt;/a&gt;. I started investigating what I could do better for recovering my health, including diet, exercise and supplements. Eventually &lt;a href="https://blog.jonas.liljegren.org/re-botad/"&gt;learned what to do&lt;/a&gt; to stay productive. I also took more time for rest and relaxation with playstation gaming, renewing my interest in game design. Especially &lt;a href="https://blog.jonas.liljegren.org/tag/systemic/"&gt;systemic story games&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;A new generation for the booking system started development in 2015, now based on Javascript, NodeJS and the graph database Neo4J. I made the jump from Perl to Javascript and took the opportunity to jump to the bleeding edge, with ES modules, web components and low complexity. That which later would be called Modern Web.&lt;/p&gt;

&lt;p&gt;I see so many problems in apps from Facebook, Youtube and others. Especially for making systems that support you switching devices or working with other people, with all information kept up to date regardless of their source. I did a lot of work to make it easy to build large interconnected semantic systems with guaranteed consistency in all async scenarios. More on that later.&lt;/p&gt;

&lt;p&gt;By 2020, the project was halted. My workplace decided to simplify and outsource all IT. The world-leading system I had developed was not the right match for the company.&lt;/p&gt;

&lt;p&gt;Now, I’m &lt;a href="https://blog.jonas.liljegren.org/techstack/"&gt;looking for my dream job&lt;/a&gt;, advancing the state of the web using bleeding edge web technologies like buildless web components and reactive state semantic graphs, connected to the latest of LLM AI using embeddings for ML vector databases.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>semanticweb</category>
      <category>webcomponents</category>
      <category>burnout</category>
    </item>
  </channel>
</rss>
