Q:

How to inject local script with require statements into Puppeteer page

I am using Puppeteer to crawl a webpage. I would like to parse the URL within the page, among other things. I get that I can move the functionality out of page.evaluate, but that is beside the main question. The question is how you inject an arbitrary script onto the page so you can use the variables/functions from the script within page.evaluate.
In my case, I am using lil-uri. I have basically this:
var puppeteer = require('puppeteer')
var URL = require('lil-uri')

puppeteer.launch().then(browser => {
  browser.newPage().then(page => {
    page.goto('https://foo.com').catch(onerror).then(() => {
      page.evaluate(fetchLinks).catch(onerror)
    })
  })
  // })
})

function onerror(err) {
  console.log('ERRR', err)
}

function fetchLinks() {
  var linkEls = document.querySelectorAll('a')
  var links = []

  for (var i = 0, n = linkEls.length; i < n; i++) {
    var el = linkEls[i]

    // PARSE URL
    var url = parseUrl(el.getAttribute('href'))

    links.push(url)
  }

  return links

  function parseUrl(href) {
    // REF THE URL LIBRARY
    var url = URL(href)
    var url2 = url.path()
    var query = []
    var q = url.query()
    if (Object.keys(q).length) {
      // query.push(...)
    }
    if (query.length) {
      url2 += '?' + query.join('&')
    }
    return url2
  }
}

This doesn't work because the require('lil-uri') is in the scope of the Node.js script, while it is really being used in the context of page.evaluate.
The question is, how to include the parseUrl and URL functions in the page properly, so they can be used within the context of page.evaluate.
Also, as you can see I put the parseUrl function within the fetchLinks function, which is not ideal because I can't reuse it between other functions I evaluate on the page. I would like to be able to do something like window.parseUrl = parseUrl in the context of page.evaluate, but I wasn't sure how to do that either. Wondering if one could show how to do those two things:

How to load a local external script into the puppeteer page.
How to load functions onto the window of the puppeteer page.

A:

You can use the page.exposeFunction to expose a function from the Node.js environment to the page itself. To quote the docs:

The method adds a function called name on the page's window object. When called, the function executes puppeteerFunction in node.js and returns a Promise which resolves to the return value of puppeteerFunction.

Code sample
The code below will expose your function parseUrl to the page. You can then call the function via window.parseUrl from within the page.evaluate.
const puppeteer = require('puppeteer');

function parseUrl(href) {
    // ...
    return '...';
}

(async () => {
    const browser = await puppeteer.launch();
    const page = await browser.newPage();
    await page.exposeFunction('parseUrl', href => parseUrl(href));

    await page.evaluate(async () => {
        const url = 'http://...';
        const parsedUrl = await window.parseUrl(url);
    });
    await browser.close();
})();

A sidenote regarding the parsing of URLs
This is not directly related to your question, but you might not necessarily need to parse the URL inside of the Node.js environment. There is the JavaScript API URL for that, which allows you to parse URLs inside the browser itself like this:
const url = new URL('http://www.example.org/path123');
console.log(url.pathname); // will print: /path123

Depending on your use case, you might not even need to expose a function as you can do it inside the browser itself.

