Skip to main content
Photo by Shubh karman Singh via Unsplash

Refactoring my screenshot script

My go-to-script to create a screenshot as header images of posts about a website was for a long time this:

1const { chromium } = require('playwright');
2(async () => {
3let browser = await chromium.launch();
4    let page = await browser.newPage();
5    await page.setViewportSize({ width: 1200, height: 600 });
6    await page.goto(process.argv[2]);
7    await page.screenshot({ path: 'header.jpg' });
8    await browser.close();
9})();

The only dynamic component here was the URL to screenshot, which I passed as a command line argument that is read as process.argv[2] in this script. Args 0 and 1 are the node and script name, so the URL as the first parameter is at index 2.

This script is called like this:

1node script.js https://example.com

I had several issues with this script:

  • it was not configurable for parameters like width and height of the screenshot and the path to the output file
  • it was a CommonJS script and not an ESM module, which is basically the standard for Node.js now

So I decided to rewrite it a little bit.

To configure this script with CLI parameters, we can use a command-line argument parser like yargs or commander. I decided on yargs for now:

 1const { chromium } = require("playwright");
 2const argv = require('yargs').argv;
 3(async () => {
 4let browser = await chromium.launch();
 5    let page = await browser.newPage();
 6    await page.setViewportSize({
 7      width: argv.width || 1200,
 8      height: argv.height || 600
 9    });
10    await page.goto(argv.url || 'https://example.com');
11    await page.screenshot({ path: argv.output || 'header.jpg' });
12    await browser.close();
13})();

In this modified script, we import the “yargs” library and parse the command-line arguments using argv. The script now accepts the following parameters:

  • --url: The URL to capture a screenshot of (default: https://example.com/).
  • --width: The width of the viewport (default: 1200).
  • --height: The height of the viewport (default: 600).
  • --output: The file name to save the screenshot as (default: header.jpg).

You can now run the script using the following command:

1node script.js \
2  --url=https://example.com \
3  --width=800 \
4  --height=600 \
5  --output=screenshot.jpg

This will capture a screenshot of the “https://example.com” website with a viewport size of 800×600 and save it as “screenshot.jpg”. If you don’t specify any of the parameters, the script will use the default values.

To rewrite this script as an ESM module, we need to change the way we import and export the code. Here’s how:

 1import { chromium } from "playwright";
 2const takeScreenshot = async (url = "https://example.com/", output = "header.jpg", width = 1200, height = 600) => {
 3  const browser = await chromium.launch();
 4  const page = await browser.newPage();
 5  await page.setViewportSize({ width, height });
 6  await page.goto(url);
 7  await page.screenshot({ path: output });
 8  await browser.close();
 9};
10export default takeScreenshot;

The takeScreenshot function accepts the same parameters as above.

To use this module in another script or module, you can import it like this:

1import takeScreenshot from "./script.js";
2await takeScreenshot("https://example.com", "screenshot.jpg", 800, 600);

Note that you need to specify the file extension “.js” when importing the module.

Now lets rewrite this script to be run from the CLI with yargs:

 1import { chromium } from "playwright";
 2import yargs from "yargs";
 3import { hideBin } from 'yargs/helpers';
 4
 5const argv = yargs(hideBin(process.argv))
 6 .option("url", {
 7  describe: "URL to capture a screenshot of",
 8  demandOption: true,
 9  type: "string"
10 })
11 .option("output", {
12  describe: "Output file name",
13  default: "header.jpg",
14  type: "string"
15 })
16 .option("width", {
17  describe: "Viewport width",
18  default: 1200,
19  type: "number"
20 })
21 .option("height", {
22  describe: "Viewport height",
23  default: 600,
24  type: "number"
25 })
26 .help()
27 .alias("help", "h").argv;
28
29export const takeScreenshot = async (url, output, width, height) => {
30 const browser = await chromium.launch();
31 const page = await browser.newPage();
32 await page.setViewportSize({ width, height });
33 await page.goto(url);
34 await page.screenshot({ path: output });
35 await browser.close();
36};
37
38// @ts-ignore
39takeScreenshot(argv.url, argv.output, argv.width, argv.height);

In this modified script, we use the yargs library to parse command-line arguments. Notice the extended option lines in the beginning. They will be automatically converted to a helpful CLI help message when running the script with the --help (or -h) parameter.

To run this script from the CLI, you can save it as a file (for example screenshot.js) and then run the following command:

1node screenshot.js --url=https://example.com --output=screenshot.jpg --width=800 --height=600

This will capture a screenshot of the “https://example.com” website with a viewport size of 800×600 and save it as “screenshot.jpg”.

I feel like this is enough change for now. If you have any questions or suggestions, feel free to leave a comment below. If you think I could optimise another part of the script, let me know too.

Back to top
Back Forward