7

I'm trying to load axios in chromium using puppeteer, the code is as follows:

const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch({headless:false})
  const page = await browser.newPage()
  await page.goto('https://httpbin.org/get')
  await page.evaluate(async () => {
    var script = document.createElement('script');
    script.setAttribute('src','https://unpkg.com/[email protected]/dist/axios.min.js');
    document.head.appendChild(script);
    var r = await axios.get('https://httpbin.org/get')
    console.log(r)
  })
})()

But when I try to execute axios.get it returns Evaluation failed: ReferenceError: axios is not defined. What's the issue here?

0

3 Answers 3

8

Use page.addScriptTag for this:

await page.goto('https://example.com');

await page.addScriptTag({ url: 'https://unpkg.com/[email protected]/dist/axios.min.js' }); 

const data = await page.evaluate(async () => {
  const response = await axios.get('https://httpbin.org/get')
  return response.data; // <-- this is important: the whole response cannot be returned
});
Sign up to request clarification or add additional context in comments.

Comments

2

In my case, I was trying to load a local script before loading a local HTML template.

I did not want to embed the script code into the HTML template since the HTML template was already too big.

The following code and the local js file with the script code (scriptCode.js) were in the same directory (hence the use of __dirname):

const path = require("path");
// ...
const page = await browser.newPage();
await page.addScriptTag({path: path.join(__dirname, 'scriptCode.js')})
await page.setContent(html);

If you have axios in a local folder, you have to point to the path where you've downloaded it.

But if you still want to download it off its CDN every time, instead of using the path option, the answer provided by Vaviloff is the perfect one.

Documentation:

Comments

1

page.addScriptTag is useful in the common case, but if you have reason to do this manually in the browser context as OP is attempting, the missing piece is setting a script.onload function to only run code from the script (like axios.get) after it's loaded.

If you want to return data from the onload function back to Node, then you can use a promise as follows:

const puppeteer = require("puppeteer"); // ^23.6.0

let browser;
(async () => {
  browser = await puppeteer.launch();
  const [page] = await browser.pages();
  const result = await page.evaluate(async () => {
    const script = document.createElement("script");
    const result = new Promise(resolve =>
      script.onload = () => 
        resolve(axios.get("https://httpbin.org/get"))
    );
    const url = "https://unpkg.com/[email protected]/dist/axios.min.js";
    script.setAttribute("src", url);
    document.head.appendChild(script);
    return (await result).data;
  });
  console.log(result);
})()
  .catch(err => console.error(err))
  .finally(() => browser?.close());

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.