From 8b28294bbdfe60cc03b637f4de87f6c75893d5e5 Mon Sep 17 00:00:00 2001 From: Rafael Oleza Date: Mon, 4 Dec 2017 16:36:35 -0800 Subject: [PATCH] Do not cache hash generation in the AssetServer Reviewed By: davidaurelio Differential Revision: D6436249 fbshipit-source-id: eebbd92ebfdf1c8f12dbbcf3f5a66166fb1bc828 --- .../AssetServer/__tests__/AssetServer-test.js | 2 +- packages/metro/src/AssetServer/index.js | 49 ++++------------ packages/metro/src/AssetServer/util.js | 57 ++++++++++++++----- packages/metro/src/Server/index.js | 2 - 4 files changed, 54 insertions(+), 56 deletions(-) diff --git a/packages/metro/src/AssetServer/__tests__/AssetServer-test.js b/packages/metro/src/AssetServer/__tests__/AssetServer-test.js index 157b6b44..f7d013b9 100644 --- a/packages/metro/src/AssetServer/__tests__/AssetServer-test.js +++ b/packages/metro/src/AssetServer/__tests__/AssetServer-test.js @@ -288,7 +288,7 @@ describe('AssetServer', () => { it('changes the hash when the passed-in file watcher emits an `all` event', () => { return server.getAssetData('/root/imgs/b.jpg').then(initialData => { mockFS.root.imgs['b@4x.jpg'] = 'updated data'; - server.onFileChange('all', '/root/imgs/b@4x.jpg'); + return server .getAssetData('/root/imgs/b.jpg') .then(data => expect(data.hash).not.toEqual(initialData.hash)); diff --git a/packages/metro/src/AssetServer/index.js b/packages/metro/src/AssetServer/index.js index 5cf28043..5f1e9c17 100644 --- a/packages/metro/src/AssetServer/index.js +++ b/packages/metro/src/AssetServer/index.js @@ -14,7 +14,6 @@ const AssetPaths = require('../node-haste/lib/AssetPaths'); -const crypto = require('crypto'); const denodeify = require('denodeify'); const fs = require('fs'); const imageSize = require('image-size'); @@ -22,15 +21,13 @@ const path = require('path'); const toLocalPath = require('../node-haste/lib/toLocalPath'); const {isAssetTypeAnImage} = require('../Bundler/util'); -const {findRoot, getAbsoluteAssetRecord, hashFiles} = require('./util'); +const { + findRoot, + getAbsoluteAssetInfo, + getAbsoluteAssetRecord, +} = require('./util'); -type AssetInfo = {| - files: Array, - hash: string, - name: string, - scales: Array, - type: string, -|}; +import type {AssetInfo} from './util'; export type AssetData = {| __packager_asset: boolean, @@ -49,13 +46,9 @@ const readFile = denodeify(fs.readFile); class AssetServer { _roots: $ReadOnlyArray; - _hashes: Map; - _files: Map; constructor(options: {|+projectRoots: $ReadOnlyArray|}) { this._roots = options.projectRoots; - this._hashes = new Map(); - this._files = new Map(); } get(assetPath: string, platform: ?string = null): Promise { @@ -78,29 +71,11 @@ class AssetServer { assetPath: string, platform: ?string = null, ): Promise { - const nameData = AssetPaths.parse( - assetPath, - new Set(platform != null ? [platform] : []), - ); - const {name, type} = nameData; + const dir = await findRoot(this._roots, path.dirname(assetPath), assetPath); - const {scales, files} = await this._getAssetRecord(assetPath, platform); + const assetAbsolutePath = path.join(dir, path.basename(assetPath)); - const hash = this._hashes.get(assetPath); - 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}; + return await getAbsoluteAssetInfo(assetAbsolutePath, platform); } async getAssetData( @@ -116,7 +91,7 @@ class AssetServer { } 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 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 * postfix, we need to find that image (or the closest one to it's resolution) diff --git a/packages/metro/src/AssetServer/util.js b/packages/metro/src/AssetServer/util.js index 7590332f..bc998dd7 100644 --- a/packages/metro/src/AssetServer/util.js +++ b/packages/metro/src/AssetServer/util.js @@ -14,6 +14,7 @@ const AssetPaths = require('../node-haste/lib/AssetPaths'); +const crypto = require('crypto'); const denodeify = require('denodeify'); const fs = require('fs'); const path = require('path'); @@ -23,6 +24,27 @@ const readDir = denodeify(fs.readdir); import type {AssetPath} from '../node-haste/lib/AssetPaths'; +export type AssetInfo = {| + files: Array, + hash: string, + name: string, + scales: Array, + 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( dir: string, files: $ReadOnlyArray, @@ -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( assetPath: string, platform: ?string = null, @@ -171,8 +180,28 @@ async function findRoot( ); } +async function getAbsoluteAssetInfo( + assetPath: string, + platform: ?string = null, +): Promise { + 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 = { findRoot, + getAbsoluteAssetInfo, getAbsoluteAssetRecord, - hashFiles: denodeify(hashFiles), }; diff --git a/packages/metro/src/Server/index.js b/packages/metro/src/Server/index.js index 981c3f84..66045b33 100644 --- a/packages/metro/src/Server/index.js +++ b/packages/metro/src/Server/index.js @@ -276,8 +276,6 @@ class Server { } onFileChange(type: string, filePath: string) { - this._assetServer.onFileChange(type, filePath); - Promise.all( this._fileChangeListeners.map(listener => listener(filePath)), ).then(