[react-packager] Implement image loading i.e. ix('img') -> require('image!img');
This commit is contained in:
parent
435cc98b34
commit
9249545047
|
@ -22,6 +22,8 @@ function ModuleDescriptor(fields) {
|
|||
|
||||
this.isPolyfill = fields.isPolyfill || false;
|
||||
|
||||
this.isAsset = fields.isAsset || false;
|
||||
|
||||
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() {
|
||||
var root = '/root';
|
||||
fs.__setMockFilesystem({
|
||||
|
|
|
@ -28,12 +28,22 @@ var validateOpts = declareOpts({
|
|||
type: 'object',
|
||||
required: true,
|
||||
},
|
||||
assetRoots: {
|
||||
type: 'array',
|
||||
default: [],
|
||||
},
|
||||
assetExts: {
|
||||
type: 'array',
|
||||
default: ['png'],
|
||||
}
|
||||
});
|
||||
|
||||
function DependecyGraph(options) {
|
||||
var opts = validateOpts(options);
|
||||
|
||||
this._roots = opts.roots;
|
||||
this._assetRoots = opts.assetRoots;
|
||||
this._assetExts = opts.assetExts;
|
||||
this._ignoreFilePath = opts.ignoreFilePath;
|
||||
this._fileWatcher = options.fileWatcher;
|
||||
|
||||
|
@ -50,7 +60,16 @@ function DependecyGraph(options) {
|
|||
}
|
||||
|
||||
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,
|
||||
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;
|
||||
|
||||
// Package relative modules starts with '.' or '..'.
|
||||
|
@ -214,32 +242,13 @@ DependecyGraph.prototype._search = function() {
|
|||
// 2. Filter the files and queue up the directories.
|
||||
// 3. Process any package.json in the files
|
||||
// 4. recur.
|
||||
return readDir(dir)
|
||||
.then(function(files){
|
||||
return q.all(files.map(function(filePath) {
|
||||
return realpath(path.join(dir, filePath)).catch(handleBrokenLink);
|
||||
}));
|
||||
})
|
||||
.then(function(filePaths) {
|
||||
filePaths = filePaths.filter(function(filePath) {
|
||||
if (filePath == null) {
|
||||
return readAndStatDir(dir)
|
||||
.spread(function(files, stats) {
|
||||
var modulePaths = files.filter(function(filePath, i) {
|
||||
if (self._ignoreFilePath(filePath)) {
|
||||
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()) {
|
||||
self._queue.push(filePath);
|
||||
return false;
|
||||
|
@ -465,6 +474,19 @@ DependecyGraph.prototype._getAbsolutePath = function(filePath) {
|
|||
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.
|
||||
*/
|
||||
|
@ -511,4 +533,70 @@ function handleBrokenLink(e) {
|
|||
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;
|
||||
|
|
|
@ -17,7 +17,6 @@ var DEFINE_MODULE_CODE = [
|
|||
].join('');
|
||||
|
||||
var DEFINE_MODULE_REPLACE_RE = /_moduleName_|_code_|_deps_/g;
|
||||
|
||||
var REL_REQUIRE_STMT = /require\(['"]([\.\/0-9A-Z_$\-]*)['"]\)/gi;
|
||||
|
||||
var validateOpts = declareOpts({
|
||||
|
@ -40,6 +39,10 @@ var validateOpts = declareOpts({
|
|||
type: 'string',
|
||||
default: 'haste',
|
||||
},
|
||||
assetRoots: {
|
||||
type: 'array',
|
||||
default: [],
|
||||
},
|
||||
});
|
||||
|
||||
function HasteDependencyResolver(options) {
|
||||
|
@ -51,11 +54,12 @@ function HasteDependencyResolver(options) {
|
|||
|
||||
this._depGraph = new DependencyGraph({
|
||||
roots: opts.projectRoots,
|
||||
assetRoots: opts.assetRoots,
|
||||
ignoreFilePath: function(filepath) {
|
||||
return filepath.indexOf('__tests__') !== -1 ||
|
||||
(opts.blacklistRE && opts.blacklistRE.test(filepath));
|
||||
},
|
||||
fileWatcher: this._fileWatcher
|
||||
fileWatcher: this._fileWatcher,
|
||||
});
|
||||
|
||||
|
||||
|
|
|
@ -40,6 +40,11 @@ describe('Packager', function() {
|
|||
var modules = [
|
||||
{id: 'foo', path: '/root/foo.js', dependencies: []},
|
||||
{id: 'bar', path: '/root/bar.js', dependencies: []},
|
||||
{ id: 'image!img',
|
||||
path: '/root/img/img.png',
|
||||
isAsset: true,
|
||||
dependencies: [],
|
||||
}
|
||||
];
|
||||
|
||||
getDependencies.mockImpl(function() {
|
||||
|
@ -74,6 +79,15 @@ describe('Packager', function() {
|
|||
'source /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([
|
||||
{runMainModule: true}
|
||||
|
|
|
@ -44,6 +44,10 @@ var validateOpts = declareOpts({
|
|||
type: 'boolean',
|
||||
default: false,
|
||||
},
|
||||
assetRoots: {
|
||||
type: 'array',
|
||||
required: false,
|
||||
},
|
||||
});
|
||||
|
||||
function Packager(options) {
|
||||
|
@ -56,7 +60,8 @@ function Packager(options) {
|
|||
blacklistRE: opts.blacklistRE,
|
||||
polyfillModuleNames: opts.polyfillModuleNames,
|
||||
nonPersistent: opts.nonPersistent,
|
||||
moduleFormat: opts.moduleFormat
|
||||
moduleFormat: opts.moduleFormat,
|
||||
assetRoots: opts.assetRoots,
|
||||
});
|
||||
|
||||
this._transformer = new Transformer({
|
||||
|
@ -118,10 +123,18 @@ Packager.prototype.getDependencies = function(main, isDev) {
|
|||
};
|
||||
|
||||
Packager.prototype._transformModule = function(module) {
|
||||
var transform;
|
||||
|
||||
if (module.isAsset) {
|
||||
transform = q(generateAssetModule(module));
|
||||
} else {
|
||||
transform = this._transformer.loadFileAndTransform(
|
||||
path.resolve(module.path)
|
||||
);
|
||||
}
|
||||
|
||||
var resolver = this._resolver;
|
||||
return this._transformer.loadFileAndTransform(
|
||||
path.resolve(module.path)
|
||||
).then(function(transformed) {
|
||||
return transform.then(function(transformed) {
|
||||
return _.extend(
|
||||
{},
|
||||
transformed,
|
||||
|
@ -140,5 +153,17 @@ Packager.prototype.getGraphDebugInfo = function() {
|
|||
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;
|
||||
|
|
|
@ -43,6 +43,10 @@ var validateOpts = declareOpts({
|
|||
type: 'boolean',
|
||||
default: false,
|
||||
},
|
||||
assetRoots: {
|
||||
type: 'array',
|
||||
required: false,
|
||||
},
|
||||
});
|
||||
|
||||
function Server(options) {
|
||||
|
|
Loading…
Reference in New Issue