Skip to content

Instantly share code, notes, and snippets.

@satya164 satya164/assetLoader.js Secret
Created Feb 16, 2018

Embed
What would you like to do?
/* @flow */
import utils from 'loader-utils';
import size from 'image-size';
import path from 'path';
import hasha from 'hasha';
import AssetResolver from './AssetResolver';
import type { Loader } from 'webpack';
type Config = {
platform: string,
root: string,
outputPath?: string | ((path: string) => string),
publicPath?: string | ((path: string) => string),
};
async function assetLoader() {
(this: Loader);
this.cacheable();
const callback = this.async();
const query = utils.getOptions(this);
const options = this.options[query.config];
const config: Config = Object.assign({}, options, query);
let info: ?{ width: number, height: number, type: string };
try {
info = size(this.resourcePath);
} catch (e) {
// Asset is not an image
}
const filepath = this.resourcePath;
const dirname = path.dirname(filepath);
const url = path.relative(config.root, dirname);
const type = path.extname(filepath).replace(/^\./, '');
const suffix = `(@\\d+(\\.\\d+)?x)?(\\.(${config.platform}|native))?\\.${type}$`;
const filename = path.basename(filepath).replace(new RegExp(suffix), '');
const longname = `${`${url.replace(/\//g, '_')}_${filename}`
.toLowerCase()
.replace(/[^a-z0-9_]/g, '')}`;
const result = await new Promise((resolve, reject) =>
this.fs.readdir(dirname, (err, res) => {
if (err) {
reject(err);
} else {
resolve(res);
}
})
);
const map = AssetResolver.collect(result, {
name: filename,
type,
platform: config.platform,
});
const scales = Object.keys(map)
.map(s => Number(s.replace(/[^\d.]/g, '')))
.sort();
const pairs = await Promise.all(
Object.keys(map).map(scale => {
this.addDependency(path.join(dirname, map[scale].name));
return new Promise((resolve, reject) =>
this.fs.readFile(path.join(dirname, map[scale].name), (err, res) => {
if (err) {
reject(err);
} else {
const name = `${longname}${scale === '@1x' ? '' : scale}.${type}`;
const dest = path.join('assets', name);
resolve({
destination: dest,
content: res,
});
}
})
);
})
);
pairs.forEach(item => {
let dest = item.destination;
if (config.outputPath) {
// support functions as outputPath to generate them dynamically
dest =
typeof config.outputPath === 'function'
? config.outputPath(dest)
: path.join(config.outputPath, dest);
}
this.emitFile(dest, item.content);
});
const buffers = pairs.map(item => item.content);
const hashes = buffers.map(b => hasha(b, { algorithm: 'md5' }));
let publicPath = `__webpack_public_path__ + ${JSON.stringify(path.join('/', 'assets'))}`;
if (config.publicPath) {
// support functions as publicPath to generate them dynamically
publicPath = JSON.stringify(
typeof config.publicPath === 'function'
? config.publicPath(url)
: path.join(config.publicPath, url)
);
}
callback(
null,
`
var AssetRegistry = require('AssetRegistry');
module.exports = AssetRegistry.registerAsset({
httpServerLocation: ${publicPath},
name: ${JSON.stringify(longname)},
width: ${info ? info.width : JSON.stringify(null)},
height: ${info ? info.height : JSON.stringify(null)},
type: ${JSON.stringify(type)},
hash: ${JSON.stringify(hashes.join())},
fileHashes: ${JSON.stringify(hashes)},
scales: ${JSON.stringify(scales)},
});
`
);
}
module.exports = assetLoader;
module.exports.raw = true;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.