UNPKG

8.16 kBMarkdownView Raw
1<a href="#">
2 <img src="https://cdn-images-1.medium.com/max/1000/1*Cmy6UutD5-ogL8dr1DySMQ.png" alt="Marko logo" width="100%" />
3</a><br />
4
5You can find the original ["10 Awesome Marko Features" article here](https://medium.com/@austinkelleher/10-awesome-marko-features-afba9d094d42)!
6
7# 10 Awesome Marko Features
8
9[Marko](http://markojs.com/) is a friendly and super fast UI library that makes
10building web apps<br> fun! In celebration of rapidly approaching [5,000 stars on
11GitHub](https://github.com/marko-js/marko) (the ultimate open source vanity
12metric), here are 10 features that will make you more productive in no
13particular order...
14
15#### 1. Shorthand Attributes
16
17Tired of constantly typing out `class` and `id` attributes? No need with Marko.
18Simply utilize the shorthand based on CSS selectors:
19
20```marko
21style {
22 .count {
23 color:#09c;
24 }
25}
26
27// Equivalent to <div class="count"/>
28<div.count/>
29
30// Equivalent to <span id="my-id"/>
31<span#my-id/>
32
33// Combined
34<button#submit.primary/>
35```
36
37#### 2. All attribute values are Just JavaScript™
38
39Unlike with HTML, you are not limited to string attribute values when using
40Marko. Attributes can have types, which makes it really easy to pass data to
41custom tags and it works for standard HTML tags too:
42
43```marko
44<div class=input.myClassName/>
45<input type="checkbox" checked=input.isChecked/>
46<awesome-component myString="Hello"/>
47<awesome-component myNumber=1/>
48<awesome-component myTemplateString=`Hello ${name}`/>
49<awesome-component myBoolean=true/>
50<awesome-component myArray=[1, 2, 3]/>
51<awesome-component myObject={hello: 'world'}/>
52<awesome-component myVariable=name/>
53<awesome-component myFunctionCall=input.foo()/>
54```
55
56#### 3. Isomorphic UI components made easy
57
58Tired of boilerplate code and trouble managing component input and state? Marko
59makes it a breeze to develop self-contained and individually testable
60components. Changing state is completely synchronous, so there won’t be any
61headaches. You can also use inline styles making it very easy to develop small
62components quickly.
63
64```marko
65class {
66 onInput(input) {
67 this.state = {
68 count: input.count || 0
69 };
70 }
71 increment() {
72 this.state.count++;
73 }
74}
75
76style {
77 .count {
78 color:#09c;
79 }
80}
81
82<div.count>${state.count}</div>
83<button on-click('increment')>
84 Click me!
85</button>
86```
87
88Do you see references to “Marko” in the snippet above? Yeah, me neither.
89
90Is your component becoming too large? Do you prefer separating your CSS,
91JavaScript, and markup code? No problem. You can easily [rip out your code into
92multiple files](http://markojs.com/docs/components/#multi-file-components):
93
94```
95components/
96 click-counter/
97 component.js
98 index.marko
99 style.css
100```
101
102#### 4. Concise syntax
103
104The DOM is just a tree structure. Indentation is a great way to describe a DOM
105tree without having to worry about matching up beginning and ending tags. Marko
106lets you choose between a concise, indentation-based syntax, and a familiar HTML
107syntax:
108
109```marko
110<!-- Count our clicks! -->
111<div.count>
112 <p>Count: ${state.count}</p>
113</div>
114<button.example-button on-click('increment')>
115 Click me!
116</button>
117```
118
119Here’s the same thing with the concise syntax:
120
121```marko
122// Count our clicks!
123div.count
124 p -- Count: ${state.count}
125button.example-button on-click('increment') — Click me!
126```
127
128Can’t make up your mind or just want to paste in that code snippet from
129StackOverflow? HTML syntax can be used within in the concise syntax. You’ll come
130back and make it consistent…_one day_.
131
132#### 5. Import JavaScript modules
133
134Do you have some helper JavaScript functions that you need to use in your views?
135Marko let’s you import any JavaScript module into your template using the same
136syntax as the JavaScript `import` statement without using Babel or any other
137build tool. No need for problematic globals (you could do that too, but please
138don’t or your coworkers will hate you).
139
140```marko
141import sum from './utils/sum';
142
143<div>The sum of 2 + 3 is ${sum(2, 3)}</div>
144```
145
146#### 6. No need to import custom tags (it’s a good thing, trust me)
147
148Marko uses your directory structure as a method for automatically registering
149custom tags. This means that Marko can implicitly import tags based on where the
150template is located on disk. Marko will search up the directory looking for
151custom tags in `components/`directories similar to how Node.js discovers modules
152in `node_modules/` directories.
153
154Given the following directory structure:
155
156```
157components/
158 fancy-button/
159 index.marko
160 fancy-container/
161 index.marko
162```
163
164If `fancy-button` is used inside of `fancy-container`, it will be implicitly<br>
165imported:
166
167```marko
168<!-- No need to use `require` or `import` because it will implicitly import custom tags -->
169<div>
170 <fancy-button color=input.buttonColor/>
171</div>
172```
173
174#### 7. Use JavaScript to set CSS classes and styles
175
176Setting CSS classes and styles is made easy using JavaScript! Marko will happily
177accept simple strings, JavaScript objects and arrays (_falsy values will be
178ignored)._
179
180```marko
181$ const fontColor = input.color || 'blue';
182$ const isActive = input.active === true;
183
184<div class=['person', isActive && 'active']
185 style={color: fontColor} />
186```
187
188#### 8. Inline JavaScript Statements
189
190Marko takes HTML and makes it more like JavaScript. You can exit out of HTML
191mode to embed a JavaScript statement by starting the line with a `$`. You can
192use this feature to embed JavaScript variables, functions, etc. where they are
193needed (take that, “separation of concerns”).
194
195```marko
196$ const randomNumber = Math.random();
197$ const person = {
198 name: 'Frank',
199 age: 32
200};
201
202<div>Random number: ${randomNumber}</div>
203<div>${person.name} is ${person.age} years old</div>
204```
205
206If you want to combine multiple JavaScript statements you can do that too:
207
208```marko
209$ {
210 const randomNumber = Math.random();
211 const person = {
212 name: 'Frank',
213 age: 32
214 };
215}
216
217<div>Random number: ${randomNumber}</div>
218<div>${person.name} is ${person.age} years old</div>
219```
220
221#### 9. Async rendering with the `<await>` tag
222
223Node.js is asynchronous. Browsers are asynchronous. Why should rendering be
224synchronous? Pass your promise along to your template and Marko will
225asynchronously render parts of your view. Turns out, [this is good for
226performance](http://www.ebaytechblog.com/2014/12/08/async-fragments-rediscovering-progressive-html-rendering-with-marko/).
227
228```marko
229$ const searchResultsPromise = searchService.performSearch(keywords);
230
231<await(searchResultsPromise)>
232 <@then|person|>
233 Hello ${person.name}!
234 </@then>
235 <@catch|err|>
236 The error was: ${err.message}.
237 </@catch>
238</await>
239```
240
241#### 10. Server side rendering is easy
242
243Can’t decide if you want to do server-side rendering or client-side rendering?
244Why are we even talking about this in 2017? It doesn’t matter. Seriously, just
245do both. Marko makes this a no-brainer since you can render a Marko template
246directly to a stream (oh, and Marko will [automatically mount UI
247components](http://markojs.com/docs/server-side-rendering/) rendered on the
248server when the page loads in the browser):
249
250```js
251require("marko/node-require").install(); // require .marko files!
252
253const http = require("http");
254const template = require("./template");
255
256http
257 .createServer()
258 .on("request", (req, res) => {
259 template.render(
260 {
261 name: "Frank",
262 count: 30,
263 colors: ["red", "green", "blue"]
264 },
265 res
266 );
267 })
268 .listen(8080);
269```
270
271#### Bonus: Friendly compile-time errors
272
273We all make mistakes _every now and then_. Typo in your custom tag? Forgot an
274ending tag? No worries! Marko will give you a friendly error message and point
275you right to the problematic code.
276
277```marko
278<!-- Ahhhh typo! This should be <fancy-button/> -->
279<fancy-buttn/>
280```
281
282You may have missed it, but it was obvious to Marko:
283
284```
285Unrecognized tag: fancy-buttn — More details: https://github.com/marko-js/marko/wiki/Error:-Unrecognized-Tag at line 2 col 1
286```
287
288Coming soon: auto correction and autonomous coding
289
290---
291
292_Cover image credit:
293_[Wikipedia](https://commons.wikimedia.org/wiki/File:Amanhecer_no_Hercules_--.jpg)