56

GitHub - dosyago-coder-0/brutal.js: A crazy-small framework for building brutali...

 5 years ago
source link: https://github.com/dosyago-coder-0/brutal.js
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

README.md

brutal.js

A crazy-small framework for building brutal/brutalist web applications

small

152 source lines of code. 2 functions: R and render

Basic usage:

  render(App(), document.getElementById('root'));

"React like"

This is React/JSX:

  function ButtonWidget(props) {
    return (
      <button onClick={() => showModal(props.name)}>
        Show {props.name} Modal
      </button>
    );
  }

This is R/brutal.js:

function ButtonWidget({name}) {
  return R`
    <button click=${() => showModal(name)}>
      Show ${name} Modal
    </button>
  `;
}

differences to notice

  • Event listeners are named by event names directly. No on- prefix. So use click not onclick
  • There is never any need to quote an attribute, brutal does it for you, so title=${title} never title="${title}"
  • every bit of HTML is tagged with an R and written with backticks. Technically, this is an ES6 template literal and template tag function.
  • Every replaced value is enclosed in ${...} instead of {...}

why brutalist?

To me, brutalist means as close to the basic raw HTML/ JavaScript as possible. There's more to do on the roadmap, but for many projects, these simple functions are enough. For example, take a look at a working TodoMVC example made with brutal.js. Everything in brutal is "as close to the metal" ( the JS / HTML ) as possible. This is ensured by their being minimal JS code, minimal opinionation (everything is just HTML elements and event handlers), leaving you free to structure things however you like.

get it

npm i --save brutalist-web

use it

<script src=node_modules/brutalist-web/r.js></script>

roadmap

  • Server side rendering / client-server symmetry
  • Encourage / macro-ise targeted forms and named iframes ( sooo brutal )
  • Encourage / bundle brutalist CSS sheets
  • Explore using intercooler-like attributes for async/await fetch

conclusion

If you know HTML and JS, you know brutal.js. Give it a spin, open an issue, make a PR, and let me know how you're using it, and where you think it should go.

projects using brutal.js

show hn


more information

case-study: just how small is it?

The above function as an arrow in React/JSX:

const ButtonWidget = ({name}) => (<button onClick={() => showModal(name)}>Show {name} Modal</button>);

That same arrow in R/brutal.js:

const ButtonWidget = ({name}) => R`<button click=${() => showModal(name)}>Show ${name} Modal</button>`;

brutal.js costs you 1 more character, and saves you around 90Kb of framework to get to that point.

so, wait, actually how small?

Just ~5Kb unzipped uminified. Compared to ~10x to 30x that gzipped minified for big frameworks.

Note: you can get a 101 SLOC ~3Kb version without any XSS protection.

case-study: differences with lit-html

Brutal is somewhat similar to lit-html.

It's also much smaller (3Kb compared to ~25kb unzipped unminified) and simpler.

And much more limited.

Brutal just supports adding event listeners to HTML, and templating values.

It does not support Promises, case-sensitive attribute names, or other "framework"-like complexities. If you want fetched data in your HTML output, fetch it before your HTML render, then render.


philosophy

A tool. Not a set of rules.

Some "Frameworks" want to restrict what you can do and "allow" and "disallow" you to do certain things, based on the "opinions" of their creators. Who cares what they think? Do what you want! Decide for yourself! Be a real human with a mind of their own and write your own code.

Maybe frameworks are just psychological emanations of the desire/need to control and be controlled? But that's not all humans can be/ not all how groups can interact. It's time for some "frameworks" that stop telling you what you can and can't do, and help you do what you want to do.

</manifesto>

why so simple?

With additional features come exponential or gemoetrically more code and bugs and interactions. This is mostly undesirable.

all about development speed (and load speed, and bandwidth cost, and complexity cost...)

Brutal just wants to help you build things in a simple way and quickly. It has all the power of HTML/CSS/JS, just in a convenient JSX like syntax, but without any big files or build steps. Just works in the browser right now.

anti-framework framework

In this sense, Brutal.js is an anti-framework.

But that's not even it's aim.

It's aim is to get as close to the raw material (HTML/CSS/JS) as possible and let you decide how to work with it based on your function. It's meant to make it fast and easy for you to build what you want.

It doesn't have to be as hard as the frameworks think it does.

Make Web Literate Again

Use Brutal to write simple functions that render to HTML right off the bat in all modern browsers, without the burden of massive amounts of code, opinionated conceptual models, learning curves and technical-debt/lock in.

The simple way the web was meant to be.


Overview

Note the following section was adapted from / inspired by the README.md of lit-html an unrelated but syntax-similar framework. Lit-html does not support adding event listeners, and Brutal does support adding event listeners.

Event-listeners

Any valid DOM/HTML event can be added. Here's a simple, literate and working example to create an editable div in Brutal.js:

const EditableDiv = content =>
  R`<div class=edit 
       dblclick=${ editContent } 
       blur=${ endEdit }>${content}</div>`;


load = () => render(EditableDiv('hello world'), document.body);


function editContent({ dblClick: { srcElement: el }}) {
  if (el.matches('.edit')) {
    el.setAttribute('contenteditable','');
  } else {
    el.closest('.edit').setAttribute('contenteditable','');
  }
}

function endEdit({ blur: { srcElement: el }}) {
  el.removeAttribute('contenteditable');
}

Performance

Brutal is designed to be lightweight and fast. It utilizes the built-in JS and HTML parsers - it doesn't include any expression or markup parser of its own.

Features

Simple expressions and literals

Anything coercible to strings are supported:

const Foo = () => R`foo is ${foo}`;

Attribute-value Expressions

const BlueDiv = () => R`<div class="${blue}"></div>`;

Arrays/Iterables

const items = [1, 2, 3];
const Items = () => R`<ul>${items.map(i => R`<li>${i}</li>`)}</ul>`;

Remember: always use R

Nested Templates

const Header = title => R`<h1>${title}</h1>`;
const App = () => R`
  ${Header('The head')}
  <p>And the body</p>
`;

Composability

These features compose so you can render iterables of functions that return arrays of nested templates, etc...

Benefits over HTML templates

Brutal has basically all of the benefits of HTML-in-JS systems like JSX, like:

Light weight

There's no need to load an expression parser and evaluator.

Access to data

Since template literals are evaluated in JavaScript, their expressions have access to every variable in that scope, including globals, module and block scopes, and this inside methods.

If the main use of templates is to inject values into HTML, this breaks down a major barrier between templates and values.

Fast expression eval

They're just JavaScript expressions.

IDE support by default

In a type-checking environment like TypeScript, expressions are checked because they are just regular script. Hover-over docs and code-completion just work as well.

Benefits over JSX

Native syntax

No tooling required. Understood by all JS editors and tools.

CSS-compatible syntax

Because template literals use ${} as the expression delimiter, CSS's use of {} isn't interpreted as an expression. You can include style tags in your templates as you would expect:

R`<style>
    :host {
      background: burlywood;
    }
  </style>
`;


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK