beyondcode / herd-community

78 stars 1 forks source link

[Bug]:Laravel Herd on Windows using exec(), importing Puppeteer fails while Playwright and simple scripts work. Works on Xampp #874

Closed ysufmv closed 2 weeks ago

ysufmv commented 2 months ago

Platform

Windows

Operating system version

Windows 11 Pro (23H2 22631.3880)

System architecture

Windows

Herd Version

1.8.0 (Pro)

PHP Version

No response

Bug description

In Laravel Herd for Windows, attempting to run exec( ) on a Node.js script that imports Puppeteer fails with an EISDIR error. Simple scripts work. And to test for an alternative I tried importing Playwright which works fine and the script executes succesfully.

The same code to import Puppeteer works correctly when executed in a XAMPP server instead of Laravel Herd, and the script succesfully executes.

The issue cropped up when I was doing some testing on my main site. To make sure there is no intereference from any other packages / scripts, I added a new Laravel instance called nodetest using Herd and chose default configurations.

The reason why I am trying to access Puppeteer on the back-end, via Laravel exec(), is because its a business logic that needs to be hidden from the front-end users, and, right now it is the only way possible I know of that can achieve the same results on my actual production server. That is not the goal of raising this issue.

The outcome from raising this issue would be to identify and resolve the reason why it fails to work on Laravel Herd while the same code works on a Xampp server. I am assuming that it is not specific to Puppeteer and other packages may also fail to import.

My Laravel Herd Active Services

image

The php & node version image

image

Sites: image

Further background: I have the following installed on Windows, prior to installing Laravel Herd: Composer Xampp for Windows PHP 8.2.12 (All services stopped for the test) Node v21.5.0 (Might be interferring - but I don't know if its relevant) npm v10.2.4 pnpm v9.0.6

Also tested on a Hyper-V Virtual Machine with a fresh Windows installation via ISO image.

Steps to reproduce

Assuming that you have Laravel Herd (1.8.0) installed. If you have Xampp or any other similar services installed, you can stop all of its services and close it.

image

image

pnpm i puppeteer

image


Route::get('/', function () {
    $output = [];
    $return_var = 0;

    $nodePath = 'node';
    $scriptPath = base_path('public/checkPuppeteer.js'); //doesn't matter if it is .mjs .js 

    $command = "\"$nodePath\" \"$scriptPath\" 2>&1";
    exec($command, $output, $return_var);

    dd($command, $output, $return_var);

    if ($return_var != 0) {
        return response()->json([
            'success' => false,
            'message' => 'Could not run Puppeteer check',
            'output' => $output,
            'return_var' => $return_var
        ], 200);
    } else {
        return response()->json([
            'success' => true,
            'message' => 'Puppeteer check ran successfully',
            'output' => $output,
            'return_var' => $return_var
        ], 200);
    }
});

Add the following code:

import puppeteer from 'puppeteer';
import { writeFileSync } from 'fs';

(async () => {
    try {
        const browser = await puppeteer.launch({ headless: true });
        const page = await browser.newPage();
        await page.goto('https://example.com');
        console.log('Puppeteer launched successfully');
        writeFileSync('./log.txt', 'Puppeteer launched successfully', 'utf8');
        await browser.close();
    } catch (error) {
        console.error('Error launching Puppeteer:', error);
        writeFileSync('./log.txt', `Error: ${error}`, 'utf8');
    }
})();

As seen:

image

image

To check if it works normally, you can run the checkPuppeteer.js on the terminal as below: 'cd' into the 'public' folder and type:

node checkPuppeteer.js

image

It should execute successfully, as above.

import { writeFileSync } from 'fs';

const testFunction = () => {
    writeFileSync('./log.txt', 'Laravel Herds is for Sheep Sites', 'utf8');
    console.log('Laravel Herds is for Sheep Sites');
};

testFunction();

It should execute succesfully:

image

For good measure I wanted to see if an alternative package would work, so I installed Playwright

pnpm install playwright 

// if you are installing playwright fresh you would need to get the binaries by executing: 

npx playwright install 

Change your checkPuppeteer.js code to below to check with Playwright:

import { chromium } from 'playwright';
import { writeFileSync } from 'fs';

(async () => {
    try {
        const browser = await chromium.launch({ headless: true });
        const page = await browser.newPage();
        await page.goto('https://example.com');
        console.log('Playwright launched successfully');
        writeFileSync('./log.txt', 'Playwright launched successfully', 'utf8');
        await browser.close();
    } catch (error) {
        console.error('Error launching Playwright:', error);
        writeFileSync('./log.txt', `Error: ${error}`, 'utf8');
    }
})();

Open the website on your browser. You would see that it takes a few more seconds to load because in the background the script is succesfully executing. Afterwards, you should see the dump on the screen showing it is succesful: image

All this works just fine on Xampp server, which was what I was using till recently. But after exploring Laravel Herd, I immediately wanted to make it my go-to development server. I subscribed to Laravel Herd Pro and was on my way to get everything sorted when this popped up, and it's been nagging me.

It may not be a major issue or something to do with my configurations. (I've tested the same on a frest Hyper-V Virtual Machine (Windows 11 with Windows ISO image)

Steps Taken

Why I am posting this: I love the simplicity of Laravel Herd and want to work with it in the future. This may be an edge case. But it forces me to go back and use Xampp or change the packages I currently use.

I may have missed some very simple solutions that could circumvent this error. So I'm all ears.

Relevant log output

""node" "D:\Sheep\nodetest2\public/checkPuppeteer.js" 2>&1"
array:21 [▼
  0 => "node:net:428"
  1 => "      throw new ErrnoException(err, 'open');"
  2 => "            ^"
  3 => ""
  4 => "Error: open EISDIR"
  5 => "    at new Socket (node:net:428:13)"
  6 => "    at process.getStdin [as stdin] (node:internal/bootstrap/switches/is_main_thread:224:17)"
  7 => "    at get (<anonymous>)"
  8 => "    at getOwn (node:internal/bootstrap/realm:202:5)"
  9 => "    at BuiltinModule.syncExports (node:internal/bootstrap/realm:377:31)"
  10 => "    at ModuleWrap.<anonymous> (node:internal/bootstrap/realm:357:17)"
  11 => "    at BuiltinModule.getESMFacade (node:internal/bootstrap/realm:362:17)"
  12 => "    at BuiltinModule.compileForPublicLoader (node:internal/bootstrap/realm:340:10)"
  13 => "    at loadBuiltinModule (node:internal/modules/helpers:101:7)"
  14 => "    at ModuleLoader.builtinStrategy (node:internal/modules/esm/translators:454:18) {"
  15 => "  errno: -4068,"
  16 => "  code: 'EISDIR',"
  17 => "  syscall: 'open'"
  18 => "}"
  19 => ""
  20 => "Node.js v21.5.0"
]
mpociot commented 1 month ago

I assume that this is somehow related to the way PHP resolves the node binary (and possibly other environment variables needed for executing this).

Could you try and re-run the same code in Herd but pass an absolute path to "node"?