Vue: Create live screenshots from Vue components

Last modified Jan 24 2021 1:07 by Kees de Kooter

TL;DR

How can you make sure that the screenshots in your documentation reflect the actual components in your application? When the application is in flux - read: always - manually clicking through the app and taking screenshots by hand is not a feasible option. We can do better than that!

Render the actual components on a dedicated page in the application, populated with the proper demo data. And let the screenshots be taken by a headless browser!

Oh and this approach could also be applied the other front-end frameworks of course.

Screenshot page component

This vue component contains instances of all components to be screenshot. The components are "dumb views" that get their state through properties. That way the entire state can be set outside the component, and demo data can be prepared specifically for documentation purposes.

<section class="screenshot-container" data-name="<the target file name>">
    <the-component :data="mockData"></the-component>
</section>

Route available only at dev time

Mount this view on a route only available at dev time.

if (process.env.NODE_ENV === 'development') {
  routes.push({
    path: '/screenshots',
    components: {
      default: Screenshots
    }
  })
}

Let puppeteer pull the shots

Puppeteer - the automated headless Chrome browser - will take care of making the screenshots. It loads your screenshot page and creates a screenshot of every screenshot-container element.

The following nodejs script does the trick.

const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch()
  const page = await browser.newPage();

  await page.goto('<url-of-your-screenshot-page>')

  // Get the handles for all screenshot elements
  const elementHandles = await page.$$('.screenshot-container')

  for (let elementHandle of elementHandles) {
    // Get the file name from the `data-name` attribute
    const fileName = await page.evaluate(
      (element) => element.dataset.name,
      elementHandle
    )
    
    const path = __dirname + '/out/' + fileName + '.png'
    await elementHandle.screenshot({ path: path })
  }

  await browser.close()
})();