Skip to content
Permalink
Browse files

feat: verbose logging option (#465)

* refactor: async/await in core

* refactor: safer removal of changed dependencies

Instead of blindly removing all dependencies of the changed file (including all of *their* dependents) now the code will check the dependencies first and only remove ones that actually changed. This speeds things up some and also solves a few issues we were seeing with files that were both in dependency chains AND used directly by another JS file.

I'll try to write a test for that later, it won't be simple.

* chore: package updates
  • Loading branch information...
tivac committed Aug 9, 2018
1 parent 3824f41 commit 5238ade7fadb0b4a0a79cec94113249b7057a72b
@@ -4,6 +4,10 @@ module.exports = {
restoreMocks : true,
notify : true,

// Work around JsDOM security issue
// https://github.com/facebook/jest/issues/6766
testURL : "http://localhost/",

coveragePathIgnorePatterns : [
"/node_modules/",
"/parsers/",

Large diffs are not rendered by default.

Oops, something went wrong.
@@ -24,25 +24,25 @@
"@tivac/eslint-config": "^2.2.1",
"browserify": "^16.2.0",
"cli-tester": "^2.0.0",
"cssnano": "^4.0.3",
"cssnano": "^4.0.5",
"dedent": "^0.7.0",
"dentist": "^1.0.3",
"eslint": "^5.2.0",
"eslint": "^5.3.0",
"eslint-plugin-jest": "^21.18.0",
"factor-bundle": "^2.5.0",
"from2-string": "^1.1.0",
"jest": "^23.4.1",
"jest-cli": "^23.4.1",
"lerna": "^3.0.0-beta.21",
"jest": "^23.4.2",
"jest-cli": "^23.4.2",
"lerna": "^3.0.0-rc.0",
"modular-css-core": "file:./packages/core",
"pegjs": "^0.10.0",
"rollup": "^0.63.4",
"rollup": "^0.63.5",
"rollup-plugin-svelte": "^4.2.1",
"shelljs": "^0.8.1",
"svelte": "^2.9.7",
"svelte": "^2.9.11",
"test-utils": "file:./packages/test-utils",
"watchify": "^3.9.0",
"webpack": "^4.16.2"
"webpack": "^4.16.5"
},
"lint-staged": {
"*.js": [
@@ -43,6 +43,7 @@ function Processor(opts) {
cwd : process.cwd(),
map : false,
rewrite : true,
verbose : false,
},
opts
);
@@ -64,6 +65,12 @@ function Processor(opts) {
this._options.resolvers = [];
}

this._log = this._options.verbose ?
// eslint-disable-next-line no-console
console.log.bind(console, "[processor]") :
// eslint-disable-next-line no-empty-function
() => {};

this._resolve = resolve.resolvers(this._options.resolvers);

this._absolute = (file) => (path.isAbsolute(file) ? file : path.join(this._options.cwd, file));
@@ -107,56 +114,68 @@ Processor.prototype = {
file = path.join(this._options.cwd, file);
}

this._log("file()", file);

return this.string(path.normalize(file), fs.readFileSync(file, "utf8"));
},

// Add a file by name + contents to the dependency graph
string(start, text) {
async string(start, text) {
if(!path.isAbsolute(start)) {
start = path.join(this._options.cwd, start);
}

return this._walk(start, text).then(() => {
var deps = this._graph.dependenciesOf(start).concat(start);
this._log("string()", start);

await this._walk(start, text);

const deps = this._graph.dependenciesOf(start).concat(start);

await series(deps, async (dep) => {
var file = this._files[dep];

if(!file.processed) {
this._log("processing", dep);

file.processed = this._process.process(
file.result,
params(this, {
from : dep,
namer : this._options.namer,
})
);
}

const result = await file.processed;

this._log("processed", dep);

return series(deps, (dep) => {
var file = this._files[dep];
file.result = result;

file.exports = Object.assign(
Object.create(null),
// export @value entries
mapValues(file.values, (obj) => obj.value),

if(!file.processed) {
file.processed = this._process.process(
file.result,
params(this, {
from : dep,
namer : this._options.namer,
})
);
}
// export classes
message(result, "classes"),

return file.processed.then((result) => {
file.exports = Object.assign(
Object.create(null),
// export @value entries
mapValues(file.values, (obj) => obj.value),

// export classes
message(result, "classes"),

// Export anything from plugins named "modular-css-export*"
result.messages
.filter((msg) => msg.plugin.indexOf("modular-css-export") === 0)
.reduce((prev, curr) => Object.assign(prev, curr.exports), Object.create(null))
);
file.result = result;
});
});
})
.then(() => ({
// Export anything from plugins named "modular-css-export*"
result.messages
.filter((msg) => msg.plugin.indexOf("modular-css-export") === 0)
.reduce((prev, curr) => Object.assign(prev, curr.exports), Object.create(null))
);
});

this._log("string() done", start);

return {
id : start,
file : start,
files : this._files,
details : this._files[start],
exports : this._files[start].exports,
}));
};
},

// Remove a file from the dependency graph
@@ -174,6 +193,8 @@ Processor.prototype = {
delete this._files[file];

this._graph.removeNode(file);

this._log("remove()", file);
});

return files;
@@ -202,7 +223,7 @@ Processor.prototype = {
},

// Get the ultimate output for specific files or the entire tree
output(args) {
async output(args) {
var opts = args || false,
{ files } = opts,
ready;
@@ -228,7 +249,7 @@ Processor.prototype = {
// Rewrite relative URLs before adding
// Have to do this every time because target file might be different!
//
return Promise.all(
const results = await Promise.all(
files.map((dep) => this._after.process(
// NOTE: the call to .clone() is really important here, otherwise this call
// modifies the .result root itself and you process URLs multiple times
@@ -241,58 +262,56 @@ Processor.prototype = {
to : opts.to,
})
))
)
.then((results) => {
// Clone the first result if available to get valid source information
var root = results.length ? results[0].root.clone() : postcss.root();

// Then destroy all its children before adding new ones
root.removeAll();

results.forEach((result) => {
// Add file path comment
var comment = postcss.comment({
text : relative(this._options.cwd, result.opts.from),

// Add a bogus-ish source property so postcss won't make weird-looking
// source-maps that break the visualizer
//
// https://github.com/postcss/postcss/releases/tag/5.1.0
// https://github.com/postcss/postcss/pull/761
// https://github.com/tivac/modular-css/pull/157
//
source : Object.assign(
{},
result.root.source,
{ end : result.root.source.start }
),
}),
idx;

root.append([ comment ].concat(result.root.nodes));

idx = root.index(comment);

// Need to manually insert a newline after the comment, but can only
// do that via whatever comes after it for some reason?
// I'm not clear why comment nodes lack a `.raws.after` property
//
// https://github.com/postcss/postcss/issues/44
if(root.nodes[idx + 1]) {
root.nodes[idx + 1].raws.before = "\n";
}
});
);

// Clone the first result if available to get valid source information
const root = results.length ? results[0].root.clone() : postcss.root();

// Then destroy all its children before adding new ones
root.removeAll();

results.forEach((result) => {
// Add file path comment
var comment = postcss.comment({
text : relative(this._options.cwd, result.opts.from),

// Add a bogus-ish source property so postcss won't make weird-looking
// source-maps that break the visualizer
//
// https://github.com/postcss/postcss/releases/tag/5.1.0
// https://github.com/postcss/postcss/pull/761
// https://github.com/tivac/modular-css/pull/157
//
source : Object.assign(
{},
result.root.source,
{ end : result.root.source.start }
),
}),
idx;

root.append([ comment ].concat(result.root.nodes));

return this._done.process(
root,
params(this, args)
);
})
.then((result) => {
result.compositions = output.compositions(this._options.cwd, this);
idx = root.index(comment);

return result;
// Need to manually insert a newline after the comment, but can only
// do that via whatever comes after it for some reason?
// I'm not clear why comment nodes lack a `.raws.after` property
//
// https://github.com/postcss/postcss/issues/44
if(root.nodes[idx + 1]) {
root.nodes[idx + 1].raws.before = "\n";
}
});

const result = await this._done.process(
root,
params(this, args)
);

result.compositions = output.compositions(this._options.cwd, this);

return result;
},

// Expose files
@@ -307,7 +326,7 @@ Processor.prototype = {

// Process files and walk their composition/value dependency tree to find
// new files we need to process
_walk(name, text) {
async _walk(name, text) {
// No need to re-process files
if(this._files[name]) {
return Promise.resolve();
@@ -321,25 +340,24 @@ Processor.prototype = {
values : false,
};

return this._before.process(
const result = await this._before.process(
text,
params(this, {
from : name,
})
)
.then((result) => {
this._files[name].result = result;

// Walk this node's dependencies, reading new files from disk as necessary
return Promise.all(
this._graph.dependenciesOf(name).map((dependency) => this._walk(
dependency,
this._files[dependency] ?
null :
fs.readFileSync(dependency, "utf8")
))
);
});
);

this._files[name].result = result;

// Walk this node's dependencies, reading new files from disk as necessary
await Promise.all(
this._graph.dependenciesOf(name).map((dependency) => this._walk(
dependency,
this._files[dependency] ?
null :
fs.readFileSync(dependency, "utf8")
))
);
},
};

Oops, something went wrong.

0 comments on commit 5238ade

Please sign in to comment.
You can’t perform that action at this time.