user1835017
user1835017

Reputation: 353

Clean way to render and re-use RactiveJS components/templates

Alright. I'm burdened by SEO reasons to amend an app done in expressjs/Ractive to support server-side rendering.

The front end side of things is packaged up using gulp and everything's organized into a clean nested component structure.

Is there any way to leverage most of what's in place to also render some of those components on the server? I've been hacking with ractive-render, but the documentation leaves so much to be desired and honestly I'm afraid it's gonna' leave me marooned in the end.

My components, for the most part, contain way too much template to slap inline on the component definition. They are organized in a folder hierarchy with the lowest level being an individual component folder containing an index.js component definition, and a template.html template file. I use ractivate for the gulp/browserify process to pull those .html template files in when building.

I'm looking for a solution that will allow me to package up the components to use both with browserify/gulp as well as with something like ractive-render to render them in express.

It's cool if it's not possible, but my research so far has been great at granting me headaches.

Upvotes: 3

Views: 583

Answers (1)

Rich Harris
Rich Harris

Reputation: 29605

It's possible – the examples.ractivejs.org site is an Express app that renders Ractive components on the server. (FWIW the repo is here, though it's a perpetual work-in-progress and may not be especially illuminating other than to show that it's possible – the shared folder contains some components that are rendered on both server and client).

Essentially, you're just instantiating a Ractive instance exactly the same as you would in a browser, except that you don't provide the el property or call ractive.render(el). Instead, you call ractive.toHTML().

So a snippet of your express app might look like this:

var Article = require( './components/Article' );
var fetchArticle = require( './utils/fetchArticle' );

var page = `
  <!DOCTYPE html>
  <html>
  <head>...</head>
  <body>
    <@content@>
    <script src='app.js'></script>
  </body>
  </html>`;

app.get( '/articles/:slug', function ( req, res ) {
  var slug = req.params.slug;

  fetchArticle( slug )
    .then( articleData => {
      var ractive = new Article({
        data: {
          article: articleData,
          user: userData
        }
      });

      var html = page
        .replace( '<@content@>', ractive.toHTML() );

      res.send( html );
    });
  });
});

Of course you could also re-use the same instance each time, just resetting the data.

Ractive doesn't currently have any way to progressively enhance server-rendered HTML – in other words when you render the component client-side, you'll trash the existing DOM. That's something we plan to address in a future release.

Upvotes: 2

Related Questions