Skip to content

Commit

Permalink
Require Node.js 18
Browse files Browse the repository at this point in the history
  • Loading branch information
sindresorhus committed Nov 6, 2023
1 parent 0fcabdf commit d34d622
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 60 deletions.
7 changes: 3 additions & 4 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,11 @@ jobs:
fail-fast: false
matrix:
node-version:
- 20
- 18
- 16
- 14
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- run: npm install
Expand Down
62 changes: 33 additions & 29 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,16 @@
"url": "https://sindresorhus.com"
},
"type": "module",
"exports": "./dist/index.js",
"types": "./dist/index.d.ts",
"exports": {
"types": "./dist/index.d.ts",
"default": "./dist/index.js"
},
"sideEffects": false,
"engines": {
"node": ">=14.16"
"node": ">=18"
},
"scripts": {
"test": "xo && nyc ava",
"test": "xo && tsc --noEmit && nyc ava",
"release": "np",
"build": "del-cli dist && tsc",
"prepare": "npm run build"
Expand Down Expand Up @@ -58,44 +61,44 @@
"dependencies": {
"array-differ": "^4.0.0",
"array-uniq": "^3.0.0",
"capture-website": "^3.2.0",
"date-fns": "^2.29.2",
"filenamify": "^5.1.1",
"capture-website": "^4.0.0",
"date-fns": "^2.30.0",
"filenamify": "^6.0.0",
"filenamify-url": "^3.0.0",
"get-res": "^3.0.0",
"lodash.template": "^4.5.0",
"log-symbols": "^5.1.0",
"make-dir": "^3.1.0",
"p-map": "^5.5.0",
"p-memoize": "^7.1.0",
"log-symbols": "^6.0.0",
"make-dir": "^4.0.0",
"p-map": "^6.0.0",
"p-memoize": "^7.1.1",
"plur": "^5.1.0",
"type-fest": "^3.1.0",
"type-fest": "^4.6.0",
"unused-filename": "^4.0.1",
"viewport-list": "^5.1.1"
},
"devDependencies": {
"@sindresorhus/tsconfig": "^3.0.1",
"@types/cookie": "^0.5.1",
"@types/get-res": "^3.0.1",
"@types/lodash.template": "^4.5.1",
"@types/node": "^18.7.14",
"@types/png.js": "^0.2.1",
"@types/sinon": "^10.0.13",
"@types/viewport-list": "^5.1.1",
"ava": "^4.3.3",
"@sindresorhus/tsconfig": "^5.0.0",
"@types/cookie": "^0.5.3",
"@types/get-res": "^3.0.2",
"@types/lodash.template": "^4.5.2",
"@types/node": "^20.8.10",
"@types/png.js": "^0.2.2",
"@types/sinon": "^17.0.0",
"@types/viewport-list": "^5.1.2",
"ava": "^5.3.1",
"cookie": "^0.5.0",
"del-cli": "^5.0.0",
"file-type": "^18.0.0",
"get-port": "^6.1.2",
"image-size": "^1.0.2",
"del-cli": "^5.1.0",
"file-type": "^18.6.0",
"get-port": "^7.0.0",
"image-dimensions": "^2.1.0",
"nyc": "^15.1.0",
"path-exists": "^5.0.0",
"pify": "^6.1.0",
"png.js": "^0.2.1",
"sinon": "^14.0.0",
"sinon": "^17.0.1",
"ts-node": "^10.9.1",
"typescript": "^4.8.2",
"xo": "^0.52.2"
"typescript": "^5.2.2",
"xo": "^0.56.0"
},
"ava": {
"workerThreads": false,
Expand All @@ -115,7 +118,8 @@
"@typescript-eslint/no-unused-vars": "off",
"@typescript-eslint/no-unsafe-assignment": "off",
"@typescript-eslint/no-unsafe-return": "off",
"@typescript-eslint/no-unsafe-call": "off"
"@typescript-eslint/no-unsafe-call": "off",
"unicorn/prefer-event-target": "off"
}
},
"nyc": {
Expand Down
46 changes: 24 additions & 22 deletions source/index.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
import process from 'node:process';
import type {Buffer} from 'node:buffer';
import {parse as parseUrl} from 'node:url';
import path from 'node:path';
import {pathToFileURL} from 'node:url';
import fs from 'node:fs';
import fsPromises from 'node:fs/promises';
import os from 'node:os';
import {EventEmitter} from 'node:events';
import type {BeforeScreenshot} from 'capture-website';
import captureWebsite, {
type Options as CaptureWebsiteOptions,
type BeforeScreenshot,
type LaunchOptions,
} from 'capture-website';
import pMemoize from 'p-memoize';
import filenamify from 'filenamify';
import {unusedFilename} from 'unused-filename';
Expand All @@ -15,7 +20,6 @@ import dateFns from 'date-fns';
import getResolutions from 'get-res';
import logSymbols from 'log-symbols';
import makeDir from 'make-dir';
import captureWebsite, {type LaunchOptions} from 'capture-website';
import viewportList from 'viewport-list';
import template from 'lodash.template';
import plur from 'plur';
Expand Down Expand Up @@ -103,7 +107,7 @@ export type Options = {
@default []
*/
readonly hide?: readonly string[];
readonly hide?: string[];

/**
Username for authenticating with HTTP auth.
Expand Down Expand Up @@ -235,13 +239,12 @@ const getResolutionsMemoized = pMemoize(getResolutions);
// @ts-expect-error - TS is not very smart.
const viewportListMemoized = pMemoize(viewportList);

// TODO: Use private class fields when targeting Node.js 12.
/**
Capture screenshots of websites in various resolutions. A good way to make sure your websites are responsive. It's speedy and generates 100 screenshots from 10 different websites in just over a minute. It can also be used to render SVG images.
*/
export default class Pageres extends EventEmitter {
readonly #options: Writable<Options>;
#stats: Stats = {} as Stats; // eslint-disable-line @typescript-eslint/consistent-type-assertions
readonly #stats: Stats = {} as Stats; // eslint-disable-line @typescript-eslint/consistent-type-assertions
readonly #items: Screenshot[] = [];
readonly #sizes: string[] = [];
readonly #urls: string[] = [];
Expand Down Expand Up @@ -369,18 +372,18 @@ export default class Pageres extends EventEmitter {
this.#urls.push(source.url);

if (sizes.length === 0 && keywords.includes('w3counter')) {
return this.resolution(source.url, options);
return this.#resolution(source.url, options);
}

if (keywords.length > 0) {
return this.viewport({url: source.url, sizes, keywords}, options);
return this.#viewport({url: source.url, sizes, keywords}, options);
}

const screenshots = await pMap(
sizes,
async (size: string): Promise<Screenshot> => {
this.#sizes.push(size);
return this.create(source.url, size, options);
return this.#create(source.url, size, options);
},
{concurrency: cpuCount * 2},
);
Expand All @@ -397,7 +400,7 @@ export default class Pageres extends EventEmitter {
return this.#items;
}

await this.save(this.#items);
await this.#save(this.#items);

return this.#items;
}
Expand Down Expand Up @@ -430,36 +433,36 @@ export default class Pageres extends EventEmitter {
console.log(`\n${logSymbols.success} Generated ${screenshots} ${words.screenshots} from ${urls} ${words.urls} and ${sizes} ${words.sizes}`);
}

private async resolution(url: string, options: Options): Promise<void> {
async #resolution(url: string, options: Options): Promise<void> {
for (const item of await getResolutionsMemoized() as Array<{item: string}>) {
this.#sizes.push(item.item);
this.#items.push(await this.create(url, item.item, options));
this.#items.push(await this.#create(url, item.item, options));
}
}

private async viewport(viewport: Viewport, options: Options): Promise<void> {
async #viewport(viewport: Viewport, options: Options): Promise<void> {
for (const item of await viewportListMemoized(viewport.keywords) as Array<{size: string}>) {
this.#sizes.push(item.size);
viewport.sizes.push(item.size);
}

for (const size of arrayUniq(viewport.sizes)) {
this.#items.push(await this.create(viewport.url, size, options));
this.#items.push(await this.#create(viewport.url, size, options));
}
}

private async save(screenshots: Screenshot[]): Promise<void> {
async #save(screenshots: Screenshot[]): Promise<void> {
await Promise.all(screenshots.map(async screenshot => {
await makeDir(this.destination());
const dest = path.join(this.destination(), screenshot.filename);
await fsPromises.writeFile(dest, screenshot);
}));
}

private async create(url: string, size: string, options: Options): Promise<Screenshot> {
async #create(url: string, size: string, options: Options): Promise<Screenshot> {
const basename = fs.existsSync(url) ? path.basename(url) : url;

let hash = parseUrl(url).hash ?? '';
let hash = new URL(url, pathToFileURL(process.cwd())).hash ?? '';
// Strip empty hash fragments: `#` `#/` `#!/`
if (/^#!?\/?$/.test(hash)) {
hash = '';
Expand All @@ -484,17 +487,16 @@ export default class Pageres extends EventEmitter {
filename = await unusedFilename(filename);
}

// TODO: Type this using the `capture-website` types
const finalOptions: any = {
const finalOptions: Writable<CaptureWebsiteOptions> = {
width: Number(width),
height: Number(height),
delay: options.delay,
timeout: options.timeout,
fullPage: !options.crop,
styles: options.css && [options.css],
styles: options.css ? [options.css] : undefined,
defaultBackground: !options.transparent,
scripts: options.script && [options.script],
cookies: options.cookies, // TODO: Support string cookies in capture-website
scripts: options.script ? [options.script] : undefined,
cookies: options.cookies as any, // TODO: Support string cookies in capture-website
element: options.selector,
hideElements: options.hide,
scaleFactor: options.scale ?? 1,
Expand Down
10 changes: 5 additions & 5 deletions test/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import fsPromises from 'node:fs/promises';
import {fileURLToPath} from 'node:url';
import path from 'node:path';
import test from 'ava';
import {imageSize} from 'image-size';
import {imageDimensionsFromData} from 'image-dimensions';
import dateFns from 'date-fns';
import PNG from 'png.js';
import pify from 'pify';
Expand Down Expand Up @@ -114,7 +114,7 @@ test.serial('success message', async t => {
await pageres.run();
pageres.successMessage();
const [message] = stub.firstCall.args;
t.true(message.includes('Generated 3 screenshots from 1 url and 1 size'), message); // eslint-disable-line ava/assertion-arguments
t.true(message.includes('Generated 3 screenshots from 1 url and 1 size'), message); // eslint-disable-line ava/assertion-arguments, @typescript-eslint/no-unsafe-argument
stub.restore();
});

Expand All @@ -134,7 +134,7 @@ test('`crop` option', async t => {
const screenshots = await new Pageres({crop: true}).source(server.url, ['1024x768']).run();
t.is(screenshots[0].filename, `${server.host}!${server.port}-1024x768-cropped.png`);

const size = imageSize(screenshots[0]) as any;
const size = imageDimensionsFromData(screenshots[0]) as any;
t.is(size.width, 1024);
t.is(size.height, 768);
});
Expand Down Expand Up @@ -172,7 +172,7 @@ test('`selector` option', async t => {
const screenshots = await new Pageres({selector: '#team'}).source(server.url, ['1024x768']).run();
t.is(screenshots[0].filename, `${server.host}!${server.port}-1024x768.png`);

const size = imageSize(screenshots[0]) as any;
const size = imageDimensionsFromData(screenshots[0]) as any;
t.is(size.width, 1024);
t.is(size.height, 80);
});
Expand Down Expand Up @@ -233,7 +233,7 @@ test('`scale` option', async t => {
crop: true,
}).source(server.url, ['120x120']).run();

const size = imageSize(screenshots[0]) as any;
const size = imageDimensionsFromData(screenshots[0]) as any;
t.is(size.width, 240);
t.is(size.height, 240);
});
Expand Down

0 comments on commit d34d622

Please sign in to comment.