Support for remote assets

Reviewed By: davidaurelio

Differential Revision: D6030886

fbshipit-source-id: c188b39e104f5c3f65a98336fecbffc93091ff4c
This commit is contained in:
Miguel Jimenez Esun 2017-10-19 18:38:10 -07:00 committed by Facebook Github Bot
parent 1a2a46a9fb
commit 0fdf36d06d
5 changed files with 167 additions and 17 deletions

View File

@ -89,9 +89,9 @@ type __TransformOptions = {
type _TransformOptions =
__TransformOptions & {env?: {[key: string]: __TransformOptions}};
declare class _Ast {}
declare class Ast {}
type TransformResult = {
ast: _Ast,
ast: Ast,
code: ?string,
ignored: boolean,
map: ?_SourceMap,
@ -101,14 +101,14 @@ type VisitFn = <State>(path: Object, state: State) => any;
declare module 'babel-core' {
declare type Plugins = _Plugins;
declare type SourceMap = _SourceMap;
declare type Ast = _Ast;
declare type Ast = Ast;
declare type TransformOptions = _TransformOptions;
declare function transform(
code: string,
options?: _TransformOptions,
): TransformResult;
declare function traverse<State>(
ast: _Ast,
ast: Ast,
visitor: {[key: string]: VisitFn<State> |
{enter?: VisitFn<State>, exit?: VisitFn<State>}},
scope?: ?Object,
@ -117,7 +117,7 @@ declare module 'babel-core' {
): void;
declare var types: {[key: string]: Function};
declare function transformFromAst(
ast: _Ast,
ast: Ast,
code?: ?string,
babelOptions?: _TransformOptions,
): TransformResult;
@ -133,7 +133,7 @@ type RawMapping = {
declare module 'babel-generator' {
declare type RawMapping = RawMapping;
declare function exports(
ast: _Ast,
ast: Ast,
options?: GeneratorOptions,
): TransformResult & {rawMappings: ?Array<RawMapping>};
}

View File

@ -0,0 +1,52 @@
/**
* 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.
*
* @emails oncall+javascript_foundation
* @format
*/
'use strict';
const generator = require('babel-generator').default;
const util = require('../util');
it('generates the right AST for remote assets', () => {
const asset = {
__packager_asset: true,
fileSystemLocation: '/js/RKJSModules/Apps/Wilde/AdsPayments/images',
hash: '3e9b7b3c4d4fa37f9eb580dc426412dbde2925ff',
height: 48,
httpServerLocation: '/assets/RKJSModules/Apps/Wilde/AdsPayments/images',
name: 'pending',
scales: [1.5, 2, 3, 4],
type: 'png',
width: 48,
};
const map = {
'/js/RKJSModules/Apps/Wilde/AdsPayments/images': {
pending: {
'2': 'img2x',
'3': 'img3x',
},
},
};
const {ast} = util.generateRemoteAssetCodeFileAst(
'gen',
asset,
'https://remote.server.com/',
map,
);
const code = generator(ast, {minified: true}).code;
expect(code).toBe(
'module.exports={"uri":"https://remote.server.com/"+{"2":"img2x","3":"img3x"}[require("gen").pickScale([2,3])]};',
);
});

View File

@ -86,7 +86,6 @@ export type AssetDescriptor = {
export type ExtendedAssetDescriptor = AssetDescriptor & {
+fileSystemLocation: string,
+files: Array<string>,
};
const sizeOf = denodeify(imageSize);

View File

@ -16,7 +16,7 @@ const babel = require('babel-core');
const babelGenerate = require('babel-generator').default;
const babylon = require('babylon');
import type {AssetDescriptor} from '.';
import type {AssetDescriptor, ExtendedAssetDescriptor} from '.';
import type {ModuleTransportLike} from '../shared/types.flow';
type SubTree<T: ModuleTransportLike> = (
@ -26,10 +26,104 @@ type SubTree<T: ModuleTransportLike> = (
const assetPropertyBlacklist = new Set(['files', 'fileSystemLocation', 'path']);
// Structure of the object: dir.name.scale = asset
export type RemoteFileMap = {
[string]: {
[string]: {
[number]: string,
},
},
};
// Structure of the object: platform.dir.name.scale = asset
export type PlatformRemoteFileMap = {
['ios' | 'android']: RemoteFileMap,
};
type AssetResult = {
remote: boolean,
ast: Ast,
};
/**
* Generates the code involved in requiring an asset, but to be loaded remotely.
* If the asset cannot be found within the map, then it falls back to the
* standard asset.
*/
function generateRemoteAssetCodeFileAst(
assetSourceResolverPath: string,
assetDescriptor: ExtendedAssetDescriptor,
remoteServer: string,
remoteFileMap: RemoteFileMap,
): ?AssetResult {
const t = babel.types;
const file = remoteFileMap[assetDescriptor.fileSystemLocation];
const descriptor = file && file[assetDescriptor.name];
if (!descriptor) {
return null;
}
// require('AssetSourceResolver')
const requireCall = t.callExpression(t.identifier('require'), [
t.stringLiteral(assetSourceResolverPath),
]);
// require('AssetSourceResolver').pickScale
const pickScale = t.memberExpression(requireCall, t.identifier('pickScale'));
// require('AssetSourceResolver').pickScale([2, 3, ...])
const call = t.callExpression(pickScale, [
t.arrayExpression(
Object.keys(descriptor)
.map(Number)
.sort((a, b) => a - b)
.map(scale => t.numericLiteral(scale)),
),
]);
// {2: 'path/to/image@2x', 3: 'path/to/image@3x', ...}
const data = babylon.parseExpression(JSON.stringify(descriptor));
// ({2: '...', 3: '...'})[require(...).pickScale(...)]
const handler = t.memberExpression(data, call, true);
// 'https://remote.server.com/' + ({2: ...})[require(...).pickScale(...)]
const result = t.binaryExpression(
'+',
t.stringLiteral(remoteServer),
handler,
);
// module.exports
const moduleExports = t.memberExpression(
t.identifier('module'),
t.identifier('exports'),
);
return {
remote: true,
ast: t.file(
t.program([
t.expressionStatement(
t.assignmentExpression(
'=',
moduleExports,
t.objectExpression([
t.objectProperty(t.stringLiteral('uri'), result),
]),
),
),
]),
),
};
}
function generateAssetCodeFileAst(
assetRegistryPath: string,
assetDescriptor: AssetDescriptor,
): Object {
): AssetResult {
const properDescriptor = filterObject(
assetDescriptor,
assetPropertyBlacklist,
@ -52,13 +146,16 @@ function generateAssetCodeFileAst(
const registerAssetCall = t.callExpression(registerAssetFunction, [
descriptorAst,
]);
return t.file(
return {
remote: false,
ast: t.file(
t.program([
t.expressionStatement(
t.assignmentExpression('=', moduleExports, registerAssetCall),
),
]),
);
),
};
}
function generateAssetTransformResult(
@ -70,7 +167,7 @@ function generateAssetTransformResult(
dependencyOffsets: Array<number>,
|} {
const {code} = babelGenerate(
generateAssetCodeFileAst(assetRegistryPath, assetDescriptor),
generateAssetCodeFileAst(assetRegistryPath, assetDescriptor).ast,
{comments: false, compact: true},
);
const dependencies = [assetRegistryPath];
@ -177,5 +274,6 @@ module.exports = {
createRamBundleGroups,
generateAssetCodeFileAst,
generateAssetTransformResult,
generateRemoteAssetCodeFileAst,
isAssetTypeAnImage,
};

View File

@ -157,6 +157,7 @@ export type TransformedCodeFile = {
+hasteID: ?string,
package?: PackageData,
+transformed: TransformResults,
+remoteAsset?: boolean,
+type: CodeFileTypes,
};