Foreword: In daily front-end development, toC business will inevitably have some screenshots or poster generating business requirements are limited by html2Canvas incompatibility or canvas drawing style limitations. Now we have a new solution, the combination of Node and Puppeteer.

puppeteer

Puppeteer met

Puppeteer is Google Chrome’s official Headless Chrome tool. As the browser market leader, Chrome Headless will become an industry benchmark for automated testing of Web applications

So what can we use puppeteer for?

  • Generate a screenshot or PDF of the page
  • Automatic simulation of user behavior, form submission, button clicking, etc
  • Create an automated test environment
  • Capture a timeline trace of the site to help diagnose performance problems.
  • Crawl SPA page and pre-render (i.e. ‘SSR’)

So the first feature is the one we use

Puppeteer installation

NPM install puppeteer // The download step may fail, CNPM or science onlineCopy the code

Main apis puppeteer

This section only describes screenshots. To query information about other features, go to github.com/puppeteer/p…

1. Start the instance

import * as puppeteer from 'puppeteer'

(async () => {
  await puppeteer.launch()
})()
Copy the code

2. Screenshot of web page

PNG screenshots

SetViewport ({width, height}) await page.goto(url) // In the whole page screenshot await page.screenshot({path: Resolve ('./screenshot/${fileName}.png '), // Screenshot save path type: 'PNG ', fullPage: false})Copy the code

Not only that, it can also simulate the device environment of mobile phones

import * as puppeteer from "puppeteer"; import * as devices from "puppeteer/DeviceDescriptors"; const iPhone = devices["iPhone 6"]; (async () => { const browser = await puppeteer.launch({ headless: false }); const page = await browser.newPage(); await page.emulate(iPhone); await page.goto("https://baidu.com/"); await browser.close(); }) ();Copy the code

PDF screenshots

(async () => { const browser = await puppeteer.launch(); const page = await browser.newPage(); await page.goto("https://example.com/"); await page.pdf({ displayHeaderFooter: true, path: 'example.pdf', format: 'A4', headerTemplate: '<b style="font-size: 30px">Hello world<b/>', footerTemplate: '<b style="font-size: 30px">Some text</b>', margin: { top: "100px", bottom: "200px", right: "30px", left: "30px", } }); await browser.close(); }) ()Copy the code

Ok, so with this we can meet our basic screenshot needs

Basic architecture

instructions

Request interface: This API will directly request to the Node service, carrying parameters including:

  • Hosted page address (for the address of the page to be captured)
  • Want the width and height of the screenshot
  • Type of screenshot (PNG/PDF)

Screenshot hosting page: Static HTML page. Url can pass parameters to control variables

After receiving the interface request, the Node service will request to host the page, build an API to capture the page, perform the screenshot operation, and return the screenshot buffer data to the requested interface. At this end, our infrastructure is organized

In the demo code

Front-end environment, assuming we now have a node environment available (Node + KOA2)

// Router layer const screenshotControllers = require('.. /controllers/puppeteer') const router = new KoaRouter() exports.router = router.post('/api/puppeteer/v1/screenshot', screenshotControllers.api.screenshot)Copy the code
// const service = require('.. /service/puppeteer') const screenshot = (ctx, next) => { return service.api.screenshot(ctx); } exports.api = { screenshot }Copy the code
// service layer const {getScreenshot} = require('.. /puppeteer/index') exports.api = { screenshot: async (ctx) => { const { width, height, url, tid} = ctx.request.body const res = await getScreenshot(url, width, Height, tid) console.log(res) if (res) {ctx.body = {code: 200, message: 'success ', data: res}}}}Copy the code
// puppeteer = require('puppeteer') const puppeteer = require('puppeteer'); const path = require('path') exports.getScreenshot = async (url, width = 800, height = 600, fileName) => { const browser = await puppeteer.launch() const page = await browser.newPage() SetViewport ({width, {width,}) {{width,}} Height}) await page.goto(url) // go screenshot await page.screenshot({path: Resolve ('./screenshot/${fileName}.png '), // Screenshot save path type: 'PNG ', fullPage: // Execute cos or OSS script to upload image to CDN environment. Close () await browser.close() return '${fileName}.png'}Copy the code

Test service availability

Starting the Node Service

Start the PSOTMAN mock request interface

1. Baidu

View the results

2. The nuggets

{
    "url": "https://juejin.cn/",
    "width": 720,
    "height": 1080,
    "tid": 0
}
Copy the code

Well, it doesn’t seem to be a problem

Specific business application

There is a need to generate posters, so what should we do?

2. Write the back-end logic according to the variable ID passed in.

3. Invoke the Node service to obtain the image buffer or image CDN address

await axios({ method: 'POST', url: 'http://xxx/api/puppeteer/v1/screenshot', data: { url: `http://xxx/postFrame/home? lecCode=lec${i}`, width: 335, height: 525, tid: `lec${i}` } })Copy the code

The result is a solution that smoothes out the differences between operating environments and reduces the failure rate of locally generated images

More benefits and collections can be found at 👇