gerald-react-scripts-fork
Version:
Gerald's fork of the configuration and scripts for Create React App.
173 lines (153 loc) • 5.55 kB
JavaScript
var loaderUtils = require('loader-utils');
var stylus = require('stylus');
var path = require('path');
var fs = require('fs');
var when = require('when');
var whenNodefn = require('when/node/function');
var CachedPathEvaluator = require('./lib/evaluator');
var PathCache = require('./lib/pathcache');
var resolver = require('./lib/resolver');
var globalImportsCaches = {};
module.exports = function(source) {
var self = this;
this.cacheable && this.cacheable();
var done = this.async();
var options = loaderUtils.parseQuery(this.query);
options.dest = options.dest || '';
options.filename = options.filename || this.resourcePath;
options.Evaluator = CachedPathEvaluator;
var configKey = options.config || 'stylus';
var stylusOptions = this.options[configKey] || {};
// Instead of assigning to options, we run them manually later so their side effects apply earlier for
// resolving paths.
var use = options.use || stylusOptions.use || [];
options.import = options.import || stylusOptions.import || [];
options.include = options.include || stylusOptions.include || [];
options.set = options.set || stylusOptions.set || {};
options.define = options.define || stylusOptions.define || {};
if (options.sourceMap != null) {
options.sourcemap = options.sourceMap;
delete options.sourceMap;
}
else if (this.sourceMap) {
options.sourcemap = { comment: false };
}
var styl = stylus(source, options);
var paths = [path.dirname(options.filename)];
function needsArray(value) {
return (Array.isArray(value)) ? value : [value];
}
if (options.paths && !Array.isArray(options.paths)) {
paths = paths.concat(options.paths);
options.paths = [options.paths];
}
var manualImports = [];
Object.keys(options).forEach(function(key) {
var value = options[key];
if (key === 'use') {
needsArray(value).forEach(function(plugin) {
if (typeof plugin === 'function') {
styl.use(plugin);
} else {
throw new Error('Plugin should be a function');
}
});
} else if (key === 'set') {
for (var name in value) {
styl.set(name, value[name]);
}
} else if (key === 'define') {
for (var defineName in value) {
styl.define(defineName, value[defineName]);
}
} else if (key === 'include') {
needsArray(value).forEach(styl.include.bind(styl));
} else if (key === 'import') {
needsArray(value).forEach(function(stylusModule) {
manualImports.push(stylusModule);
});
} else {
styl.set(key, value);
if (key === 'resolve url' && value) {
styl.define('url', resolver());
}
}
});
var shouldCacheImports = stylusOptions.importsCache !== false;
var importsCache;
if (stylusOptions.importsCache !== false) {
if (typeof stylusOptions.importsCache === 'object') {
importsCache = stylusOptions.importsCache;
} else {
if(!globalImportsCaches[configKey]) globalImportsCaches[configKey] = {};
importsCache = globalImportsCaches[configKey];
}
}
// Use input file system's readFile if available. The normal webpack input
// file system is cached with entries purged when they are detected to be
// changed on disk by the watcher.
var readFile;
try {
var inputFileSystem = this._compiler.inputFileSystem;
readFile = inputFileSystem.readFile.bind(inputFileSystem);
} catch (error) {
readFile = fs.readFile;
}
var boundResolvers = PathCache.resolvers(options, this.resolve);
var pathCacheHelpers = {
resolvers: boundResolvers,
readFile: readFile,
};
// Use plugins here so that resolve related side effects can be used while we resolve imports.
(Array.isArray(use) ? use : [use]).forEach(styl.use, styl);
when
// Resolve manual imports like @import files.
.reduce(manualImports, function resolveManualImports(carry, filename) {
return PathCache.resolvers
.reduce(boundResolvers, path.dirname(options.filename), filename)
.then(function(paths) { return carry.concat(paths); });
}, [])
// Resolve dependencies of
.then(function(paths) {
paths.forEach(styl.import.bind(styl));
paths.forEach(self.addDependency);
var readFile = whenNodefn.lift(pathCacheHelpers.readFile);
return when.reduce(paths, function(cache, filepath) {
return readFile(filepath)
.then(function(source) {
return PathCache.createFromFile(
pathCacheHelpers, cache, source.toString(), filepath
);
});
}, {
contexts: {},
sources: {},
imports: importsCache,
});
})
.then(function(cache) {
return PathCache
.createFromFile(pathCacheHelpers, cache, source, options.filename);
})
.then(function(importPathCache) {
// CachedPathEvaluator will use this PathCache to find its dependencies.
options.cache = importPathCache;
importPathCache.allDeps().forEach(function(f) {
self.addDependency(path.normalize(f));
});
// var paths = importPathCache.origins;
styl.render(function(err, css) {
if (err) {
done(err);
} else {
if (styl.sourcemap) {
styl.sourcemap.sourcesContent = styl.sourcemap.sources.map(function (file) {
return importPathCache.sources[path.resolve(file)]
});
}
done(null, css, styl.sourcemap);
}
});
})
.catch(done);
};