html-snapshots 5.11.0 → 6.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.nvmrc +1 -0
- package/HISTORY.md +6 -0
- package/README.md +66 -106
- package/eslint.config.js +9 -8
- package/lib/async/exists.js +1 -1
- package/lib/async/index.js +4 -3
- package/lib/common/sitemap/sitemap-collection.js +2 -2
- package/lib/common/sitemap/sitemap.js +5 -5
- package/lib/html-snapshots.js +41 -78
- package/lib/input-generators/_base.js +10 -9
- package/lib/input-generators/array.js +1 -1
- package/lib/input-generators/index.js +2 -2
- package/lib/input-generators/robots.js +1 -1
- package/lib/input-generators/textfile.js +2 -2
- package/lib/playwright/index.js +125 -0
- package/lib/playwright/removeScripts.js +11 -0
- package/lib/puppeteer/index.js +7 -7
- package/lib/puppeteer/removeScripts.js +1 -1
- package/package.json +23 -31
- package/lib/phantom/customFilter.js +0 -24
- package/lib/phantom/default.js +0 -21
- package/lib/phantom/modules/cli.js +0 -100
- package/lib/phantom/modules/detectors.js +0 -48
- package/lib/phantom/modules/globals.js +0 -43
- package/lib/phantom/modules/selectorDetect.js +0 -108
- package/lib/phantom/modules/verbose.js +0 -71
- package/lib/phantom/removeScripts.js +0 -30
package/.nvmrc
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
24.16
|
package/HISTORY.md
CHANGED
|
@@ -3,6 +3,12 @@ An overview of the [Breaking Changes](#breaking-changes) and [Node Support](#nod
|
|
|
3
3
|
|
|
4
4
|
## Breaking Changes
|
|
5
5
|
|
|
6
|
+
### Introduced in v6.0.0
|
|
7
|
+
#### Dropped support for Node 20
|
|
8
|
+
#### Dropped support for Phantomjs
|
|
9
|
+
#### Added Playwright as a secondary browser choice
|
|
10
|
+
#### Added standard AggregateError usage for multi-error reporting
|
|
11
|
+
|
|
6
12
|
### Introduced in v5.0.0
|
|
7
13
|
#### Dropped support for Node 18
|
|
8
14
|
|
package/README.md
CHANGED
|
@@ -7,34 +7,46 @@
|
|
|
7
7
|
> Takes html snapshots of your site's crawlable pages when an element you select is rendered.
|
|
8
8
|
|
|
9
9
|
## Contents
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
10
|
+
- [html-snapshots](#html-snapshots)
|
|
11
|
+
- [Contents](#contents)
|
|
12
|
+
- [Overview](#overview)
|
|
13
|
+
- [Getting Started](#getting-started)
|
|
14
|
+
- [Installation](#installation)
|
|
15
|
+
- [Grunt Task](#grunt-task)
|
|
16
|
+
- [More Information](#more-information)
|
|
17
|
+
- [Process Model](#process-model)
|
|
18
|
+
- [API](#api)
|
|
19
|
+
- [*Promise* run (options\[, callback\])](#promise-run-options-callback)
|
|
20
|
+
- [Callback](#callback)
|
|
21
|
+
- [Example Usage](#example-usage)
|
|
22
|
+
- [Quick Example](#quick-example)
|
|
23
|
+
- [Options](#options)
|
|
24
|
+
- [Input Control Options](#input-control-options)
|
|
25
|
+
- [Sitemap Only Input Options](#sitemap-only-input-options)
|
|
26
|
+
- [Origin Options](#origin-options)
|
|
27
|
+
- [Output Control Options](#output-control-options)
|
|
28
|
+
- [Snapshot Control Options](#snapshot-control-options)
|
|
29
|
+
- [Process Control Options](#process-control-options)
|
|
30
|
+
- [Example Rewrite Rule](#example-rewrite-rule)
|
|
31
|
+
- [Connect-modrewrite](#connect-modrewrite)
|
|
32
|
+
- [Middleware Example](#middleware-example)
|
|
33
|
+
- [License](#license)
|
|
24
34
|
|
|
25
35
|
## Overview
|
|
26
36
|
html-snapshots is a flexible html snapshot library that uses a headless browser to take html snapshots of your webpages served from your site. A snapshot is only taken when a specified selector is detected visible in the output html. This tool is useful when your site is largely ajax content, or an SPA, and you want your dynamic content indexed by search engines.
|
|
27
37
|
|
|
28
38
|
html-snapshots gets urls to process from either a robots.txt, sitemap.xml, or sitemap-index.xml. Alternatively, you can supply an array with completely arbitrary urls, or a line delimited textfile with arbitrary host-relative paths.
|
|
29
39
|
|
|
40
|
+
## Change History
|
|
41
|
+
This is an old project that has evolved since 2013. I've endeavored to keep it easy to use and upgrade. However, before upgrading, please review the release notes and the [history](HISTORY.md) for breaking changes.
|
|
42
|
+
|
|
30
43
|
## Getting Started
|
|
31
44
|
|
|
32
45
|
### Installation
|
|
33
|
-
The simplest way to install html-snapshots is to use [npm](http://npmjs.org)
|
|
34
|
-
install html-snapshots` will download html-snapshots and all dependencies.
|
|
46
|
+
The simplest way to install html-snapshots is to use [npm](http://npmjs.org). `npm
|
|
47
|
+
install html-snapshots` will download html-snapshots and all dependencies. To install the browsers required by playwright, you must also run `npx playwright install`. See [Playwright Docs](https://playwright.dev/docs/browsers) for additional details.
|
|
35
48
|
|
|
36
|
-
|
|
37
|
-
This is a node library that just works with gulp as-is.
|
|
49
|
+
By default, html-snapshots uses **Puppeteer** under the hood. You can optionally configure it to use **Playwright** instead by setting the [`browser`](#process-control-options) option to `"playwright"`.
|
|
38
50
|
|
|
39
51
|
### Grunt Task
|
|
40
52
|
If you are interested in the grunt task that uses this library, check out [grunt-html-snapshots](http://github.com/localnerve/grunt-html-snapshots).
|
|
@@ -45,6 +57,7 @@ Here are some [background and other notes](/docs/notes.md) regarding this projec
|
|
|
45
57
|
+ [How To Use Without Knowing About Page Content](/docs/notes.md#what-if-i-dont-know-about-the-rendered-page-content)
|
|
46
58
|
+ [Caveats](/docs/notes.md#caveats)
|
|
47
59
|
+ [Support History](HISTORY.md)
|
|
60
|
+
+ [Web Automation & Building AI agents](/docs/web-automation-building.md)
|
|
48
61
|
|
|
49
62
|
### Process Model
|
|
50
63
|
html-snapshots takes snapshots in parallel, each page getting its own browser process. Each browser process dies after snapshotting one page. You can limit the number of browser processes that can ever run at once with the `processLimit` option. This effectively sets up a process pool for browser instances. The default processLimit is 4 browser instances. When a browser process dies, and another snapshot needs to be taken, a new browser process is spawned to take the vacant slot. This continues until a `processLimit` number of processes are running at once.
|
|
@@ -63,7 +76,7 @@ htmlSnapshots.run(options[, callback])
|
|
|
63
76
|
// `completed` is an array of paths to the completed snapshots.
|
|
64
77
|
})
|
|
65
78
|
.catch(errorObject => {
|
|
66
|
-
// `errorObject` is an instance of Error
|
|
79
|
+
// `errorObject` is an instance of Error or AggregateError
|
|
67
80
|
// `errorObject.completed` is an array of paths to the snapshots that did successfully complete.
|
|
68
81
|
// `errorObject.notCompleted` is an array of paths to files that DID NOT successfully complete.
|
|
69
82
|
});
|
|
@@ -73,9 +86,9 @@ The callback is optional because the run method returns a Promise that resolves
|
|
|
73
86
|
|
|
74
87
|
Signature of the optional callback:
|
|
75
88
|
```javascript
|
|
76
|
-
callback (
|
|
89
|
+
callback (errorOrAggregateErrorObject, arrayOfPathsToCompletedSnapshots)
|
|
77
90
|
```
|
|
78
|
-
*For the callback, in the error case, the errorObject does not have the new extra properties `completed` and `notCompleted`. However, `arrayOfPathsToCompletedSnapshots` is supplied, and contains the paths to the snapshots that successfully completed.*
|
|
91
|
+
*For the callback, in the error \(or AggregateError\) case, the errorObject does not have the new extra properties `completed` and `notCompleted`. However, `arrayOfPathsToCompletedSnapshots` is supplied, and contains the paths to the snapshots that successfully completed.*
|
|
79
92
|
|
|
80
93
|
## Example Usage
|
|
81
94
|
This example reads the pages from a mix of sitemap or sitemap-index files found in the robots.txt and produces snapshots in the ./snapshots directory. In this example, a selector named "#dynamic-content" appears in all pages across the site. Once this selector is visible in a page, the html snapshot is taken and saved to ./snapshots.
|
|
@@ -202,7 +215,7 @@ An older (version 0.13.2), more in depth usage example is located in this [artic
|
|
|
202
215
|
|
|
203
216
|
`"function"` If the value is a function, it is called for every page and passed a single argument that is the url (or path in the case of robots.txt style) found in the input. The function must return a value to use for this option for the page it is given. The value returned for a given page must be a string.
|
|
204
217
|
|
|
205
|
-
NOTE: By default, selectors must conform to [this spec](http://www.w3.org/TR/selectors-api/#grammar), as they are used by [querySelector](https://developer.mozilla.org/en-US/docs/Web/API/document.querySelector). If you need selectors not supported by this, you must
|
|
218
|
+
NOTE: By default, selectors must conform to [this spec](http://www.w3.org/TR/selectors-api/#grammar), as they are used by [querySelector](https://developer.mozilla.org/en-US/docs/Web/API/document.querySelector). If you need selectors not supported by this, you must load jQuery in your page and use a custom snapshot script.
|
|
206
219
|
|
|
207
220
|
* **snapshotScript** {String|Object}
|
|
208
221
|
+ default: This library's default snapshot script. Which one is used is determined by the [`browser`](#process-control-options) option.
|
|
@@ -212,18 +225,6 @@ An older (version 0.13.2), more in depth usage example is located in this [artic
|
|
|
212
225
|
|
|
213
226
|
`"string"` If the value is a string, it must an absolute path to a custom script you supply.
|
|
214
227
|
|
|
215
|
-
+ `browser: "phantomjs"`:
|
|
216
|
-
html-snapshots will spawn a separate phantomjs process to run your snapshot script and give it the following [arguments](http://phantomjs.org/api/system/property/args.html):
|
|
217
|
-
+ `system.args[0]` The path to your PhantomJS script.
|
|
218
|
-
+ `system.args[1]` The output file path.
|
|
219
|
-
+ `system.args[2]` The url to snapshot.
|
|
220
|
-
+ `system.args[3]` The selector to watch for to signal page completion.
|
|
221
|
-
+ `system.args[4]` The overall timeout \(milliseconds\).
|
|
222
|
-
+ `system.args[5]` The interval \(milliseconds\) to watch for the selector.
|
|
223
|
-
+ `system.args[6]` A flag indicating jQuery selectors should be supported.
|
|
224
|
-
+ `system.args[7]` A flag indicating verbose output is desired.
|
|
225
|
-
+ `system.args[8]` A custom module to load.
|
|
226
|
-
|
|
227
228
|
+ `browser: "puppeteer"`:
|
|
228
229
|
html-snapshots will spawn your script as a separate process and give it the following arguments:
|
|
229
230
|
+ `process.argv[0]` The path to NodeJS.
|
|
@@ -237,11 +238,24 @@ An older (version 0.13.2), more in depth usage example is located in this [artic
|
|
|
237
238
|
+ `process.argv[8]` A slowMo time \(milliseconds\) to slow the browser down.
|
|
238
239
|
+ `process.argv[9]` Stringified Puppeteer launch options.
|
|
239
240
|
|
|
241
|
+
+ `browser: "playwright"`:
|
|
242
|
+
html-snapshots will spawn your script as a separate process and give it the following arguments:
|
|
243
|
+
+ `process.argv[0]` The path to NodeJS.
|
|
244
|
+
+ `process.argv[1]` The path to your snapshot script.
|
|
245
|
+
+ `process.argv[2]` The output file path.
|
|
246
|
+
+ `process.argv[3]` The url to snapshot.
|
|
247
|
+
+ `process.argv[4]` The selector to wait for to signal page completion.
|
|
248
|
+
+ `process.argv[5]` The overall timeout \(milliseconds\).
|
|
249
|
+
+ `process.argv[6]` The path to a custom NodeJS module that returns a filter function.
|
|
250
|
+
+ `process.argv[7]` A debug flag to kick the browser into headed, slowMo mode.
|
|
251
|
+
+ `process.argv[8]` A slowMo time \(milliseconds\) to slow the browser down.
|
|
252
|
+
+ `process.argv[9]` Stringified Playwright launch options. May include a `browserType` key (`"chromium"`, `"firefox"`, or `"webkit"`). Defaults to `"chromium"`.
|
|
253
|
+
|
|
240
254
|
`"object"` If an object is supplied, it has the following properties:
|
|
241
255
|
+ `script` This must be one of the following values:
|
|
242
|
-
+ `"removeScripts"` This runs the default snapshot script with an output filter that removes all script tags
|
|
256
|
+
+ `"removeScripts"` This runs the default snapshot script with an output filter that removes all script tags from the html snapshot before it is saved.
|
|
243
257
|
+ `"customFilter"` This runs the default snapshot script, but allows you to supply any output filter.
|
|
244
|
-
+ `module` This property is required only if you supplied a value of `"customFilter"` for the `script` property. This must be an absolute path to a
|
|
258
|
+
+ `module` This property is required only if you supplied a value of `"customFilter"` for the `script` property. This must be an absolute path to a NodeJS module you supply. Your module will be `require`d and called as a function to filter the html snapshot output. Your module's function will receive the entire raw html content as a single input string, and must return the filtered html content.
|
|
245
259
|
|
|
246
260
|
customFilter Example:
|
|
247
261
|
```javascript
|
|
@@ -261,43 +275,14 @@ An older (version 0.13.2), more in depth usage example is located in this [artic
|
|
|
261
275
|
A more complete example using custom options is available [here](/examples/custom).
|
|
262
276
|
|
|
263
277
|
* **debug** {Object}
|
|
264
|
-
> This options is only supported with the puppeteer browser script.
|
|
265
278
|
+ default: `{ flag: false, slowMo: 500 }`
|
|
266
|
-
+ Setting the `debug.flag` to true starts
|
|
267
|
-
|
|
268
|
-
* **useJQuery** {Boolean|Object|Function}
|
|
269
|
-
> This option is only supported with the phantomjs browser script.
|
|
270
|
-
+ default: `false`
|
|
271
|
-
+ Specifies to use jQuery selectors to detect when to snapshot a page. Please note that you cannot use these selectors if the page to be snapshotted does not load jQuery itself. To return to the behavior prior to v0.6.x, set this to `true`.
|
|
272
|
-
|
|
273
|
-
The value can be one of these *javascript types*:
|
|
274
|
-
|
|
275
|
-
`"boolean"` If the value is a boolean, it is used for every page. Note that if it is any scalar type such as "string" or "number", it will be interpreted as a boolean using javascript rules. Coerced string values "true", "yes", and "1" are specifically true, all others are false.
|
|
276
|
-
|
|
277
|
-
`"object"` If the value is an object, it is interpreted as key/value pairs where the key must match the url (or path in the case of robots.txt style) found by the input generator. This allows you to specify the use of jQuery for individual pages. The reserved key "__default" allows you to specify a default jQuery usage so you don't have to specify usage for every individual page.
|
|
278
|
-
|
|
279
|
-
`"function"` If the value is a function, it is called for every page and passed a single argument that is the url (or path in the case of robots.txt style) found in the input. The function must return a value to use for this option for the page it is given. The value returned for a given page must be a boolean.
|
|
280
|
-
|
|
281
|
-
NOTE: You do not *have to* use this option if your page uses jQuery. You only need this if your selector is not supported by [querySelector](https://developer.mozilla.org/en-US/docs/Web/API/document.querySelector). However, if you do use this option, the page being snapshotted must load jQuery itself.
|
|
282
|
-
|
|
283
|
-
* **verbose** {Boolean|Object|Function}
|
|
284
|
-
> This option is only used with the phantomjs browser script
|
|
285
|
-
+ default: `false`
|
|
286
|
-
+ Specifies to turn on extended console output in the PhantomJS process for debugging purposes. Can be applied to all pages, or just specific page(s). It is recommended to do this one page at a time, as the output can be large, and interleaved with parallel processes. See following explanation of types for how to debug just one page, and also [this example](/examples/verbose).
|
|
287
|
-
|
|
288
|
-
The value can be one of these *javascript types*:
|
|
289
|
-
|
|
290
|
-
`"boolean"` If the value is a boolean, it is used for every page. Note that if it is any scalar type such as "string" or "number", it will be interpreted as a boolean using javascript rules. Coerced string values "true", "yes", and "1" are specifically true, all others are false.
|
|
291
|
-
|
|
292
|
-
`"object"` If the value is an object, it is interpreted as key/value pairs where the key must match the url (or path in the case of robots.txt style) found by the input generator. This allows you to specify the use of verbose output for individual pages. The reserved key "__default" allows you to specify the default `verbose` usage so you don't have to specify usage for every individual page.
|
|
293
|
-
|
|
294
|
-
`"function"` If the value is a function, it is called for every page and passed a single argument that is the url (or path in the case of robots.txt style) found in the input. The function must return a value to use for this option for the page it is given. The value returned for a given page must be a boolean.
|
|
279
|
+
+ Supported with both puppeteer and playwright browser scripts. Setting the `debug.flag` to true starts the browser in headed mode with devtools open (devtools is only supported for chromium-based browsers). `debug.slowMo` is a time in milliseconds to reduce browser processing speed (larger numbers slows down the browser more). Recommended use is with a single problem page input using an Array source.
|
|
295
280
|
|
|
296
281
|
### Process Control Options
|
|
297
282
|
|
|
298
283
|
* **browser** {String}
|
|
299
284
|
+ default: `"puppeteer"`
|
|
300
|
-
+ Specifies which browser process to use in the crawl. Can be one of "
|
|
285
|
+
+ Specifies which browser process to use in the crawl. Can be one of `"puppeteer"` or `"playwright"`.
|
|
301
286
|
|
|
302
287
|
* **timeout** {Number|Object|Function}
|
|
303
288
|
+ default: 10000 \(milliseconds\)
|
|
@@ -313,19 +298,14 @@ An older (version 0.13.2), more in depth usage example is located in this [artic
|
|
|
313
298
|
|
|
314
299
|
* **processLimit** {Number}
|
|
315
300
|
+ default: 4
|
|
316
|
-
+ Limits the number of child
|
|
301
|
+
+ Limits the number of child browser processes that can ever be actively running in parallel. A value of 1 effectively forces the snapshots to be taken in series (only one at a time). Useful if you need to limit the number of processes spawned by this library. Experiment with what works best. One guideline suggests about [4 per CPU](http://stackoverflow.com/questions/9961254/how-to-manage-a-pool-of-phantomjs-instances).
|
|
317
302
|
|
|
318
303
|
* **pollInterval** {Number}
|
|
319
304
|
+ default: 500 \(milliseconds\)
|
|
320
305
|
+ Specifies the rate at which html-snapshots checks to see if a browser script has completed. Applies to all pages.
|
|
321
306
|
|
|
322
|
-
* **checkInterval** {Number}
|
|
323
|
-
> This option is only used with the phantomjs browser script
|
|
324
|
-
+ default: 250 (milliseconds)
|
|
325
|
-
+ Specifies the rate at which the PhantomJS script checks to see if the selector is visible yet. Applies to all pages.
|
|
326
|
-
|
|
327
307
|
* **puppeteerLaunchOptions** {Object|Function}
|
|
328
|
-
> This
|
|
308
|
+
> This option is only used with the puppeteer browser script
|
|
329
309
|
+ default: {}
|
|
330
310
|
+ Specifies launch options to give to Puppeteer. Can specify per page or for all pages. Puppeteer function options (like targetFilter) are not supported. Launch options will override any puppeteer debug options supplied.
|
|
331
311
|
|
|
@@ -335,46 +315,26 @@ An older (version 0.13.2), more in depth usage example is located in this [artic
|
|
|
335
315
|
|
|
336
316
|
"`function`" If the value is a function, it is called for every page and passed a single argument that is the url found in the input. The function must return puppeteer launch options to use for the page it is given. The value returned for a given page must be an object to be given directly to `puppeter.launch`.
|
|
337
317
|
|
|
338
|
-
* **
|
|
339
|
-
> This option is only used with the
|
|
340
|
-
+ default:
|
|
341
|
-
+ Specifies options to give to
|
|
342
|
-
|
|
343
|
-
Checkout [the source](https://github.com/ariya/phantomjs/blob/master/src/config.cpp#L49) for PhantomJS options coming next.
|
|
344
|
-
|
|
318
|
+
* **playwrightLaunchOptions** {Object|Function}
|
|
319
|
+
> This option is only used with the playwright browser script
|
|
320
|
+
+ default: {}
|
|
321
|
+
+ Specifies launch options to give to Playwright. Can specify per page or for all pages. The object may include a `browserType` key (`"chromium"`, `"firefox"`, or `"webkit"`) to select which browser engine to use. Defaults to `"chromium"`. Launch options will override any playwright debug options supplied.
|
|
322
|
+
|
|
345
323
|
The value can be one of these *javascript types*:
|
|
346
324
|
|
|
347
|
-
`"
|
|
348
|
-
|
|
349
|
-
`"array"` If the value is an array, it can contain multiple option strings used for every page.
|
|
350
|
-
|
|
351
|
-
`"object"` If the value is an object, it is interpreted as key/value pairs where the key must match the url (or path in the case of robots.txt style) found by the input generator. This allows you to specify PhantomJS options for individual pages. The reserved key "__default" allows you to specify default options so you don't have to specify options for every individual page. The values can be either a string \(for a single option\), or an array \(for multiple options \).
|
|
325
|
+
`"object"` If the value is an object, it can contain any playwright launch options, and is applied for all pages. The object (minus `browserType`) will be given directly to `browserType.launch`.
|
|
352
326
|
|
|
353
|
-
`
|
|
327
|
+
"`function`" If the value is a function, it is called for every page and passed a single argument that is the url found in the input. The function must return playwright launch options to use for the page it is given. The value returned for a given page must be an object to be given directly to `browserType.launch`.
|
|
354
328
|
|
|
355
|
-
|
|
329
|
+
Example using Firefox:
|
|
356
330
|
```javascript
|
|
357
|
-
// option snippet showing multiple options for all pages
|
|
358
331
|
{
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
// option snippet showing multiple options for one page only (object notation)
|
|
363
|
-
{
|
|
364
|
-
phantomjsOptions: {
|
|
365
|
-
// key must exactly match the page as defined in the input (sitemap, array, robots, etc)
|
|
366
|
-
"http://mysite.com/mypage": ["--load-images=false", "--ignore-ssl-errors=true"],
|
|
332
|
+
browser: "playwright",
|
|
333
|
+
playwrightLaunchOptions: {
|
|
334
|
+
browserType: "firefox"
|
|
367
335
|
}
|
|
368
336
|
}
|
|
369
337
|
```
|
|
370
|
-
An example demonstrating how to **debug** a PhantomJS script is available [here](/examples/debug-phantomjs). It also demonstrates per-page option usage.
|
|
371
|
-
|
|
372
|
-
* **phantomjs** {String}
|
|
373
|
-
> This option is only used with the phantomjs browser script
|
|
374
|
-
+ default: A package local reference to PhantomJS.
|
|
375
|
-
+ Specifies the PhantomJS executable to run. Applies to all pages. Override this if you want to supply a path to a different version of PhantomJS. To reference PhantomJS globally in your environment, just use the value, "phantomjs". Remember, it must be found in your environment path to execute.
|
|
376
|
-
See [PhantomJS](http://phantomjs.org/) for more information.
|
|
377
|
-
Also [PhantomJS 2](https://github.com/ariya/phantomjs/wiki/PhantomJS-2).
|
|
378
338
|
|
|
379
339
|
## Example Rewrite Rule
|
|
380
340
|
Here is an example apache rewrite rule for rewriting \_escaped\_fragment\_ requests to the snapshots directory on your server.
|
|
@@ -400,4 +360,4 @@ Here is the [article](/docs/example-heroku-redis.md) on how this middleware work
|
|
|
400
360
|
## License
|
|
401
361
|
This software is free to use under the LocalNerve, LLC MIT license. See the [LICENSE file](/LICENSE) for license text and copyright information.
|
|
402
362
|
|
|
403
|
-
Third-party open source code used are listed in the [package.json file](/package.json).
|
|
363
|
+
Third-party open source code used are listed in the [package.json file](/package.json).
|
package/eslint.config.js
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
const js = require(
|
|
2
|
-
const globals = require(
|
|
1
|
+
const js = require("@eslint/js");
|
|
2
|
+
const globals = require("globals");
|
|
3
3
|
|
|
4
4
|
module.exports = [{
|
|
5
5
|
ignores: [
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
"tmp/**",
|
|
7
|
+
"coverage/**",
|
|
8
|
+
"examples/**",
|
|
9
|
+
"test/suites/html-snapshots/server/**"
|
|
10
10
|
]
|
|
11
11
|
}, {
|
|
12
12
|
languageOptions: {
|
|
13
|
-
sourceType:
|
|
13
|
+
sourceType: "commonjs",
|
|
14
14
|
globals: {
|
|
15
15
|
...globals.node
|
|
16
16
|
}
|
|
@@ -18,6 +18,7 @@ module.exports = [{
|
|
|
18
18
|
files: ["**/*.js"],
|
|
19
19
|
rules: {
|
|
20
20
|
...js.configs.recommended.rules,
|
|
21
|
-
"no-console": 0
|
|
21
|
+
"no-console": 0,
|
|
22
|
+
"quotes": ["error", "double"]
|
|
22
23
|
}
|
|
23
24
|
}];
|
package/lib/async/exists.js
CHANGED
package/lib/async/index.js
CHANGED
|
@@ -8,9 +8,8 @@
|
|
|
8
8
|
* Licensed under the MIT license.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
const crypto = require("crypto");
|
|
11
|
+
const crypto = require("node:crypto");
|
|
12
12
|
const AsyncLock = require("async-lock");
|
|
13
|
-
const combineErrors = require("combine-errors");
|
|
14
13
|
const pathExists = require("./exists");
|
|
15
14
|
|
|
16
15
|
const L_WAIT = 10000;
|
|
@@ -332,7 +331,9 @@ class Notifier {
|
|
|
332
331
|
* @returns {Object} The error property.
|
|
333
332
|
*/
|
|
334
333
|
getError () {
|
|
335
|
-
return this.errors.length > 0
|
|
334
|
+
return this.errors.length > 0
|
|
335
|
+
? this.errors.length > 1 ? new AggregateError(this.errors) : this.errors[0]
|
|
336
|
+
: undefined;
|
|
336
337
|
}
|
|
337
338
|
|
|
338
339
|
/**
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
* Copyright (c) 2013 - 2025 Alex Grant, LocalNerve, contributors
|
|
5
5
|
* Licensed under the MIT license.
|
|
6
6
|
*/
|
|
7
|
-
const fs = require("fs");
|
|
8
|
-
const pathLib = require("path");
|
|
7
|
+
const fs = require("node:fs");
|
|
8
|
+
const pathLib = require("node:path");
|
|
9
9
|
const common = require("../index");
|
|
10
10
|
const base = require("../../input-generators/_base");
|
|
11
11
|
|
|
@@ -8,11 +8,11 @@
|
|
|
8
8
|
* Licensed under the MIT license.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
const fs = require("fs");
|
|
12
|
-
const util = require("util");
|
|
13
|
-
const path = require("path");
|
|
14
|
-
const urlm = require("url");
|
|
15
|
-
const zlib = require("zlib");
|
|
11
|
+
const fs = require("node:fs");
|
|
12
|
+
const util = require("node:util");
|
|
13
|
+
const path = require("node:path");
|
|
14
|
+
const urlm = require("node:url");
|
|
15
|
+
const zlib = require("node:zlib");
|
|
16
16
|
const xml2js = require("xml2js");
|
|
17
17
|
const smi = require("./sitemap-index");
|
|
18
18
|
const common = require("../index");
|
package/lib/html-snapshots.js
CHANGED
|
@@ -10,52 +10,19 @@
|
|
|
10
10
|
* Licensed under the MIT license.
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
const spawn = require("child_process")
|
|
14
|
-
const path = require("path");
|
|
15
|
-
const EventEmitter = require("events")
|
|
16
|
-
const fs = require("fs");
|
|
13
|
+
const { spawn } = require("node:child_process");
|
|
14
|
+
const path = require("node:path");
|
|
15
|
+
const { EventEmitter } = require("node:events");
|
|
16
|
+
const fs = require("node:fs");
|
|
17
17
|
const asyncLib = require("async");
|
|
18
18
|
const common = require("./common");
|
|
19
19
|
const inputFactory = require("./input-generators");
|
|
20
|
-
const Notifier = require("./async")
|
|
20
|
+
const { Notifier } = require("./async");
|
|
21
21
|
|
|
22
|
-
/**
|
|
23
|
-
* Determine the default phantomJS module path. This is overridden by the
|
|
24
|
-
* phatomjs option.
|
|
25
|
-
*
|
|
26
|
-
* This function, (technique and concerns) originated from karma-phantomjs-launcher:
|
|
27
|
-
*
|
|
28
|
-
* The MIT License
|
|
29
|
-
* Copyright (C) 2011-2013 Google, Inc.
|
|
30
|
-
*
|
|
31
|
-
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
32
|
-
* this software and associated documentation files (the "Software"), to deal in
|
|
33
|
-
* the Software without restriction, including without limitation the rights to
|
|
34
|
-
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
|
35
|
-
* of the Software, and to permit persons to whom the Software is furnished to do
|
|
36
|
-
* so, subject to the following conditions:
|
|
37
|
-
*
|
|
38
|
-
* The above copyright notice and this permission notice shall be included in all
|
|
39
|
-
* copies or substantial portions of the Software.
|
|
40
|
-
*/
|
|
41
|
-
function defaultPhantomJSExePath () {
|
|
42
|
-
// If the path we're given by phantomjs is to a .cmd, it is pointing to a global copy.
|
|
43
|
-
// Using the cmd as the process to execute causes problems cleaning up the processes
|
|
44
|
-
// so we walk from the cmd to the phantomjs.exe and use that instead.
|
|
45
|
-
|
|
46
|
-
const phantomSource = require("phantomjs-prebuilt").path;
|
|
47
|
-
|
|
48
|
-
if (path.extname(phantomSource).toLowerCase() === ".cmd") {
|
|
49
|
-
return path.join(path.dirname( phantomSource ), "//node_modules//phantomjs-prebuilt//lib//phantom//bin//phantomjs.exe");
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
return phantomSource;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
const phantomDir = "./phantom";
|
|
56
|
-
const phantomSnapshotScript = path.join(phantomDir, "default.js");
|
|
57
22
|
const puppeteerDir = "./puppeteer";
|
|
58
23
|
const puppeteerSnapshotScript = path.join(puppeteerDir, "index.js");
|
|
24
|
+
const playwrightDir = "./playwright";
|
|
25
|
+
const playwrightSnapshotScript = path.join(playwrightDir, "index.js");
|
|
59
26
|
|
|
60
27
|
/**
|
|
61
28
|
* This module's defaults
|
|
@@ -63,9 +30,8 @@ const puppeteerSnapshotScript = path.join(puppeteerDir, "index.js");
|
|
|
63
30
|
const defaults = Object.freeze({
|
|
64
31
|
input: "robots",
|
|
65
32
|
browser: "puppeteer",
|
|
66
|
-
phantomjs: defaultPhantomJSExePath(),
|
|
67
|
-
phantomSnapshotScript: path.join(__dirname, phantomSnapshotScript),
|
|
68
33
|
puppeteer: path.join(__dirname, puppeteerSnapshotScript),
|
|
34
|
+
playwright: path.join(__dirname, playwrightSnapshotScript),
|
|
69
35
|
snapshotScript: path.join(__dirname, puppeteerSnapshotScript),
|
|
70
36
|
outputDirClean: false,
|
|
71
37
|
pollInterval: 500,
|
|
@@ -73,22 +39,18 @@ const defaults = Object.freeze({
|
|
|
73
39
|
});
|
|
74
40
|
|
|
75
41
|
/**
|
|
76
|
-
* The worker task that launches phantomjs.
|
|
77
|
-
*
|
|
78
42
|
* @param {Object} input - An input object from an input generator.
|
|
79
|
-
* @param {Array} input.phantomjsOptions - Actual Phantomjs options.
|
|
80
43
|
* @param {String} input.outputFile - The output file that the html is written to.
|
|
81
44
|
* @param {String} input.url - The url to get the html from.
|
|
82
45
|
* @param {String} input.selector - The selector to wait for.
|
|
83
|
-
* @param {String} input.timeout - The
|
|
84
|
-
* @param {
|
|
85
|
-
* @param {
|
|
86
|
-
* @param {Boolean} input.verbose - True if verbose output is desired.
|
|
46
|
+
* @param {String} input.timeout - The entire process timeout.
|
|
47
|
+
* @param {Object} input.debug - The debug object.
|
|
48
|
+
* @param {Object} input.puppeteerLaunchOptions - overriding puppeteer launch options.
|
|
87
49
|
* @param {Object} options - Input options.
|
|
88
50
|
* @param {Object} options.snapshotScript - Snapshot script options.
|
|
89
51
|
* @param {String} options.snapshotScript.script - Snapshot script name.
|
|
90
52
|
* @param {String} options.snapshotScript.module - Snapshot script module.
|
|
91
|
-
* @param {String} options.
|
|
53
|
+
* @param {String} options.puppeteer - Full path to the puppeteer exec.
|
|
92
54
|
* @param {Object} notifier - The async Notifier instance for this run.
|
|
93
55
|
* @param {Function} notifier.remove - Remove an outputFile from notifier.
|
|
94
56
|
* @param {Function} notifier.setError - Set an error on the notifier.
|
|
@@ -96,34 +58,34 @@ const defaults = Object.freeze({
|
|
|
96
58
|
* @param {Function} notifier.known - Check if a file is or has been processed.
|
|
97
59
|
* @param {Function} qcb - async.queue callback function.
|
|
98
60
|
*/
|
|
99
|
-
function
|
|
100
|
-
let
|
|
61
|
+
function puppeteerWorker (input, options, notifier, qcb) {
|
|
62
|
+
let filter = "false";
|
|
101
63
|
let snapshotScript = options.snapshotScript;
|
|
102
|
-
const phantomjsOptions =
|
|
103
|
-
Array.isArray(input.phantomjsOptions) ? input.phantomjsOptions : [input.phantomjsOptions];
|
|
104
64
|
|
|
105
65
|
// If the outputFile has NOT already been seen by the notifier, process.
|
|
106
66
|
if (!notifier.known(input.outputFile)) {
|
|
107
67
|
|
|
108
|
-
// map snapshotScript object script
|
|
68
|
+
// map snapshotScript object script
|
|
109
69
|
if (common.isObject(options.snapshotScript)) {
|
|
110
|
-
snapshotScript =
|
|
111
|
-
|
|
70
|
+
snapshotScript = options.puppeteer;
|
|
71
|
+
if (options.snapshotScript.script === "removeScripts") {
|
|
72
|
+
filter = "./removeScripts";
|
|
73
|
+
} else {
|
|
74
|
+
filter = options.snapshotScript.module;
|
|
75
|
+
}
|
|
112
76
|
}
|
|
113
77
|
|
|
114
|
-
cp = spawn(
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
snapshotScript,
|
|
118
|
-
input.outputFile,
|
|
78
|
+
const cp = spawn(
|
|
79
|
+
snapshotScript,
|
|
80
|
+
[ input.outputFile,
|
|
119
81
|
input.url,
|
|
120
82
|
input.selector,
|
|
121
83
|
input.timeout,
|
|
122
|
-
|
|
123
|
-
input.
|
|
124
|
-
input.
|
|
125
|
-
|
|
126
|
-
]
|
|
84
|
+
filter,
|
|
85
|
+
input.debug.flag,
|
|
86
|
+
input.debug.slowMo,
|
|
87
|
+
JSON.stringify(input.puppeteerLaunchOptions)
|
|
88
|
+
], { cwd: process.cwd(), stdio: "inherit", detached: true }
|
|
127
89
|
);
|
|
128
90
|
|
|
129
91
|
cp.on("error", function (e) {
|
|
@@ -139,8 +101,7 @@ function phantomjsWorker (input, options, notifier, qcb) {
|
|
|
139
101
|
|
|
140
102
|
// start counting
|
|
141
103
|
notifier.add(input.outputFile, input.timeout);
|
|
142
|
-
}
|
|
143
|
-
else {
|
|
104
|
+
} else {
|
|
144
105
|
// The input.outputFile is being or has been processed this run.
|
|
145
106
|
qcb(0);
|
|
146
107
|
}
|
|
@@ -153,12 +114,14 @@ function phantomjsWorker (input, options, notifier, qcb) {
|
|
|
153
114
|
* @param {String} input.selector - The selector to wait for.
|
|
154
115
|
* @param {String} input.timeout - The entire process timeout.
|
|
155
116
|
* @param {Object} input.debug - The debug object.
|
|
156
|
-
* @param {Object} input.
|
|
117
|
+
* @param {Object} input.playwrightLaunchOptions - overriding playwright launch options.
|
|
118
|
+
* May include a `browserType` key ("chromium" | "firefox" | "webkit") to select
|
|
119
|
+
* the browser engine. Defaults to "chromium".
|
|
157
120
|
* @param {Object} options - Input options.
|
|
158
121
|
* @param {Object} options.snapshotScript - Snapshot script options.
|
|
159
122
|
* @param {String} options.snapshotScript.script - Snapshot script name.
|
|
160
123
|
* @param {String} options.snapshotScript.module - Snapshot script module.
|
|
161
|
-
* @param {String} options.
|
|
124
|
+
* @param {String} options.playwright - Full path to the playwright exec.
|
|
162
125
|
* @param {Object} notifier - The async Notifier instance for this run.
|
|
163
126
|
* @param {Function} notifier.remove - Remove an outputFile from notifier.
|
|
164
127
|
* @param {Function} notifier.setError - Set an error on the notifier.
|
|
@@ -166,7 +129,7 @@ function phantomjsWorker (input, options, notifier, qcb) {
|
|
|
166
129
|
* @param {Function} notifier.known - Check if a file is or has been processed.
|
|
167
130
|
* @param {Function} qcb - async.queue callback function.
|
|
168
131
|
*/
|
|
169
|
-
function
|
|
132
|
+
function playwrightWorker (input, options, notifier, qcb) {
|
|
170
133
|
let filter = "false";
|
|
171
134
|
let snapshotScript = options.snapshotScript;
|
|
172
135
|
|
|
@@ -175,7 +138,7 @@ function puppeteerWorker (input, options, notifier, qcb) {
|
|
|
175
138
|
|
|
176
139
|
// map snapshotScript object script
|
|
177
140
|
if (common.isObject(options.snapshotScript)) {
|
|
178
|
-
snapshotScript = options.
|
|
141
|
+
snapshotScript = options.playwright;
|
|
179
142
|
if (options.snapshotScript.script === "removeScripts") {
|
|
180
143
|
filter = "./removeScripts";
|
|
181
144
|
} else {
|
|
@@ -192,7 +155,7 @@ function puppeteerWorker (input, options, notifier, qcb) {
|
|
|
192
155
|
filter,
|
|
193
156
|
input.debug.flag,
|
|
194
157
|
input.debug.slowMo,
|
|
195
|
-
JSON.stringify(input.
|
|
158
|
+
JSON.stringify(input.playwrightLaunchOptions)
|
|
196
159
|
], { cwd: process.cwd(), stdio: "inherit", detached: true }
|
|
197
160
|
);
|
|
198
161
|
|
|
@@ -230,10 +193,10 @@ function prepOptions (options) {
|
|
|
230
193
|
options.input = "array";
|
|
231
194
|
}
|
|
232
195
|
|
|
233
|
-
// If
|
|
234
|
-
if (options.browser ===
|
|
196
|
+
// If playwright browser, make sure the default snapshotScript is correctly set.
|
|
197
|
+
if (options.browser === "playwright") {
|
|
235
198
|
if (!options.snapshotScript || options.snapshotScript === options.puppeteer) {
|
|
236
|
-
options.snapshotScript = options.
|
|
199
|
+
options.snapshotScript = options.playwright;
|
|
237
200
|
}
|
|
238
201
|
}
|
|
239
202
|
}
|
|
@@ -306,7 +269,7 @@ function run (options, listener) {
|
|
|
306
269
|
options._abort = notifier.abort.bind(notifier, q);
|
|
307
270
|
|
|
308
271
|
const worker =
|
|
309
|
-
options.browser ===
|
|
272
|
+
options.browser === "playwright" ? playwrightWorker : puppeteerWorker;
|
|
310
273
|
|
|
311
274
|
// generate input for the snapshots.
|
|
312
275
|
return inputGenerator.run(options, input => {
|