Marko

Rendering

To render a Marko view, you need to require it.

example.js
var fancyButton = require("./components/fancy-button");

Note: If you are targeting node.js, you will need to enable the require extension in order to require .marko files or you will need to precompile all of your templates using Marko CLI. If you are targeting the browser, you will need to use a bundler like lasso, webpack or rollup.

Once you have a view, you can pass input data and render it:

example.js
var button = require("./components/fancy-button");
var html = button.renderToString({ label: "Click me!" });

console.log(html);

The input data becomes available as input within a view, so if fancy-button.marko looked like this:

./components/fancy-button.marko
<button>${input.label}</button>
button -- ${input.label}

The output HTML would be:

<button>Click me!</button>

Rendering methods

We used the renderToString method above to render the view, but there are a number of different method signatures that can be used to render.

Many of these methods return a RenderResult which is an object with helper methods for working with the rendered output.

renderSync(input)

paramstypedescription
inputObjectthe input data used to render the view
return valueRenderResultThe result of the render

Using renderSync forces the render to complete synchronously. If a tag attempts to run asynchronously, an error will be thrown.

var view = require("./view"); // Import `./view.marko`
var result = view.renderSync({});

result.appendTo(document.body);

render(input)

paramstypedescription
inputObjectthe input data used to render the view
return valueAsyncStream/AsyncVDOMBuilderthe async out render target

The render method returns an async out which is used to generate HTML on the server or a virtual DOM in the browser. In either case, the async out has a then method that follows the Promises/A+ spec, so it can be used as if it were a Promise. This promise resolves to a RenderResult.

var view = require("./view"); // Import `./view.marko`
var resultPromise = view.render({});

resultPromise.then(result => {
  result.appendTo(document.body);
});

render(input, callback)

paramstypedescription
inputObjectthe input data used to render the view
callbackFunctiona function to call when the render is complete
callback valueRenderResultThe result of the render
return valueAsyncStream/AsyncVDOMBuilderthe async out render target
var view = require("./view"); // Import `./view.marko`

view.render({}, (err, result) => {
  result.appendTo(document.body);
});

render(input, stream)

paramstypedescription
inputObjectthe input data used to render the view
streamWritableStreama writeable stream
return valueAsyncStream/AsyncVDOMBuilderthe async out render target

The HTML output is written to the passed stream.

var http = require("http");
var view = require("./view"); // Import `./view.marko`

http.createServer((req, res) => {
  res.setHeader("content-type", "text/html");
  view.render({}, res);
});

render(input, out)

paramstypedescription
inputObjectthe input data used to render the view
outAsyncStream/AsyncVDOMBuilderThe async out to render to
return valueAsyncStream/AsyncVDOMBuilderThe out that was passed

The render method also allows passing an existing async out. If you do this, render will not automatically end the async out (this allows rendering a view in the middle of another view). If the async out won't be ended by other means, you are responsible for ending it.

var view = require("./view"); // Import `./view.marko`
var out = view.createOut();

view.render({}, out);

out.on("finish", () => {
  console.log(out.getOutput());
});

out.end();

renderToString(input)

paramstypedescription
inputObjectthe input data used to render the view
return valueStringThe HTML string produced by the render

Returns an HTML string and forces the render to complete synchronously. If a tag attempts to run asynchronously, an error will be thrown.

var view = require("./view"); // Import `./view.marko`
var html = view.renderToString({});

document.body.innerHTML = html;

renderToString(input, callback)

paramstypedescription
inputObjectthe input data used to render the view
callback valueStringThe HTML string produced by the render
return valueundefinedN/A

An HTML string is passed to the callback.

var view = require("./view"); // Import `./view.marko`

view.renderToString({}, (err, html) => {
  document.body.innerHTML = html;
});

stream(input)

The stream method returns a node.js style stream of the output HTML. This method is available on the server, but is not available by default in the browser. If you need to use streams in the browser, you may require('marko/stream') as part of your client-side bundle.

var fs = require("fs");
var view = require("./view"); // Import `./view.marko`
var writeStream = fs.createWriteStream("output.html");

view.stream({}).pipe(writeStream);

RenderResult

getComponent()

getComponents(selector)

afterInsert(doc)

getNode(doc)

getOutput()

appendTo(targetEl)

insertAfter(targetEl)

insertBefore(targetEl)

prependTo(targetEl)

replace(targetEl)

replaceChildrenOf(targetEl)

Global data

If you need to make data available globally to all views that are rendered as the result of a call to one of the above render methods, you can pass the data as a $global property on the input data object. This object will be removed from input and merged into the out.global property.

view.render({
  $global: {
    flags: ["mobile"]
  }
});

To prevent sensitive data to be accidentally shipped to the browser, by default none of the keys in out.global is going to be sent to the browser. If you want the data to be serialized and ship to the frontend you need to specify it in serializedGlobals inside the $global object and they persist across re-renderings. The values need to be serializable.

app.get("/", (req, res) => {
  const ua = req.get("User-Agent");
  const isIos = !!ua.match(/iPad|iPhone/);
  const isAndroid = !!ua.match(/Android/);

  require("./index.marko").render(
    {
      $global: {
        isIos, // isPad is serialized and available on the server and the browser in out.global.isPad
        isAndroid, // isAndroid is serialized and available on the server and the browser in out.global.isAndroid
        req, // req is going to be available only server side and will not be serialized because in not present in serializedGlobals below

        serializedGlobals: {
          isIos: true, // Tell marko to serialize isIos above
          isAndroid: true // Tell marko to serialize isAndroid above
        }
      }
    },
    res
  );
});

Use $global with judgement. It is global and visible in any component.

Check this PR for more details.

EDIT

Contributors

Helpful? You can thank these awesome people! You can also edit this doc if you see any issues or want to improve it.

Chat in Marko's Discord Server