mithril
Version:
A framework for building brilliant applications
272 lines (266 loc) • 18.6 kB
HTML
<head>
<meta charset=UTF-8>
<title> Introduction - Mithril.js</title>
<link href="https://fonts.googleapis.com/css?family=Open+Sans" rel=stylesheet>
<link href=style.css rel=stylesheet>
<link rel=icon type=image/png sizes=32x32 href=favicon.png>
<meta name=viewport content="width=device-width,initial-scale=1">
</head>
<body>
<header>
<section>
<a class=hamburger href=javascript:;>≡</a>
<h1><img src=logo.svg> Mithril <small>2.0.3</small></h1>
<nav>
<a href=index.html>Guide</a>
<a href=api.html>API</a>
<a href=https://gitter.im/MithrilJS/mithril.js>Chat</a>
<a href=https://github.com/MithrilJS/mithril.js>GitHub</a>
</nav>
</section>
</header>
<main>
<section>
<h1 id=introduction><a href=#introduction>Introduction</a></h1>
<ul>
<li>Getting Started<ul>
<li><strong><a href=index.html>Introduction</a></strong><ul>
<li><a href=#what-is-mithril>What is Mithril?</a></li>
<li><a href=#getting-started>Getting started</a></li>
<li><a href=#hello-world>Hello world</a></li>
<li><a href=#dom-elements>DOM elements</a></li>
<li><a href=#components>Components</a></li>
<li><a href=#routing>Routing</a></li>
<li><a href=#xhr>XHR</a></li>
</ul>
</li>
<li><a href=installation.html>Installation</a></li>
<li><a href=simple-application.html>Tutorial</a></li>
<li><a href=learning-mithril.html>Learning Resources</a></li>
<li><a href=support.html>Getting Help</a></li>
</ul>
</li>
<li>Resources<ul>
<li><a href=jsx.html>JSX</a></li>
<li><a href=es6.html>ES6+ on legacy browsers</a></li>
<li><a href=animation.html>Animation</a></li>
<li><a href=testing.html>Testing</a></li>
<li><a href=examples.html>Examples</a></li>
<li><a href=integrating-libs.html>3rd Party Integration</a></li>
<li><a href=paths.html>Path Handling</a></li>
</ul>
</li>
<li>Key concepts<ul>
<li><a href=vnodes.html>Vnodes</a></li>
<li><a href=components.html>Components</a></li>
<li><a href=lifecycle-methods.html>Lifecycle methods</a></li>
<li><a href=keys.html>Keys</a></li>
<li><a href=autoredraw.html>Autoredraw system</a></li>
</ul>
</li>
<li>Social<ul>
<li><a href=https://github.com/MithrilJS/mithril.js/wiki/JOBS>Mithril Jobs</a></li>
<li><a href=contributing.html>How to contribute</a></li>
<li><a href=credits.html>Credits</a></li>
<li><a href=code-of-conduct.html>Code of Conduct</a></li>
</ul>
</li>
<li>Misc<ul>
<li><a href=framework-comparison.html>Framework comparison</a></li>
<li><a href=change-log.html>Change log/Migration</a></li>
<li><a href=https://mithril.js.org/archive/v1.1.6/ >v1 Documentation</a></li>
<li><a href=https://mithril.js.org/archive/v0.2.5/ >v0.2 Documentation</a></li>
</ul>
</li>
</ul>
<hr>
<h3 id=what-is-mithril?><a href=#what-is-mithril?>What is Mithril?</a></h3>
<p>Mithril is a modern client-side JavaScript framework for building Single Page Applications. It's small (< 10kb gzip), fast and provides routing and XHR utilities out of the box.</p>
<div style="display:flex;margin:0 0 30px;">
<div style=width:50%;>
<h5>Download size</h5>
<small>Mithril (9.5kb)</small>
<div style="animation:grow 0.08s;background:#1e5799;height:3px;margin:0 10px 10px 0;transform-origin:0;width:4%;"></div>
<small style=color:#aaa;>Vue + Vue-Router + Vuex + fetch (40kb)</small>
<div style="animation:grow 0.4s;background:#1e5799;height:3px;margin:0 10px 10px 0;transform-origin:0;width:20%"></div>
<small style=color:#aaa;>React + React-Router + Redux + fetch (64kb)</small>
<div style="animation:grow 0.64s;background:#1e5799;height:3px;margin:0 10px 10px 0;transform-origin:0;width:32%"></div>
<small style=color:#aaa;>Angular (135kb)</small>
<div style="animation:grow 1.35s;background:#1e5799;height:3px;margin:0 10px 10px 0;transform-origin:0;width:68%"></div>
</div>
<div style=width:50%;>
<h5>Performance</h5>
<small>Mithril (6.4ms)</small>
<div style="animation:grow 0.64s;background:#1e5799;height:3px;margin:0 10px 10px 0;transform-origin:0;width:24%;"></div>
<small style=color:#aaa;>Vue (9.8ms)</small>
<div style="animation:grow 0.98s;background:#1e5799;height:3px;margin:0 10px 10px 0;transform-origin:0;width:40%"></div>
<small style=color:#aaa;>React (12.1ms)</small>
<div style="animation:grow 1.21s;background:#1e5799;height:3px;margin:0 10px 10px 0;transform-origin:0;width:48%"></div>
<small style=color:#aaa;>Angular (11.5ms)</small>
<div style="animation:grow 1.15s;background:#1e5799;height:3px;margin:0 10px 10px 0;transform-origin:0;width:44%"></div>
</div>
</div>
<p>Mithril is used by companies like Vimeo and Nike, and open source platforms like Lichess.</p>
<p>If you are an experienced developer and want to know how Mithril compares to other frameworks, see the <a href=framework-comparison.html>framework comparison</a> page.</p>
<p>Mithril supports IE11, Firefox ESR, and the last two versions of Firefox, Edge, Safari, and Chrome. No polyfills required.</p>
<p><em>Looking for the v1 docs? <a href=https://mithril.js.org/archive/v1.1.6/index.html>Click here</a>.</em></p>
<hr>
<h3 id=getting-started><a href=#getting-started>Getting started</a></h3>
<p>An easy way to try out Mithril is to include it from a CDN and follow this tutorial. It'll cover the majority of the API surface (including routing and XHR) but it'll only take 10 minutes.</p>
<p>Let's create an HTML file to follow along:</p>
<pre><code class=language-html><body>
<script src="https://unpkg.com/mithril/mithril.js"></script>
<script>
var root = document.body
// your code goes here!
</script>
</body></code></pre>
<p>To make things simpler you can fork this pen which already has the latest version of mithril loaded.</p>
<p data-height=265 data-theme-id=light data-slug-hash=XRrXVR data-default-tab=js,result data-user=tivac data-embed-version=2 data-pen-title="Mithril Scaffold" data-preview=true class=codepen>See the Pen <a href=https://codepen.io/tivac/pen/XRrXVR/ >Mithril Scaffold</a> by Pat Cavit (<a href=https://codepen.io/tivac>@tivac</a>) on <a href=https://codepen.io>CodePen</a>.</p>
<script async src=https://production-assets.codepen.io/assets/embed/ei.js></script>
<p>Mithril is also loaded onto this page already, so you can start poking at the <code>m</code> object in the developer console right away if you'd like!</p>
<hr>
<h3 id=hello-world><a href=#hello-world>Hello world</a></h3>
<p>Let's start as small as we can: render some text on screen. Copy the code below into your file (and by copy, I mean type it out - you'll learn better)</p>
<pre><code class=language-javascript>var root = document.body
m.render(root, "Hello world")</code></pre>
<p>Now, let's change the text to something else. Add this line of code under the previous one:</p>
<pre><code class=language-javascript>m.render(root, "My first app")</code></pre>
<p>As you can see, you use the same code to both create and update HTML. Mithril automatically figures out the most efficient way of updating the text, rather than blindly recreating it from scratch.</p>
<h4 id=live-example><a href=#live-example>Live Example</a></h4>
<p data-height=265 data-theme-id=light data-slug-hash=KmPdOO data-default-tab=js,result data-user=tivac data-embed-version=2 data-pen-title="Mithril Hello World" data-preview=true class=codepen>See the Pen <a href=https://codepen.io/tivac/pen/KmPdOO/ >Mithril Hello World</a> by Pat Cavit (<a href=https://codepen.io/tivac>@tivac</a>) on <a href=https://codepen.io>CodePen</a>.</p>
<script async src=https://production-assets.codepen.io/assets/embed/ei.js></script>
<hr>
<h3 id=dom-elements><a href=#dom-elements>DOM elements</a></h3>
<p>Let's wrap our text in an <code><h1></code> tag.</p>
<pre><code class=language-javascript>m.render(root, m("h1", "My first app"))</code></pre>
<p>The <code>m()</code> function can be used to describe any HTML structure you want. So if you need to add a class to the <code><h1></code>:</p>
<pre><code class=language-javascript>m("h1", {class: "title"}, "My first app")</code></pre>
<p>If you want to have multiple elements:</p>
<pre><code class=language-javascript>[
m("h1", {class: "title"}, "My first app"),
m("button", "A button"),
]</code></pre>
<p>And so on:</p>
<pre><code class=language-javascript>m("main", [
m("h1", {class: "title"}, "My first app"),
m("button", "A button"),
])</code></pre>
<h4 id=live-example0><a href=#live-example0>Live Example</a></h4>
<p data-height=275 data-theme-id=light data-slug-hash=gWYade data-default-tab=js,result data-user=tivac data-embed-version=2 data-pen-title="Simple Mithril Example" data-preview=true class=codepen>See the Pen <a href=https://codepen.io/tivac/pen/gWYade/ >Simple Mithril Example</a> by Pat Cavit (<a href=https://codepen.io/tivac>@tivac</a>) on <a href=https://codepen.io>CodePen</a>.</p>
<script async src=https://production-assets.codepen.io/assets/embed/ei.js></script>
<p>Note: If you prefer <code><html></code> syntax, <a href=jsx.html>it's possible to use it via a Babel plugin</a>.</p>
<pre><code class=language-jsx>// HTML syntax via Babel's JSX plugin
<main>
<h1 class="title">My first app</h1>
<button>A button</button>
</main></code></pre>
<hr>
<h3 id=components><a href=#components>Components</a></h3>
<p>A Mithril component is just an object with a <code>view</code> function. Here's the code above as a component:</p>
<pre><code class=language-javascript>var Hello = {
view: function() {
return m("main", [
m("h1", {class: "title"}, "My first app"),
m("button", "A button"),
])
}
}</code></pre>
<p>To activate the component, we use <code>m.mount</code>.</p>
<pre><code class=language-javascript>m.mount(root, Hello)</code></pre>
<p>As you would expect, doing so creates this markup:</p>
<pre><code class=language-html><main>
<h1 class="title">My first app</h1>
<button>A button</button>
</main></code></pre>
<p>The <code>m.mount</code> function is similar to <code>m.render</code>, but instead of rendering some HTML only once, it activates Mithril's auto-redrawing system. To understand what that means, let's add some events:</p>
<pre><code class=language-javascript>var count = 0 // added a variable
var Hello = {
view: function() {
return m("main", [
m("h1", {class: "title"}, "My first app"),
// changed the next line
m("button", {onclick: function() {count++}}, count + " clicks"),
])
}
}
m.mount(root, Hello)</code></pre>
<p>We defined an <code>onclick</code> event on the button, which increments a variable <code>count</code> (which was declared at the top). We are now also rendering the value of that variable in the button label.</p>
<p>You can now update the label of the button by clicking the button. Since we used <code>m.mount</code>, you don't need to manually call <code>m.render</code> to apply the changes in the <code>count</code> variable to the HTML; Mithril does it for you.</p>
<p>If you're wondering about performance, it turns out Mithril is very fast at rendering updates, because it only touches the parts of the DOM it absolutely needs to. So in our example above, when you click the button, the text in it is the only part of the DOM Mithril actually updates.</p>
<h4 id=live-example1><a href=#live-example1>Live Example</a></h4>
<p data-height=300 data-theme-id=light data-slug-hash=rmBOQV data-default-tab=js,result data-user=tivac data-embed-version=2 data-pen-title="Mithril Component Example" data-preview=true class=codepen>See the Pen <a href=https://codepen.io/tivac/pen/rmBOQV/ >Mithril Component Example</a> by Pat Cavit (<a href=https://codepen.io/tivac>@tivac</a>) on <a href=https://codepen.io>CodePen</a>.</p>
<script async src=https://production-assets.codepen.io/assets/embed/ei.js></script>
<hr>
<h3 id=routing><a href=#routing>Routing</a></h3>
<p>Routing just means going from one screen to another in an application with several screens.</p>
<p>Let's add a splash page that appears before our click counter. First we create a component for it:</p>
<pre><code class=language-javascript>var Splash = {
view: function() {
return m("a", {href: "#!/hello"}, "Enter!")
}
}</code></pre>
<p>As you can see, this component simply renders a link to <code>#!/hello</code>. The <code>#!</code> part is known as a hashbang, and it's a common convention used in Single Page Applications to indicate that the stuff after it (the <code>/hello</code> part) is a route path.</p>
<p>Now that we're going to have more than one screen, we use <code>m.route</code> instead of <code>m.mount</code>.</p>
<pre><code class=language-javascript>m.route(root, "/splash", {
"/splash": Splash,
"/hello": Hello,
})</code></pre>
<p>The <code>m.route</code> function still has the same auto-redrawing functionality that <code>m.mount</code> does, and it also enables URL awareness; in other words, it lets Mithril know what to do when it sees a <code>#!</code> in the URL.</p>
<p>The <code>"/splash"</code> right after <code>root</code> means that's the default route, i.e. if the hashbang in the URL doesn't point to one of the defined routes (<code>/splash</code> and <code>/hello</code>, in our case), then Mithril redirects to the default route. So if you open the page in a browser and your URL is <code>https://localhost</code>, then you get redirected to <code>https://localhost/#!/splash</code>.</p>
<p>Also, as you would expect, clicking on the link on the splash page takes you to the click counter screen we created earlier. Notice that now your URL will point to <code>https://localhost/#!/hello</code>. You can navigate back and forth to the splash page using the browser's back and next button.</p>
<h4 id=live-example2><a href=#live-example2>Live Example</a></h4>
<p data-height=300 data-theme-id=light data-slug-hash=qmWOvr data-default-tab=js,result data-user=tivac data-embed-version=2 data-pen-title="Mithril Routing Example" data-preview=true class=codepen>See the Pen <a href=https://codepen.io/tivac/pen/qmWOvr/ >Mithril Routing Example</a> by Pat Cavit (<a href=https://codepen.io/tivac>@tivac</a>) on <a href=https://codepen.io>CodePen</a>.</p>
<script async src=https://production-assets.codepen.io/assets/embed/ei.js></script>
<hr>
<h3 id=xhr><a href=#xhr>XHR</a></h3>
<p>Basically, XHR is just a way to talk to a server.</p>
<p>Let's change our click counter to make it save data on a server. For the server, we'll use <a href=https://rem-rest-api.herokuapp.com>REM</a>, a mock REST API designed for toy apps like this tutorial.</p>
<p>First we create a function that calls <code>m.request</code>. The <code>url</code> specifies an endpoint that represents a resource, the <code>method</code> specifies the type of action we're taking (typically the <code>PUT</code> method <a href=https://en.wiktionary.org/wiki/upsert>upserts</a>), <code>body</code> is the payload that we're sending to the endpoint and <code>withCredentials</code> means to enable cookies (a requirement for the REM API to work)</p>
<pre><code class=language-javascript>var count = 0
var increment = function() {
m.request({
method: "PUT",
url: "//rem-rest-api.herokuapp.com/api/tutorial/1",
body: {count: count + 1},
withCredentials: true,
})
.then(function(data) {
count = parseInt(data.count)
})
}</code></pre>
<p>Calling the increment function <a href=https://en.wiktionary.org/wiki/upsert>upserts</a> an object <code>{count: 1}</code> to the <code>/api/tutorial/1</code> endpoint. This endpoint returns an object with the same <code>count</code> value that was sent to it. Notice that the <code>count</code> variable is only updated after the request completes, and it's updated with the response value from the server now.</p>
<p>Let's replace the event handler in the component to call the <code>increment</code> function instead of incrementing the <code>count</code> variable directly:</p>
<pre><code class=language-javascript>var Hello = {
view: function() {
return m("main", [
m("h1", {class: "title"}, "My first app"),
m("button", {onclick: increment}, count + " clicks"),
])
}
}</code></pre>
<p>Clicking the button should now update the count.</p>
<h4 id=live-example3><a href=#live-example3>Live Example</a></h4>
<p class=codepen data-height=265 data-theme-id=light data-default-tab=js,result data-user=isiahmeadows data-slug-hash=aeBZEq data-preview=true style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="Mithril XHR Example">
<span>See the Pen <a href=https://codepen.io/isiahmeadows/pen/aeBZEq/ >
Mithril XHR Example</a> by Isiah Meadows (<a href=https://codepen.io/isiahmeadows>@isiahmeadows</a>) on <a href=https://codepen.io>CodePen</a>.</span>
</p>
<script async src=https://static.codepen.io/assets/embed/ei.js></script>
<hr>
<p>We covered how to create and update HTML, how to create components, routes for a Single Page Application, and interacted with a server via XHR.</p>
<p>This should be enough to get you started writing the frontend for a real application. Now that you are comfortable with the basics of the Mithril API, <a href=simple-application.html>be sure to check out the simple application tutorial</a>, which walks you through building a realistic application.</p>
<hr>
<small>License: MIT. © Leo Horie.</small>
</section>
</main>
<script src=https://cdnjs.cloudflare.com/ajax/libs/prism/1.6.0/prism.min.js defer></script>
<script src=https://cdnjs.cloudflare.com/ajax/libs/prism/1.6.0/components/prism-jsx.min.js defer></script>
<script src=https://unpkg.com/mithril@2.0.3/mithril.js async></script>
<script>
document.querySelector(".hamburger").onclick = function() {
document.body.className = document.body.className === "navigating" ? "" : "navigating"
document.querySelector("h1 + ul").onclick = function() {
document.body.className = ''
}
}
</script>