MiuJS: a framework for building HTML applications packed with the minimum necessary functionality

mast1ff

mast1ff

Posted on April 27, 2022

MiuJS: a framework for building HTML applications packed with the minimum necessary functionality

MiuJS in a minute

Github

MiuJS is a full-stack framework running on Node.js that includes utilities necessary for developing small websites.
It does not rely on specific front-end libraries such as React or Vue.js, yet packs as many features as possible that are necessary for development.

Features

  • Runs server-side instead of SSG
  • Built-in controller to handle non-GET requests
  • HTML-first development using Nunjucks templates, pre-built templates to avoid using fs in production
  • Scoped CSS feature, no mass production of CSS files
  • No external library dependencies for client-side JavaScript bundles (initial 5kb or less in production builds!)
  • Built-in dev server with live reload and built-in production server with connect

Recommended for

  • Creating web pages that do not want to overload the client-side
  • Lightweight websites that are not platform specific
  • Corporate sites with templates + small amount of POST actions, etc.

Incompatibility

  • Large scale website and web application development
  • SPA development
  • Blogs and documentation sites with large amounts of local Markdown

Although the above is a narrow demand, I believe that it can be useful for those who fell that existing frameworks are over-specified when they want to speed up the construction of a small site.
If you are interested, please continue reading.


As of 2022, there are countless libraries and mods named "web frameworks" regardless of languages.
When developing the actual core software of a product, large frameworks such as Ruby on Rails and Django may be used.

However, if you are building a website just to introduce that product, for example, these frameworks feel over-engineered.
There are various options to solve this, but the main issues I felt were:

  • I love React used by Next.js, Remix, etc., but the bundle size is a concern for creating a small site.
  • Sveltekit made by Svelte as well as 1.
  • CMSs such as Wordpress are similarly over-specified and have too many files to begin with.
  • There is an option to use a static site generator (e.g. Hugo), but it needs to be built every time data is updated.

In other words, what I wanted was:

  • Requires few or no development time
  • Small in size
  • Runs on the server-side

Considering the existing options

First, I narrowed down our choices of frameworks that could satisfy the above.

I tried various small frameworks such as Sinatra and Gin, but I felt that most of them are based on the assumption of customization to the extent that they extend the HTTP router.

The goal of this project is to develop a small website. I wanted a utility that specializes in front-end rather than extensibility.

Therefore, I decided to create our own framework.

Create a framework

Requirements

  • Ability to use template engines with low learning costs
  • Support for server-side rendering
  • Not a static site generator
  • Built-in HTTP server, capable of handing POST requests

Additional

  • JavaScript bundling
  • Can use scoped CSS, or CSS modules, etc.
  • Can run without JavaScript
  • Live reload during development
  • No fs in server runtime (want to run with Vercel, Netlify, etc.)

I have developed a web framework that can satisfy these requirements as much as possible.

MiuJS

The result is MiuJS, which meets all of the above requirements.

MiuJS Website

From project creation to build

As detailed use is described on our website, I will only provide a simplified introduction.

Create project

It can be created from npx by the create-miu package.

npx create-miu@latest my-project
Enter fullscreen mode Exit fullscreen mode

At this stage, the deployment targets can be selected from built-in server, Netlify, and Vercel, each with templates for JavaScript and TypeScript.

Development

Built-in dev server with live reload.

yarn dev
# or 
npm run dev
Enter fullscreen mode Exit fullscreen mode

Request workflow

Image description
MiuJS server requests are processed in the following order:

  • Request handlers created for each platform, such as createVercelRequestHandler
  • Function calls corresponding to request methods such as get, post described in files under src/routes
  • createServerRequest function in src/entry-server.js

Basically, each Route file plays the role of a controller in MVC, and detailed processing can be described here.

Route files

Under src/routes, Next.js-like file system routing in employed, with src/routes/index.js automatically routed to /, src/routes/about.js to /about, and so on.
In addition, each Route file can be implemented by exporting a function with an HTTP method name.

import type { RouteAction } from "miujs/node";
import { render, json } from "miujs/node";

// http://localhost:3000/posts#GET
export const get: RouteAction = ({ createContent }) = > {
  return render(createContent({ layout: "default" }), { status: 200 });
};

// http://localhost:3000/posts#POST
export const post: RouteAction = ({ query, params }) => {
  console.log(`query: `, query);
  console.log(`params: `, params);

  return json({}, { status: 200 });
};
Enter fullscreen mode Exit fullscreen mode

Templating

The createContent function passed from RouteAction has a built-in mechanism for using template files from cached post-build Nunjucks templates without using fs, and this function can be used to generate html rendered Nunjucks from the specified directory.

import type { RouteAction } from "miujs/node";
import { render } from "miujs/node";

export const get: RouteAction = async ({ createContent, params }) => {
  const data = await fetchSource({ handle: params!.handle }).catch(() => null);
  if (!data) {
    return render(createContent({ layout: "404" }), { status: 404 });
  }
  return render(
    createContent({
      layout: "default", // Templates that are entry points that reference files under src/layouts
      sections: [ // Section name and scope variables that reference to files under src/sections
        { name: "header", settings: { name: "Akiyoshi" } }
      ],
      data // Global data
    }),
    { status: 200, headers: { "Cache-Control": "public, max-age=900" } }
  );
};
Enter fullscreen mode Exit fullscreen mode
<!-- layouts/default.njk -->
<!DOCTYPE html>
<html>
  <head>
    <title>{{ data.title }}</title>
  </head>
  <body>
    The contents of the `sections` are compiled and inserted in the following comment fragment.
    <!-- content -->
  </body>
</html>
Enter fullscreen mode Exit fullscreen mode
<!-- sections/header.njk -->
<header>
  The `settings` scope provides access to section-specific scope variables.
</header>
Enter fullscreen mode Exit fullscreen mode

Scoped CSS

Scoped CSS can be applied to content in src/partials and src/sections with markup like Vue.js or Svelte.

<style scoped>
  .price:scope {
    display: flex;
    align-items: center;
  }
</style>

<template>
  <div class="price"><small>$</small>{{ price }}</div>
</template>
Enter fullscreen mode Exit fullscreen mode

Build

Build is also completed with a single command.

yarn build
# or 
npm run build
Enter fullscreen mode Exit fullscreen mode

Build for each server target (node, netlify, vercel) based on the settings described in miu.config.js.

Deploy

The built-in server works only with Node.js, so it can be deployed to any environment where the Node.js runtime is available.

yarn serve
# or 
npm run serve
Enter fullscreen mode Exit fullscreen mode

Deploying to services that use serverless functions such as Vercel or Netlify requires some tricky configuration, but the templates in the create-miu package include configuration files, so you can deploy without configuration, except in cases where special handling is required.


Future implementations

This framework is intended to meet the niche demand of developing "small websites that need a server-side but do not want to be as over-specified as existing full-stack frameworks.

In implementing the necessary functionality, most of the code, such as session storage, is implemented in time by copying parts of it from frameworks I admire, such as Remix. Since MiuJS is not intended to be used for developing large-scale applications, the usage scenario may be limited to begin with.


If anyone matches this narrow demand, please use it if you like.

Thanks for reading.

MiuJS Github
MiuJS website

I plan to rewrite this area so that it can be used more simply in a PHP-like manner.

💖 💪 🙅 🚩
mast1ff
mast1ff

Posted on April 27, 2022

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related