mirror of https://github.com/status-im/metro.git
Updates from Tue 8 Sep
This commit is contained in:
commit
1a428c2c90
|
@ -59,6 +59,14 @@ var options = parseCommandLine([{
|
||||||
type: 'string',
|
type: 'string',
|
||||||
default: require.resolve('./transformer.js'),
|
default: require.resolve('./transformer.js'),
|
||||||
description: 'Specify a custom transformer to be used (absolute path)'
|
description: 'Specify a custom transformer to be used (absolute path)'
|
||||||
|
}, {
|
||||||
|
command: 'resetCache',
|
||||||
|
description: 'Removes cached files',
|
||||||
|
default: false,
|
||||||
|
}, {
|
||||||
|
command: 'reset-cache',
|
||||||
|
description: 'Removes cached files',
|
||||||
|
default: false,
|
||||||
}]);
|
}]);
|
||||||
|
|
||||||
if (options.projectRoots) {
|
if (options.projectRoots) {
|
||||||
|
@ -229,6 +237,7 @@ function getAppMiddleware(options) {
|
||||||
transformModulePath: transformerPath,
|
transformModulePath: transformerPath,
|
||||||
assetRoots: options.assetRoots,
|
assetRoots: options.assetRoots,
|
||||||
assetExts: ['png', 'jpeg', 'jpg'],
|
assetExts: ['png', 'jpeg', 'jpg'],
|
||||||
|
resetCache: options.resetCache || options['reset-cache'],
|
||||||
polyfillModuleNames: [
|
polyfillModuleNames: [
|
||||||
require.resolve(
|
require.resolve(
|
||||||
'../Libraries/JavaScriptAppEngine/polyfills/document.js'
|
'../Libraries/JavaScriptAppEngine/polyfills/document.js'
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
jest
|
jest
|
||||||
|
.dontMock('../../lib/getPlatformExtension')
|
||||||
.dontMock('../../lib/getAssetDataFromName')
|
.dontMock('../../lib/getAssetDataFromName')
|
||||||
.dontMock('../');
|
.dontMock('../');
|
||||||
|
|
||||||
|
@ -47,6 +48,43 @@ describe('AssetServer', () => {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
pit('should work for the simple case with platform ext', () => {
|
||||||
|
const server = new AssetServer({
|
||||||
|
projectRoots: ['/root'],
|
||||||
|
assetExts: ['png'],
|
||||||
|
});
|
||||||
|
|
||||||
|
fs.__setMockFilesystem({
|
||||||
|
'root': {
|
||||||
|
imgs: {
|
||||||
|
'b.ios.png': 'b ios image',
|
||||||
|
'b.android.png': 'b android image',
|
||||||
|
'c.png': 'c general image',
|
||||||
|
'c.android.png': 'c android image',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return Promise.all([
|
||||||
|
server.get('imgs/b.png', 'ios').then(
|
||||||
|
data => expect(data).toBe('b ios image')
|
||||||
|
),
|
||||||
|
server.get('imgs/b.png', 'android').then(
|
||||||
|
data => expect(data).toBe('b android image')
|
||||||
|
),
|
||||||
|
server.get('imgs/c.png', 'android').then(
|
||||||
|
data => expect(data).toBe('c android image')
|
||||||
|
),
|
||||||
|
server.get('imgs/c.png', 'ios').then(
|
||||||
|
data => expect(data).toBe('c general image')
|
||||||
|
),
|
||||||
|
server.get('imgs/c.png').then(
|
||||||
|
data => expect(data).toBe('c general image')
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
pit('should work for the simple case with jpg', () => {
|
pit('should work for the simple case with jpg', () => {
|
||||||
const server = new AssetServer({
|
const server = new AssetServer({
|
||||||
projectRoots: ['/root'],
|
projectRoots: ['/root'],
|
||||||
|
@ -95,6 +133,37 @@ describe('AssetServer', () => {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
pit('should pick the bigger one with platform ext', () => {
|
||||||
|
const server = new AssetServer({
|
||||||
|
projectRoots: ['/root'],
|
||||||
|
assetExts: ['png'],
|
||||||
|
});
|
||||||
|
|
||||||
|
fs.__setMockFilesystem({
|
||||||
|
'root': {
|
||||||
|
imgs: {
|
||||||
|
'b@1x.png': 'b1 image',
|
||||||
|
'b@2x.png': 'b2 image',
|
||||||
|
'b@4x.png': 'b4 image',
|
||||||
|
'b@4.5x.png': 'b4.5 image',
|
||||||
|
'b@1x.ios.png': 'b1 ios image',
|
||||||
|
'b@2x.ios.png': 'b2 ios image',
|
||||||
|
'b@4x.ios.png': 'b4 ios image',
|
||||||
|
'b@4.5x.ios.png': 'b4.5 ios image',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return Promise.all([
|
||||||
|
server.get('imgs/b@3x.png').then(data =>
|
||||||
|
expect(data).toBe('b4 image')
|
||||||
|
),
|
||||||
|
server.get('imgs/b@3x.png', 'ios').then(data =>
|
||||||
|
expect(data).toBe('b4 ios image')
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
pit('should support multiple project roots', () => {
|
pit('should support multiple project roots', () => {
|
||||||
const server = new AssetServer({
|
const server = new AssetServer({
|
||||||
projectRoots: ['/root', '/root2'],
|
projectRoots: ['/root', '/root2'],
|
||||||
|
|
|
@ -20,7 +20,6 @@ const stat = Promise.denodeify(fs.stat);
|
||||||
const readDir = Promise.denodeify(fs.readdir);
|
const readDir = Promise.denodeify(fs.readdir);
|
||||||
const readFile = Promise.denodeify(fs.readFile);
|
const readFile = Promise.denodeify(fs.readFile);
|
||||||
|
|
||||||
|
|
||||||
const validateOpts = declareOpts({
|
const validateOpts = declareOpts({
|
||||||
projectRoots: {
|
projectRoots: {
|
||||||
type: 'array',
|
type: 'array',
|
||||||
|
@ -39,9 +38,9 @@ class AssetServer {
|
||||||
this._assetExts = opts.assetExts;
|
this._assetExts = opts.assetExts;
|
||||||
}
|
}
|
||||||
|
|
||||||
get(assetPath) {
|
get(assetPath, platform = null) {
|
||||||
const assetData = getAssetDataFromName(assetPath);
|
const assetData = getAssetDataFromName(assetPath);
|
||||||
return this._getAssetRecord(assetPath).then(record => {
|
return this._getAssetRecord(assetPath, platform).then(record => {
|
||||||
for (let i = 0; i < record.scales.length; i++) {
|
for (let i = 0; i < record.scales.length; i++) {
|
||||||
if (record.scales[i] >= assetData.resolution) {
|
if (record.scales[i] >= assetData.resolution) {
|
||||||
return readFile(record.files[i]);
|
return readFile(record.files[i]);
|
||||||
|
@ -52,14 +51,14 @@ class AssetServer {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getAssetData(assetPath) {
|
getAssetData(assetPath, platform = null) {
|
||||||
const nameData = getAssetDataFromName(assetPath);
|
const nameData = getAssetDataFromName(assetPath);
|
||||||
const data = {
|
const data = {
|
||||||
name: nameData.name,
|
name: nameData.name,
|
||||||
type: nameData.type,
|
type: nameData.type,
|
||||||
};
|
};
|
||||||
|
|
||||||
return this._getAssetRecord(assetPath).then(record => {
|
return this._getAssetRecord(assetPath, platform).then(record => {
|
||||||
data.scales = record.scales;
|
data.scales = record.scales;
|
||||||
|
|
||||||
return Promise.all(
|
return Promise.all(
|
||||||
|
@ -85,9 +84,10 @@ class AssetServer {
|
||||||
* 1. We first parse the directory of the asset
|
* 1. We first parse the directory of the asset
|
||||||
* 2. We check to find a matching directory in one of the project roots
|
* 2. We check to find a matching directory in one of the project roots
|
||||||
* 3. We then build a map of all assets and their scales in this directory
|
* 3. We then build a map of all assets and their scales in this directory
|
||||||
* 4. Then pick the closest resolution (rounding up) to the requested one
|
* 4. Then try to pick platform-specific asset records
|
||||||
|
* 5. Then pick the closest resolution (rounding up) to the requested one
|
||||||
*/
|
*/
|
||||||
_getAssetRecord(assetPath) {
|
_getAssetRecord(assetPath, platform = null) {
|
||||||
const filename = path.basename(assetPath);
|
const filename = path.basename(assetPath);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -104,11 +104,20 @@ class AssetServer {
|
||||||
const files = res[1];
|
const files = res[1];
|
||||||
const assetData = getAssetDataFromName(filename);
|
const assetData = getAssetDataFromName(filename);
|
||||||
|
|
||||||
const map = this._buildAssetMap(dir, files);
|
const map = this._buildAssetMap(dir, files, platform);
|
||||||
const record = map[assetData.assetName];
|
|
||||||
|
let record;
|
||||||
|
if (platform != null){
|
||||||
|
record = map[getAssetKey(assetData.assetName, platform)] ||
|
||||||
|
map[assetData.assetName];
|
||||||
|
} else {
|
||||||
|
record = map[assetData.assetName];
|
||||||
|
}
|
||||||
|
|
||||||
if (!record) {
|
if (!record) {
|
||||||
throw new Error('Asset not found');
|
throw new Error(
|
||||||
|
`Asset not found: ${assetPath} for platform: ${platform}`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return record;
|
return record;
|
||||||
|
@ -141,9 +150,10 @@ class AssetServer {
|
||||||
const map = Object.create(null);
|
const map = Object.create(null);
|
||||||
assets.forEach(function(asset, i) {
|
assets.forEach(function(asset, i) {
|
||||||
const file = files[i];
|
const file = files[i];
|
||||||
let record = map[asset.assetName];
|
const assetKey = getAssetKey(asset.assetName, asset.platform);
|
||||||
|
let record = map[assetKey];
|
||||||
if (!record) {
|
if (!record) {
|
||||||
record = map[asset.assetName] = {
|
record = map[assetKey] = {
|
||||||
scales: [],
|
scales: [],
|
||||||
files: [],
|
files: [],
|
||||||
};
|
};
|
||||||
|
@ -151,6 +161,7 @@ class AssetServer {
|
||||||
|
|
||||||
let insertIndex;
|
let insertIndex;
|
||||||
const length = record.scales.length;
|
const length = record.scales.length;
|
||||||
|
|
||||||
for (insertIndex = 0; insertIndex < length; insertIndex++) {
|
for (insertIndex = 0; insertIndex < length; insertIndex++) {
|
||||||
if (asset.resolution < record.scales[insertIndex]) {
|
if (asset.resolution < record.scales[insertIndex]) {
|
||||||
break;
|
break;
|
||||||
|
@ -164,4 +175,12 @@ class AssetServer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getAssetKey(assetName, platform) {
|
||||||
|
if (platform != null) {
|
||||||
|
return `${assetName} : ${platform}`;
|
||||||
|
} else {
|
||||||
|
return assetName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = AssetServer;
|
module.exports = AssetServer;
|
||||||
|
|
|
@ -115,13 +115,18 @@ class Bundle {
|
||||||
getMinifiedSourceAndMap() {
|
getMinifiedSourceAndMap() {
|
||||||
this._assertFinalized();
|
this._assertFinalized();
|
||||||
|
|
||||||
|
if (this._minifiedSourceAndMap) {
|
||||||
|
return this._minifiedSourceAndMap;
|
||||||
|
}
|
||||||
|
|
||||||
const source = this._getSource();
|
const source = this._getSource();
|
||||||
try {
|
try {
|
||||||
return UglifyJS.minify(source, {
|
this._minifiedSourceAndMap = UglifyJS.minify(source, {
|
||||||
fromString: true,
|
fromString: true,
|
||||||
outSourceMap: 'bundle.js',
|
outSourceMap: 'bundle.js',
|
||||||
inSourceMap: this.getSourceMap(),
|
inSourceMap: this.getSourceMap(),
|
||||||
});
|
});
|
||||||
|
return this._minifiedSourceAndMap;
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
// Sometimes, when somebody is using a new syntax feature that we
|
// Sometimes, when somebody is using a new syntax feature that we
|
||||||
// don't yet have transform for, the untransformed line is sent to
|
// don't yet have transform for, the untransformed line is sent to
|
||||||
|
@ -186,6 +191,10 @@ class Bundle {
|
||||||
|
|
||||||
options = options || {};
|
options = options || {};
|
||||||
|
|
||||||
|
if (options.minify) {
|
||||||
|
return this.getMinifiedSourceAndMap().map;
|
||||||
|
}
|
||||||
|
|
||||||
if (this._shouldCombineSourceMaps) {
|
if (this._shouldCombineSourceMaps) {
|
||||||
return this._getCombinedSourceMaps(options);
|
return this._getCombinedSourceMaps(options);
|
||||||
}
|
}
|
||||||
|
|
|
@ -154,7 +154,7 @@ class Bundler {
|
||||||
bundle.setMainModuleId(result.mainModuleId);
|
bundle.setMainModuleId(result.mainModuleId);
|
||||||
return Promise.all(
|
return Promise.all(
|
||||||
result.dependencies.map(
|
result.dependencies.map(
|
||||||
module => this._transformModule(bundle, module).then(transformed => {
|
module => this._transformModule(bundle, module, platform).then(transformed => {
|
||||||
if (bar) {
|
if (bar) {
|
||||||
bar.tick();
|
bar.tick();
|
||||||
}
|
}
|
||||||
|
@ -182,13 +182,13 @@ class Bundler {
|
||||||
return this._resolver.getDependencies(main, { dev: isDev, platform });
|
return this._resolver.getDependencies(main, { dev: isDev, platform });
|
||||||
}
|
}
|
||||||
|
|
||||||
_transformModule(bundle, module) {
|
_transformModule(bundle, module, platform = null) {
|
||||||
let transform;
|
let transform;
|
||||||
|
|
||||||
if (module.isAsset_DEPRECATED()) {
|
if (module.isAsset_DEPRECATED()) {
|
||||||
transform = this.generateAssetModule_DEPRECATED(bundle, module);
|
transform = this.generateAssetModule_DEPRECATED(bundle, module);
|
||||||
} else if (module.isAsset()) {
|
} else if (module.isAsset()) {
|
||||||
transform = this.generateAssetModule(bundle, module);
|
transform = this.generateAssetModule(bundle, module, platform);
|
||||||
} else if (module.isJSON()) {
|
} else if (module.isJSON()) {
|
||||||
transform = generateJSONModule(module);
|
transform = generateJSONModule(module);
|
||||||
} else {
|
} else {
|
||||||
|
@ -243,12 +243,12 @@ class Bundler {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
generateAssetModule(bundle, module) {
|
generateAssetModule(bundle, module, platform = null) {
|
||||||
const relPath = getPathRelativeToRoot(this._projectRoots, module.path);
|
const relPath = getPathRelativeToRoot(this._projectRoots, module.path);
|
||||||
|
|
||||||
return Promise.all([
|
return Promise.all([
|
||||||
sizeOf(module.path),
|
sizeOf(module.path),
|
||||||
this._assetServer.getAssetData(relPath),
|
this._assetServer.getAssetData(relPath, platform),
|
||||||
]).then(function(res) {
|
]).then(function(res) {
|
||||||
const dimensions = res[0];
|
const dimensions = res[0];
|
||||||
const assetData = res[1];
|
const assetData = res[1];
|
||||||
|
|
|
@ -16,6 +16,7 @@ jest
|
||||||
.dontMock('../../crawlers')
|
.dontMock('../../crawlers')
|
||||||
.dontMock('../../crawlers/node')
|
.dontMock('../../crawlers/node')
|
||||||
.dontMock('../../replacePatterns')
|
.dontMock('../../replacePatterns')
|
||||||
|
.dontMock('../../../lib/getPlatformExtension')
|
||||||
.dontMock('../../../lib/getAssetDataFromName')
|
.dontMock('../../../lib/getAssetDataFromName')
|
||||||
.dontMock('../../fastfs')
|
.dontMock('../../fastfs')
|
||||||
.dontMock('../../AssetModule_DEPRECATED')
|
.dontMock('../../AssetModule_DEPRECATED')
|
||||||
|
@ -424,6 +425,90 @@ describe('DependencyGraph', function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
pit('should respect platform extension in assets', function() {
|
||||||
|
var root = '/root';
|
||||||
|
fs.__setMockFilesystem({
|
||||||
|
'root': {
|
||||||
|
'index.js': [
|
||||||
|
'/**',
|
||||||
|
' * @providesModule index',
|
||||||
|
' */',
|
||||||
|
'require("./imgs/a.png");',
|
||||||
|
'require("./imgs/b.png");',
|
||||||
|
'require("./imgs/c.png");',
|
||||||
|
].join('\n'),
|
||||||
|
'imgs': {
|
||||||
|
'a@1.5x.ios.png': '',
|
||||||
|
'b@.7x.ios.png': '',
|
||||||
|
'c.ios.png': '',
|
||||||
|
'c@2x.ios.png': '',
|
||||||
|
},
|
||||||
|
'package.json': JSON.stringify({
|
||||||
|
name: 'rootPackage'
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var dgraph = new DependencyGraph({
|
||||||
|
roots: [root],
|
||||||
|
fileWatcher: fileWatcher,
|
||||||
|
assetExts: ['png', 'jpg'],
|
||||||
|
cache: cache,
|
||||||
|
});
|
||||||
|
|
||||||
|
dgraph.setup({ platform: 'ios' });
|
||||||
|
|
||||||
|
return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) {
|
||||||
|
expect(deps)
|
||||||
|
.toEqual([
|
||||||
|
{
|
||||||
|
id: 'index',
|
||||||
|
path: '/root/index.js',
|
||||||
|
dependencies: [
|
||||||
|
'./imgs/a.png',
|
||||||
|
'./imgs/b.png',
|
||||||
|
'./imgs/c.png',
|
||||||
|
],
|
||||||
|
isAsset: false,
|
||||||
|
isAsset_DEPRECATED: false,
|
||||||
|
isJSON: false,
|
||||||
|
isPolyfill: false,
|
||||||
|
resolution: undefined,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'rootPackage/imgs/a.png',
|
||||||
|
path: '/root/imgs/a@1.5x.ios.png',
|
||||||
|
resolution: 1.5,
|
||||||
|
dependencies: [],
|
||||||
|
isAsset: true,
|
||||||
|
isAsset_DEPRECATED: false,
|
||||||
|
isJSON: false,
|
||||||
|
isPolyfill: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'rootPackage/imgs/b.png',
|
||||||
|
path: '/root/imgs/b@.7x.ios.png',
|
||||||
|
resolution: 0.7,
|
||||||
|
dependencies: [],
|
||||||
|
isAsset: true,
|
||||||
|
isAsset_DEPRECATED: false,
|
||||||
|
isJSON: false,
|
||||||
|
isPolyfill: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'rootPackage/imgs/c.png',
|
||||||
|
path: '/root/imgs/c.ios.png',
|
||||||
|
resolution: 1,
|
||||||
|
dependencies: [],
|
||||||
|
isAsset: true,
|
||||||
|
isAsset_DEPRECATED: false,
|
||||||
|
isJSON: false,
|
||||||
|
isPolyfill: false,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
pit('Deprecated and relative assets can live together', function() {
|
pit('Deprecated and relative assets can live together', function() {
|
||||||
var root = '/root';
|
var root = '/root';
|
||||||
fs.__setMockFilesystem({
|
fs.__setMockFilesystem({
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/**
|
/**
|
||||||
* Copyright (c) 2015-present, Facebook, Inc.
|
* Copyright (c) 2015-present, Facebook, Inc.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
|
@ -17,6 +17,7 @@ const crawl = require('../crawlers');
|
||||||
const debug = require('debug')('DependencyGraph');
|
const debug = require('debug')('DependencyGraph');
|
||||||
const declareOpts = require('../../lib/declareOpts');
|
const declareOpts = require('../../lib/declareOpts');
|
||||||
const getAssetDataFromName = require('../../lib/getAssetDataFromName');
|
const getAssetDataFromName = require('../../lib/getAssetDataFromName');
|
||||||
|
const getPontentialPlatformExt = require('../../lib/getPlatformExtension');
|
||||||
const isAbsolutePath = require('absolute-path');
|
const isAbsolutePath = require('absolute-path');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const util = require('util');
|
const util = require('util');
|
||||||
|
@ -274,7 +275,7 @@ class DependencyGraph {
|
||||||
|
|
||||||
// `platformExt` could be set in the `setup` method.
|
// `platformExt` could be set in the `setup` method.
|
||||||
if (!this._platformExt) {
|
if (!this._platformExt) {
|
||||||
const platformExt = getPlatformExt(entryPath);
|
const platformExt = getPontentialPlatformExt(entryPath);
|
||||||
if (platformExt && this._opts.platforms.indexOf(platformExt) > -1) {
|
if (platformExt && this._opts.platforms.indexOf(platformExt) > -1) {
|
||||||
this._platformExt = platformExt;
|
this._platformExt = platformExt;
|
||||||
} else {
|
} else {
|
||||||
|
@ -390,12 +391,18 @@ class DependencyGraph {
|
||||||
return Promise.resolve().then(() => {
|
return Promise.resolve().then(() => {
|
||||||
if (this._isAssetFile(potentialModulePath)) {
|
if (this._isAssetFile(potentialModulePath)) {
|
||||||
const {name, type} = getAssetDataFromName(potentialModulePath);
|
const {name, type} = getAssetDataFromName(potentialModulePath);
|
||||||
const pattern = new RegExp('^' + name + '(@[\\d\\.]+x)?\\.' + type);
|
|
||||||
|
let pattern = '^' + name + '(@[\\d\\.]+x)?';
|
||||||
|
if (this._platformExt != null) {
|
||||||
|
pattern += '(\\.' + this._platformExt + ')?';
|
||||||
|
}
|
||||||
|
pattern += '\\.' + type;
|
||||||
|
|
||||||
// We arbitrarly grab the first one, because scale selection
|
// We arbitrarly grab the first one, because scale selection
|
||||||
// will happen somewhere
|
// will happen somewhere
|
||||||
const [assetFile] = this._fastfs.matches(
|
const [assetFile] = this._fastfs.matches(
|
||||||
path.dirname(potentialModulePath),
|
path.dirname(potentialModulePath),
|
||||||
pattern
|
new RegExp(pattern)
|
||||||
);
|
);
|
||||||
|
|
||||||
if (assetFile) {
|
if (assetFile) {
|
||||||
|
@ -496,7 +503,7 @@ class DependencyGraph {
|
||||||
const modules = this._hasteMap[name];
|
const modules = this._hasteMap[name];
|
||||||
if (this._platformExt != null) {
|
if (this._platformExt != null) {
|
||||||
for (let i = 0; i < modules.length; i++) {
|
for (let i = 0; i < modules.length; i++) {
|
||||||
if (getPlatformExt(modules[i].path) === this._platformExt) {
|
if (getPontentialPlatformExt(modules[i].path) === this._platformExt) {
|
||||||
return modules[i];
|
return modules[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -662,15 +669,6 @@ function normalizePath(modulePath) {
|
||||||
return modulePath.replace(/\/$/, '');
|
return modulePath.replace(/\/$/, '');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract platform extension: index.ios.js -> ios
|
|
||||||
function getPlatformExt(file) {
|
|
||||||
const parts = path.basename(file).split('.');
|
|
||||||
if (parts.length < 3) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return parts[parts.length - 2];
|
|
||||||
}
|
|
||||||
|
|
||||||
util.inherits(NotFoundError, Error);
|
util.inherits(NotFoundError, Error);
|
||||||
|
|
||||||
module.exports = DependencyGraph;
|
module.exports = DependencyGraph;
|
||||||
|
|
|
@ -245,8 +245,16 @@ describe('processRequest', () => {
|
||||||
expect(res.end).toBeCalledWith('i am image');
|
expect(res.end).toBeCalledWith('i am image');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return 404', () => {
|
it('should parse the platform option', () => {
|
||||||
|
const req = {url: '/assets/imgs/a.png?platform=ios'};
|
||||||
|
const res = {end: jest.genMockFn()};
|
||||||
|
|
||||||
|
AssetServer.prototype.get.mockImpl(() => Promise.resolve('i am image'));
|
||||||
|
|
||||||
|
server.processRequest(req, res);
|
||||||
|
jest.runAllTimers();
|
||||||
|
expect(AssetServer.prototype.get).toBeCalledWith('imgs/a.png', 'ios');
|
||||||
|
expect(res.end).toBeCalledWith('i am image');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -278,7 +278,8 @@ class Server {
|
||||||
_processAssetsRequest(req, res) {
|
_processAssetsRequest(req, res) {
|
||||||
const urlObj = url.parse(req.url, true);
|
const urlObj = url.parse(req.url, true);
|
||||||
const assetPath = urlObj.pathname.match(/^\/assets\/(.+)$/);
|
const assetPath = urlObj.pathname.match(/^\/assets\/(.+)$/);
|
||||||
this._assetServer.get(assetPath[1])
|
const assetEvent = Activity.startEvent(`processing asset request ${assetPath[1]}`);
|
||||||
|
this._assetServer.get(assetPath[1], urlObj.query.platform)
|
||||||
.then(
|
.then(
|
||||||
data => res.end(data),
|
data => res.end(data),
|
||||||
error => {
|
error => {
|
||||||
|
@ -286,7 +287,7 @@ class Server {
|
||||||
res.writeHead('404');
|
res.writeHead('404');
|
||||||
res.end('Asset not found');
|
res.end('Asset not found');
|
||||||
}
|
}
|
||||||
).done();
|
).done(() => Activity.endEvent(assetEvent));
|
||||||
}
|
}
|
||||||
|
|
||||||
_processProfile(req, res) {
|
_processProfile(req, res) {
|
||||||
|
@ -370,7 +371,9 @@ class Server {
|
||||||
res.end(bundleSource);
|
res.end(bundleSource);
|
||||||
Activity.endEvent(startReqEventId);
|
Activity.endEvent(startReqEventId);
|
||||||
} else if (requestType === 'map') {
|
} else if (requestType === 'map') {
|
||||||
var sourceMap = JSON.stringify(p.getSourceMap());
|
var sourceMap = JSON.stringify(p.getSourceMap({
|
||||||
|
minify: options.minify,
|
||||||
|
}));
|
||||||
res.setHeader('Content-Type', 'application/json');
|
res.setHeader('Content-Type', 'application/json');
|
||||||
res.end(sourceMap);
|
res.end(sourceMap);
|
||||||
Activity.endEvent(startReqEventId);
|
Activity.endEvent(startReqEventId);
|
||||||
|
|
|
@ -12,6 +12,7 @@ const Bundle = require('../Bundler/Bundle');
|
||||||
const Promise = require('promise');
|
const Promise = require('promise');
|
||||||
const bser = require('bser');
|
const bser = require('bser');
|
||||||
const debug = require('debug')('ReactPackager:SocketClient');
|
const debug = require('debug')('ReactPackager:SocketClient');
|
||||||
|
const fs = require('fs');
|
||||||
const net = require('net');
|
const net = require('net');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const tmpdir = require('os').tmpdir();
|
const tmpdir = require('os').tmpdir();
|
||||||
|
@ -29,7 +30,16 @@ class SocketClient {
|
||||||
this._sock = net.connect(sockPath);
|
this._sock = net.connect(sockPath);
|
||||||
this._ready = new Promise((resolve, reject) => {
|
this._ready = new Promise((resolve, reject) => {
|
||||||
this._sock.on('connect', () => resolve(this));
|
this._sock.on('connect', () => resolve(this));
|
||||||
this._sock.on('error', (e) => reject(e));
|
this._sock.on('error', (e) => {
|
||||||
|
e.message = `Error connecting to server on ${sockPath} ` +
|
||||||
|
`with error: ${e.message}`;
|
||||||
|
|
||||||
|
if (fs.existsSync(LOG_PATH)) {
|
||||||
|
e.message += '\nServer logs:\n' + fs.readFileSync(LOG_PATH, 'utf8');
|
||||||
|
}
|
||||||
|
|
||||||
|
reject(e);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
this._resolvers = Object.create(null);
|
this._resolvers = Object.create(null);
|
||||||
|
|
|
@ -16,6 +16,7 @@ const fs = require('fs');
|
||||||
const net = require('net');
|
const net = require('net');
|
||||||
|
|
||||||
const MAX_IDLE_TIME = 30 * 1000;
|
const MAX_IDLE_TIME = 30 * 1000;
|
||||||
|
const MAX_STARTUP_TIME = 5 * 60 * 1000;
|
||||||
|
|
||||||
class SocketServer {
|
class SocketServer {
|
||||||
constructor(sockPath, options) {
|
constructor(sockPath, options) {
|
||||||
|
@ -35,13 +36,15 @@ class SocketServer {
|
||||||
process.on('exit', () => fs.unlinkSync(sockPath));
|
process.on('exit', () => fs.unlinkSync(sockPath));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this._numConnections = 0;
|
||||||
this._server.on('connection', (sock) => this._handleConnection(sock));
|
this._server.on('connection', (sock) => this._handleConnection(sock));
|
||||||
|
|
||||||
// Disable the file watcher.
|
// Disable the file watcher.
|
||||||
options.nonPersistent = true;
|
options.nonPersistent = true;
|
||||||
this._packagerServer = new Server(options);
|
this._packagerServer = new Server(options);
|
||||||
this._jobs = 0;
|
this._jobs = 0;
|
||||||
this._dieEventually();
|
this._dieEventually(MAX_STARTUP_TIME);
|
||||||
}
|
}
|
||||||
|
|
||||||
onReady() {
|
onReady() {
|
||||||
|
@ -50,10 +53,13 @@ class SocketServer {
|
||||||
|
|
||||||
_handleConnection(sock) {
|
_handleConnection(sock) {
|
||||||
debug('connection to server', process.pid);
|
debug('connection to server', process.pid);
|
||||||
|
this._numConnections++;
|
||||||
|
sock.on('close', () => this._numConnections--);
|
||||||
|
|
||||||
const bunser = new bser.BunserBuf();
|
const bunser = new bser.BunserBuf();
|
||||||
sock.on('data', (buf) => bunser.append(buf));
|
sock.on('data', (buf) => bunser.append(buf));
|
||||||
bunser.on('value', (m) => this._handleMessage(sock, m));
|
bunser.on('value', (m) => this._handleMessage(sock, m));
|
||||||
|
bunser.on('error', (e) => console.error(e));
|
||||||
}
|
}
|
||||||
|
|
||||||
_handleMessage(sock, m) {
|
_handleMessage(sock, m) {
|
||||||
|
@ -113,15 +119,15 @@ class SocketServer {
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
_dieEventually() {
|
_dieEventually(delay = MAX_IDLE_TIME) {
|
||||||
clearTimeout(this._deathTimer);
|
clearTimeout(this._deathTimer);
|
||||||
this._deathTimer = setTimeout(() => {
|
this._deathTimer = setTimeout(() => {
|
||||||
if (this._jobs <= 0) {
|
if (this._jobs <= 0 && this._numConnections <= 0) {
|
||||||
debug('server dying', process.pid);
|
debug('server dying', process.pid);
|
||||||
process.exit();
|
process.exit();
|
||||||
}
|
}
|
||||||
this._dieEventually();
|
this._dieEventually();
|
||||||
}, MAX_IDLE_TIME);
|
}, delay);
|
||||||
}
|
}
|
||||||
|
|
||||||
static listenOnServerIPCMessages() {
|
static listenOnServerIPCMessages() {
|
||||||
|
|
|
@ -20,7 +20,7 @@ const path = require('path');
|
||||||
const tmpdir = require('os').tmpdir();
|
const tmpdir = require('os').tmpdir();
|
||||||
const {spawn} = require('child_process');
|
const {spawn} = require('child_process');
|
||||||
|
|
||||||
const CREATE_SERVER_TIMEOUT = 60000;
|
const CREATE_SERVER_TIMEOUT = 5 * 60 * 1000;
|
||||||
|
|
||||||
const SocketInterface = {
|
const SocketInterface = {
|
||||||
getOrCreateSocketFor(options) {
|
getOrCreateSocketFor(options) {
|
||||||
|
@ -42,8 +42,16 @@ const SocketInterface = {
|
||||||
if (fs.existsSync(sockPath)) {
|
if (fs.existsSync(sockPath)) {
|
||||||
var sock = net.connect(sockPath);
|
var sock = net.connect(sockPath);
|
||||||
sock.on('connect', () => {
|
sock.on('connect', () => {
|
||||||
|
SocketClient.create(sockPath).then(
|
||||||
|
client => {
|
||||||
sock.end();
|
sock.end();
|
||||||
resolve(SocketClient.create(sockPath));
|
resolve(client);
|
||||||
|
},
|
||||||
|
error => {
|
||||||
|
sock.end();
|
||||||
|
reject(error);
|
||||||
|
}
|
||||||
|
);
|
||||||
});
|
});
|
||||||
sock.on('error', (e) => {
|
sock.on('error', (e) => {
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -1,52 +0,0 @@
|
||||||
'use strict';
|
|
||||||
|
|
||||||
jest.autoMockOff();
|
|
||||||
var getAssetDataFromName = require('../getAssetDataFromName');
|
|
||||||
|
|
||||||
describe('getAssetDataFromName', function() {
|
|
||||||
it('should extract resolution simple case', function() {
|
|
||||||
var data = getAssetDataFromName('test@2x.png');
|
|
||||||
expect(data).toEqual({
|
|
||||||
assetName: 'test.png',
|
|
||||||
resolution: 2,
|
|
||||||
type: 'png',
|
|
||||||
name: 'test',
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should default resolution to 1', function() {
|
|
||||||
var data = getAssetDataFromName('test.png');
|
|
||||||
expect(data).toEqual({
|
|
||||||
assetName: 'test.png',
|
|
||||||
resolution: 1,
|
|
||||||
type: 'png',
|
|
||||||
name: 'test',
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should support float', function() {
|
|
||||||
var data = getAssetDataFromName('test@1.1x.png');
|
|
||||||
expect(data).toEqual({
|
|
||||||
assetName: 'test.png',
|
|
||||||
resolution: 1.1,
|
|
||||||
type: 'png',
|
|
||||||
name: 'test',
|
|
||||||
});
|
|
||||||
|
|
||||||
data = getAssetDataFromName('test@.1x.png');
|
|
||||||
expect(data).toEqual({
|
|
||||||
assetName: 'test.png',
|
|
||||||
resolution: 0.1,
|
|
||||||
type: 'png',
|
|
||||||
name: 'test',
|
|
||||||
});
|
|
||||||
|
|
||||||
data = getAssetDataFromName('test@0.2x.png');
|
|
||||||
expect(data).toEqual({
|
|
||||||
assetName: 'test.png',
|
|
||||||
resolution: 0.2,
|
|
||||||
type: 'png',
|
|
||||||
name: 'test',
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -0,0 +1,123 @@
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
jest.dontMock('../getPlatformExtension')
|
||||||
|
.dontMock('../getAssetDataFromName');
|
||||||
|
|
||||||
|
describe('getAssetDataFromName', () => {
|
||||||
|
let getAssetDataFromName;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
getAssetDataFromName = require('../getAssetDataFromName');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should get data from name', () => {
|
||||||
|
expect(getAssetDataFromName('a/b/c.png')).toEqual({
|
||||||
|
resolution: 1,
|
||||||
|
assetName: 'a/b/c.png',
|
||||||
|
type: 'png',
|
||||||
|
name: 'c',
|
||||||
|
platform: null,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(getAssetDataFromName('a/b/c@1x.png')).toEqual({
|
||||||
|
resolution: 1,
|
||||||
|
assetName: 'a/b/c.png',
|
||||||
|
type: 'png',
|
||||||
|
name: 'c',
|
||||||
|
platform: null,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(getAssetDataFromName('a/b/c@2.5x.png')).toEqual({
|
||||||
|
resolution: 2.5,
|
||||||
|
assetName: 'a/b/c.png',
|
||||||
|
type: 'png',
|
||||||
|
name: 'c',
|
||||||
|
platform: null,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(getAssetDataFromName('a/b/c.ios.png')).toEqual({
|
||||||
|
resolution: 1,
|
||||||
|
assetName: 'a/b/c.png',
|
||||||
|
type: 'png',
|
||||||
|
name: 'c',
|
||||||
|
platform: 'ios',
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(getAssetDataFromName('a/b/c@1x.ios.png')).toEqual({
|
||||||
|
resolution: 1,
|
||||||
|
assetName: 'a/b/c.png',
|
||||||
|
type: 'png',
|
||||||
|
name: 'c',
|
||||||
|
platform: 'ios',
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(getAssetDataFromName('a/b/c@2.5x.ios.png')).toEqual({
|
||||||
|
resolution: 2.5,
|
||||||
|
assetName: 'a/b/c.png',
|
||||||
|
type: 'png',
|
||||||
|
name: 'c',
|
||||||
|
platform: 'ios',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('resolution extraction', () => {
|
||||||
|
it('should extract resolution simple case', () => {
|
||||||
|
var data = getAssetDataFromName('test@2x.png');
|
||||||
|
expect(data).toEqual({
|
||||||
|
assetName: 'test.png',
|
||||||
|
resolution: 2,
|
||||||
|
type: 'png',
|
||||||
|
name: 'test',
|
||||||
|
platform: null,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should default resolution to 1', () => {
|
||||||
|
var data = getAssetDataFromName('test.png');
|
||||||
|
expect(data).toEqual({
|
||||||
|
assetName: 'test.png',
|
||||||
|
resolution: 1,
|
||||||
|
type: 'png',
|
||||||
|
name: 'test',
|
||||||
|
platform: null,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should support float', () => {
|
||||||
|
var data = getAssetDataFromName('test@1.1x.png');
|
||||||
|
expect(data).toEqual({
|
||||||
|
assetName: 'test.png',
|
||||||
|
resolution: 1.1,
|
||||||
|
type: 'png',
|
||||||
|
name: 'test',
|
||||||
|
platform: null,
|
||||||
|
});
|
||||||
|
|
||||||
|
data = getAssetDataFromName('test@.1x.png');
|
||||||
|
expect(data).toEqual({
|
||||||
|
assetName: 'test.png',
|
||||||
|
resolution: 0.1,
|
||||||
|
type: 'png',
|
||||||
|
name: 'test',
|
||||||
|
platform: null,
|
||||||
|
});
|
||||||
|
|
||||||
|
data = getAssetDataFromName('test@0.2x.png');
|
||||||
|
expect(data).toEqual({
|
||||||
|
assetName: 'test.png',
|
||||||
|
resolution: 0.2,
|
||||||
|
type: 'png',
|
||||||
|
name: 'test',
|
||||||
|
platform: null,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,24 @@
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
jest.dontMock('../getPlatformExtension');
|
||||||
|
|
||||||
|
describe('getPlatformExtension', function() {
|
||||||
|
it('should get platform ext', function() {
|
||||||
|
var getPlatformExtension = require('../getPlatformExtension');
|
||||||
|
expect(getPlatformExtension('a.ios.js')).toBe('ios');
|
||||||
|
expect(getPlatformExtension('a.android.js')).toBe('android');
|
||||||
|
expect(getPlatformExtension('/b/c/a.ios.js')).toBe('ios');
|
||||||
|
expect(getPlatformExtension('/b/c.android/a.ios.js')).toBe('ios');
|
||||||
|
expect(getPlatformExtension('/b/c/a@1.5x.ios.png')).toBe('ios');
|
||||||
|
expect(getPlatformExtension('/b/c/a@1.5x.lol.png')).toBe(null);
|
||||||
|
expect(getPlatformExtension('/b/c/a.lol.png')).toBe(null);
|
||||||
|
});
|
||||||
|
});
|
|
@ -1,14 +1,29 @@
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var path = require('path');
|
const path = require('path');
|
||||||
|
const getPlatformExtension = require('./getPlatformExtension');
|
||||||
|
|
||||||
function getAssetDataFromName(filename) {
|
function getAssetDataFromName(filename) {
|
||||||
var ext = path.extname(filename);
|
const ext = path.extname(filename);
|
||||||
|
const platformExt = getPlatformExtension(filename);
|
||||||
|
|
||||||
var re = new RegExp('@([\\d\\.]+)x\\' + ext + '$');
|
let pattern = '@([\\d\\.]+)x';
|
||||||
|
if (platformExt != null) {
|
||||||
|
pattern += '(\\.' + platformExt + ')?';
|
||||||
|
}
|
||||||
|
pattern += '\\' + ext + '$';
|
||||||
|
const re = new RegExp(pattern);
|
||||||
|
|
||||||
var match = filename.match(re);
|
const match = filename.match(re);
|
||||||
var resolution;
|
let resolution;
|
||||||
|
|
||||||
if (!(match && match[1])) {
|
if (!(match && match[1])) {
|
||||||
resolution = 1;
|
resolution = 1;
|
||||||
|
@ -19,12 +34,21 @@ function getAssetDataFromName(filename) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var assetName = match ? filename.replace(re, ext) : filename;
|
let assetName;
|
||||||
|
if (match) {
|
||||||
|
assetName = filename.replace(re, ext);
|
||||||
|
} else if (platformExt != null) {
|
||||||
|
assetName = filename.replace(new RegExp(`\\.${platformExt}\\${ext}`), ext);
|
||||||
|
} else {
|
||||||
|
assetName = filename;
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
resolution: resolution,
|
resolution: resolution,
|
||||||
assetName: assetName,
|
assetName: assetName,
|
||||||
type: ext.slice(1),
|
type: ext.slice(1),
|
||||||
name: path.basename(assetName, ext)
|
name: path.basename(assetName, ext),
|
||||||
|
platform: platformExt,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
const SUPPORTED_PLATFORM_EXTS = ['android', 'ios'];
|
||||||
|
|
||||||
|
const re = new RegExp(
|
||||||
|
'[^\\.]+\\.(' + SUPPORTED_PLATFORM_EXTS.join('|') + ')\\.\\w+$'
|
||||||
|
);
|
||||||
|
|
||||||
|
// Extract platform extension: index.ios.js -> ios
|
||||||
|
function getPlatformExtension(file) {
|
||||||
|
const match = file.match(re);
|
||||||
|
if (match && match[1]) {
|
||||||
|
return match[1];
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = getPlatformExtension;
|
|
@ -39,6 +39,7 @@ function transform(srcTxt, filename, options) {
|
||||||
'es7.objectRestSpread',
|
'es7.objectRestSpread',
|
||||||
'flow',
|
'flow',
|
||||||
'react',
|
'react',
|
||||||
|
'react.displayName',
|
||||||
'regenerator',
|
'regenerator',
|
||||||
],
|
],
|
||||||
plugins: plugins,
|
plugins: plugins,
|
||||||
|
|
Loading…
Reference in New Issue