You can find the original "10 Awesome Marko Features" article here!
Marko is a friendly and super fast UI library that makes building web apps
fun! In celebration of rapidly approaching 5,000 stars on GitHub (the ultimate open source vanity metric), here are 10 features that will make you more productive in no particular order...
Tired of constantly typing out class
and id
attributes? No need with Marko. Simply utilize the shorthand based on CSS selectors:
style {}// Equivalent to <div class="count"/><div.count/>// Equivalent to <span id="my-id"/><span#my-id/>// Combined<button#submit.primary/>
style {}// Equivalent to <div class="count"/>div.count// Equivalent to <span id="my-id"/>span#my-id// Combinedbutton#submit.primary
Unlike with HTML, you are not limited to string attribute values when using Marko. Attributes can have types, which makes it really easy to pass data to custom tags and it works for standard HTML tags too:
<div class=input.myClassName/><input type="checkbox" checked=input.isChecked/><awesome-component myString="Hello"/><awesome-component myNumber=1/><awesome-component myTemplateString=`Hello `/><awesome-component myBoolean=true/><awesome-component myArray=1, 2, 3/><awesome-component myObject={hello: 'world'}/><awesome-component myVariable=name/><awesome-component myFunctionCall=input.foo/>
div class=input.myClassNameinput type="checkbox" checked=input.isCheckedawesome-component myString="Hello"awesome-component myNumber=1awesome-component myTemplateString=`Hello `awesome-component myBoolean=trueawesome-component myArray=1, 2, 3awesome-component myObject={hello: "world"}awesome-component myVariable=nameawesome-component myFunctionCall=input.foo
Tired of boilerplate code and trouble managing component input and state? Marko makes it a breeze to develop self-contained and individually testable components. Changing state is completely synchronous, so there won’t be any headaches. You can also use inline styles making it very easy to develop small components quickly.
classstyle {}<div.count></div><button on-click'increment')>Click me!</button>
classstyle {}div.count --button on-click"increment") -- Click me!
Do you see references to “Marko” in the snippet above? Yeah, me neither.
Is your component becoming too large? Do you prefer separating your CSS, JavaScript, and markup code? No problem. You can easily rip out your code into multiple files:
components/click-counter/component.jsindex.markostyle.css
The DOM is just a tree structure. Indentation is a great way to describe a DOM tree without having to worry about matching up beginning and ending tags. Marko lets you choose between a concise, indentation-based syntax, and a familiar HTML syntax:
<!-- Count our clicks! --><div.count><p>Count: </p></div><button.example-button on-click'increment')>Click me!</button>
// Count our clicks!div.countp -- Count:button.example-button on-click"increment") -- Click me!
Here’s the same thing with the concise syntax:
// Count our clicks!div.countp -- Count:button.example-button on-click'increment') — Click me!
// Count our clicks!div.countp -- Count:button.example-button on-click"increment") — Click me!
Can’t make up your mind or just want to paste in that code snippet from StackOverflow? HTML syntax can be used within in the concise syntax. You’ll come back and make it consistent…one day.
Do you have some helper JavaScript functions that you need to use in your views? Marko let’s you import any JavaScript module into your template using the same syntax as the JavaScript import
statement without using Babel or any other build tool. No need for problematic globals (you could do that too, but please don’t or your coworkers will hate you).
import<div>The sum of 2 + 3 is </div>
importdiv -- The sum of 2 + 3 is
Marko uses your directory structure as a method for automatically registering custom tags. This means that Marko can implicitly import tags based on where the template is located on disk. Marko will search up the directory looking for custom tags in components/
directories similar to how Node.js discovers modules in node_modules/
directories.
Given the following directory structure:
components/fancy-button/index.markofancy-container/index.marko
If fancy-button
is used inside of fancy-container
, it will be implicitly
imported:
<!-- No need to use `require` or `import` because it will implicitly import custom tags --><div><fancy-button color=input.buttonColor/></div>
// No need to use `require` or `import` because it will implicitly import custom tagsdivfancy-button color=input.buttonColor
Setting CSS classes and styles is made easy using JavaScript! Marko will happily accept simple strings, JavaScript objects and arrays (falsy values will be ignored).
<div class='person', isActive && 'active'style={color: fontColor} />
div class="person", isActive && "active" style={color: fontColor}
Marko takes HTML and makes it more like JavaScript. You can exit out of HTML mode to embed a JavaScript statement by starting the line with a $
. You can use this feature to embed JavaScript variables, functions, etc. where they are needed (take that, “separation of concerns”).
<div>Random number: </div><div> is years old</div>
div -- Random number:div -- is years old
If you want to combine multiple JavaScript statements you can do that too:
<div>Random number: </div><div> is years old</div>
div -- Random number:div -- is years old
<await>
tagNode.js is asynchronous. Browsers are asynchronous. Why should rendering be synchronous? Pass your promise along to your template and Marko will asynchronously render parts of your view. Turns out, this is good for performance.
<awaitsearchResultsPromise><@thenperson>Hello !</@then><@catcherr>The error was: .</@catch></await>
awaitsearchResultsPromise@thenperson -- Hello !@catcherr -- The error was: .
Can’t decide if you want to do server-side rendering or client-side rendering? Why are we even talking about this in 2017? It doesn’t matter. Seriously, just do both. Marko makes this a no-brainer since you can render a Marko template directly to a stream (oh, and Marko will automatically mount UI components rendered on the server when the page loads in the browser):
; // require .marko files!const http = ;const template = ;http;
We all make mistakes every now and then. Typo in your custom tag? Forgot an ending tag? No worries! Marko will give you a friendly error message and point you right to the problematic code.
<!-- Ahhhh typo! This should be <fancy-button/> --><fancy-buttn/>
// Ahhhh typo! This should be <fancy-button/>fancy-buttn
You may have missed it, but it was obvious to Marko:
Unrecognized tag: fancy-buttn — More details: https://github.com/marko-js/marko/wiki/Error:-Unrecognized-Tag at line 2 col 1
Coming soon: auto correction and autonomous coding
Cover image credit: _[Wikipedia](https://commons.wikimedia.org/wiki/File:Amanhecer_no_Hercules--.jpg)
EDITHelpful? You can thank these awesome people! You can also edit this doc if you see any issues or want to improve it.