1 | #!/usr/bin/env node
|
2 |
|
3 | const path = require('path');
|
4 | const os = require('os');
|
5 | const program = require('commander');
|
6 | const chalk = require('chalk');
|
7 | const ora = require('ora');
|
8 | const detect = require('detect-port');
|
9 | const imagemin = require('imagemin');
|
10 | const imageminMozjpeg = require('imagemin-mozjpeg');
|
11 | const imageminPngquant = require('imagemin-pngquant');
|
12 |
|
13 | const createServer = require('../utils/createServer');
|
14 | const getPuppeteer = require('../utils/getPuppeteer');
|
15 | const packageJSON = require('../package.json');
|
16 |
|
17 | const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
18 |
|
19 | const cwd = process.cwd();
|
20 | const DEFAULT_PORT = 8100;
|
21 |
|
22 | exec();
|
23 |
|
24 | async function exec() {
|
25 | try {
|
26 | program
|
27 | .version(packageJSON.version)
|
28 | .usage('-u https://www.example.com')
|
29 | .option('-u, --url <url>', 'The target url or path to local server')
|
30 | .option(
|
31 | '-l, --local [local]',
|
32 | 'Set up a local server in [local] directory and take screenshot, defaults set up in `./`',
|
33 | )
|
34 | .option('-s, --selector <selector>', 'Select a element through CSS selector')
|
35 | .option('-t, --timeout <timeout>', 'screenshot with a delay')
|
36 | .option('-o, --output <output>', 'Output path')
|
37 | .parse(process.argv);
|
38 |
|
39 | const { url, selector, local, timeout } = program;
|
40 | const output = program.output || path.join(cwd, 'screenshot.png');
|
41 |
|
42 |
|
43 | const formatedSelector = selector && !/^(#|\.)/.test(selector) && selector !== 'body' ? `#${selector}` : selector;
|
44 |
|
45 | if (!url && !local) {
|
46 | console.log(chalk.red('The -u or -l is required! Using the following command:'));
|
47 | console.log(chalk.red('screenshot -u https://www.example.com\n'));
|
48 | program.help();
|
49 | }
|
50 |
|
51 | if (local) {
|
52 | const port = await detect(DEFAULT_PORT);
|
53 | const serverPath = local === true ? cwd : local;
|
54 | await screenshotWithLocalServer(serverPath, port, url, formatedSelector, output, timeout);
|
55 | } else {
|
56 | await screenshot(url, formatedSelector, output, timeout);
|
57 | }
|
58 | } catch (err) {
|
59 | console.error(err);
|
60 | process.exit(1);
|
61 | }
|
62 | }
|
63 |
|
64 |
|
65 |
|
66 |
|
67 |
|
68 |
|
69 |
|
70 |
|
71 |
|
72 |
|
73 | async function screenshotWithLocalServer(serverPath, port, targetUrl, selector, output, timeout) {
|
74 | targetUrl = targetUrl ? `http://127.0.0.1:${port}${targetUrl}` : `http://127.0.0.1:${port}/build/index.html`;
|
75 |
|
76 | const server = createServer(serverPath, port);
|
77 | console.log(chalk.white(`Create local server with port ${port}`));
|
78 | console.log(chalk.white(`The screenshot target url: ${targetUrl}`));
|
79 |
|
80 | await screenshot(targetUrl, selector, output, timeout);
|
81 |
|
82 | server.close();
|
83 | }
|
84 |
|
85 |
|
86 |
|
87 |
|
88 |
|
89 |
|
90 |
|
91 |
|
92 | async function screenshot(url, selector, output, timeout) {
|
93 |
|
94 | const spinner = ora('screenshoting ...').start();
|
95 |
|
96 | try {
|
97 | const puppeteer = await getPuppeteer();
|
98 |
|
99 |
|
100 | const browser = await puppeteer.launch(
|
101 | /freebsd|linux/.test(os.platform) ? { args: ['--no-sandbox', '--disable-setuid-sandbox'] } : {},
|
102 | );
|
103 |
|
104 |
|
105 | const page = await browser.newPage();
|
106 |
|
107 |
|
108 | page.setViewport({
|
109 | width: 1240,
|
110 | height: 600,
|
111 | deviceScaleFactor: 2,
|
112 | });
|
113 |
|
114 |
|
115 | await page.goto(url);
|
116 |
|
117 | if (timeout) {
|
118 | await sleep(timeout);
|
119 | }
|
120 |
|
121 |
|
122 | if (selector) {
|
123 | const el = await page.$(selector);
|
124 |
|
125 | if (!el) {
|
126 | throw Error(`Could not find element that matches selector: ${selector}.`);
|
127 | }
|
128 |
|
129 | await el.screenshot({ path: output });
|
130 | } else {
|
131 |
|
132 | await page.screenshot({ path: output });
|
133 | }
|
134 |
|
135 | const outputDir = path.dirname(output);
|
136 |
|
137 | await minifyImg(output, outputDir);
|
138 |
|
139 |
|
140 | await browser.close();
|
141 |
|
142 | spinner.succeed(chalk.green('Screenshot success!'));
|
143 | console.log(chalk.green(`Screenshot output path: ${output}`));
|
144 | } catch (err) {
|
145 | spinner.fail(chalk.red('Screenshot fail!'));
|
146 |
|
147 |
|
148 |
|
149 | if (err.message === 'Chromium revision is not downloaded. Run "npm install" or "yarn install"') {
|
150 | console.log(chalk.red('\n\nPuppeteer Install fail. \nPlease install puppeteer using the following commands:'));
|
151 | console.log(chalk.white('\n npm uninstall puppeteer -g'));
|
152 | console.log(
|
153 | chalk.white(
|
154 | '\n PUPPETEER_DOWNLOAD_HOST=https://storage.googleapis.com.cnpmjs.org npm i puppeteer -g --registry=https://registry.npmmirror.com',
|
155 | ),
|
156 | );
|
157 | console.log(chalk.white('\n screenshot -u http://www.example.com\n'));
|
158 | } else {
|
159 | console.error(err);
|
160 | }
|
161 | process.exit(1);
|
162 | }
|
163 | }
|
164 |
|
165 |
|
166 |
|
167 |
|
168 |
|
169 |
|
170 |
|
171 |
|
172 | async function minifyImg(imgPath, outputDir) {
|
173 | return imagemin([imgPath], outputDir, {
|
174 | plugins: [imageminMozjpeg(), imageminPngquant()],
|
175 | });
|
176 | }
|