Installing Puppeteer on a FreeBSD server
- FreeBSD
- Puppeteer
- Node.js
- Unix
This is a good one. I was recently tasked with setting up the web application on a brand-new server provisioned by a client. Nothing extraordinary, the tech stack was based on Laravel talking to a few React pages using Inertia.js.
I SSHed into the server, installed the composer dependencies and tried to run npm install
. That's when I hit the first snag:
npm ERR! file://[omitted]/node_modules/puppeteer/lib/esm/puppeteer/node/install.js:39
npm ERR! throw new Error('The current platform is not supported.');
npm ERR! ^
npm ERR!
npm ERR! Error: The current platform is not supported.
npm ERR! at downloadBrowser (file://[omitted]/node_modules/puppeteer/lib/esm/puppeteer/node/install.js:39:15)
npm ERR! at file://[omitted]/node_modules/puppeteer/install.mjs:40:3
Interesting. The Node.js version seems to be correct, and I've never run into any issues with dependencies on this project before, neither on my Mac locally, nor on the Ubuntu staging server. Let's try to see how the puppeteer
package checks the platform. In node_modules/puppeteer/install.mjs
we can see what's being executed which throws the exception:
try {
const {downloadBrowser} = await (async () => {
try {
return await import('puppeteer/internal/node/install.js');
} catch {
console.warn(
'Skipping browser installation because the Puppeteer build is not available. Run `npm install` again after you have re-built Puppeteer.'
);
process.exit(0);
}
})();
downloadBrowser();
} catch (error) {
console.warn('Browser download failed', error);
}
Let's dig deeper, looking inside puppeteer/internal/node/install.js
there's the downloadBrowser()
function which in turn calls detectBrowserPlatform()
:
const platform = detectBrowserPlatform();
if (!platform) {
throw new Error('The current platform is not supported.');
}
And that seems to be a simple switch:
export function detectBrowserPlatform(): BrowserPlatform | undefined {
const platform = os.platform();
switch (platform) {
case 'darwin':
return os.arch() === 'arm64'
? BrowserPlatform.MAC_ARM
: BrowserPlatform.MAC;
case 'linux':
return BrowserPlatform.LINUX;
case 'win32':
return os.arch() === 'x64' ||
// Windows 11 for ARM supports x64 emulation
(os.arch() === 'arm64' && isWindows11(os.release()))
? BrowserPlatform.WIN64
: BrowserPlatform.WIN32;
default:
return undefined;
}
}
OK! Let's try it out. I created a temporary .js script with the following content:
import os from 'os';
const platform = os.platform();
console.log({ platform });
Let's run it:
$ node test-platform.js
And look at the output:
{ platform: 'freebsd' }
Bingo! For the first time in 20 years of doing web development professionally, I'm having to deal with a FreeBSD unix server. Puppeteer doesn't support it out of the box, apparently due to lack of official binaries for Chromium on FreeBSD.
Let's get this fixed:
$ pkg install chromium
$ chrome --version
Chromium 123.0.6312.122
And now we only need to run npm install
and make sure puppeteer doesn't try to download the binaries. We need to set the env variable PUPPETEER_SKIP_DOWNLOAD
(or npm_config_puppeteer_skip_download
or npm_package_config_puppeteer_skip_download
):
$ export PUPPETEER_SKIP_DOWNLOAD=1
export: Command not found.
Ops! FreeBSD again, everything needs to be different. Let's try this:
$ setenv PUPPETEER_SKIP_DOWNLOAD 1 && npm install
All done, finally. If you run into the same problem, hopefully this will save you a few minutes of Googling.
PS. If you liked this article, please share to spread the word.