mirror of https://github.com/status-im/metro.git
Do not cache hash generation in the AssetServer
Reviewed By: davidaurelio Differential Revision: D6436249 fbshipit-source-id: eebbd92ebfdf1c8f12dbbcf3f5a66166fb1bc828
This commit is contained in:
parent
5fb41e6fc8
commit
8b28294bbd
|
@ -288,7 +288,7 @@ describe('AssetServer', () => {
|
||||||
it('changes the hash when the passed-in file watcher emits an `all` event', () => {
|
it('changes the hash when the passed-in file watcher emits an `all` event', () => {
|
||||||
return server.getAssetData('/root/imgs/b.jpg').then(initialData => {
|
return server.getAssetData('/root/imgs/b.jpg').then(initialData => {
|
||||||
mockFS.root.imgs['b@4x.jpg'] = 'updated data';
|
mockFS.root.imgs['b@4x.jpg'] = 'updated data';
|
||||||
server.onFileChange('all', '/root/imgs/b@4x.jpg');
|
|
||||||
return server
|
return server
|
||||||
.getAssetData('/root/imgs/b.jpg')
|
.getAssetData('/root/imgs/b.jpg')
|
||||||
.then(data => expect(data.hash).not.toEqual(initialData.hash));
|
.then(data => expect(data.hash).not.toEqual(initialData.hash));
|
||||||
|
|
|
@ -14,7 +14,6 @@
|
||||||
|
|
||||||
const AssetPaths = require('../node-haste/lib/AssetPaths');
|
const AssetPaths = require('../node-haste/lib/AssetPaths');
|
||||||
|
|
||||||
const crypto = require('crypto');
|
|
||||||
const denodeify = require('denodeify');
|
const denodeify = require('denodeify');
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const imageSize = require('image-size');
|
const imageSize = require('image-size');
|
||||||
|
@ -22,15 +21,13 @@ const path = require('path');
|
||||||
const toLocalPath = require('../node-haste/lib/toLocalPath');
|
const toLocalPath = require('../node-haste/lib/toLocalPath');
|
||||||
|
|
||||||
const {isAssetTypeAnImage} = require('../Bundler/util');
|
const {isAssetTypeAnImage} = require('../Bundler/util');
|
||||||
const {findRoot, getAbsoluteAssetRecord, hashFiles} = require('./util');
|
const {
|
||||||
|
findRoot,
|
||||||
|
getAbsoluteAssetInfo,
|
||||||
|
getAbsoluteAssetRecord,
|
||||||
|
} = require('./util');
|
||||||
|
|
||||||
type AssetInfo = {|
|
import type {AssetInfo} from './util';
|
||||||
files: Array<string>,
|
|
||||||
hash: string,
|
|
||||||
name: string,
|
|
||||||
scales: Array<number>,
|
|
||||||
type: string,
|
|
||||||
|};
|
|
||||||
|
|
||||||
export type AssetData = {|
|
export type AssetData = {|
|
||||||
__packager_asset: boolean,
|
__packager_asset: boolean,
|
||||||
|
@ -49,13 +46,9 @@ const readFile = denodeify(fs.readFile);
|
||||||
|
|
||||||
class AssetServer {
|
class AssetServer {
|
||||||
_roots: $ReadOnlyArray<string>;
|
_roots: $ReadOnlyArray<string>;
|
||||||
_hashes: Map<?string, string>;
|
|
||||||
_files: Map<string, string>;
|
|
||||||
|
|
||||||
constructor(options: {|+projectRoots: $ReadOnlyArray<string>|}) {
|
constructor(options: {|+projectRoots: $ReadOnlyArray<string>|}) {
|
||||||
this._roots = options.projectRoots;
|
this._roots = options.projectRoots;
|
||||||
this._hashes = new Map();
|
|
||||||
this._files = new Map();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get(assetPath: string, platform: ?string = null): Promise<Buffer> {
|
get(assetPath: string, platform: ?string = null): Promise<Buffer> {
|
||||||
|
@ -78,29 +71,11 @@ class AssetServer {
|
||||||
assetPath: string,
|
assetPath: string,
|
||||||
platform: ?string = null,
|
platform: ?string = null,
|
||||||
): Promise<AssetInfo> {
|
): Promise<AssetInfo> {
|
||||||
const nameData = AssetPaths.parse(
|
const dir = await findRoot(this._roots, path.dirname(assetPath), assetPath);
|
||||||
assetPath,
|
|
||||||
new Set(platform != null ? [platform] : []),
|
|
||||||
);
|
|
||||||
const {name, type} = nameData;
|
|
||||||
|
|
||||||
const {scales, files} = await this._getAssetRecord(assetPath, platform);
|
const assetAbsolutePath = path.join(dir, path.basename(assetPath));
|
||||||
|
|
||||||
const hash = this._hashes.get(assetPath);
|
return await getAbsoluteAssetInfo(assetAbsolutePath, platform);
|
||||||
if (hash != null) {
|
|
||||||
return {files, hash, name, scales, type};
|
|
||||||
}
|
|
||||||
|
|
||||||
const hasher = crypto.createHash('md5');
|
|
||||||
|
|
||||||
if (files.length > 0) {
|
|
||||||
await hashFiles(files.slice(), hasher);
|
|
||||||
}
|
|
||||||
|
|
||||||
const freshHash = hasher.digest('hex');
|
|
||||||
this._hashes.set(assetPath, freshHash);
|
|
||||||
files.forEach(f => this._files.set(f, assetPath));
|
|
||||||
return {files, hash: freshHash, name, scales, type};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async getAssetData(
|
async getAssetData(
|
||||||
|
@ -116,7 +91,7 @@ class AssetServer {
|
||||||
}
|
}
|
||||||
|
|
||||||
const isImage = isAssetTypeAnImage(path.extname(assetPath).slice(1));
|
const isImage = isAssetTypeAnImage(path.extname(assetPath).slice(1));
|
||||||
const assetData = await this._getAssetInfo(localPath, platform);
|
const assetData = await getAbsoluteAssetInfo(assetPath, platform);
|
||||||
const dimensions = isImage ? imageSize(assetData.files[0]) : null;
|
const dimensions = isImage ? imageSize(assetData.files[0]) : null;
|
||||||
const scale = assetData.scales[0];
|
const scale = assetData.scales[0];
|
||||||
|
|
||||||
|
@ -134,10 +109,6 @@ class AssetServer {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
onFileChange(type: string, filePath: string) {
|
|
||||||
this._hashes.delete(this._files.get(filePath));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given a request for an image by path. That could contain a resolution
|
* 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)
|
* postfix, we need to find that image (or the closest one to it's resolution)
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
|
|
||||||
const AssetPaths = require('../node-haste/lib/AssetPaths');
|
const AssetPaths = require('../node-haste/lib/AssetPaths');
|
||||||
|
|
||||||
|
const crypto = require('crypto');
|
||||||
const denodeify = require('denodeify');
|
const denodeify = require('denodeify');
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
@ -23,6 +24,27 @@ const readDir = denodeify(fs.readdir);
|
||||||
|
|
||||||
import type {AssetPath} from '../node-haste/lib/AssetPaths';
|
import type {AssetPath} from '../node-haste/lib/AssetPaths';
|
||||||
|
|
||||||
|
export type AssetInfo = {|
|
||||||
|
files: Array<string>,
|
||||||
|
hash: string,
|
||||||
|
name: string,
|
||||||
|
scales: Array<number>,
|
||||||
|
type: string,
|
||||||
|
|};
|
||||||
|
|
||||||
|
const hashFiles = denodeify(function hashFilesCb(files, hash, callback) {
|
||||||
|
if (!files.length) {
|
||||||
|
callback(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fs
|
||||||
|
.createReadStream(files.shift())
|
||||||
|
.on('data', data => hash.update(data))
|
||||||
|
.once('end', () => hashFilesCb(files, hash, callback))
|
||||||
|
.once('error', error => callback(error));
|
||||||
|
});
|
||||||
|
|
||||||
function buildAssetMap(
|
function buildAssetMap(
|
||||||
dir: string,
|
dir: string,
|
||||||
files: $ReadOnlyArray<string>,
|
files: $ReadOnlyArray<string>,
|
||||||
|
@ -82,19 +104,6 @@ function getAssetKey(assetName, platform) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function hashFiles(files, hash, callback) {
|
|
||||||
if (!files.length) {
|
|
||||||
callback(null);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
fs
|
|
||||||
.createReadStream(files.shift())
|
|
||||||
.on('data', data => hash.update(data))
|
|
||||||
.once('end', () => hashFiles(files, hash, callback))
|
|
||||||
.once('error', error => callback(error));
|
|
||||||
}
|
|
||||||
|
|
||||||
async function getAbsoluteAssetRecord(
|
async function getAbsoluteAssetRecord(
|
||||||
assetPath: string,
|
assetPath: string,
|
||||||
platform: ?string = null,
|
platform: ?string = null,
|
||||||
|
@ -171,8 +180,28 @@ async function findRoot(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function getAbsoluteAssetInfo(
|
||||||
|
assetPath: string,
|
||||||
|
platform: ?string = null,
|
||||||
|
): Promise<AssetInfo> {
|
||||||
|
const nameData = AssetPaths.parse(
|
||||||
|
assetPath,
|
||||||
|
new Set(platform != null ? [platform] : []),
|
||||||
|
);
|
||||||
|
const {name, type} = nameData;
|
||||||
|
|
||||||
|
const {scales, files} = await getAbsoluteAssetRecord(assetPath, platform);
|
||||||
|
const hasher = crypto.createHash('md5');
|
||||||
|
|
||||||
|
if (files.length > 0) {
|
||||||
|
await hashFiles(files.slice(), hasher);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {files, hash: hasher.digest('hex'), name, scales, type};
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
findRoot,
|
findRoot,
|
||||||
|
getAbsoluteAssetInfo,
|
||||||
getAbsoluteAssetRecord,
|
getAbsoluteAssetRecord,
|
||||||
hashFiles: denodeify(hashFiles),
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -276,8 +276,6 @@ class Server {
|
||||||
}
|
}
|
||||||
|
|
||||||
onFileChange(type: string, filePath: string) {
|
onFileChange(type: string, filePath: string) {
|
||||||
this._assetServer.onFileChange(type, filePath);
|
|
||||||
|
|
||||||
Promise.all(
|
Promise.all(
|
||||||
this._fileChangeListeners.map(listener => listener(filePath)),
|
this._fileChangeListeners.map(listener => listener(filePath)),
|
||||||
).then(
|
).then(
|
||||||
|
|
Loading…
Reference in New Issue