mirror of https://github.com/status-im/metro.git
[react-packager] Implement image loading i.e. ix('img') -> require('image!img');
This commit is contained in:
parent
449ed58546
commit
d2cf0de12e
|
@ -22,6 +22,8 @@ function ModuleDescriptor(fields) {
|
||||||
|
|
||||||
this.isPolyfill = fields.isPolyfill || false;
|
this.isPolyfill = fields.isPolyfill || false;
|
||||||
|
|
||||||
|
this.isAsset = fields.isAsset || false;
|
||||||
|
|
||||||
this._fields = fields;
|
this._fields = fields;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -56,6 +56,40 @@ describe('DependencyGraph', function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
pit('should get dependencies', function() {
|
||||||
|
var root = '/root';
|
||||||
|
fs.__setMockFilesystem({
|
||||||
|
'root': {
|
||||||
|
'index.js': [
|
||||||
|
'/**',
|
||||||
|
' * @providesModule index',
|
||||||
|
' */',
|
||||||
|
'require("image!a")'
|
||||||
|
].join('\n'),
|
||||||
|
'imgs': {
|
||||||
|
'a.png': ''
|
||||||
|
},
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var dgraph = new DependencyGraph({
|
||||||
|
roots: [root],
|
||||||
|
fileWatcher: fileWatcher,
|
||||||
|
assetRoots: ['/root/imgs']
|
||||||
|
});
|
||||||
|
return dgraph.load().then(function() {
|
||||||
|
expect(dgraph.getOrderedDependencies('/root/index.js'))
|
||||||
|
.toEqual([
|
||||||
|
{id: 'index', path: '/root/index.js', dependencies: ['image!a']},
|
||||||
|
{ id: 'image!a',
|
||||||
|
path: '/root/imgs/a.png',
|
||||||
|
dependencies: [],
|
||||||
|
isAsset: true
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
pit('should get recursive dependencies', function() {
|
pit('should get recursive dependencies', function() {
|
||||||
var root = '/root';
|
var root = '/root';
|
||||||
fs.__setMockFilesystem({
|
fs.__setMockFilesystem({
|
||||||
|
|
|
@ -28,12 +28,22 @@ var validateOpts = declareOpts({
|
||||||
type: 'object',
|
type: 'object',
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
|
assetRoots: {
|
||||||
|
type: 'array',
|
||||||
|
default: [],
|
||||||
|
},
|
||||||
|
assetExts: {
|
||||||
|
type: 'array',
|
||||||
|
default: ['png'],
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
function DependecyGraph(options) {
|
function DependecyGraph(options) {
|
||||||
var opts = validateOpts(options);
|
var opts = validateOpts(options);
|
||||||
|
|
||||||
this._roots = opts.roots;
|
this._roots = opts.roots;
|
||||||
|
this._assetRoots = opts.assetRoots;
|
||||||
|
this._assetExts = opts.assetExts;
|
||||||
this._ignoreFilePath = opts.ignoreFilePath;
|
this._ignoreFilePath = opts.ignoreFilePath;
|
||||||
this._fileWatcher = options.fileWatcher;
|
this._fileWatcher = options.fileWatcher;
|
||||||
|
|
||||||
|
@ -50,7 +60,16 @@ function DependecyGraph(options) {
|
||||||
}
|
}
|
||||||
|
|
||||||
DependecyGraph.prototype.load = function() {
|
DependecyGraph.prototype.load = function() {
|
||||||
return this._loading || (this._loading = this._search());
|
if (this._loading != null) {
|
||||||
|
return this._loading;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._loading = q.all([
|
||||||
|
this._search(),
|
||||||
|
this._buildAssetMap(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
return this._loading;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -115,6 +134,15 @@ DependecyGraph.prototype.resolveDependency = function(
|
||||||
fromModule,
|
fromModule,
|
||||||
depModuleId
|
depModuleId
|
||||||
) {
|
) {
|
||||||
|
// Process asset requires.
|
||||||
|
var assetMatch = depModuleId.match(/^image!(.+)/);
|
||||||
|
if (assetMatch && assetMatch[1]) {
|
||||||
|
if (!this._assetMap[assetMatch[1]]) {
|
||||||
|
throw new Error('Cannot find asset: ' + assetMatch[1]);
|
||||||
|
}
|
||||||
|
return this._assetMap[assetMatch[1]];
|
||||||
|
}
|
||||||
|
|
||||||
var packageJson, modulePath, dep;
|
var packageJson, modulePath, dep;
|
||||||
|
|
||||||
// Package relative modules starts with '.' or '..'.
|
// Package relative modules starts with '.' or '..'.
|
||||||
|
@ -214,32 +242,13 @@ DependecyGraph.prototype._search = function() {
|
||||||
// 2. Filter the files and queue up the directories.
|
// 2. Filter the files and queue up the directories.
|
||||||
// 3. Process any package.json in the files
|
// 3. Process any package.json in the files
|
||||||
// 4. recur.
|
// 4. recur.
|
||||||
return readDir(dir)
|
return readAndStatDir(dir)
|
||||||
.then(function(files){
|
.spread(function(files, stats) {
|
||||||
return q.all(files.map(function(filePath) {
|
var modulePaths = files.filter(function(filePath, i) {
|
||||||
return realpath(path.join(dir, filePath)).catch(handleBrokenLink);
|
if (self._ignoreFilePath(filePath)) {
|
||||||
}));
|
|
||||||
})
|
|
||||||
.then(function(filePaths) {
|
|
||||||
filePaths = filePaths.filter(function(filePath) {
|
|
||||||
if (filePath == null) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return !self._ignoreFilePath(filePath);
|
|
||||||
});
|
|
||||||
|
|
||||||
var statsP = filePaths.map(function(filePath) {
|
|
||||||
return lstat(filePath).catch(handleBrokenLink);
|
|
||||||
});
|
|
||||||
|
|
||||||
return [
|
|
||||||
filePaths,
|
|
||||||
q.all(statsP)
|
|
||||||
];
|
|
||||||
})
|
|
||||||
.spread(function(files, stats) {
|
|
||||||
var modulePaths = files.filter(function(filePath, i) {
|
|
||||||
if (stats[i].isDirectory()) {
|
if (stats[i].isDirectory()) {
|
||||||
self._queue.push(filePath);
|
self._queue.push(filePath);
|
||||||
return false;
|
return false;
|
||||||
|
@ -465,6 +474,19 @@ DependecyGraph.prototype._getAbsolutePath = function(filePath) {
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
DependecyGraph.prototype._buildAssetMap = function() {
|
||||||
|
if (this._assetRoots == null || this._assetRoots.length === 0) {
|
||||||
|
return q();
|
||||||
|
}
|
||||||
|
|
||||||
|
var self = this;
|
||||||
|
return buildAssetMap(this._assetRoots, this._assetExts)
|
||||||
|
.then(function(map) {
|
||||||
|
self._assetMap = map;
|
||||||
|
return map;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extract all required modules from a `code` string.
|
* Extract all required modules from a `code` string.
|
||||||
*/
|
*/
|
||||||
|
@ -511,4 +533,70 @@ function handleBrokenLink(e) {
|
||||||
return q();
|
return q();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function readAndStatDir(dir) {
|
||||||
|
return readDir(dir)
|
||||||
|
.then(function(files){
|
||||||
|
return q.all(files.map(function(filePath) {
|
||||||
|
return realpath(path.join(dir, filePath)).catch(handleBrokenLink);
|
||||||
|
}));
|
||||||
|
}).then(function(files) {
|
||||||
|
files = files.filter(function(f) {
|
||||||
|
return !!f;
|
||||||
|
});
|
||||||
|
|
||||||
|
var stats = files.map(function(filePath) {
|
||||||
|
return lstat(filePath).catch(handleBrokenLink);
|
||||||
|
});
|
||||||
|
|
||||||
|
return [
|
||||||
|
files,
|
||||||
|
q.all(stats),
|
||||||
|
];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given a list of roots and list of extensions find all the files in
|
||||||
|
* the directory with that extension and build a map of those assets.
|
||||||
|
*/
|
||||||
|
function buildAssetMap(roots, exts) {
|
||||||
|
var queue = roots.slice(0);
|
||||||
|
var map = Object.create(null);
|
||||||
|
|
||||||
|
function search() {
|
||||||
|
var root = queue.shift();
|
||||||
|
|
||||||
|
if (root == null) {
|
||||||
|
return q(map);
|
||||||
|
}
|
||||||
|
|
||||||
|
return readAndStatDir(root).spread(function(files, stats) {
|
||||||
|
files.forEach(function(file, i) {
|
||||||
|
if (stats[i].isDirectory()) {
|
||||||
|
queue.push(file);
|
||||||
|
} else {
|
||||||
|
var ext = path.extname(file).replace(/^\./, '');
|
||||||
|
if (exts.indexOf(ext) !== -1) {
|
||||||
|
var assetName = path.basename(file, '.' + ext);
|
||||||
|
if (map[assetName] != null) {
|
||||||
|
debug('Conflcting assets', assetName);
|
||||||
|
}
|
||||||
|
|
||||||
|
map[assetName] = new ModuleDescriptor({
|
||||||
|
id: 'image!' + assetName,
|
||||||
|
path: path.resolve(file),
|
||||||
|
isAsset: true,
|
||||||
|
dependencies: [],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return search();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return search();
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = DependecyGraph;
|
module.exports = DependecyGraph;
|
||||||
|
|
|
@ -17,7 +17,6 @@ var DEFINE_MODULE_CODE = [
|
||||||
].join('');
|
].join('');
|
||||||
|
|
||||||
var DEFINE_MODULE_REPLACE_RE = /_moduleName_|_code_|_deps_/g;
|
var DEFINE_MODULE_REPLACE_RE = /_moduleName_|_code_|_deps_/g;
|
||||||
|
|
||||||
var REL_REQUIRE_STMT = /require\(['"]([\.\/0-9A-Z_$\-]*)['"]\)/gi;
|
var REL_REQUIRE_STMT = /require\(['"]([\.\/0-9A-Z_$\-]*)['"]\)/gi;
|
||||||
|
|
||||||
var validateOpts = declareOpts({
|
var validateOpts = declareOpts({
|
||||||
|
@ -40,6 +39,10 @@ var validateOpts = declareOpts({
|
||||||
type: 'string',
|
type: 'string',
|
||||||
default: 'haste',
|
default: 'haste',
|
||||||
},
|
},
|
||||||
|
assetRoots: {
|
||||||
|
type: 'array',
|
||||||
|
default: [],
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
function HasteDependencyResolver(options) {
|
function HasteDependencyResolver(options) {
|
||||||
|
@ -51,11 +54,12 @@ function HasteDependencyResolver(options) {
|
||||||
|
|
||||||
this._depGraph = new DependencyGraph({
|
this._depGraph = new DependencyGraph({
|
||||||
roots: opts.projectRoots,
|
roots: opts.projectRoots,
|
||||||
|
assetRoots: opts.assetRoots,
|
||||||
ignoreFilePath: function(filepath) {
|
ignoreFilePath: function(filepath) {
|
||||||
return filepath.indexOf('__tests__') !== -1 ||
|
return filepath.indexOf('__tests__') !== -1 ||
|
||||||
(opts.blacklistRE && opts.blacklistRE.test(filepath));
|
(opts.blacklistRE && opts.blacklistRE.test(filepath));
|
||||||
},
|
},
|
||||||
fileWatcher: this._fileWatcher
|
fileWatcher: this._fileWatcher,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -40,6 +40,11 @@ describe('Packager', function() {
|
||||||
var modules = [
|
var modules = [
|
||||||
{id: 'foo', path: '/root/foo.js', dependencies: []},
|
{id: 'foo', path: '/root/foo.js', dependencies: []},
|
||||||
{id: 'bar', path: '/root/bar.js', dependencies: []},
|
{id: 'bar', path: '/root/bar.js', dependencies: []},
|
||||||
|
{ id: 'image!img',
|
||||||
|
path: '/root/img/img.png',
|
||||||
|
isAsset: true,
|
||||||
|
dependencies: [],
|
||||||
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
getDependencies.mockImpl(function() {
|
getDependencies.mockImpl(function() {
|
||||||
|
@ -74,6 +79,15 @@ describe('Packager', function() {
|
||||||
'source /root/bar.js',
|
'source /root/bar.js',
|
||||||
'/root/bar.js'
|
'/root/bar.js'
|
||||||
]);
|
]);
|
||||||
|
expect(p.addModule.mock.calls[2]).toEqual([
|
||||||
|
'lol module.exports = ' +
|
||||||
|
JSON.stringify({ uri: 'img', isStatic: true}) +
|
||||||
|
'; lol',
|
||||||
|
'module.exports = ' +
|
||||||
|
JSON.stringify({ uri: 'img', isStatic: true}) +
|
||||||
|
';',
|
||||||
|
'/root/img/img.png'
|
||||||
|
]);
|
||||||
|
|
||||||
expect(p.finalize.mock.calls[0]).toEqual([
|
expect(p.finalize.mock.calls[0]).toEqual([
|
||||||
{runMainModule: true}
|
{runMainModule: true}
|
||||||
|
|
|
@ -44,6 +44,10 @@ var validateOpts = declareOpts({
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
|
assetRoots: {
|
||||||
|
type: 'array',
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
function Packager(options) {
|
function Packager(options) {
|
||||||
|
@ -56,7 +60,8 @@ function Packager(options) {
|
||||||
blacklistRE: opts.blacklistRE,
|
blacklistRE: opts.blacklistRE,
|
||||||
polyfillModuleNames: opts.polyfillModuleNames,
|
polyfillModuleNames: opts.polyfillModuleNames,
|
||||||
nonPersistent: opts.nonPersistent,
|
nonPersistent: opts.nonPersistent,
|
||||||
moduleFormat: opts.moduleFormat
|
moduleFormat: opts.moduleFormat,
|
||||||
|
assetRoots: opts.assetRoots,
|
||||||
});
|
});
|
||||||
|
|
||||||
this._transformer = new Transformer({
|
this._transformer = new Transformer({
|
||||||
|
@ -118,10 +123,18 @@ Packager.prototype.getDependencies = function(main, isDev) {
|
||||||
};
|
};
|
||||||
|
|
||||||
Packager.prototype._transformModule = function(module) {
|
Packager.prototype._transformModule = function(module) {
|
||||||
var resolver = this._resolver;
|
var transform;
|
||||||
return this._transformer.loadFileAndTransform(
|
|
||||||
|
if (module.isAsset) {
|
||||||
|
transform = q(generateAssetModule(module));
|
||||||
|
} else {
|
||||||
|
transform = this._transformer.loadFileAndTransform(
|
||||||
path.resolve(module.path)
|
path.resolve(module.path)
|
||||||
).then(function(transformed) {
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
var resolver = this._resolver;
|
||||||
|
return transform.then(function(transformed) {
|
||||||
return _.extend(
|
return _.extend(
|
||||||
{},
|
{},
|
||||||
transformed,
|
transformed,
|
||||||
|
@ -140,5 +153,17 @@ Packager.prototype.getGraphDebugInfo = function() {
|
||||||
return this._resolver.getDebugInfo();
|
return this._resolver.getDebugInfo();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function generateAssetModule(module) {
|
||||||
|
var code = 'module.exports = ' + JSON.stringify({
|
||||||
|
uri: module.id.replace(/^[^!]+!/, ''),
|
||||||
|
isStatic: true,
|
||||||
|
}) + ';';
|
||||||
|
|
||||||
|
return {
|
||||||
|
code: code,
|
||||||
|
sourceCode: code,
|
||||||
|
sourcePath: module.path,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = Packager;
|
module.exports = Packager;
|
||||||
|
|
|
@ -43,6 +43,10 @@ var validateOpts = declareOpts({
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
|
assetRoots: {
|
||||||
|
type: 'array',
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
function Server(options) {
|
function Server(options) {
|
||||||
|
|
Loading…
Reference in New Issue