mirror of
https://github.com/zhigang1992/react-native.git
synced 2026-02-12 17:30:12 +08:00
Summary: @public 1. Default to first class support of popular image formats 2. Add tests to make sure we support other than png Test Plan: 1. ./runJestTests.sh 2. Add test.png and test.jpg images in the Playground app dir 3. require both images and render then in the playground app 4. they render
162 lines
4.0 KiB
JavaScript
162 lines
4.0 KiB
JavaScript
/**
|
|
* Copyright (c) 2015-present, Facebook, Inc.
|
|
* All rights reserved.
|
|
*
|
|
* This source code is licensed under the BSD-style license found in the
|
|
* LICENSE file in the root directory of this source tree. An additional grant
|
|
* of patent rights can be found in the PATENTS file in the same directory.
|
|
*/
|
|
'use strict';
|
|
|
|
var declareOpts = require('../lib/declareOpts');
|
|
var getAssetDataFromName = require('../lib/getAssetDataFromName');
|
|
var path = require('path');
|
|
var Promise = require('bluebird');
|
|
var fs = require('fs');
|
|
var crypto = require('crypto');
|
|
|
|
var lstat = Promise.promisify(fs.lstat);
|
|
var readDir = Promise.promisify(fs.readdir);
|
|
var readFile = Promise.promisify(fs.readFile);
|
|
|
|
module.exports = AssetServer;
|
|
|
|
var validateOpts = declareOpts({
|
|
projectRoots: {
|
|
type: 'array',
|
|
required: true,
|
|
},
|
|
assetExts: {
|
|
type: 'array',
|
|
required: true,
|
|
},
|
|
});
|
|
|
|
function AssetServer(options) {
|
|
var opts = validateOpts(options);
|
|
this._roots = opts.projectRoots;
|
|
this._assetExts = opts.assetExts;
|
|
}
|
|
|
|
/**
|
|
* Given a request for an image by path. That could contain a resolution
|
|
* postfix, we need to find that image (or the closest one to it's resolution)
|
|
* in one of the project roots:
|
|
*
|
|
* 1. We first parse the directory of the asset
|
|
* 2. We check to find a matching directory in one of the project roots
|
|
* 3. We then build a map of all assets and their scales in this directory
|
|
* 4. Then pick the closest resolution (rounding up) to the requested one
|
|
*/
|
|
|
|
AssetServer.prototype._getAssetRecord = function(assetPath) {
|
|
var filename = path.basename(assetPath);
|
|
|
|
return findRoot(
|
|
this._roots,
|
|
path.dirname(assetPath)
|
|
).then(function(dir) {
|
|
return [
|
|
dir,
|
|
readDir(dir),
|
|
];
|
|
}).spread(function(dir, files) {
|
|
var assetData = getAssetDataFromName(filename);
|
|
var map = buildAssetMap(dir, files);
|
|
var record = map[assetData.assetName];
|
|
|
|
if (!record) {
|
|
throw new Error('Asset not found');
|
|
}
|
|
|
|
return record;
|
|
});
|
|
};
|
|
|
|
AssetServer.prototype.get = function(assetPath) {
|
|
var assetData = getAssetDataFromName(assetPath);
|
|
return this._getAssetRecord(assetPath).then(function(record) {
|
|
for (var i = 0; i < record.scales.length; i++) {
|
|
if (record.scales[i] >= assetData.resolution) {
|
|
return readFile(record.files[i]);
|
|
}
|
|
}
|
|
|
|
return readFile(record.files[record.files.length - 1]);
|
|
});
|
|
};
|
|
|
|
AssetServer.prototype.getAssetData = function(assetPath) {
|
|
var nameData = getAssetDataFromName(assetPath);
|
|
var data = {
|
|
name: nameData.name,
|
|
type: nameData.type,
|
|
};
|
|
|
|
return this._getAssetRecord(assetPath).then(function(record) {
|
|
data.scales = record.scales;
|
|
|
|
return Promise.all(
|
|
record.files.map(function(file) {
|
|
return lstat(file);
|
|
})
|
|
);
|
|
}).then(function(stats) {
|
|
var hash = crypto.createHash('md5');
|
|
|
|
stats.forEach(function(stat) {
|
|
hash.update(stat.mtime.getTime().toString());
|
|
});
|
|
|
|
data.hash = hash.digest('hex');
|
|
return data;
|
|
});
|
|
};
|
|
|
|
function findRoot(roots, dir) {
|
|
return Promise.some(
|
|
roots.map(function(root) {
|
|
var absPath = path.join(root, dir);
|
|
return lstat(absPath).then(function(stat) {
|
|
if (!stat.isDirectory()) {
|
|
throw new Error('Looking for dirs');
|
|
}
|
|
stat._path = absPath;
|
|
return stat;
|
|
});
|
|
}),
|
|
1
|
|
).spread(
|
|
function(stat) {
|
|
return stat._path;
|
|
}
|
|
);
|
|
}
|
|
|
|
function buildAssetMap(dir, files) {
|
|
var assets = files.map(getAssetDataFromName);
|
|
var map = Object.create(null);
|
|
assets.forEach(function(asset, i) {
|
|
var file = files[i];
|
|
var record = map[asset.assetName];
|
|
if (!record) {
|
|
record = map[asset.assetName] = {
|
|
scales: [],
|
|
files: [],
|
|
};
|
|
}
|
|
|
|
var insertIndex;
|
|
var length = record.scales.length;
|
|
for (insertIndex = 0; insertIndex < length; insertIndex++) {
|
|
if (asset.resolution < record.scales[insertIndex]) {
|
|
break;
|
|
}
|
|
}
|
|
record.scales.splice(insertIndex, 0, asset.resolution);
|
|
record.files.splice(insertIndex, 0, path.join(dir, file));
|
|
});
|
|
|
|
return map;
|
|
}
|