Skip to content
This repository has been archived by the owner on Jan 18, 2024. It is now read-only.

[image-utils] add env variable to disable sharp resolution #2269

Merged
merged 2 commits into from
Jun 17, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ jobs:
dev-server,
expo-cli,
expo-codemod,
image-utils,
json-file,
metro-config,
package-manager,
Expand Down
12 changes: 11 additions & 1 deletion packages/image-utils/README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
# `@expo/image-utils`

A library for image processing functionality in Expo CLI. It uses `sharp` for image processing if it's available through a global `sharp-cli` installation. Otherwise it uses `jimp`, a Node library with no native dependencies, and warns the user that they may want to install `sharp-cli` for faster image processing.
A library for image processing functionality in Expo CLI. It uses `sharp` for image processing if it's available through a global `sharp-cli` installation. Otherwise it uses `jimp`, a Node library with no native dependencies, and warns the user that they may want to install `sharp-cli` for faster image processing.

## Advanced Configuration

This package can be configured using the following environment variables.

### EXPO_IMAGE_UTILS_NO_SHARP

When truthy, this will force global `sharp-cli` resolution methods like `isAvailableAsync()` and `findSharpInstanceAsync()` to fail. Other processes can use this to fallback on Jimp for image modifications. By default this is falsy (undefined).

`findSharpInstanceAsync()` will throw an error if disabled because it shouldn't be invoked if `isAvailableAsync()` returns `false`.
7 changes: 7 additions & 0 deletions packages/image-utils/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
const path = require('path');

module.exports = {
preset: '../../jest/unit-test-config',
rootDir: path.resolve(__dirname),
displayName: require('./package').name,
};
1 change: 1 addition & 0 deletions packages/image-utils/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"scripts": {
"watch": "tsc --watch",
"build": "tsc",
"test": "jest",
"prepare": "yarn run clean && yarn build",
"clean": "rimraf build ./tsconfig.tsbuildinfo"
},
Expand Down
21 changes: 21 additions & 0 deletions packages/image-utils/src/__tests__/sharp-test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
beforeEach(() => {
delete process.env.EXPO_IMAGE_UTILS_NO_SHARP;
});

// Test that the environment variable can be used to disable sharp-cli for easier testing of image generation.
describe('isAvailableAsync', () => {
it(`can be disabled using an environment variable`, async () => {
process.env.EXPO_IMAGE_UTILS_NO_SHARP = '1';
const { isAvailableAsync } = require('../sharp');
expect(await isAvailableAsync()).toBe(false);
});
});
describe('findSharpInstanceAsync', () => {
it(`will throw an error if sharp-cli is disabled in the environment`, async () => {
process.env.EXPO_IMAGE_UTILS_NO_SHARP = '1';
const { findSharpInstanceAsync } = require('../sharp');
expect(findSharpInstanceAsync()).rejects.toThrowError(
'sharp-cli has been disabled with the environment variable'
);
});
});
19 changes: 19 additions & 0 deletions packages/image-utils/src/sharp.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import semver from 'semver';
import spawnAsync from '@expo/spawn-async';
import resolveFrom from 'resolve-from';
import { boolish } from 'getenv';
import { Options, SharpCommandOptions, SharpGlobalOptions } from './sharp.types';

const SHARP_HELP_PATTERN = /\n\nSpecify --help for available options/g;
Expand All @@ -25,7 +26,16 @@ export async function resizeBufferAsync(buffer: Buffer, sizes: number[]): Promis
return resizedBuffers;
}

const isSharpDisabled = boolish('EXPO_IMAGE_UTILS_NO_SHARP', false);

/**
* Returns `true` if a global sharp instance can be found.
* This functionality can be overridden with `process.env.EXPO_IMAGE_UTILS_NO_SHARP=1`.
*/
export async function isAvailableAsync(): Promise<boolean> {
if (isSharpDisabled) {
return false;
}
try {
return !!(await findSharpBinAsync());
} catch (_) {
Expand Down Expand Up @@ -127,7 +137,16 @@ async function findSharpBinAsync(): Promise<string> {
return _sharpBin;
}

/**
* Returns the instance of `sharp` installed by the global `sharp-cli` package.
* This method will throw errors if the `sharp` instance cannot be found, these errors can be circumvented by ensuring `isAvailableAsync()` resolves to `true`.
*/
export async function findSharpInstanceAsync(): Promise<any | null> {
if (isSharpDisabled) {
throw new Error(
'Global instance of sharp-cli cannot be retrieved because sharp-cli has been disabled with the environment variable `EXPO_IMAGE_UTILS_NO_SHARP`'
);
}
if (_sharpInstance) {
return _sharpInstance;
}
Expand Down