New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

gatsby-transformer-cloudinary

Package Overview
Dependencies
Maintainers
2
Versions
46
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

gatsby-transformer-cloudinary - npm Package Compare versions

Comparing version 2.1.1 to 2.2.0

11

CHANGELOG.md

@@ -1,3 +0,12 @@

# Version Next
# Version 2.2.0
Improvements:
- Only throw an error on missing Cloudinary credentials if those credentials are actually needed to upload an image to Cloudinary.
- base64 images are no longer generated unless a query requesting them is run.
- defaultTracedSVG values are now passed along as tracedSVG values.
- Improved base64 caching so that if a second request for the same base64 image is made before the first response is received, only one request is made.
# Version 2.1.1
Additions:

@@ -4,0 +13,0 @@

@@ -39,2 +39,3 @@ const stringify = require('fast-json-stable-stringify');

defaultBase64,
defaultTracedSVG,
}) => {

@@ -72,2 +73,3 @@ let breakpoints = getDefaultBreakpoints(width);

defaultBase64,
defaultTracedSVG,

@@ -74,0 +76,0 @@ // Add the required internal Gatsby node fields.

@@ -164,2 +164,15 @@ const { createImageNode } = require('./create-image-node');

it('sets the defaultTracedSVG image', async () => {
const options = getDefaultOptions();
getPluginOptions.mockReturnValue(options);
const args = getDefaultArgs({
defaultTracedSVG: 'defaultTracedSVG',
});
const actual = createImageNode(args);
const expected = { defaultTracedSVG: 'defaultTracedSVG' };
expect(actual).toEqual(expect.objectContaining(expected));
});
it('creates a node ID', async () => {

@@ -166,0 +179,0 @@ const options = getDefaultOptions();

@@ -13,2 +13,21 @@ import { graphql } from 'gatsby';

export const cloudinaryAssetFluidNoBase64 = graphql`
fragment CloudinaryAssetFluid_noBase64 on CloudinaryAssetFluid {
aspectRatio
sizes
src
srcSet
}
`;
export const cloudinaryAssetFluidTracedSVG = graphql`
fragment CloudinaryAssetFluid_tracedSVG on CloudinaryAssetFluid {
aspectRatio
sizes
src
srcSet
tracedSVG
}
`;
export const cloudinaryAssetFluidLimitPresentationSize = graphql`

@@ -30,1 +49,20 @@ fragment CloudinaryAssetFluidLimitPresentationSize on CloudinaryAssetFluid {

`;
export const cloudinaryAssetFixedNoBase64 = graphql`
fragment CloudinaryAssetFixed_noBase64 on CloudinaryAssetFixed {
height
src
srcSet
width
}
`;
export const cloudinaryAssetFixedTracedSVG = graphql`
fragment CloudinaryAssetFixed_tracedSVG on CloudinaryAssetFixed {
height
src
srcSet
tracedSVG
width
}
`;

36

gatsby-node.js

@@ -56,6 +56,7 @@ const fs = require('fs-extra');

aspectRatio: Float
base64: String!
base64: String
height: Float
src: String
srcSet: String
tracedSVG: String
width: Float

@@ -66,3 +67,3 @@ }

aspectRatio: Float!
base64: String!
base64: String
presentationHeight: Float

@@ -73,2 +74,3 @@ presentationWidth: Float

srcSet: String!
tracedSVG: String
}

@@ -91,2 +93,3 @@ `);

defaultBase64,
defaultTracedSVG,
},

@@ -102,4 +105,9 @@ {

},
) =>
getFixedImageObject({
_context,
info,
) => {
const fieldsToSelect = info.fieldNodes[0].selectionSet.selections.map(
item => item.name.value,
);
return getFixedImageObject({
base64Transformations,

@@ -110,2 +118,4 @@ base64Width,

defaultBase64,
fieldsToSelect,
defaultTracedSVG,
height,

@@ -120,3 +130,4 @@ ignoreDefaultBase64,

width,
}),
});
},
},

@@ -130,2 +141,3 @@ fluid: {

defaultBase64,
defaultTracedSVG,
originalHeight,

@@ -144,4 +156,9 @@ originalWidth,

},
) =>
getFluidImageObject({
_context,
info,
) => {
const fieldsToSelect = info.fieldNodes[0].selectionSet.selections.map(
item => item.name.value,
);
return getFluidImageObject({
base64Transformations,

@@ -153,2 +170,4 @@ base64Width,

defaultBase64,
fieldsToSelect,
defaultTracedSVG,
ignoreDefaultBase64,

@@ -162,3 +181,4 @@ maxWidth,

version,
}),
});
},
},

@@ -165,0 +185,0 @@ },

@@ -87,2 +87,3 @@ const flatMap = require('lodash/flatMap');

defaultBase64,
defaultTracedSVG,
originalHeight,

@@ -114,2 +115,3 @@ originalWidth,

defaultBase64,
defaultTracedSVG,
});

@@ -116,0 +118,0 @@

@@ -25,2 +25,3 @@ const { createAssetNodesFromData } = require('./create-asset-nodes-from-data');

defaultBase64: 'defaultBase64',
defaultTracedSVG: 'defaultTracedSVG',
},

@@ -103,2 +104,3 @@ },

defaultBase64: assetData.defaultBase64,
defaultTracedSVG: assetData.defaultTracedSVG,
}),

@@ -105,0 +107,0 @@ );

@@ -19,2 +19,4 @@ const { getPluginOptions } = require('./options');

defaultBase64,
fieldsToSelect,
defaultTracedSVG,
height,

@@ -30,15 +32,2 @@ ignoreDefaultBase64 = false,

}) => {
const base64 = await getBase64({
base64Transformations,
base64Width,
chained,
cloudName,
defaultBase64,
ignoreDefaultBase64,
public_id,
reporter,
transformations,
version,
});
const src = getImageURL({

@@ -101,9 +90,26 @@ public_id,

return {
base64,
const fixedImageObject = {
height: Math.round(displayHeight),
src,
srcSet,
tracedSVG: defaultTracedSVG,
width: Math.round(displayWidth),
};
if (fieldsToSelect.includes('base64')) {
fixedImageObject.base64 = await getBase64({
base64Transformations,
base64Width,
chained,
cloudName,
defaultBase64,
ignoreDefaultBase64,
public_id,
reporter,
transformations,
version,
});
}
return fixedImageObject;
};

@@ -118,2 +124,4 @@

defaultBase64,
fieldsToSelect,
defaultTracedSVG,
ignoreDefaultBase64 = false,

@@ -135,14 +143,2 @@ maxWidth,

const sizes = `(max-width: ${max}px) 100vw, ${max}px`;
const base64 = await getBase64({
base64Transformations,
base64Width,
chained,
cloudName,
defaultBase64,
ignoreDefaultBase64,
public_id,
reporter,
transformations,
version,
});
const src = getImageURL({

@@ -183,5 +179,4 @@ public_id,

return {
const fluidImageObject = {
aspectRatio,
base64,
presentationWidth,

@@ -192,3 +187,21 @@ presentationHeight,

srcSet,
tracedSVG: defaultTracedSVG,
};
if (fieldsToSelect.includes('base64')) {
fluidImageObject.base64 = await getBase64({
base64Transformations,
base64Width,
chained,
cloudName,
defaultBase64,
ignoreDefaultBase64,
public_id,
reporter,
transformations,
version,
});
}
return fluidImageObject;
};

@@ -195,0 +208,0 @@

@@ -21,2 +21,4 @@ const {

originalHeight: 1080,
fieldsToSelect: ['base64'],
defaultTracedSVG: 'defaultTracedSVG',
...args,

@@ -81,2 +83,22 @@ };

it('does not return base64 if base64 is not a field to select', async () => {
const options = getDefaultOptions();
getPluginOptions.mockReturnValue(options);
const args = getDefaultArgs({ fieldsToSelect: [] });
expect((await getFluidImageObject(args)).base64).toEqual(undefined);
});
it('returns a tracedSVG image', async () => {
const options = getDefaultOptions();
getPluginOptions.mockReturnValue(options);
const args = getDefaultArgs();
const expectedTracedSVG = args.defaultTracedSVG;
expect(await getFluidImageObject(args)).toEqual(
expect.objectContaining({ tracedSVG: expectedTracedSVG }),
);
});
it('does not fetch base64 images multiple times', async () => {

@@ -99,5 +121,6 @@ const options = getDefaultOptions();

cloudName: 'cloudName',
// enableDefaultTranformations: true,
originalWidth: 1920,
originalHeight: 1080,
fieldsToSelect: ['base64'],
defaultTracedSVG: 'defaultTracedSVG',
...args,

@@ -234,2 +257,23 @@ };

it('does not return base64 if base64 is not a field to select', async () => {
const options = getDefaultOptions();
getPluginOptions.mockReturnValue(options);
const args = getDefaultArgs({ fieldsToSelect: [] });
expect((await getFluidImageObject(args)).base64).toEqual(undefined);
});
it('returns a tracedSVG image', async () => {
const options = getDefaultOptions();
getPluginOptions.mockReturnValue(options);
const args = getDefaultArgs();
const expectedTracedSVG = args.defaultTracedSVG;
expect(await getFluidImageObject(args)).toEqual(
expect.objectContaining({ tracedSVG: expectedTracedSVG }),
);
});
it('does not fetch base64 images multiple times', async () => {

@@ -236,0 +280,0 @@ const options = getDefaultOptions();

@@ -88,8 +88,7 @@ const axios = require('axios');

logBase64Retrieval(url, reporter);
const result = await axios.get(url, { responseType: 'arraybuffer' });
const data = Buffer.from(result.data).toString('base64');
base64Cache[url] = `data:image/jpeg;base64,${data}`;
base64Cache[url] = axios.get(url, { responseType: 'arraybuffer' });
}
return base64Cache[url];
const response = await base64Cache[url];
const data = Buffer.from(response.data).toString('base64');
return `data:image/jpeg;base64,${data}`;
}

@@ -96,0 +95,0 @@

@@ -14,13 +14,3 @@ let options = null;

const requiredOptions = ['apiKey', 'apiSecret', 'cloudName'];
exports.setPluginOptions = ({ pluginOptions, reporter }) => {
requiredOptions.forEach(optionKey => {
if (pluginOptions[optionKey] == null) {
reporter.panic(
`[gatsby-transformer-cloudinary] "${optionKey}" is a required plugin option. You can add it to the options object for "gatsby-transformer-cloudinary" in your gatsby-config file.`,
);
}
});
if (

@@ -27,0 +17,0 @@ pluginOptions.breakpointsMaxImages &&

{
"name": "gatsby-transformer-cloudinary",
"version": "2.1.1",
"version": "2.2.0",
"description": "Transform local files into Cloudinary-managed assets for Gatsby sites.",

@@ -5,0 +5,0 @@ "main": "index.js",

@@ -164,2 +164,3 @@ # gatsby-transformer-cloudinary

defaultBase64: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mMMXG/8HwAEwAI0Bj1bnwAAAABJRU5ErkJggg==",
defaultTracedSVG: "data:image/svg+xml,%3Csvg%20height%3D%229999%22%20viewBox%3D%220%200%209999%209999%22%20width%3D%229999%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20d%3D%22m0%200h9999v9999h-9999z%22%20fill%3D%22%23f9fafb%22%2F%3E%3C%2Fsvg%3E",
}

@@ -175,2 +176,6 @@ }

No API calls to Cloudinary for base64 images will be made if your GraphQL queries do not request base64 images.
The property `defaultTracedSVG` in the node above can be used by your CMS/backend to provide precomputed or cached SVG placeholders for your images. The provided string must comply with [RFC 2397](https://tools.ietf.org/html/rfc2397). It should also be encoded with something like JavaScript's `encodeURIComponent()`.
### Plugin options

@@ -182,5 +187,5 @@

| ------------------------------ | --------- | -------- | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `cloudName` | `String` | true | n/a | Cloud name of your Cloudinary account, can be obtained from your [Cloudinary console](https://cloudinary.com/console/). This should be stored and retrieved as an environment variable. |
| `apiKey` | `String` | true | n/a | API Key of your Cloudinary account, can be obtained from your [Cloudinary console](https://cloudinary.com/console/). This should be stored and retrieved as an environment variable. |
| `apiSecret` | `String` | true | n/a | API Secret of your Cloudinary account, can be obtained from your [Cloudinary console](https://cloudinary.com/console/). This should be stored and retrieved as an environment variable. |
| `cloudName` | `String` | false | n/a | Cloud name of your Cloudinary account, can be obtained from your [Cloudinary console](https://cloudinary.com/console/). This should be stored and retrieved as an environment variable. |
| `apiKey` | `String` | false | n/a | API Key of your Cloudinary account, can be obtained from your [Cloudinary console](https://cloudinary.com/console/). This should be stored and retrieved as an environment variable. |
| `apiSecret` | `String` | false | n/a | API Secret of your Cloudinary account, can be obtained from your [Cloudinary console](https://cloudinary.com/console/). This should be stored and retrieved as an environment variable. |
| `uploadFolder` | `String` | false | n/a | An optional folder name where the uploaded assets will be stored on Cloudinary. |

@@ -196,2 +201,4 @@ | `fluidMaxWidth` | `Int` | false | 1000 | The maximum width needed for an image. If specifying a width bigger than the original image, the width of the original image is used instead. Used when calculating breakpoints. |

The options `cloudName`, `apiKey`, and `apiSecret` are required if any images will be uploaded to Cloudinary during the build process. If you're solely using images already uploaded to Cloudinary, then these options can be safely omitted.
> Note: Each derived image created for a breakpoint will consume one Cloudinary transformation. Enable the `useCloudinaryBreakpoints` option with care. If the `createDerived` option is enabled, transformations will only be consumed when the images are first created. However, created images will consume Cloudinary storage space. If `overwriteExisting` is enabled, each image that you upload will consume one transformation each time your Gatsby cache gets cleared and the image gets re-uploaded. For this reason, it's recommended that you keep `overWriteExisting` disabled and instead set the `overwriteExisting` parameter of `createRemoteImageNode` on a per-image basis when you know that an image has actually been updated.

@@ -225,2 +232,13 @@

### Fragments
The fragments below can be used when querying your Cloudinary assets:
- `CloudinaryAssetFluid`
- `CloudinaryAssetFluid_noBase64`
- `CloudinaryAssetFluid_tracedSVG`
- `CloudinaryAssetFixed`
- `CloudinaryAssetFixed_noBase64`
- `CloudinaryAssetFixed_tracedSVG`
### Avoiding stretched images using the fluid type

@@ -227,0 +245,0 @@

@@ -15,2 +15,3 @@ const cloudinary = require('cloudinary').v2;

}) => {
verifyRequiredOptions(reporter);
const {

@@ -111,1 +112,13 @@ apiKey,

};
function verifyRequiredOptions(reporter) {
const requiredOptions = ['apiKey', 'apiSecret', 'cloudName'];
const pluginOptions = getPluginOptions();
requiredOptions.forEach(optionKey => {
if (pluginOptions[optionKey] == null) {
reporter.panic(
`[gatsby-transformer-cloudinary] "${optionKey}" is a required plugin option. You can add it to the options object for "gatsby-transformer-cloudinary" in your gatsby-config file.`,
);
}
});
}

@@ -12,2 +12,8 @@ const {

const defaultPluginOptions = {
apiKey: 'apiKey',
apiSecret: 'apiSecret',
cloudName: 'cloudName',
};
describe('uploadImageToCloudinary', () => {

@@ -178,3 +184,6 @@ function getDefaultArgs(args) {

const overwriteExisting = 'overwriteExistingDouble';
getPluginOptions.mockReturnValue({ overwriteExisting });
getPluginOptions.mockReturnValue({
...defaultPluginOptions,
overwriteExisting,
});

@@ -190,2 +199,65 @@ await uploadImageNodeToCloudinary({ node, reporter });

});
it('requires the apiKey option', async () => {
const reporter = {
panic: jest.fn(() => {
throw Error();
}),
};
const node = { relativePath: 'relativePath.jpg' };
getPluginOptions.mockReturnValue({
...defaultPluginOptions,
apiKey: null,
});
try {
await uploadImageNodeToCloudinary({ node, reporter });
} catch {}
expect(reporter.panic).toHaveBeenCalledWith(
'[gatsby-transformer-cloudinary] "apiKey" is a required plugin option. You can add it to the options object for "gatsby-transformer-cloudinary" in your gatsby-config file.',
);
});
it('requires the apiSecret option', async () => {
const reporter = {
panic: jest.fn(() => {
throw Error();
}),
};
const node = { relativePath: 'relativePath.jpg' };
getPluginOptions.mockReturnValue({
...defaultPluginOptions,
apiSecret: null,
});
try {
await uploadImageNodeToCloudinary({ node, reporter });
} catch {}
expect(reporter.panic).toHaveBeenCalledWith(
'[gatsby-transformer-cloudinary] "apiSecret" is a required plugin option. You can add it to the options object for "gatsby-transformer-cloudinary" in your gatsby-config file.',
);
});
it('requires the cloudName option', async () => {
const reporter = {
panic: jest.fn(() => {
throw Error();
}),
};
const node = { relativePath: 'relativePath.jpg' };
getPluginOptions.mockReturnValue({
...defaultPluginOptions,
cloudName: null,
});
try {
await uploadImageNodeToCloudinary({ node, reporter });
} catch {}
expect(reporter.panic).toHaveBeenCalledWith(
'[gatsby-transformer-cloudinary] "cloudName" is a required plugin option. You can add it to the options object for "gatsby-transformer-cloudinary" in your gatsby-config file.',
);
});
});
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc