From e6a6085dfa82524baa18bbdb57b4e40f14338e71 Mon Sep 17 00:00:00 2001 From: Nagy Szabolcs Date: Thu, 21 Mar 2024 19:10:44 +0200 Subject: [PATCH] fix(worker): Fix import error when using pkg with node v20 --- lib/worker.js | 4 +++- package.json | 3 ++- test/pkg/index.js | 37 +++++++++++++++++++++++++++++++++ test/pkg/pkg.config.json | 15 ++++++++++++++ test/pkg/pkg.test.js | 44 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 101 insertions(+), 2 deletions(-) create mode 100644 test/pkg/index.js create mode 100644 test/pkg/pkg.config.json create mode 100644 test/pkg/pkg.test.js diff --git a/lib/worker.js b/lib/worker.js index 03d02d1..198a957 100644 --- a/lib/worker.js +++ b/lib/worker.js @@ -44,8 +44,10 @@ async function start () { if ((error.code === 'ENOTDIR' || error.code === 'ERR_MODULE_NOT_FOUND') && filename.startsWith('file://')) { worker = realRequire(decodeURIComponent(filename.replace('file://', ''))) - } else if (error.code === undefined) { + } else if (error.code === undefined || error.code === 'ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING') { // When bundled with pkg, an undefined error is thrown when called with realImport + // When bundled with pkg and using node v20, an ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING error is thrown when called with realImport + // More info at: https://github.com/pinojs/thread-stream/issues/143 worker = realRequire(decodeURIComponent(filename.replace(process.platform === 'win32' ? 'file:///' : 'file://', ''))) } else { throw error diff --git a/package.json b/package.json index a87b82e..a44e9d8 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "devDependencies": { "@types/node": "^20.1.0", "@types/tap": "^15.0.0", + "@yao-pkg/pkg": "^5.11.5", "desm": "^1.3.0", "fastbench": "^1.0.1", "husky": "^9.0.6", @@ -22,7 +23,7 @@ "why-is-node-running": "^2.2.2" }, "scripts": { - "test": "standard && npm run transpile && tap test/*.test.*js && tap --ts test/*.test.*ts", + "test": "standard && npm run transpile && tap \"test/**/*.test.*js\" && tap --ts test/*.test.*ts", "test:ci": "standard && npm run transpile && npm run test:ci:js && npm run test:ci:ts", "test:ci:js": "tap --no-check-coverage --coverage-report=lcovonly \"test/**/*.test.*js\"", "test:ci:ts": "tap --ts --no-check-coverage --coverage-report=lcovonly \"test/**/*.test.*ts\"", diff --git a/test/pkg/index.js b/test/pkg/index.js new file mode 100644 index 0000000..4f40ac5 --- /dev/null +++ b/test/pkg/index.js @@ -0,0 +1,37 @@ +'use strict' + +/** + * This file is packaged using pkg in order to test if worker.js works in that context + */ + +const { test } = require('tap') +const { join } = require('path') +const { file } = require('../helper') +const ThreadStream = require('../..') + +test('bundlers support with .js file', function (t) { + t.plan(1) + + globalThis.__bundlerPathsOverrides = { + 'thread-stream-worker': join(__dirname, '..', 'custom-worker.js') + } + + const dest = file() + + process.on('uncaughtException', (error) => { + console.log(error) + }) + + const stream = new ThreadStream({ + filename: join(__dirname, '..', 'to-file.js'), + workerData: { dest }, + sync: true + }) + + stream.worker.removeAllListeners('message') + stream.worker.once('message', (message) => { + t.equal(message.code, 'CUSTOM-WORKER-CALLED') + }) + + stream.end() +}) diff --git a/test/pkg/pkg.config.json b/test/pkg/pkg.config.json new file mode 100644 index 0000000..38905e0 --- /dev/null +++ b/test/pkg/pkg.config.json @@ -0,0 +1,15 @@ +{ + "pkg": { + "assets": [ + "../custom-worker.js", + "../to-file.js" + ], + "targets": [ + "node14", + "node16", + "node18", + "node20" + ], + "outputPath": "test/pkg" + } +} \ No newline at end of file diff --git a/test/pkg/pkg.test.js b/test/pkg/pkg.test.js new file mode 100644 index 0000000..7914fa3 --- /dev/null +++ b/test/pkg/pkg.test.js @@ -0,0 +1,44 @@ +'use strict' + +const { test } = require('tap') +const config = require('./pkg.config.json') +const { promisify } = require('util') +const { unlink } = require('fs/promises') +const { join } = require('path') +const { platform } = require('process') +const exec = promisify(require('child_process').exec) + +test('worker test when packaged into executable using pkg', async (t) => { + const packageName = 'index' + + // package the app into several node versions, check config for more info + const filePath = `${join(__dirname, packageName)}.js` + const configPath = join(__dirname, 'pkg.config.json') + const { stderr } = await exec(`npx pkg ${filePath} --config ${configPath}`) + + // there should be no error when packaging + t.equal(stderr, '') + + // pkg outputs files in the following format by default: {filename}-{node version} + for (const target of config.pkg.targets) { + // execute the packaged test + let executablePath = `${join(config.pkg.outputPath, packageName)}-${target}` + + // when on windows, we need the .exe extension + if (platform === 'win32') { + executablePath = `${executablePath}.exe` + } else { + executablePath = `./${executablePath}` + } + + const { stderr } = await exec(executablePath) + + // check if there were no errors + t.equal(stderr, '') + + // clean up afterwards + await unlink(executablePath) + } + + t.end() +})