npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

isomorphic-mithril

v1.1.1

Published

Isomorphic mithril via Koa.js

Downloads

1

Readme

Isomorphic Mithril via Koa.js

This module allows you, to render mithril templates on the client as well as on the server. It supports data retrieval in the veign of m.request() and basically presents your users with a fully rendered page on first page load. It makes use of a modified version of Stephan Hoyers mithril-node-render code.

Example

The example below makes use of ES6 syntax. It also does not show a way to serve the client side script. Run it through browserify, and serve it however you would like.

views.js: The definition of your views. Routes should be defined compatible with m.router. They will be made available under these rules on the server and will be mounted via m.mount in the browser.

import m from 'mithril';

export default {
	'/post/:post...': {
		controller({i}) {
			this.post = m.prop({});
			i.request('GET', `/post/${i.param('post')}`).end(this.post);
		},
		view(ctrl) {
			return m('div', [ctrl.post().content]);
		}
	}
};

frame.js: A server only frame to wrap your views in. As mithril can not mount into the entire document, but rather only into document.body, we have to specify the remainder of a valid html document. A <!doctype html> tag will be prepended to the rendered pages automatically.

import m from 'mithril';

export default {
	view(ctrl, body) {
		return m('html', [
			m('body', [
				body
			])
		]);
	}
}

Server: The module provides an extended koa constructor. It allows you to call .mount to attach your views.

import isomorphic from 'isomorphic-mithril';
import route from 'koa-route';

import frame from './frame';
import views from './views';

let app = isomorphic();
app.mount(frame, '/', views);
app.use(route.get('/post/:postId', function* () {
	this.body = {content: 'Some content'}
}));

app.listen(process.env.PORT || 3000);

Browser: Very similar to the server side, just specify a html element instead of a frame and your done.

import Isomorphic from 'isomorphic-mithril';
import views from './views';
import m from 'mithril';

let app = new Isomorphic();
app.mount(document.body, '/', views);

app.listen(m);

Details

This module abstracts away sever mithril.js features and makes them usable in the browser as well as on a server. First you instantiate a new application instance:

let app = new Isomorphic();

Server

If you are executing this on the server, app is now a koa application. You can call all the usual things on it like .use(), .listen() etc.

In addition it provides a .mount() method. This method is built to resemble m.mount(). It takes the same three arguments as m.mount(), but the target (usually document.body) should now be a mithril component. This component will be called and rendered with the current view as its only argument.

Your server will automatically respond to any defined routes with the rendered view.

client

On the client, your app will be an object with syntax closely resembling that of a koa instance. You also call app.mount(), this time exactly like you would call m.mount(). And to actually attach the routes, you call m.listen(m). You have to pass your mithril instance, to prevent mutliple versions of mithril being used at once (yours and the one required by the module).

The i object

One of the nicest things about mithril is the way it handles asynchronous events. Because calls to m.request or m.startComputation/m.endComputation do not work in server side rendering, your top-level views will be passed an object with a single property named i. Assigned to this property is an object with a multitude of methods, which can be used on the client as well on the server.

i.browser

Simple boolean specifying in which environment the code is running

i.error()

Calls .throw() on the current koa context. Useful to throw errors on the server, if e.g. the requested route does not exist. On the client it just straight up opens the current route. This allows you to use server side error pages.

i.param()

Works like m.param() on the client as well as on the server.

i.route()

Use like m.route(). Mode is always pathname. When called with one argument (used to redirect), this.redirect() is called on the koa route.

i.startComputation() / i.endComputation()

Work identical to m.startComputation() / m.endComputation(). On the server components are rendered top down, waiting for the top level controller to end all computations before progressing. This should allow you to handle asynchronous tasks nicely.

i.redraw()

On the client simply calls m.redraw. On the server, this is a noop, as we should not have a need to manually redraw. Usually you would either call m.redraw to force a redraw while some asynchronous task is still running or after some event happened. Both of these use-cases are unimportant on the server.

i.request()

Similar to m.request, i.request queries a network source for data, returns a mithril promise and calls the computation handlers accordingly. The syntax is a different one though, as for proper isomorphism, we use superagent as the underlying library.

The request method takes the method as its first and the url as its second argument:

let something = i.query('GET', '/some/path/on/your/server').end();

You can chain all the methods superagent supports inbetween the query and end calls. As an additional utility, you may use the .end() method just like you would call .then().

So this works:

let somethingElse = m.prop('default');
i.query('GET', '/some/other/stuff').end(somethingElse);

On the server, any headers from the original request are copied (to preserve cookies etc.) before querying the koa server.