Skip to content

Commit

Permalink
Removed sharp, Added rev-hash checking, Added tests
Browse files Browse the repository at this point in the history
  • Loading branch information
niftylettuce committed Oct 18, 2017
1 parent 2439c74 commit 02ce647
Show file tree
Hide file tree
Showing 6 changed files with 196 additions and 172 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@
node_modules
coverage
.nyc_output
.env
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
* :cloud: Converts `<img>` tags with Base64-Encoded Data URI's to absolute paths stored on [S3][] (or optionally [CloudFront][]).
* :muscle: Supports all image types (`png|jpg|jpeg|gif|svg`) and converts them to optimized `png` using [sharp][]. Unfortunately Gmail does not have great SVG support, and not all clients can render SVG – so we use PNG's for now.
* :lock: Uses `uuid.v4()` to prevent asset naming collisions in your S3 bucket (and to avoid Gmail image cache issues) via [uuid][].
* :lock: Uses [rev-hash][] to prevent asset naming collisions in your S3 bucket (and to avoid Gmail image cache issues).
* :zap: Encodes your images using gzip so your downloads are [compressed and faster][s3-article] (uses `zlib.gzip`) via [zlib][].
* :tada: Perfect alternative to [cid][cid-url] embedded images.
* :crystal_ball: Built for [Lad][] and [font-awesome-assets][].
Expand Down Expand Up @@ -143,7 +143,7 @@ Here's a snippet from the navbar shown in the screenshot above. We utilize [font

[cloudfront]: https://aws.amazon.com/cloudfront/pricing/

[uuid]: https://www.npmjs.com/package/uuid
[rev-hash]: https://github.com/sindresorhus/rev-hash

[zlib]: https://nodejs.org/api/zlib.html

Expand Down
17 changes: 7 additions & 10 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
const { promisify } = require('util');
const zlib = require('zlib');
const sharp = require('sharp');
const uuid = require('uuid');
const _ = require('lodash');
const ms = require('ms');
const AWS = require('aws-sdk');
const revHash = require('rev-hash');

const regexp = new RegExp(
// eslint-disable-next-line max-len
Expand Down Expand Up @@ -68,19 +67,17 @@ const base64ToS3 = opts => {

function transformImage(original, start, mimeType, base64, end) {
return new Promise(async (resolve, reject) => {
// create a buffer of the base64 image
// and convert it to a png
const buffer = await sharp(Buffer.from(base64, 'base64'))
.png()
.toBuffer();

try {
// create a buffer of the base64 image
// and convert it to a png
const buffer = Buffer.from(base64, 'base64');

// apply transformation and gzip file
const Body = await promisify(zlib.gzip).bind(zlib)(buffer);

// generate random filename
// get the file extension based on mimeType
const Key = `${opts.dir}${uuid.v4()}.png`;
const Key = `${opts.dir}${revHash(base64)}.png`;

const obj = {
Key,
Expand All @@ -95,7 +92,7 @@ const base64ToS3 = opts => {
// <https://github.com/aws/aws-sdk-js/pull/1079>
// await s3obj.upload({ Body }).promise();
//
// so instead we use es6-promisify to convert it to a promise
// so instead we use promisify to convert it to a promise
const data = await promisify(s3.upload).bind(s3)(obj);

const replacement = _.isString(opts.cloudFrontDomainName)
Expand Down
6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@
"dependencies": {
"aws-sdk": "^2.122.0",
"lodash": "^4.17.4",
"sharp": "^0.18.4",
"uuid": "^3.1.0"
"rev-hash": "^2.0.0"
},
"ava": {
"failFast": true,
Expand All @@ -24,8 +23,10 @@
"devDependencies": {
"auto-bind": "^1.1.0",
"ava": "^0.22.0",
"cheerio": "^1.0.0-rc.2",
"codecov": "^2.3.0",
"cross-env": "^5.0.5",
"dotenv": "^4.0.0",
"eslint": "^4.5.0",
"eslint-config-prettier": "^2.3.0",
"eslint-plugin-prettier": "^2.2.0",
Expand All @@ -37,6 +38,7 @@
"prettier": "^1.6.1",
"remark-cli": "^4.0.0",
"remark-preset-github": "^0.0.6",
"validator": "^9.0.0",
"xo": "^0.19.0"
},
"engines": {
Expand Down
70 changes: 69 additions & 1 deletion test/test.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,75 @@
const test = require('ava');

const nodemailer = require('nodemailer');
const ms = require('ms');
const dotenv = require('dotenv');
const cheerio = require('cheerio');
const validator = require('validator');
const base64ToS3 = require('../');

const html =
// eslint-disable-next-line max-len
'<img width="16" height="16" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAACXBIWXMAAAsTAAALEwEAmpwYAAABYklEQVRoge2ZsUoDQRCGv4uigsRgEQOBwya1WlsIdnmYPIOFvW1eRPuAjyDkBS6VsQlaxeYssgfnarzc3OpkZT5YuOV2Z/6fnTtub0HONTAF8oZt6mL9KcfAoqHwclu4mLVpCQ1cAB3h3O/oAOeSibvChPte/xZ4qRmjC9yU+gdCLSKGfC6BgSDGwIsxlAiRltDW4JfQHpACScW8vtc/FeT25/SpXskcmAHv/o0UeACWhHuz/FZbOq1pIb4HzLdAWN02B3o7wBi49JckAg6BbgJklJYjMrKE1XJES/SvUTOgjRnQxgxoYwa0SYCRtggjdkJ9nxeMfhhTLtcgeaN/iKM3EHI/UPwIOAOu1ox5BJ7cdZC8IQ0cAW8bjm0DryGShiyhO1bCqmi7sUGwLaU2ZkAbM6DNvzAw0xbRgKwFTLRVNGAC8f5efwZOCiexHXDcO81fjpI2PWLSImfNEZNhGIYOH2xyJC1ddamJAAAAAElFTkSuQmCC" />';
const transport = nodemailer.createTransport({ jsonTransport: true });

dotenv.config();

transport.use(
'compile',
base64ToS3({
maxAge: ms('1d'),
dir: 'nodemailer/',
cloudFrontDomainName: process.env.AWS_CLOUDFRONT_DOMAIN,
aws: {
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
params: {
Bucket: process.env.AWS_BUCKET
}
}
})
);

test('returns a function', t => {
t.true(typeof base64ToS3 === 'function');
});

test('converts base64 encoded image', async t => {
const res = await transport.sendMail({
html,
subject: 'subject',
to: '[email protected]',
from: '[email protected]'
});

const $ = cheerio.load(JSON.parse(res.message).html);
t.true(validator.isURL($('img').attr('src')));
});

test('converts the same image and does not create new path', async t => {
let res = await transport.sendMail({
html,
subject: 'subject',
to: '[email protected]',
from: '[email protected]'
});

let $ = cheerio.load(JSON.parse(res.message).html);

const url = $('img').attr('src');

t.true(validator.isURL(url));

res = await transport.sendMail({
html,
subject: 'subject',
to: '[email protected]',
from: '[email protected]'
});

$ = cheerio.load(JSON.parse(res.message).html);

const clone = $('img').attr('src');
t.true(validator.isURL(clone));

t.is(url, clone);
});
Loading

0 comments on commit 02ce647

Please sign in to comment.