Skip to content

Commit

Permalink
Support sync APIs
Browse files Browse the repository at this point in the history
  • Loading branch information
ragingwind committed May 27, 2019
1 parent b8bcd65 commit 5b5b69f
Show file tree
Hide file tree
Showing 5 changed files with 2,484 additions and 2,452 deletions.
177 changes: 117 additions & 60 deletions index.js
@@ -1,67 +1,124 @@
const {join, basename, extname} = require('path')
const fs = require('fs-extra')
const jimp = require('jimp')
const findCacheDir = require('find-cache-dir')
const hasha = require('hasha')

const writeIcon = (file, icon, size) => {
return new Promise(resolve => {
if (fs.pathExistsSync(icon)) {
resolve(icon)
return
}

file.clone().resize(size, size).quality(100).write(icon, () => {
resolve(icon)
})
})
}
const { join, basename, extname } = require('path');
const fs = require('fs-extra');
const jimp = require('jimp');
const findCacheDir = require('find-cache-dir');
const hasha = require('hasha');
const sync = require('sync');

const prepareCacheRoot = src => {
return hasha.fromFile(src, {algorithm: 'md5'}).then(hash => {
const cacheRoot = join(findCacheDir({name: 'pwa-manifest-icons', create: true}), hash)
return fs.ensureDir(cacheRoot).then(() => Promise.resolve(cacheRoot))
})
}
const joinCachePath = hash =>
join(findCacheDir({ name: 'pwa-manifest-icons', create: true }), hash);

const cacheIcons = ({src, output, sizes}) => {
return prepareCacheRoot(src).then(cacheRoot => {
return jimp.read(src).then(file => {
return Promise.all(sizes.map(size => writeIcon(file, join(cacheRoot, `icon-${size}x${size}.png`), size)))
})
})
}
const getCachePath = async src => {
return joinCachePath(await hasha.fromFile(src, { algorithm: 'md5' }));
};

const getCachePathSync = src => {
return joinCachePath(hasha.fromFileSync(src, { algorithm: 'md5' }));
};

const cacheIcons = async ({ src, sizes }) => {
const cachepath = await getCachePath(src);
await fs.ensureDir(cachepath);
const file = await jimp.read(src);

return await Promise.all(
sizes.map(async size => {
const icon = join(cachepath, `icon-${size}x${size}.png`);

if (fs.pathExistsSync(icon)) {
return icon;
}

await file
.clone()
.resize(size, size)
.quality(100)
.write(icon);

return icon;
})
);
};

const cacheIconsSync = ({ src, sizes }) => {
const cachepath = getCachePathSync(src);
const icons = [];
fs.ensureDirSync(cachepath);

sync(() => {
const file = jimp.read.sync(src);
sizes.forEach(size => {
const icon = join(cachepath, `icon-${size}x${size}.png`);

const copyIcons = (icons, {output}) => {
return Promise.all(icons.map(icon => fs.copy(icon, join(output, basename(icon)))))
icons.push(icon);

if (fs.pathExistsSync(icon)) {
return icon;
}

file
.clone()
.resize(size, size)
.quality(100)
.write.sync(icon);
});
});

return icons;
};

const copyIcons = (icons, { output }) => {
return Promise.all(
icons.map(icon => {
return fs.copy(icon, join(output, basename(icon)));
})
);
};

const copyIconsSync = (icons, { output }) => {
icons.forEach(icon => {
fs.copySync(icon, join(output, basename(icon)));
});
};

const remapIconPath = (icons, { sizes, publicPath }) => {
return icons.map((icon, i) => {
return {
src: publicPath ? join(publicPath, basename(icon)) : icon,
sizes: `${sizes[i]}x${sizes[i]}`,
type: `image/${extname(icon).slice(1)}`
};
});
};

const mergeOptions = opts => {
if (!opts || !opts.src) {
throw new Error('Source image path, or buffer must be exist');
}

return {
cache: false,
output: './',
publicPath: null,
sizes: [192, 512],
...opts
};
};

async function generateIcons(options) {
const opts = mergeOptions(options);
const icons = await cacheIcons(opts);
await copyIcons(icons, opts);
return remapIconPath(icons, opts);
}

const remapIconPath = (icons, {sizes, publicPath}) => {
return icons.map((icon, i) => {
return {
src: publicPath ? join(publicPath, basename(icon)) : icon,
sizes: `${sizes[i]}x${sizes[i]}`,
type: `image/${extname(icon).slice(1)}`
}
})
function generateIconsSync(options) {
const opts = mergeOptions(options);
const icons = cacheIconsSync(opts);
copyIconsSync(icons, opts);
return remapIconPath(icons, opts);
}

module.exports = opts => {
if (!opts || !opts.src) {
throw new Error('Source image path, or buffer must be exist')
}

opts = {
cache: false,
output: './',
publicPath: null,
sizes: [192, 512],
...opts
}

return cacheIcons(opts).then(icons => {
return copyIcons(icons, opts).then(() => {
return remapIconPath(icons, opts)
})
})
}
module.exports = generateIcons;

module.exports.sync = generateIconsSync;
11 changes: 6 additions & 5 deletions package.json
Expand Up @@ -25,12 +25,13 @@
"test": "jest"
},
"devDependencies": {
"jest": "^22.4.2"
"jest": "^24.8.0"
},
"dependencies": {
"find-cache-dir": "^1.0.0",
"fs-extra": "^5.0.0",
"hasha": "^3.0.0",
"jimp": "^0.2.28"
"find-cache-dir": "^3.0.0",
"fs-extra": "^7.0.1",
"hasha": "^5.0.0",
"jimp": "^0.6.4",
"sync": "^0.2.5"
}
}
34 changes: 21 additions & 13 deletions readme.md
Expand Up @@ -16,19 +16,27 @@ const manifest = {
...defaultManifest
};

const manifest.icons = await manifestIcons({
// path for source image
src: path.resolve(process.cwd(). './assets/icon.png'),
// using cached images
cache: true,
// root path for output icons
output: './static/manifest/icons',
// revamp icon path with publicPath, which will be returned after resize. if null, using
// output path
publicPath: '/static/manifest/icons/',
// sizes for resizing, default is 192, 512
sizes: [192, 512]
})
(() => {
const manifest.icons = await manifestIcons({
// path for source image
src: path.resolve(process.cwd(). './assets/icon.png'),
// using cached images
cache: true,
// root path for output icons
output: './static/manifest/icons',
// revamp icon path with publicPath, which will be returned after resize. if null, using
// output path
publicPath: '/static/manifest/icons/',
// sizes for resizing, default is 192, 512
sizes: [192, 512]
});
})();

// or using sync APIs powered by https://github.com/ybogdanov/node-sync

const manifest.icons = manifestIcons.sync({
...
});
```

# License
Expand Down
98 changes: 65 additions & 33 deletions test/index.test.js
@@ -1,38 +1,70 @@
const {join, resolve} = require('path')
const fs = require('fs-extra')
const fn = require('../')
const { join, resolve } = require('path');
const fs = require('fs-extra');
const fn = require('../');

const srcImage = join(__dirname, 'fixtures/icon-192x192.png')
const srcImage = join(__dirname, 'fixtures/icon-192x192.png');

beforeAll(() => {
fs.removeSync(resolve(__dirname, '.tmp'))
fs.removeSync(resolve(__dirname, '../node_modules/.cache/pwa-manifest-icons'))
fs.ensureDirSync(resolve(__dirname, '.tmp'))
})
fs.removeSync(resolve(__dirname, '.tmp'));
fs.removeSync(
resolve(__dirname, '../node_modules/.cache/pwa-manifest-icons')
);
fs.ensureDirSync(resolve(__dirname, '.tmp'));
});

test('typeof', () => {
expect(typeof fn).toBe('function')
})

test('generate icon', async () => {
const opts = {
src:srcImage,
cache: true,
output: `${__dirname}/.tmp/static/manifest/icons/`,
publicPath: '/static/manifest/icons/',
sizes: [192, 512]
}

const icon = size => join(opts.output, `icon-${size}x${size}.png`)
const exist = () => opts.sizes.every(async size => await fs.pathExists(icon(size)))
const match = (sizes, icons) => sizes.every((size, i) => icons[i].src === `/static/manifest/icons/icon-${size}x${size}.png`)

try {
const icons = await fn(opts)

expect(exist()).toBe(true)
expect(match(opts.sizes, icons)).toBe(true)
} catch (e) {
console.log(e)
}
}, 1000 * 50)
expect(typeof fn).toBe('function');
});

test(
'generate icon',
async () => {
const opts = {
src: srcImage,
cache: true,
output: `${__dirname}/.tmp/static/manifest/icons/`,
publicPath: '/static/manifest/icons/',
sizes: [192, 512]
};

const icon = size => join(opts.output, `icon-${size}x${size}.png`);
const exist = () => opts.sizes.every(size => fs.existsSync(icon(size)));
const match = (sizes, icons) =>
sizes.every(
(size, i) =>
icons[i].src === `/static/manifest/icons/icon-${size}x${size}.png`
);

try {
const icons = await fn(opts);

expect(exist()).toBe(true);
expect(match(opts.sizes, icons)).toBe(true);
} catch (e) {
console.log('Error', e);
}
},
1000 * 50
);

test(
'generate icon in sync',
() => {
const opts = {
src: srcImage,
cache: true,
output: `${__dirname}/.tmp/static/manifest/icons/`,
publicPath: '/static/manifest/icons/',
sizes: [192, 512]
};

const icon = size => join(opts.output, `icon-${size}x${size}.png`);
const exist = () => opts.sizes.every(size => fs.existsSync(icon(size)));

console.log('start1')
fn.sync(opts);

expect(exist()).toBe(true);
},
1000 * 50
);

0 comments on commit 5b5b69f

Please sign in to comment.