DEV Community

Cover image for Up and Running with Marko and Vite!
Austin Gardner
Austin Gardner

Posted on

Up and Running with Marko and Vite!

In this tutorial I will show you some of the basics of Marko.js and getting it set up with Vite.js!

Why Marko

Marko.js is a JS framework that is SSR (server-side rendered) by default with an MPA (multi-page app) architecture. eBay runs on it. It has been around for a few years but has gotten a lot of updates lately, like the new Vite plugin. Additionally new features that are coming soon like a concise syntax and improved performance will make Marko.js a great choice for many JS devs.

Did I mention even Dan Abramov (of the React core team) said we're on track to go where no JS framework has gone before?

MPA + SSR -- By Default!

Marko's MPA architecture allows it to run without needing a router like React Router or Vue Router, making things that much simpler for devs. And because it is SSR by default, there is no need to worry about anything like Next.js or Gatsby.

In this tutorial I will show how this all works.

Why Vite.js

Vite, like Webpack, takes care of your bundling needs, putting all of your HTML, CSS, JS and in our case .marko files together to serve to the browser.

Unlike Webpack, Vite is WAY faster and has an extremely minimal configuration. In this case we'll just use the command line and we won't have to worry about any configuration!

Vite also gives us hot module reloading, so when you save, the page automatically reloads. This is a very nice feature because you don't have to restart your dev server when you make changes to your code, it just reloads itself for you.

Let's Go!

First, you need NPX installed. If you haven't done that yet, go here and follow the instructions to install NVM, which will then allow you to get Node.js and NPX on your device.

Here is the repo for the finished code if you don't want to go through the tutorial step-by-step.

We'll call our app's directory marko-vite. Let's run npx @marko/create marko-vite in the command line. Then arrow down to Example from marko-js/examples, hit enter, then arrow to vite-express and hit enter again.

A directory named marko-vite will be generated for us.

Open it up in your code editor, and let's nuke some things.
Delete the components, pages, and services directories.

Next, make a new pages directory and put a file called index.js into it, with the following code:

import template from "./template.marko";

export default (req, res) => {
  res.marko(template, {});
};

Enter fullscreen mode Exit fullscreen mode

This just tells our server when it comes to this page, to load in our Marko template.

Next, let's make a basic Marko page!

Make a new file in the src/pages/ directory and call it template.marko, and add the following code:

<!DOCTYPE html>
<html>
<head>
  <title>Marko + Vite</title>
</head>
<body>
<h1>Hello World!</h1>
<div>
    <a href="/goodbye">Goodbye!</a>
</div>
<div>
    <a href="/counters">Count!</a>
</div>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

WAIT! Doesn't that look just like HTML? Marko is a superset of HTML, so anything that is HTML can be taken care of by Marko.

Next, let's make a file named goodbye.js in the src/pages directory and put the following code in:

import goodbye from "./goodbye.marko";

export default (req, res) => {
  res.marko(goodbye, {});
};
Enter fullscreen mode Exit fullscreen mode

and another file called goodbye.marko:

<!DOCTYPE html>
<html>
<head>
  <title>Marko + Vite</title>
</head>
<body>
<h1>See you later world!</h1>
<div>
    <div>
        Bye Bye!
    </div>
    👋
</div>
<div>
    <a href="/">Hello Again!</a>
</div>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

Then let's update the src/index.js file to make sure we have the right routes. We'll worry about the /counters in a little bit:

import { Router } from "express";
import indexPage from "./pages/index";
import goodbyePage from "./pages/goodbye";

export default Router()
  .get("/", indexPage)
  .get("/goodbye", goodbyePage)
Enter fullscreen mode Exit fullscreen mode

Running the project

Now let's run the project! run npm run dev and navigate to localhost:3000. You should see something like this:

Screen Shot 2021-05-20 at 4.03.13 PM

and then if you navigate to the goodbye link, you should see something like this:

Screen Shot 2021-05-20 at 4.03.23 PM

But wait! We haven't added JS to the browser yet! Let's keep rolling!

Adding Components!

let's make a file in src/pages/ called counters.js and add the code:

import counters from "./counters.marko";

export default (req, res) => {
  res.marko(counters, {});
};
Enter fullscreen mode Exit fullscreen mode

then another file in src/pages/ called counters.marko and add the code:

<!DOCTYPE html>
<html>
<head>
  <title>Marko + Vite</title>
</head>
<body>
<h1>Count 'em up!</h1>
<div>
    <counter/>
    <counter/>
    <counter/>
    <counter/>
    <counter/>
</div>
<div>
    <a href="/">Back to home</a>
</div>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

Woah! This looks different... where are those counter tags coming from? That's no longer valid HTML! You see, Marko automatically detects Marko components in our src/ directory, and then adds them into their respective places. Pretty nifty!

Adding Counters

Let's make a new directory under src called components and then make the file src/components/counter.marko. Then let's add the code:

class {
    onCreate() {
        this.state = {
            count: 0
        };
    }
    increment() {
        this.state.count++;
    }
}

<div>
    Count is: <output>${state.count}</output>
</div>
<div>
    <button on-click('increment')>
        Click Here!   
    </button>
</div>
Enter fullscreen mode Exit fullscreen mode

Here we have a basic counter, which increments based on the on-click handler we added to the button. Marko allows us to combine the JS and the HTML in one page in this way!

(There are cases where you can or should separate out the JS from the .marko file -> see Marko docs for more info).

Now we're almost ready to show off our counters! We just need to add the new <a/> tag into our template.marko file and add the routes into our src/index.js file.

Now our src/index.js file will look like this:

import { Router } from "express";
import indexPage from "./pages/index";
import goodbyePage from "./pages/goodbye";
import countersPage from "./pages/counters";

export default Router()
  .get("/", indexPage)
  .get("/goodbye", goodbyePage)
  .get("/counters", countersPage);
Enter fullscreen mode Exit fullscreen mode

and our src/pages/template.marko like this:

<!DOCTYPE html>
<html>
<head>
  <title>Marko + Vite</title>
</head>
<body>
<h1>Hello World!</h1>
<div>
    <a href="/goodbye">Goodbye!</a>
</div>
<div>
    <a href="/counters">Count!</a>
</div>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

Notice how on saving the files, Vite re-runs things for us - that is hot module reloading at work. Then from our base page, clicking on the count! link gives us a lot of buttons to click on! Alright!!

Screen Shot 2021-05-20 at 4.15.31 PM

Conclusion

Here we can see that using Marko with Vite allows us to use some shortcuts compared to React. SSR by default, no router needed.

Read more about the future of Marko!

See Ryan Carniato's posts FLUURT overview for an overview of the future changes to Marko; UI language for more specifics on the conciseness of Marko's future syntax; and Michael Rawling's Maybe you don't need that SPA about how Marko's server-native architecture puts Marko on the path to sub-component level hydration, enabling high levels of SSR performance.

Top comments (7)

Collapse
 
knyto2 profile image
Kenny To

Thanks for the quick tutorial! I'm running into an issue with creating the starter app

npx @marko/create marko-vite

Default starter app   throw new DegitError(`could not download ${url}`, {
  Example from marko-js/      ^s

DegitError: could not download https://github.com/marko-js/examples/archive/d291aecad7b91babb255b09500c06334cdb21ad3.tar.gz
Enter fullscreen mode Exit fullscreen mode

Any ideas?

Collapse
 
nicolab profile image
Nicolas Talle

Wow impressive! Exactly what I need, I will test it, thanks :)

Collapse
 
austingardner profile image
Austin Gardner

You're welcome Nicolas! Also feel free to join the Marko Discord server if you want to learn more about Marko!

discord.com/invite/marko

Collapse
 
nicolab profile image
Nicolas Talle

Thanks, I'm in Marko's Discord (Nico64) ;)
In the meantime, I had the opportunity to test Marko, the SSR etc. It's validated, I'm using it for the redesign/refacto of a SaaS!

Collapse
 
artydev profile image
artydev

Thank you

Collapse
 
sugartayta profile image
bruno gonzales

Great article!

Collapse
 
austingardner profile image
Austin Gardner

Thanks Bruno!