Skip to content

Commit 6d23efd

Browse files
fathybdevongovett
authored andcommitted
Warn instead of error when an fs call cannot be evaluated (#587)
1 parent fddfdb9 commit 6d23efd

6 files changed

Lines changed: 98 additions & 20 deletions

File tree

ā€Žsrc/Logger.jsā€Ž

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,16 @@ class Logger {
4444
this.write(this.chalk.bold(message), true);
4545
}
4646

47-
warn(message) {
47+
warn(err) {
4848
if (this.logLevel < 2) {
4949
return;
5050
}
5151

52+
let {message, stack} = prettyError(err, {color: this.color});
5253
this.write(this.chalk.yellow(`${emoji.warning} ${message}`));
54+
if (stack) {
55+
this.write(stack);
56+
}
5357
}
5458

5559
error(err) {

ā€Žsrc/WorkerFarm.jsā€Ž

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ class WorkerFarm extends Farm {
3939

4040
async initRemoteWorkers(options) {
4141
this.started = false;
42+
this.warmWorkers = 0;
4243

4344
let promises = [];
4445
for (let i = 0; i < this.options.maxConcurrentWorkers; i++) {
@@ -52,36 +53,40 @@ class WorkerFarm extends Farm {
5253
}
5354

5455
receive(data) {
55-
if (!this.children[data.child]) {
56-
// This handles premature death
57-
// normally only accurs for workers
58-
// that are still warming up when killed
59-
return;
60-
}
61-
6256
if (data.event) {
6357
this.emit(data.event, ...data.args);
6458
} else if (data.type === 'logger') {
65-
logger.handleMessage(data);
66-
} else {
59+
if (this.shouldUseRemoteWorkers()) {
60+
logger.handleMessage(data);
61+
}
62+
} else if (this.children[data.child]) {
6763
super.receive(data);
6864
}
6965
}
7066

67+
shouldUseRemoteWorkers() {
68+
return this.started && this.warmWorkers >= this.activeChildren;
69+
}
70+
7171
async run(...args) {
7272
// Child process workers are slow to start (~600ms).
7373
// While we're waiting, just run on the main thread.
7474
// This significantly speeds up startup time.
75-
if (this.started && this.warmWorkers >= this.activeChildren) {
75+
if (this.shouldUseRemoteWorkers()) {
7676
return this.remoteWorker.run(...args, false);
7777
} else {
7878
// Workers have started, but are not warmed up yet.
7979
// Send the job to a remote worker in the background,
8080
// but use the result from the local worker - it will be faster.
8181
if (this.started) {
82-
this.remoteWorker.run(...args, true).then(() => {
83-
this.warmWorkers++;
84-
});
82+
this.remoteWorker.run(...args, true).then(
83+
() => {
84+
this.warmWorkers++;
85+
},
86+
() => {
87+
// ignore error
88+
}
89+
);
8590
}
8691

8792
return this.localWorker.run(...args, false);

ā€Žsrc/visitors/fs.jsā€Ž

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ const t = require('babel-types');
22
const Path = require('path');
33
const fs = require('fs');
44
const template = require('babel-template');
5+
const logger = require('../Logger');
56

67
const bufferTemplate = template('Buffer(CONTENT, ENC)');
78

@@ -31,12 +32,32 @@ module.exports = {
3132
__dirname: Path.dirname(asset.name),
3233
__filename: asset.basename
3334
};
34-
let [filename, ...args] = path
35-
.get('arguments')
36-
.map(arg => evaluate(arg, vars));
37-
filename = Path.resolve(filename);
35+
let filename, args, res;
36+
37+
try {
38+
[filename, ...args] = path
39+
.get('arguments')
40+
.map(arg => evaluate(arg, vars));
41+
42+
filename = Path.resolve(filename);
43+
res = fs.readFileSync(filename, ...args);
44+
} catch (err) {
45+
if (err instanceof NodeNotEvaluatedError) {
46+
// Warn using a code frame
47+
err.fileName = asset.name;
48+
asset.generateErrorMessage(err);
49+
logger.warn(err);
50+
return;
51+
}
52+
53+
// Add location info so we log a code frame with the error
54+
err.loc =
55+
path.node.arguments.length > 0
56+
? path.node.arguments[0].loc.start
57+
: path.node.loc.start;
58+
throw err;
59+
}
3860

39-
let res = fs.readFileSync(filename, ...args);
4061
let replacementNode;
4162
if (Buffer.isBuffer(res)) {
4263
replacementNode = bufferTemplate({
@@ -153,6 +174,12 @@ function getBindingPath(path, name) {
153174
return binding && binding.path;
154175
}
155176

177+
function NodeNotEvaluatedError(node) {
178+
this.message = 'Cannot statically evaluate fs argument';
179+
this.node = node;
180+
this.loc = node.loc.start;
181+
}
182+
156183
function evaluate(path, vars) {
157184
// Inline variables
158185
path.traverse({
@@ -165,8 +192,9 @@ function evaluate(path, vars) {
165192
});
166193

167194
let res = path.evaluate();
195+
168196
if (!res.confident) {
169-
throw new Error('Could not statically evaluate fs call');
197+
throw new NodeNotEvaluatedError(path.node);
170198
}
171199

172200
return res.value;

ā€Žtest/fs.jsā€Ž

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,41 @@ describe('fs', function() {
7676
assert.equal(typeof output.test, 'function');
7777
assert.equal(output.test(), 'test-pkg-ignore-fs-ok');
7878
});
79+
80+
// TODO: check if the logger has warned the user
81+
it('should ignore fs calls when the filename is not evaluable', async function() {
82+
let b = await bundle(
83+
__dirname + '/integration/fs-file-non-evaluable/index.js'
84+
);
85+
let thrown = false;
86+
87+
try {
88+
run(b);
89+
} catch (e) {
90+
assert.equal(e.message, 'require(...).readFileSync is not a function');
91+
92+
thrown = true;
93+
}
94+
95+
assert.equal(thrown, true);
96+
});
97+
98+
it('should ignore fs calls when the options are not evaluable', async function() {
99+
let b = await bundle(
100+
__dirname + '/integration/fs-options-non-evaluable/index.js'
101+
);
102+
let thrown = false;
103+
104+
try {
105+
run(b);
106+
} catch (e) {
107+
assert.equal(e.message, 'require(...).readFileSync is not a function');
108+
109+
thrown = true;
110+
}
111+
112+
assert.equal(thrown, true);
113+
});
79114
});
80115

81116
describe('--target=node', function() {
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
module.exports = require('fs').readFileSync(Date.now())
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
const dir = __dirname
2+
3+
module.exports = require('fs').readFileSync(dir + '/test.txt', {
4+
encoding: (typeof Date.now()).replace(/number/, 'utf-8')
5+
})

0 commit comments

Comments
Ā (0)
⚔