From a2d54b069728be06463ebbd8b4e1739841f83ec0 Mon Sep 17 00:00:00 2001 From: Devon Govett Date: Thu, 30 Sep 2021 10:49:08 -0700 Subject: [PATCH 1/2] Require sharp from the main thread to prevent issues on worker exit --- packages/transformers/image/package.json | 1 + .../transformers/image/src/ImageTransformer.js | 15 +++++++++++++++ packages/transformers/image/src/loadSharp.js | 5 +++++ 3 files changed, 21 insertions(+) create mode 100644 packages/transformers/image/src/loadSharp.js diff --git a/packages/transformers/image/package.json b/packages/transformers/image/package.json index 987b4800ac6..e9cefdb7381 100644 --- a/packages/transformers/image/package.json +++ b/packages/transformers/image/package.json @@ -17,6 +17,7 @@ }, "dependencies": { "@parcel/plugin": "2.0.0-rc.0", + "@parcel/workers": "2.0.0-rc.0", "nullthrows": "^1.1.1" }, "devDependencies": { diff --git a/packages/transformers/image/src/ImageTransformer.js b/packages/transformers/image/src/ImageTransformer.js index be04989e578..1901c4d510a 100644 --- a/packages/transformers/image/src/ImageTransformer.js +++ b/packages/transformers/image/src/ImageTransformer.js @@ -2,6 +2,7 @@ import {validateConfig} from './validateConfig'; import {Transformer} from '@parcel/plugin'; import nullthrows from 'nullthrows'; +import WorkerFarm from '@parcel/workers'; // from https://github.com/lovell/sharp/blob/df7b8ba73808fc494be413e88cfb621b6279218c/lib/output.js#L6-L17 const FORMATS = new Map([ @@ -18,6 +19,8 @@ const FORMATS = new Map([ const SHARP_RANGE = '^0.29.1'; +let isSharpLoadedOnMainThread = false; + export default (new Transformer({ async loadConfig({config}) { let configFile: any = await config.getConfig( @@ -61,6 +64,18 @@ export default (new Transformer({ const outputOptions = config[format]; if (width || height || quality || targetFormat || outputOptions) { + // Sharp must be required from the main thread as well to prevent errors when workers exit + // See https://sharp.pixelplumbing.com/install#worker-threads and https://github.com/lovell/sharp/issues/2263 + if (WorkerFarm.isWorker() && !isSharpLoadedOnMainThread) { + let api = WorkerFarm.getWorkerApi(); + await api.callMaster({ + location: __dirname + '/loadSharp.js', + args: [], + }); + + isSharpLoadedOnMainThread = true; + } + let inputBuffer = await asset.getBuffer(); let sharp = await options.packageManager.require( 'sharp', diff --git a/packages/transformers/image/src/loadSharp.js b/packages/transformers/image/src/loadSharp.js new file mode 100644 index 00000000000..05fb642d4f8 --- /dev/null +++ b/packages/transformers/image/src/loadSharp.js @@ -0,0 +1,5 @@ +// This is used to load sharp on the main thread, which prevents errors when worker threads exit +// See https://sharp.pixelplumbing.com/install#worker-threads and https://github.com/lovell/sharp/issues/2263 +module.exports = () => { + require('sharp'); +}; From cc487e3b24f8d920cb4c73c66b785dc04c495869 Mon Sep 17 00:00:00 2001 From: Devon Govett Date: Thu, 30 Sep 2021 10:56:29 -0700 Subject: [PATCH 2/2] Use package manager to load sharp on main thread --- .../image/src/ImageTransformer.js | 19 ++++++++-------- packages/transformers/image/src/loadSharp.js | 22 +++++++++++++++++-- 2 files changed, 30 insertions(+), 11 deletions(-) diff --git a/packages/transformers/image/src/ImageTransformer.js b/packages/transformers/image/src/ImageTransformer.js index 1901c4d510a..eac4100cf3a 100644 --- a/packages/transformers/image/src/ImageTransformer.js +++ b/packages/transformers/image/src/ImageTransformer.js @@ -3,6 +3,7 @@ import {validateConfig} from './validateConfig'; import {Transformer} from '@parcel/plugin'; import nullthrows from 'nullthrows'; import WorkerFarm from '@parcel/workers'; +import loadSharp from './loadSharp'; // from https://github.com/lovell/sharp/blob/df7b8ba73808fc494be413e88cfb621b6279218c/lib/output.js#L6-L17 const FORMATS = new Map([ @@ -17,8 +18,6 @@ const FORMATS = new Map([ ['heif', 'heif'], ]); -const SHARP_RANGE = '^0.29.1'; - let isSharpLoadedOnMainThread = false; export default (new Transformer({ @@ -70,20 +69,22 @@ export default (new Transformer({ let api = WorkerFarm.getWorkerApi(); await api.callMaster({ location: __dirname + '/loadSharp.js', - args: [], + args: [ + options.packageManager, + asset.filePath, + options.shouldAutoInstall, + ], }); isSharpLoadedOnMainThread = true; } let inputBuffer = await asset.getBuffer(); - let sharp = await options.packageManager.require( - 'sharp', + let sharp = await loadSharp( + options.packageManager, asset.filePath, - { - range: SHARP_RANGE, - shouldAutoInstall: options.shouldAutoInstall, - }, + options.shouldAutoInstall, + true, ); let imagePipeline = sharp(inputBuffer); diff --git a/packages/transformers/image/src/loadSharp.js b/packages/transformers/image/src/loadSharp.js index 05fb642d4f8..52e598cbf26 100644 --- a/packages/transformers/image/src/loadSharp.js +++ b/packages/transformers/image/src/loadSharp.js @@ -1,5 +1,23 @@ +// @flow +import type {PackageManager} from '@parcel/package-manager'; +import type {FilePath} from '@parcel/types'; + +const SHARP_RANGE = '^0.29.1'; + // This is used to load sharp on the main thread, which prevents errors when worker threads exit // See https://sharp.pixelplumbing.com/install#worker-threads and https://github.com/lovell/sharp/issues/2263 -module.exports = () => { - require('sharp'); +module.exports = async ( + packageManager: PackageManager, + filePath: FilePath, + shouldAutoInstall: boolean, + shouldReturn: boolean, +): Promise => { + let sharp = await packageManager.require('sharp', filePath, { + range: SHARP_RANGE, + shouldAutoInstall: shouldAutoInstall, + }); + + if (shouldReturn) { + return sharp; + } };