-
Notifications
You must be signed in to change notification settings - Fork 0
/
puppeteer.js
110 lines (99 loc) · 3.39 KB
/
puppeteer.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
const puppeteer = require('puppeteer')
const fs = require('fs')
class PuppeteerRenderer {
constructor(rendererOptions) {
this._options = rendererOptions || {}
this._puppeteer = null
}
// 初始化浏览器
async initialize() {
try {
// Workaround for Linux SUID Sandbox issues.
if (!this._options.args) this._options.args = []
this._options.args.push('--disable-web-security')
if (process.platform === 'linux') {
if (this._options.args.indexOf('--no-sandbox') === -1) {
this._options.args.push('--no-sandbox')
this._options.args.push('--disable-setuid-sandbox')
}
}
this._puppeteer = await puppeteer.launch(this._options)
} catch (e) {
console.error(e)
console.error('[PuppeteerRenderer] 初始化PuppeteerRenderer失败')
throw e
}
return this._puppeteer
}
// 处理请求拦截
async handleRequestInterception(page, baseURL) {
// 劫持所有请求
await page.setRequestInterception(true)
page.on('request', req => {
// 匹配类型,只过滤'fetch', 'xhr', 'websocket'三种类型的请求,否则会导致图片等网络资源无法加载
const isLocalApi = ['fetch', 'xhr', 'websocket'].indexOf(req.resourceType()) > -1 && req.url().startsWith(baseURL)
// 跳过所有本地请求
if (this._options.skipRequest && isLocalApi) {
req.abort();
return;
}
// 强制匹配请求地址,并进行mock
if (this._options.forceMock && Object.prototype.toString.call(this._options.forceMock) === '[object Object]' && this._options.forceMock[req.url()]) {
req.respond({
contentType: 'application/json; charset=utf-8',
body: JSON.stringify(this._options.forceMock[req.url()]),
});
return;
}
if (isLocalApi) {
let apiPath = req.url().split('/');
apiPath = '/' + apiPath.splice(3).join('/');
// 匹配本地请求路径,并进行数据mock
if (
this._options.mock &&
Object.prototype.toString.call(this._options.mock) === '[object Object]' && this._options.mock[apiPath]
) {
// 自定义返回请求数据
req.respond({
contentType: 'application/json; charset=utf-8',
body: JSON.stringify(this._options.mock[apiPath])
});
return;
}
}
req.continue()
})
}
// 关闭浏览器
close() {
this._puppeteer.close()
}
// 渲染指定路径
async renderRoutes(routes, Prerenderer) {
const options = Prerenderer.getOptions()
const pagePromises = Promise.all(
routes.map(async route => {
const page = await this._puppeteer.newPage()
const baseURL = `http://localhost:${options.port}`
await page.setViewport(options.renderOption ? (options.renderOption.viewport || { 'width': 1920, 'height': 1080 }) : { 'width': 1920, 'height': 1080 })
await this.handleRequestInterception(page, baseURL)
await page.goto(`${baseURL}${route}`, { waituntil: 'networkidle2', domcontentloaded: true, timeout: 60000000 });
// 等待某个class
if (options.renderOption && options.renderOption.waitForElement && typeof options.renderOption.waitForElement === 'string') {
await page.waitForSelector(options.renderOption.waitForElement)
}
// sleep 1s
await page.waitForTimeout(1000)
const result = {
originalRoute: route,
route: await page.evaluate('window.location.pathname'),
html: await page.content()
}
await page.close()
return result
})
)
return pagePromises
}
}
module.exports = PuppeteerRenderer