Code Monkey home page Code Monkey logo

html-strong's Introduction

html-strong

Opinionated, strongly typed HTML suitable for server side rendering and templating.

Early WIP.

Why?

I wanted to learn more about web development and write Rust at the same time.

What does it look like

TODO.

See the Axum hello world example.

See the Hacker News clone example (WIP).

Features

Strongly typed

Gives us IDE support and compile time guarantees.

No user-facing macros

Most templating libraries I've seen do this. I wanted to avoid this because some macros break rust-analyzer.

Also, domain specific languages carry an extra cognitive load that I'm not always interested in having.

Templating is Rust code

Create HTML dynamically using normal Rust control loops.

Future efforts

Ergonomics

Try finding improvements.

Example:

o(Td::default())
	.add_class("subtext")
	.kid(score_span)
	.add_text(" by ")
	.kid(user_href)
	.add_text(ONE_SPACE)
	.kid(unv_span)
	.add_text(PIPE_DELIMITER)
	.kid(hide_a)
	.add_text(PIPE_DELIMITER)

Would look better as:

o(Td
	.class("subtext")
	.kid(score_span)
	.text(" by ")
	.kid(user_href)
	.text(ONE_SPACE)
	.kid(unv_span)
	.text(PIPE_DELIMITER)
	.kid(hide_a)
	.text(PIPE_DELIMITER)

All tag struct implement the Tag trait.

If we use an extension trait, we should be able to make e.g. class available for any struct which implements Tag.

Missing stuff

Lots of tags and attributes are missing. Add them as we go.

Optimization pass

I ❤️ "Don't let the perfect be the enemy of the good". Allocate and box stuff liberally, then benchmark later and see where/if optimization are needed.

Caching

Try using the cached library (in examples) to see if we can get a nice pattern going for not having to re-render templates all the time.

Figure out CSS

What do we do about CSS?

  • Ignore it? We can already set an id and add classes to tags, the user can then handle CSS.
  • Find an API for adding style to tags?
  • Attempt a similar API (or library) for writing CSS?

html-strong's People

Contributors

torsteingrindvik avatar

Watchers

 avatar

html-strong's Issues

Figure out how to avoid boilerplate in attributes

A typical attribute impl now:

// Source image.
#[derive(Debug, Clone)]
struct Src(String);

impl Attribute for Src {
    fn name(&self) -> &'static str {
        "src"
    }

    fn value(&self) -> String {
        self.0.to_string()
    }
}

/// Image width.
#[derive(Debug, Clone)]
struct Width(usize);

impl Attribute for Width {
    fn name(&self) -> &'static str {
        "width"
    }

    fn value(&self) -> String {
        self.0.to_string()
    }
}

/// Image height.
#[derive(Debug, Clone)]
struct Height(usize);

impl Attribute for Height {
    fn name(&self) -> &'static str {
        "height"
    }

    fn value(&self) -> String {
        self.0.to_string()
    }
}

A lot of boilerplate.

Perhaps we could do:

#[derive(Debug, Clone, Attribute("src")]
struct Src(String);

#[derive(Debug, Clone, Attribute("width")]
struct Width(String);

#[derive(Debug, Clone, Attribute("height")]
struct Height(String);

for newtypes where the .0 is a string.

Or figure out something else.

Move convenience functions into `NodeExt`

We have functions such as add_style, add_class, add_text, etc on Node.
They all add to the global attrs.

As such these are convenience functions, and don't enable more functionality.

Therefore, it feels more precise to have these only in NodeExt instead of on Node itself.

Enable adding/removing classes?

Right now, if we do Div.class("a").class("b") we end up with <div class="a" class="b"></div>, which interestingly some browsers swallow up and turn into <div class="b"></div> (iirc).

The workaround now is to instead do Div.class("a b"), which does the correct thing.

If we allowed the same user APIs but stored it on the node differently, we could fix this.
We could then also allow removing classes.

Rename `tags` -> `element`?

It seems that what is referred to as tags in code should perhaps be called element in web vernacular.
We're learning!

Create a common `<nav>` for examples

HN example has a settings page which is now not visible from anywhere.
Blog example simply has no nav either.

Create a nav which can be used by both.
This also shows more how templating works.

Clean up stale tests, unused code

Early experiments have left a bit of tests which serve no real purpose, and code which is commented out and/or not in use outside tests.

Delete.

Remove uses of `o(...)`

The convenience function o(...) was used to go from a specific impl Tag type to Node.

So code like

let thing = o(Div).add_class("hi").kid(o(Span).add_class("hello"));

was common.

Now, we have an extension trait NodeExt, which allows us to instead write the above as:

let thing = Div.class("hi").kid(Span.class("hello"));

Which works by using the fact that all elements implement NodeExt, and e.g. class(...) takes the NodeExt implementor, turns it into a node, then continues working on it.

New style is cleaner, so purge the old!

Create a Hacker News cousin.

Instead of a clone.
The clone mimics the HTML structure closely.

The cousin will instead follow the KISS principle.

Try to make HTML structure as simple as possible,
then do bootstrap/tailwind for CSS or roll own if we only need a few things.

Rename `kid` -> `child`?

We save a few keystrokes by keeping kid, but it looks jarring and is probably not used anywhere else.
Maybe we can do some import ... as ,,, tricks if child gets too long.

Clean up Hacker News clone.

Since we cloned it by looking at the HTML source without having a good overview of it, the code isn't very neat.

Perhaps have a good spring cleaning of it or refactor it into more logical components.

Serve all examples by a `cargo r`

Either this, or refactor the axum parts into a common example dependency.

If we solve #3 , then we can simply tie together examples using that to navigate in-between.

This also lowers the barrier for adding new examples, since there is less boilerplate.
It also then highlights what the responsibility of html-strong is, vs. what axum does.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.