| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221 |
- 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 cloneDeep = require('lodash.clonedeep');
- 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 = cloneDeep(loaderUtils.getOptions(this) || {});
- options.dest = options.dest || '';
- options.filename = options.filename || this.resourcePath;
- options.Evaluator = CachedPathEvaluator;
- var configKey, stylusOptions;
- if (this.stylus) {
- configKey = options.config || 'default';
- stylusOptions = this.stylus[configKey] || {};
- } else if (this.options) {
- configKey = options.config || 'stylus';
- stylusOptions = this.options[configKey] || {};
- } else {
- stylusOptions = {};
- }
- // 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 || {};
- options.paths = options.paths || stylusOptions.paths;
- 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);
- };
- var LoaderOptionsPlugin = require('webpack').LoaderOptionsPlugin;
- // Webpack 2 plugin for setting options that'll be available to stylus-loader.
- function OptionsPlugin(options) {
- if (!LoaderOptionsPlugin) {
- throw new Error(
- 'webpack.LoaderOptionPlugin is not available. A newer version of webpack is needed.'
- );
- }
- var stylusOptions = {};
- var test = options.test || /\.styl$/;
- var include = options.include;
- var exclude = options.exclude;
- var loaderOptions = {
- stylus: stylusOptions,
- };
- for (var key in options) {
- if (['test', 'include', 'exclude'].indexOf(key) === -1) {
- stylusOptions[key] = options[key];
- }
- }
- if (test) {
- loaderOptions.test = test;
- }
- if (include) {
- loaderOptions.include = include;
- }
- if (exclude) {
- loaderOptions.exclude = exclude;
- }
- this.plugin = new LoaderOptionsPlugin(loaderOptions);
- };
- module.exports.OptionsPlugin = OptionsPlugin;
- OptionsPlugin.prototype.apply = function(compiler) {
- this.plugin.apply(compiler);
- };
|