-
Notifications
You must be signed in to change notification settings - Fork 9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(browser): Run puppeteer in browser (POC) #2374
Conversation
@Janpot thank you for the PR, it turned out to be quite minimalistic. I evaluate this PR as a "what needs to be changed in pptr so that this can be implemented as a third-party library". From this standpoint, I see two things we need to address:
@JoelEinbinder claimed he has another approach that achieves the same results. Joel, can you please share your code? |
@aslushnikov
|
why would you want to run in from the browser? |
For instance (but not limited to): https://chrome.browserless.io/ |
Hello. For some reason I want to do fair actions (clicks, typing, etc) in my functional tests. So let me share my experience to run pptr in browser without any changes of original source code. For // webpack.config.js
module.exports = {
/* ... */
resolve: {
alias: {
ws: path.join(__dirname, 'helpers/websocket.js'),
fs: path.join(__dirname, 'helpers/dummy.js'),
}
}
} // chrome-devtools.js
import { Connection } from 'puppeteer/lib/Connection'
import Browser from 'puppeteer/lib/Browser'
import uuidv4 from 'uuid/v4'
let attachPromise = null
const id = uuidv4()
export default function attachDevTools() {
if (attachPromise) return attachPromise
attachPromise = fetch(`/attach?id=${id}`)
.then(res => res.json())
.then(async ({ targetInfo, browserDebuggerUrl }) => {
const { targetId } = targetInfo
window.addEventListener('beforeunload', () => fetch(`/detach?targetId=${targetId}`))
const connection = await Connection.createForWebSocket(browserDebuggerUrl)
const browser = await Browser.create(connection, { appMode: true })
const pages = await browser.pages()
// NOTE We don't want to crash browser under events flood
// Disables network tracking, prevents network events from being sent to the client
pages.forEach(p => p._client.send('Network.disable', {}))
return pages.find(p => p.target()._targetId == targetId)
})
return attachPromise
} That's issues I faced:
If you agree with that usage of pptr, maybe I can do PR to make this in proper way |
Ah, about 1st issue, I didn’t know that chrome have command line option to disable cors security checks, so proxy server is not needed. And another issue, I think could solve through sending guid to the console, for example, and check every page to find that guid. |
I rewrite attach function without express server and without using import { Connection } from 'puppeteer/lib/Connection'
import Browser from 'puppeteer/lib/Browser'
import uuidv4 from 'uuid/v4'
export default async function attachDevTools() {
const response = await fetch('http://localhost:9222/json/version')
const data = await response.json()
const connection = await Connection.createForWebSocket(data.webSocketDebuggerUrl)
const browser = await Browser.create(connection, { appMode: true })
const pages = await browser.pages()
// Disables network tracking, prevents network events from being sent to the client
// NOTE Because we don't want crash browser under events flood
pages.forEach(p => p._client.send('Network.disable', {}))
return new Promise(resolve => {
const expectedGuid = uuid()
const findCurrentPage = index => async msg => {
if (msg.type() != 'debug') return
const [firstArg] = msg.args()
const receivedGuid = await firstArg.jsonValue()
if (receivedGuid == expectedGuid) {
resolve(pages[index])
}
}
pages.forEach((p, index) => p.once('console', findCurrentPage(index)))
console.debug(expectedGuid)
})
} |
This patch removes all dynamic requires in Puppeteer. This should make it much simpler to bundle puppeteer/puppeteer-core packages. We used dynamic requires in a few places in lib/: - BrowserFetcher was choosing between `http` and `https` based on some runtime value. This was easy to fix with explicit `require`. - BrowserFetcher and Launcher needed to know project root to store chromium revisions and to read package name and chromium revision from package.json. (projectRoot value would be different in node6). Instead of doing a backwards logic to infer these variables, we now pass them directly from `//index.js`. With this patch, I was able to bundle Puppeteer using browserify and the following config in `package.json`: ```json "browser": { "./lib/BrowserFetcher.js": false, "ws": "./lib/BrowserWebSocket", "fs": false, "child_process": false, "rimraf": false, "readline": false } ``` (where `lib/BrowserWebSocket.js` is a courtesy of @Janpot from puppeteer#2374) And command: ```sh $ browserify -r puppeteer:./index.js > ppweb.js ``` References puppeteer#2119
This patch removes all dynamic requires in Puppeteer. This should make it much simpler to bundle puppeteer/puppeteer-core packages. We used dynamic requires in a few places in lib/: - BrowserFetcher was choosing between `http` and `https` based on some runtime value. This was easy to fix with explicit `require`. - BrowserFetcher and Launcher needed to know project root to store chromium revisions and to read package name and chromium revision from package.json. (projectRoot value would be different in node6). Instead of doing a backwards logic to infer these variables, we now pass them directly from `//index.js`. With this patch, I was able to bundle Puppeteer using browserify and the following config in `package.json`: ```json "browser": { "./lib/BrowserFetcher.js": false, "ws": "./lib/BrowserWebSocket", "fs": false, "child_process": false, "rimraf": false, "readline": false } ``` (where `lib/BrowserWebSocket.js` is a courtesy of @Janpot from #2374) And command: ```sh $ browserify -r puppeteer:./index.js > ppweb.js ``` References #2119
This patch: - adds "browser" field to the package.json with default bundling options. - introduces "bundle" and "unit-bundle" commands to create bundle and test bundle - starts running bundle tests on Travis Node 8 bots Fixes puppeteer#2374.
Closing in favor of #3239 |
This patch: - adds "browser" field to the package.json with default bundling options. - introduces "bundle" and "unit-bundle" commands to create bundle and test bundle - starts running bundle tests on Travis Node 8 bots Fixes #2374.
Proof of concept for #2119