Skip to content
2 changes: 1 addition & 1 deletion .github/ISSUE_TEMPLATE/installation.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
name: Installation
about: Something went wrong during either 'npm install sharp' or 'require("sharp")'
about: Something went wrong during either 'npm install sharp' or 'import "sharp"'
labels: installation

---
Expand Down
2 changes: 1 addition & 1 deletion .github/ISSUE_TEMPLATE/possible-bug.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ labels: triage
<!-- Please place an [x] in the box to confirm. -->

- [ ] Running `npm install sharp` completes without error.
- [ ] Running `node -e "require('sharp')"` completes without error.
- [ ] Running `node -e "import 'sharp'"` completes without error.

If you cannot confirm both of these, please open an [installation issue](https://github.com/lovell/sharp/issues/new?labels=installation&template=installation.md) instead.

Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,4 @@ package-lock.json
.astro
docs/dist
release-notes.md
dist
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ npm install sharp
```

```javascript
// ESM
import sharp from 'sharp';

// CJS
const sharp = require('sharp');
```

Expand Down
4 changes: 2 additions & 2 deletions lib/channel.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
SPDX-License-Identifier: Apache-2.0
*/

const is = require('./is');
import is from './is';

/**
* Boolean operations for bandbool.
Expand Down Expand Up @@ -163,7 +163,7 @@ function bandbool (boolOp) {
* @module Sharp
* @private
*/
module.exports = (Sharp) => {
export default (Sharp) => {
Object.assign(Sharp.prototype, {
// Public instance functions
removeAlpha,
Expand Down
6 changes: 3 additions & 3 deletions lib/colour.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
SPDX-License-Identifier: Apache-2.0
*/

const color = require('@img/colour');
const is = require('./is');
import color from '@img/colour';
import is from './is';

/**
* Colourspaces.
Expand Down Expand Up @@ -175,7 +175,7 @@ function _setBackgroundColourOption (key, value) {
* @module Sharp
* @private
*/
module.exports = (Sharp) => {
export default (Sharp) => {
Object.assign(Sharp.prototype, {
// Public
tint,
Expand Down
4 changes: 2 additions & 2 deletions lib/composite.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
SPDX-License-Identifier: Apache-2.0
*/

const is = require('./is');
import is from './is';

/**
* Blend modes.
Expand Down Expand Up @@ -206,7 +206,7 @@ function composite (images) {
* @module Sharp
* @private
*/
module.exports = (Sharp) => {
export default (Sharp) => {
Sharp.prototype.composite = composite;
Sharp.blend = blend;
};
14 changes: 7 additions & 7 deletions lib/constructor.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
SPDX-License-Identifier: Apache-2.0
*/

const util = require('node:util');
const stream = require('node:stream');
const is = require('./is');
import util from 'node:util';
import stream from 'node:stream';
import is from './is';

require('./sharp');
import './sharp';

// Use NODE_DEBUG=sharp to enable libvips warnings
const debuglog = util.debuglog('sharp');
Expand Down Expand Up @@ -426,8 +426,8 @@ Object.setPrototypeOf(Sharp, stream.Duplex);
* @example
* // Create a pipeline that will download an image, resize it and format it to different files
* // Using Promises to know when the pipeline is complete
* const fs = require("fs");
* const got = require("got");
* import fs from "node:fs";
* import got from "got";
* const sharpStream = sharp({ failOn: 'none' });
*
* const promises = [];
Expand Down Expand Up @@ -496,4 +496,4 @@ Object.assign(Sharp.prototype, { clone });
* @module Sharp
* @private
*/
module.exports = Sharp;
export default Sharp;
29 changes: 19 additions & 10 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,23 @@
SPDX-License-Identifier: Apache-2.0
*/

const Sharp = require('./constructor');
require('./input')(Sharp);
require('./resize')(Sharp);
require('./composite')(Sharp);
require('./operation')(Sharp);
require('./colour')(Sharp);
require('./channel')(Sharp);
require('./output')(Sharp);
require('./utility')(Sharp);
import Sharp from './constructor';
import input from './input';
import resize from './resize';
import composite from './composite';
import operation from './operation';
import colour from './colour';
import channel from './channel';
import output from './output';
import utility from './utility';

module.exports = Sharp;
input(Sharp);
resize(Sharp);
composite(Sharp);
operation(Sharp);
colour(Sharp);
channel(Sharp);
output(Sharp);
utility(Sharp);

export default Sharp;
6 changes: 3 additions & 3 deletions lib/input.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
SPDX-License-Identifier: Apache-2.0
*/

const is = require('./is');
const sharp = require('./sharp');
import is from './is';
import sharp from './sharp';

/**
* Justification alignment
Expand Down Expand Up @@ -792,7 +792,7 @@ function stats (callback) {
* @module Sharp
* @private
*/
module.exports = (Sharp) => {
export default (Sharp) => {
Object.assign(Sharp.prototype, {
// Private
_inputOptionsFromObject,
Expand Down
2 changes: 1 addition & 1 deletion lib/is.js
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ const nativeError = (native, context) => {
return context;
};

module.exports = {
export default {
defined,
object,
plainObject,
Expand Down
18 changes: 10 additions & 8 deletions lib/libvips.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,16 @@
SPDX-License-Identifier: Apache-2.0
*/

const { spawnSync } = require('node:child_process');
const { createHash } = require('node:crypto');
const semverCoerce = require('semver/functions/coerce');
const semverGreaterThanOrEqualTo = require('semver/functions/gte');
const semverSatisfies = require('semver/functions/satisfies');
const detectLibc = require('detect-libc');
import { spawnSync } from 'node:child_process';
import { createHash } from 'node:crypto';
import fs from 'node:fs';
import semverCoerce from 'semver/functions/coerce';
import semverGreaterThanOrEqualTo from 'semver/functions/gte';
import semverSatisfies from 'semver/functions/satisfies';
import detectLibc from 'detect-libc';

const { config, engines, optionalDependencies } = require('../package.json');
// Cannot use an import because sometimes it can need the attr or with keyword
const { config, engines, optionalDependencies } = JSON.parse(fs.readFileSync(new URL('../package.json', import.meta.url), 'utf-8'));

/* node:coverage ignore next */
const minimumLibvipsVersionLabelled = process.env.npm_package_config_libvips || config.libvips;
Expand Down Expand Up @@ -189,7 +191,7 @@ const useGlobalLibvips = (logger) => {
return !!globalVipsVersion && semverGreaterThanOrEqualTo(globalVipsVersion, minimumLibvipsVersion);
};

module.exports = {
export default {
minimumLibvipsVersion,
prebuiltPlatforms,
buildPlatformArch,
Expand Down
4 changes: 2 additions & 2 deletions lib/operation.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
SPDX-License-Identifier: Apache-2.0
*/

const is = require('./is');
import is from './is';

/**
* How accurate an operation should be.
Expand Down Expand Up @@ -987,7 +987,7 @@ function modulate (options) {
* @module Sharp
* @private
*/
module.exports = (Sharp) => {
export default (Sharp) => {
Object.assign(Sharp.prototype, {
autoOrient,
rotate,
Expand Down
8 changes: 4 additions & 4 deletions lib/output.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
SPDX-License-Identifier: Apache-2.0
*/

const path = require('node:path');
const is = require('./is');
const sharp = require('./sharp');
import path from 'node:path';
import is from './is';
import sharp from './sharp';

const formats = new Map([
['heic', 'heif'],
Expand Down Expand Up @@ -1630,7 +1630,7 @@ function _pipeline (callback, stack) {
* @module Sharp
* @private
*/
module.exports = (Sharp) => {
export default (Sharp) => {
Object.assign(Sharp.prototype, {
// Public
toFile,
Expand Down
4 changes: 2 additions & 2 deletions lib/resize.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
SPDX-License-Identifier: Apache-2.0
*/

const is = require('./is');
import is from './is';

/**
* Weighting to apply when using contain/cover fit.
Expand Down Expand Up @@ -579,7 +579,7 @@ function trim (options) {
* @module Sharp
* @private
*/
module.exports = (Sharp) => {
export default (Sharp) => {
Object.assign(Sharp.prototype, {
resize,
extend,
Expand Down
14 changes: 7 additions & 7 deletions lib/sharp.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@

// Inspects the runtime environment and exports the relevant sharp.node binary

const { familySync, versionSync } = require('detect-libc');
import { familySync, versionSync } from 'detect-libc';

const { runtimePlatformArch, isUnsupportedNodeRuntime, prebuiltPlatforms, minimumLibvipsVersion } = require('./libvips');
import { runtimePlatformArch, isUnsupportedNodeRuntime, prebuiltPlatforms, minimumLibvipsVersion } from './libvips';
const runtimePlatform = runtimePlatformArch();

const paths = [
Expand All @@ -23,7 +23,7 @@ let path, sharp;
const errors = [];
for (path of paths) {
try {
sharp = require(path);
sharp = await import(path);
break;
} catch (err) {
errors.push(err);
Expand All @@ -37,9 +37,7 @@ if (sharp && path.startsWith('@img/sharp-linux-x64') && !sharp._isUsingX64V2())
sharp = null;
}

if (sharp) {
module.exports = sharp;
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Conditional exports are not supported by ESM but it doesn't matter here because importing the module will throw as needed

} else {
if (!sharp) {
const [isLinux, isMacOs, isWindows] = ['linux', 'darwin', 'win32'].map(os => runtimePlatform.startsWith(os));

const help = [`Could not load the "sharp" module using the ${runtimePlatform} runtime`];
Expand Down Expand Up @@ -79,7 +77,7 @@ if (sharp) {
}
if (isLinux && /(symbol not found|CXXABI_)/i.test(messages)) {
try {
const { config } = require(`@img/sharp-libvips-${runtimePlatform}/package`);
const { config } = await import(`@img/sharp-libvips-${runtimePlatform}/package`);
const libcFound = `${familySync()} ${versionSync()}`;
const libcRequires = `${config.musl ? 'musl' : 'glibc'} ${config.musl || config.glibc}`;
help.push(
Expand Down Expand Up @@ -119,3 +117,5 @@ if (sharp) {
);
throw new Error(help.join('\n'));
}

export default sharp
25 changes: 14 additions & 11 deletions lib/utility.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@
SPDX-License-Identifier: Apache-2.0
*/

const events = require('node:events');
const detectLibc = require('detect-libc');
import events from 'node:events';
import fs from 'node:fs';
import detectLibc from 'detect-libc';

const is = require('./is');
const { runtimePlatformArch } = require('./libvips');
const sharp = require('./sharp');
import is from './is';
import { runtimePlatformArch } from './libvips';
import sharp from './sharp';

const runtimePlatform = runtimePlatformArch();
const libvipsVersion = sharp.libvipsVersion();
Expand Down Expand Up @@ -61,19 +62,20 @@ let versions = {
if (!libvipsVersion.isGlobal) {
if (!libvipsVersion.isWasm) {
try {
versions = require(`@img/sharp-${runtimePlatform}/versions`);
versions = await import(`@img/sharp-${runtimePlatform}/versions`);
} catch (_) {
try {
versions = require(`@img/sharp-libvips-${runtimePlatform}/versions`);
versions = await import(`@img/sharp-libvips-${runtimePlatform}/versions`);
} catch (_) {}
}
} else {
try {
versions = require('@img/sharp-wasm32/versions');
versions = await import('@img/sharp-wasm32/versions');
} catch (_) {}
}
}
versions.sharp = require('../package.json').version;
// Cannot use an import because sometimes it can need the attr or with keyword
versions.sharp = JSON.parse(fs.readFileSync(new URL('../package.json', import.meta.url), 'utf-8')).version;

/* node:coverage ignore next 5 */
if (versions.heif && format.heif) {
Expand Down Expand Up @@ -156,7 +158,8 @@ if (detectLibc.familySync() === detectLibc.GLIBC && !sharp._isUsingJemalloc()) {
sharp.concurrency(1);
} else if (detectLibc.familySync() === detectLibc.MUSL && sharp.concurrency() === 1024) {
// Reduce default concurrency when musl thread over-subscription detected
sharp.concurrency(require('node:os').availableParallelism());
const { availableParallelism } = await import('node:os')
sharp.concurrency(availableParallelism());
}

/**
Expand Down Expand Up @@ -277,7 +280,7 @@ function unblock (options) {
* @module Sharp
* @private
*/
module.exports = (Sharp) => {
export default (Sharp) => {
Sharp.cache = cache;
Sharp.concurrency = concurrency;
Sharp.counters = counters;
Expand Down
Loading