Skip to content

Do not use global cache #115

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
May 18, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ b.on('css stream', function (css) {
- `generateScopedName`: (API only) a function to override the default behaviour of creating locally scoped classnames.
- `global`: optional boolean. Set to `true` if you want `css-modulesify` to apply to `node_modules` as well as local files. You can read more about it in the [browserify docs](https://github.com/substack/node-browserify/#btransformtr-opts).
- `filePattern`: optional regular expression string to specify css file names. (default: `\.css$`)
- `cache`: optional object to persist cache between runs.

### Events
- `b.on('css stream', callback)` The callback is called with a readable stream containing the compiled CSS. You can write this to a file.
Expand Down
77 changes: 65 additions & 12 deletions cmify.js
Original file line number Diff line number Diff line change
@@ -1,34 +1,87 @@
var stream = require("stream");
var path = require("path");
var util = require("util");
var stream = require('stream');
var util = require('util');
var assign = require('object-assign');
var path = require('path');

util.inherits(Cmify, stream.Transform);
function Cmify(filename, opts) {
function Cmify (filename, opts) {
if (!(this instanceof Cmify)) {
return new Cmify(filename, opts);
}

stream.Transform.call(this);

this.cssFilePattern = new RegExp(opts.cssFilePattern || '\.css$');
this._data = "";
this._data = '';
this._filename = filename;
this._cssOutFilename = opts.cssOutFilename;
this._loader = opts.loader;
this._tokensByFile = opts.tokensByFile;
this._rootDir = opts.rootDir;
opts.cssFiles.push(filename);
}

Cmify.prototype.isCssFile = function (filename) {
return this.cssFilePattern.test(filename)
}
return this.cssFilePattern.test(filename);
};

Cmify.prototype._transform = function (buf, enc, callback) {
// only handle .css files
if (!this.isCssFile(this._filename)) {
this.push(buf)
return callback()
this.push(buf);
return callback();
}

this._data += buf
callback()
this._data += buf;
callback();
};

Cmify.prototype._flush = function (callback) {
var self = this;
var filename = this._filename;

// only handle .css files
if (!this.isCssFile(filename)) { return callback(); }

// grab the correct loader
var loader = this._loader;
var tokensByFile = this._tokensByFile;

// convert css to js before pushing
// reset the `tokensByFile` state
var relFilename = path.relative(this._rootDir, filename);
tokensByFile[filename] = loader.tokensByFile[filename] = null;

loader.fetch(relFilename, '/').then(function (tokens) {
var deps = loader.deps.dependenciesOf(filename);
var output = deps.map(function (f) {
return 'require("' + f + '")';
});
output.push('module.exports = ' + JSON.stringify(tokens));

var isValid = true;
var isUndefined = /\bundefined\b/;
Object.keys(tokens).forEach(function (k) {
if (isUndefined.test(tokens[k])) {
isValid = false;
}
});

if (!isValid) {
var err = 'Composition in ' + filename + ' contains an undefined reference';
console.error(err);
output.push('console.error("' + err + '");');
}

assign(tokensByFile, loader.tokensByFile);

self.push(output.join('\n'));
return callback();
}).catch(function (err) {
self.push('console.error("' + err + '");');
self.emit('error', err);
return callback();
});
};

module.exports = Cmify
module.exports = Cmify;
125 changes: 46 additions & 79 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ var path = require('path');
var Cmify = require('./cmify');
var Core = require('css-modules-loader-core');
var FileSystemLoader = require('./file-system-loader');
var assign = require('object-assign');
var stringHash = require('string-hash');
var ReadableStream = require('stream').Readable;
var through = require('through2');
Expand Down Expand Up @@ -75,35 +74,8 @@ function normalizeManifestPaths (tokensByFile, rootDir) {
return output;
}

// caches
//
// persist these for as long as the process is running. #32

// keep track of all tokens so we can avoid duplicates
var tokensByFile = {};

// we need a separate loader for each entry point
var loadersByFile = {};

module.exports = function (browserify, options) {
options = options || {};

// if no root directory is specified, assume the cwd
var rootDir = options.rootDir || options.d || browserify._options.basedir;
if (rootDir) { rootDir = path.resolve(rootDir); }
if (!rootDir) { rootDir = process.cwd(); }

var transformOpts = {};
if (options.global || options.g) {
transformOpts.global = true;
}

var cssOutFilename = options.output || options.o;
var jsonOutFilename = options.json || options.jsonOutput;
transformOpts.cssOutFilename = cssOutFilename;
transformOpts.cssFilePattern = options.filePattern;

// PostCSS plugins passed to FileSystemLoader
// PostCSS plugins passed to FileSystemLoader
function getPlugins (options) {
var plugins = options.use || options.u;
if (!plugins) {
plugins = getDefaultPlugins(options);
Expand All @@ -119,7 +91,7 @@ module.exports = function (browserify, options) {
plugins = (Array.isArray(postcssBefore) ? postcssBefore : [postcssBefore]).concat(plugins).concat(postcssAfter);

// load plugins by name (if a string is used)
plugins = plugins.map(function requirePlugin (name) {
return plugins.map(function requirePlugin (name) {
// assume not strings are already required plugins
if (typeof name !== 'string') {
return name;
Expand All @@ -144,58 +116,54 @@ module.exports = function (browserify, options) {

return plugin;
});
}

// create a loader for this entry file
if (!loadersByFile[cssOutFilename]) {
loadersByFile[cssOutFilename] = new FileSystemLoader(rootDir, plugins);
module.exports = function (browserify, options) {
options = options || {};

// if no root directory is specified, assume the cwd
var rootDir = options.rootDir || options.d || browserify._options.basedir;
if (rootDir) {
rootDir = path.resolve(rootDir);
}
if (!rootDir) {
rootDir = process.cwd();
}

// TODO: clean this up so there's less scope crossing
Cmify.prototype._flush = function (callback) {
var self = this;
var filename = this._filename;

// only handle .css files
if (!this.isCssFile(filename)) { return callback(); }

// grab the correct loader
var loader = loadersByFile[this._cssOutFilename];

// convert css to js before pushing
// reset the `tokensByFile` cache
var relFilename = path.relative(rootDir, filename);
tokensByFile[filename] = loader.tokensByFile[filename] = null;

loader.fetch(relFilename, '/').then(function (tokens) {
var deps = loader.deps.dependenciesOf(filename);
var output = deps.map(function (f) {
return 'require("' + f + '")';
});
output.push('module.exports = ' + JSON.stringify(tokens));

var isValid = true;
var isUndefined = /\bundefined\b/;
Object.keys(tokens).forEach(function (k) {
if (isUndefined.test(tokens[k])) {
isValid = false;
}
});

if (!isValid) {
var err = 'Composition in ' + filename + ' contains an undefined reference';
console.error(err);
output.push('console.error("' + err + '");');
}
var cssOutFilename = options.output || options.o;
var jsonOutFilename = options.json || options.jsonOutput;
var loader;
// keep track of all tokens so we can avoid duplicates
var tokensByFile;
if (options.cache) {
if (options.cache.loaders) {
loader = options.cache.loaders[cssOutFilename];
} else {
options.cache.loaders = {};
}
if (options.cache.tokens) {
tokensByFile = options.cache.tokens;
} else {
options.cache.tokens = {};
}
}

assign(tokensByFile, loader.tokensByFile);
loader = loader || new FileSystemLoader(rootDir, getPlugins(options));
tokensByFile = tokensByFile || {};

self.push(output.join('\n'));
return callback();
}).catch(function (err) {
self.push('console.error("' + err + '");');
self.emit('error', err);
return callback();
});
if (options.cache) {
options.cache.loaders[cssOutFilename] = loader;
options.cache.tokens = tokensByFile;
}

var transformOpts = {
cssFilePattern: options.filePattern
, cssFiles: []
, cssOutFilename: cssOutFilename
, global: options.global || options.g
, loader: loader
, rootDir: rootDir
, tokensByFile: tokensByFile
};

browserify.transform(Cmify, transformOpts);
Expand All @@ -214,7 +182,6 @@ module.exports = function (browserify, options) {

// Combine the collected sources for a single bundle into a single CSS file
var self = this;
var loader = loadersByFile[cssOutFilename];
var css = loader.finalSource;

// end the output stream
Expand Down
2 changes: 2 additions & 0 deletions tests/cache.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ tape('multiple builds', function (t) {
fs: fakeFs
});

var cssModulesifyCache = {};
var getBundler = rebundler(function (cache, packageCache) {
return browserify(path.join(simpleCaseDir, 'main.js'), {
cache: cache
Expand All @@ -34,6 +35,7 @@ tape('multiple builds', function (t) {
.plugin(cssModulesify, {
rootDir: path.join(simpleCaseDir)
, output: cssOutFilename
, cache: cssModulesifyCache
});
});

Expand Down
10 changes: 5 additions & 5 deletions tests/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@ var cssOutFilename = 'out.css';
function runTestCase (dir) {
tape('case: ' + dir, function (t) {
// load (optional) custom setup for this testcase
var customPath = path.join(casesDir, dir, 'custom.js')
var customOpts
var customPath = path.join(casesDir, dir, 'custom.js');
var customOpts;
try {
fs.accessSync(customPath)
customOpts = require(customPath)
fs.accessSync(customPath);
customOpts = require(customPath);
} catch (e) {
customOpts = {}
customOpts = {};
}

var fakeFs = {
Expand Down