mirror of https://github.com/status-im/metro.git
Support for remote assets
Reviewed By: davidaurelio Differential Revision: D6030886 fbshipit-source-id: c188b39e104f5c3f65a98336fecbffc93091ff4c
This commit is contained in:
parent
1a2a46a9fb
commit
0fdf36d06d
|
@ -89,9 +89,9 @@ type __TransformOptions = {
|
||||||
|
|
||||||
type _TransformOptions =
|
type _TransformOptions =
|
||||||
__TransformOptions & {env?: {[key: string]: __TransformOptions}};
|
__TransformOptions & {env?: {[key: string]: __TransformOptions}};
|
||||||
declare class _Ast {}
|
declare class Ast {}
|
||||||
type TransformResult = {
|
type TransformResult = {
|
||||||
ast: _Ast,
|
ast: Ast,
|
||||||
code: ?string,
|
code: ?string,
|
||||||
ignored: boolean,
|
ignored: boolean,
|
||||||
map: ?_SourceMap,
|
map: ?_SourceMap,
|
||||||
|
@ -101,14 +101,14 @@ type VisitFn = <State>(path: Object, state: State) => any;
|
||||||
declare module 'babel-core' {
|
declare module 'babel-core' {
|
||||||
declare type Plugins = _Plugins;
|
declare type Plugins = _Plugins;
|
||||||
declare type SourceMap = _SourceMap;
|
declare type SourceMap = _SourceMap;
|
||||||
declare type Ast = _Ast;
|
declare type Ast = Ast;
|
||||||
declare type TransformOptions = _TransformOptions;
|
declare type TransformOptions = _TransformOptions;
|
||||||
declare function transform(
|
declare function transform(
|
||||||
code: string,
|
code: string,
|
||||||
options?: _TransformOptions,
|
options?: _TransformOptions,
|
||||||
): TransformResult;
|
): TransformResult;
|
||||||
declare function traverse<State>(
|
declare function traverse<State>(
|
||||||
ast: _Ast,
|
ast: Ast,
|
||||||
visitor: {[key: string]: VisitFn<State> |
|
visitor: {[key: string]: VisitFn<State> |
|
||||||
{enter?: VisitFn<State>, exit?: VisitFn<State>}},
|
{enter?: VisitFn<State>, exit?: VisitFn<State>}},
|
||||||
scope?: ?Object,
|
scope?: ?Object,
|
||||||
|
@ -117,7 +117,7 @@ declare module 'babel-core' {
|
||||||
): void;
|
): void;
|
||||||
declare var types: {[key: string]: Function};
|
declare var types: {[key: string]: Function};
|
||||||
declare function transformFromAst(
|
declare function transformFromAst(
|
||||||
ast: _Ast,
|
ast: Ast,
|
||||||
code?: ?string,
|
code?: ?string,
|
||||||
babelOptions?: _TransformOptions,
|
babelOptions?: _TransformOptions,
|
||||||
): TransformResult;
|
): TransformResult;
|
||||||
|
@ -133,7 +133,7 @@ type RawMapping = {
|
||||||
declare module 'babel-generator' {
|
declare module 'babel-generator' {
|
||||||
declare type RawMapping = RawMapping;
|
declare type RawMapping = RawMapping;
|
||||||
declare function exports(
|
declare function exports(
|
||||||
ast: _Ast,
|
ast: Ast,
|
||||||
options?: GeneratorOptions,
|
options?: GeneratorOptions,
|
||||||
): TransformResult & {rawMappings: ?Array<RawMapping>};
|
): TransformResult & {rawMappings: ?Array<RawMapping>};
|
||||||
}
|
}
|
||||||
|
|
|
@ -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])]};',
|
||||||
|
);
|
||||||
|
});
|
|
@ -86,7 +86,6 @@ export type AssetDescriptor = {
|
||||||
|
|
||||||
export type ExtendedAssetDescriptor = AssetDescriptor & {
|
export type ExtendedAssetDescriptor = AssetDescriptor & {
|
||||||
+fileSystemLocation: string,
|
+fileSystemLocation: string,
|
||||||
+files: Array<string>,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const sizeOf = denodeify(imageSize);
|
const sizeOf = denodeify(imageSize);
|
||||||
|
|
|
@ -16,7 +16,7 @@ const babel = require('babel-core');
|
||||||
const babelGenerate = require('babel-generator').default;
|
const babelGenerate = require('babel-generator').default;
|
||||||
const babylon = require('babylon');
|
const babylon = require('babylon');
|
||||||
|
|
||||||
import type {AssetDescriptor} from '.';
|
import type {AssetDescriptor, ExtendedAssetDescriptor} from '.';
|
||||||
import type {ModuleTransportLike} from '../shared/types.flow';
|
import type {ModuleTransportLike} from '../shared/types.flow';
|
||||||
|
|
||||||
type SubTree<T: ModuleTransportLike> = (
|
type SubTree<T: ModuleTransportLike> = (
|
||||||
|
@ -26,10 +26,104 @@ type SubTree<T: ModuleTransportLike> = (
|
||||||
|
|
||||||
const assetPropertyBlacklist = new Set(['files', 'fileSystemLocation', 'path']);
|
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(
|
function generateAssetCodeFileAst(
|
||||||
assetRegistryPath: string,
|
assetRegistryPath: string,
|
||||||
assetDescriptor: AssetDescriptor,
|
assetDescriptor: AssetDescriptor,
|
||||||
): Object {
|
): AssetResult {
|
||||||
const properDescriptor = filterObject(
|
const properDescriptor = filterObject(
|
||||||
assetDescriptor,
|
assetDescriptor,
|
||||||
assetPropertyBlacklist,
|
assetPropertyBlacklist,
|
||||||
|
@ -52,13 +146,16 @@ function generateAssetCodeFileAst(
|
||||||
const registerAssetCall = t.callExpression(registerAssetFunction, [
|
const registerAssetCall = t.callExpression(registerAssetFunction, [
|
||||||
descriptorAst,
|
descriptorAst,
|
||||||
]);
|
]);
|
||||||
return t.file(
|
return {
|
||||||
|
remote: false,
|
||||||
|
ast: t.file(
|
||||||
t.program([
|
t.program([
|
||||||
t.expressionStatement(
|
t.expressionStatement(
|
||||||
t.assignmentExpression('=', moduleExports, registerAssetCall),
|
t.assignmentExpression('=', moduleExports, registerAssetCall),
|
||||||
),
|
),
|
||||||
]),
|
]),
|
||||||
);
|
),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function generateAssetTransformResult(
|
function generateAssetTransformResult(
|
||||||
|
@ -70,7 +167,7 @@ function generateAssetTransformResult(
|
||||||
dependencyOffsets: Array<number>,
|
dependencyOffsets: Array<number>,
|
||||||
|} {
|
|} {
|
||||||
const {code} = babelGenerate(
|
const {code} = babelGenerate(
|
||||||
generateAssetCodeFileAst(assetRegistryPath, assetDescriptor),
|
generateAssetCodeFileAst(assetRegistryPath, assetDescriptor).ast,
|
||||||
{comments: false, compact: true},
|
{comments: false, compact: true},
|
||||||
);
|
);
|
||||||
const dependencies = [assetRegistryPath];
|
const dependencies = [assetRegistryPath];
|
||||||
|
@ -177,5 +274,6 @@ module.exports = {
|
||||||
createRamBundleGroups,
|
createRamBundleGroups,
|
||||||
generateAssetCodeFileAst,
|
generateAssetCodeFileAst,
|
||||||
generateAssetTransformResult,
|
generateAssetTransformResult,
|
||||||
|
generateRemoteAssetCodeFileAst,
|
||||||
isAssetTypeAnImage,
|
isAssetTypeAnImage,
|
||||||
};
|
};
|
||||||
|
|
|
@ -157,6 +157,7 @@ export type TransformedCodeFile = {
|
||||||
+hasteID: ?string,
|
+hasteID: ?string,
|
||||||
package?: PackageData,
|
package?: PackageData,
|
||||||
+transformed: TransformResults,
|
+transformed: TransformResults,
|
||||||
|
+remoteAsset?: boolean,
|
||||||
+type: CodeFileTypes,
|
+type: CodeFileTypes,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue