From 3e9063fba6e954ca892fe340ddb8761d01f92c13 Mon Sep 17 00:00:00 2001 From: Jean Lauliac Date: Fri, 21 Apr 2017 03:56:49 -0700 Subject: [PATCH] packager: AssetServer: @flow Reviewed By: davidaurelio Differential Revision: D4921672 fbshipit-source-id: 6405275bbd04550d7dd87cd5b8ef35a6cf5904f2 --- .../metro-bundler/src/AssetServer/index.js | 104 ++++++++++-------- packages/metro-bundler/src/Bundler/index.js | 26 ++--- packages/metro-bundler/src/Server/index.js | 2 +- .../node-haste/lib/getAssetDataFromName.js | 6 +- 4 files changed, 76 insertions(+), 62 deletions(-) diff --git a/packages/metro-bundler/src/AssetServer/index.js b/packages/metro-bundler/src/AssetServer/index.js index 1688a599..c18caa3a 100644 --- a/packages/metro-bundler/src/AssetServer/index.js +++ b/packages/metro-bundler/src/AssetServer/index.js @@ -5,16 +5,20 @@ * 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. + * + * @flow */ + 'use strict'; const crypto = require('crypto'); -const declareOpts = require('../lib/declareOpts'); const denodeify = require('denodeify'); const fs = require('fs'); const getAssetDataFromName = require('../node-haste').getAssetDataFromName; const path = require('path'); +import type {AssetData} from '../node-haste/lib/getAssetDataFromName'; + const createTimeoutPromise = timeout => new Promise((resolve, reject) => { setTimeout(reject, timeout, 'fs operation timeout'); }); @@ -33,27 +37,24 @@ const stat = timeoutableDenodeify(fs.stat, FS_OP_TIMEOUT); const readDir = timeoutableDenodeify(fs.readdir, FS_OP_TIMEOUT); const readFile = timeoutableDenodeify(fs.readFile, FS_OP_TIMEOUT); -const validateOpts = declareOpts({ - projectRoots: { - type: 'array', - required: true, - }, - assetExts: { - type: 'array', - required: true, - }, -}); - class AssetServer { - constructor(options) { - const opts = validateOpts(options); - this._roots = opts.projectRoots; - this._assetExts = opts.assetExts; + + _roots: $ReadOnlyArray; + _assetExts: $ReadOnlyArray; + _hashes: Map; + _files: Map; + + constructor(options: {| + +assetExts: $ReadOnlyArray, + +projectRoots: $ReadOnlyArray, + |}) { + this._roots = options.projectRoots; + this._assetExts = options.assetExts; this._hashes = new Map(); this._files = new Map(); } - get(assetPath, platform = null) { + get(assetPath: string, platform: ?string = null): Promise { const assetData = getAssetDataFromName(assetPath, new Set([platform])); return this._getAssetRecord(assetPath, platform).then(record => { for (let i = 0; i < record.scales.length; i++) { @@ -66,39 +67,41 @@ class AssetServer { }); } - getAssetData(assetPath, platform = null) { + getAssetData(assetPath: string, platform: ?string = null): Promise<{| + files: Array, + hash: string, + name: string, + scales: Array, + type: string, + |}> { const nameData = getAssetDataFromName(assetPath, new Set([platform])); - const data = { - name: nameData.name, - type: nameData.type, - }; + const {name, type} = nameData; return this._getAssetRecord(assetPath, platform).then(record => { - data.scales = record.scales; - data.files = record.files; + const {scales, files} = record; - if (this._hashes.has(assetPath)) { - data.hash = this._hashes.get(assetPath); - return data; + const hash = this._hashes.get(assetPath); + if (hash != null) { + return {files, hash, name, scales, type}; } return new Promise((resolve, reject) => { - const hash = crypto.createHash('md5'); - hashFiles(data.files.slice(), hash, error => { + const hasher = crypto.createHash('md5'); + hashFiles(files.slice(), hasher, error => { if (error) { reject(error); } else { - data.hash = hash.digest('hex'); - this._hashes.set(assetPath, data.hash); - data.files.forEach(f => this._files.set(f, assetPath)); - resolve(data); + const freshHash = hasher.digest('hex'); + this._hashes.set(assetPath, freshHash); + files.forEach(f => this._files.set(f, assetPath)); + resolve({files, hash: freshHash, name, scales, type}); } }); }); }); } - onFileChange(type, filePath) { + onFileChange(type: string, filePath: string) { this._hashes.delete(this._files.get(filePath)); } @@ -113,7 +116,10 @@ class AssetServer { * 4. Then try to pick platform-specific asset records * 5. Then pick the closest resolution (rounding up) to the requested one */ - _getAssetRecord(assetPath, platform = null) { + _getAssetRecord(assetPath: string, platform: ?string = null): Promise<{| + files: Array, + scales: Array, + |}> { const filename = path.basename(assetPath); return ( @@ -135,14 +141,15 @@ class AssetServer { let record; if (platform != null) { - record = map[getAssetKey(assetData.assetName, platform)] || - map[assetData.assetName]; + record = map.get(getAssetKey(assetData.assetName, platform)) || + map.get(assetData.assetName); } else { - record = map[assetData.assetName]; + record = map.get(assetData.assetName); } if (!record) { throw new Error( + /* $FlowFixMe: platform can be null */ `Asset not found: ${assetPath} for platform: ${platform}` ); } @@ -152,7 +159,7 @@ class AssetServer { ); } - _findRoot(roots, dir, debugInfoFile) { + _findRoot(roots: $ReadOnlyArray, dir: string, debugInfoFile: string): Promise { return Promise.all( roots.map(root => { const absRoot = path.resolve(root); @@ -185,18 +192,23 @@ class AssetServer { }); } - _buildAssetMap(dir, files, platform) { - const assets = files.map(this._getAssetDataFromName.bind(this, new Set([platform]))); - const map = Object.create(null); + _buildAssetMap(dir: string, files: $ReadOnlyArray, platform: ?string): Map, + scales: Array, + |}> { + const platforms = new Set(platform != null ? [platform] : []); + const assets = files.map(this._getAssetDataFromName.bind(this, platforms)); + const map = new Map(); assets.forEach(function(asset, i) { const file = files[i]; const assetKey = getAssetKey(asset.assetName, asset.platform); - let record = map[assetKey]; + let record = map.get(assetKey); if (!record) { - record = map[assetKey] = { + record = { scales: [], files: [], }; + map.set(assetKey, record); } let insertIndex; @@ -214,8 +226,8 @@ class AssetServer { return map; } - _getAssetDataFromName(platform, file) { - return getAssetDataFromName(file, platform); + _getAssetDataFromName(platforms: Set, file: string): AssetData { + return getAssetDataFromName(file, platforms); } } diff --git a/packages/metro-bundler/src/Bundler/index.js b/packages/metro-bundler/src/Bundler/index.js index eb0252eb..98a42654 100644 --- a/packages/metro-bundler/src/Bundler/index.js +++ b/packages/metro-bundler/src/Bundler/index.js @@ -59,18 +59,18 @@ export type GetTransformOptions = ( getDependencies: string => Promise>, ) => Promise; -type Asset = { - __packager_asset: boolean, - fileSystemLocation: string, - httpServerLocation: string, - width: ?number, - height: ?number, - scales: number, - files: Array, - hash: string, - name: string, - type: string, -}; +type Asset = {| + +__packager_asset: boolean, + +fileSystemLocation: string, + +httpServerLocation: string, + +width: ?number, + +height: ?number, + +scales: Array, + +files: Array, + +hash: string, + +name: string, + +type: string, +|}; const sizeOf = denodeify(imageSize); @@ -696,7 +696,7 @@ class Bundler { return { asset, code, - meta: {dependencies, dependencyOffsets}, + meta: {dependencies, dependencyOffsets, preloaded: null}, }; }); } diff --git a/packages/metro-bundler/src/Server/index.js b/packages/metro-bundler/src/Server/index.js index 98a6066e..198452d0 100644 --- a/packages/metro-bundler/src/Server/index.js +++ b/packages/metro-bundler/src/Server/index.js @@ -428,7 +428,7 @@ class Server { _rangeRequestMiddleware( req: IncomingMessage, res: ServerResponse, - data: string, + data: string | Buffer, assetPath: string, ) { if (req.headers && req.headers.range) { diff --git a/packages/metro-bundler/src/node-haste/lib/getAssetDataFromName.js b/packages/metro-bundler/src/node-haste/lib/getAssetDataFromName.js index e4127918..05e816dd 100644 --- a/packages/metro-bundler/src/node-haste/lib/getAssetDataFromName.js +++ b/packages/metro-bundler/src/node-haste/lib/getAssetDataFromName.js @@ -14,13 +14,15 @@ const getPlatformExtension = require('./getPlatformExtension'); const path = require('path'); -function getAssetDataFromName(filename: string, platforms: Set): {| +export type AssetData = {| assetName: string, name: string, platform: ?string, resolution: number, type: string, -|} { +|}; + +function getAssetDataFromName(filename: string, platforms: Set): AssetData { const ext = path.extname(filename); const platformExt = getPlatformExtension(filename, platforms);