Skip to content
This repository has been archived by the owner on Mar 6, 2024. It is now read-only.

Commit

Permalink
More loader context support and some refactors
Browse files Browse the repository at this point in the history
- this.request
- this.context
- this.resourceQuery
- this.loaderIndex
  • Loading branch information
amireh committed Mar 27, 2016
1 parent eb4634f commit e0ac462
Show file tree
Hide file tree
Showing 9 changed files with 116 additions and 37 deletions.
23 changes: 16 additions & 7 deletions lib/HappyFakeLoaderContext.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
function HappyFakeLoaderContext(source, sourcePath, query, options) {
function HappyFakeLoaderContext() {
if (!(this instanceof HappyFakeLoaderContext)) {
return new HappyFakeLoaderContext(source, sourcePath);
return new HappyFakeLoaderContext();
}

// for compiler RPCs, like this.resolve()
Expand All @@ -9,14 +9,19 @@ function HappyFakeLoaderContext(source, sourcePath, query, options) {
// for loader RPCs, like this.emitWarning()
this._remoteLoaderId = null;

this.resource = sourcePath;
this.resourcePath = sourcePath;
this.request = sourcePath;
this.request = null;
this.query = null;

this.context = null;
this.resource = null;
this.resourcePath = null;
this.resourceQuery = null;

this.data = {};
this.loaders = [{}];
this.loaderIndex = 0;
this.options = options;
this.query = query || '';

this.options = null;
this.result = null;

return this;
Expand All @@ -32,6 +37,10 @@ HappyFakeLoaderContext.prototype.async = function() {
return this.callback.bind(this);
};

HappyFakeLoaderContext.prototype.exec = function() {
throw new Error("loaderContext.exec is not supported");
};

HappyFakeLoaderContext.prototype.emitWarning = function(message) {
this._compiler._sendMessage('emitWarning', {
remoteLoaderId: this._remoteLoaderId,
Expand Down
7 changes: 6 additions & 1 deletion lib/HappyLoader.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,14 @@ function HappyLoader(inSource, inSourceMap) {

this.happy.compile(inSource, inSourceMap, {
remoteLoaderId: id,

// TODO: maybe too much data being pushed down the drain here? we can infer
// all of this from `this.request`
context: this.context,
request: this.request,
resource: this.resource,
resourcePath: this.resourcePath,
loaders: this.loaders,
resourceQuery: this.resourceQuery,
}, function(err, code, map) {
HappyRPCHandler.unregisterActiveLoader(id);

Expand Down
4 changes: 2 additions & 2 deletions lib/HappyPlugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ HappyPlugin.prototype.compileInBackground = function(source, map, loaderContext,

this.cache.invalidateEntryFor(filePath);

this.threadPool.getThread().compile(filePath, loaderContext, function(result) {
this.threadPool.getThread().compile(loaderContext, function(result) {
var contents = fs.readFileSync(result.compiledPath, 'utf-8')

if (!result.success) {
Expand All @@ -260,7 +260,7 @@ HappyPlugin.prototype.compileInForeground = function(source, map, loaderContext,
// successful version (if any)
this.cache.invalidateEntryFor(filePath);

WebpackUtils.applyLoaders(runContext, source, map, filePath, function(err, result) {
WebpackUtils.applyLoaders(runContext, source, map, function(err, result) {
if (err) {
return done(err);
}
Expand Down
3 changes: 2 additions & 1 deletion lib/HappyThread.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,8 @@ function HappyThread(threadId, config) {
},
};

function compile(filePath, loaderContext, done) {
function compile(loaderContext, done) {
var filePath = loaderContext.resourcePath;
assert(!!fd, "You must launch a compilation thread before attemping to use it!!!");

callbacks.on(filePath, done);
Expand Down
4 changes: 2 additions & 2 deletions lib/HappyWorker.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ HappyWorker.prototype.compile = function(params, done) {
"Bad message; expected @compiledPath to contain path to the compiled file!"
);

var sourcePath = params.sourcePath;
var sourcePath = params.loaderContext.resourcePath;
var compiledPath = params.compiledPath;
var success = false;
var source = fs.readFileSync(sourcePath, 'utf-8');
Expand All @@ -34,7 +34,7 @@ HappyWorker.prototype.compile = function(params, done) {
loaders: this.options.loaders,
loaderContext: params.loaderContext,
compilerOptions: this.options.compilerOptions
}, source, null, sourcePath, function(err, result) {
}, source, null, function(err, result) {
if (err) {
console.error(err);
fs.writeFileSync(compiledPath, serializeError(err), 'utf-8');
Expand Down
2 changes: 1 addition & 1 deletion lib/__tests__/HappyThread.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ describe("HappyThread", function() {
subject.open(function(openError) {
if (openError) return done(openError);

subject.compile(inputFile.getPath(), {}, function(result) {
subject.compile({ resourcePath: inputFile.getPath() }, function(result) {
assert.equal(result.error, undefined);
assert.equal(fs.readFileSync(result.compiledPath, 'utf-8'), 'hehe');

Expand Down
8 changes: 7 additions & 1 deletion lib/__tests__/HappyWorkerChannel.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,10 @@ describe('HappyWorkerChannel', function() {
fd.local.send({
name: 'COMPILE',
sourcePath: fixturePath('a.js'),
compiledPath: tempPath('a.out')
compiledPath: tempPath('a.out'),
loaderContext: {
resourcePath: fixturePath('a.js')
}
});
});

Expand All @@ -52,6 +55,9 @@ describe('HappyWorkerChannel', function() {
name: 'COMPILE',
sourcePath: fixturePath('a.js'),
compiledPath: tempPath('a.out'),
loaderContext: {
resourcePath: fixturePath('a.js')
}
});
});
});
Expand Down
30 changes: 24 additions & 6 deletions lib/__tests__/applyLoaders.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,10 @@ describe("applyLoaders", function() {
this.callback(null, source, map);
});

Subject({ loaders }, 'hello!', null, './a.js', done);
Subject({
loaders,
loaderContext: { resourcePath: './a.js' }
}, 'hello!', null, done);
});

it('passes the source code to the loader', function() {
Expand All @@ -58,7 +61,10 @@ describe("applyLoaders", function() {
return source + '5';
});

Subject({ loaders: FIXTURES.singleLoader }, 'hello!', null, './a.js', function(err, result) {
Subject({
loaders: FIXTURES.singleLoader,
loaderContext: { resourcePath: './a.js' }
}, 'hello!', null, function(err, result) {
assert.equal(result.code, 'hello!5');
done();
});
Expand All @@ -70,7 +76,10 @@ describe("applyLoaders", function() {
});

it('propagates it', function(done) {
Subject({ loaders: FIXTURES.singleLoader }, 'hello!', null, './a.js', function(err) {
Subject({
loaders: FIXTURES.singleLoader,
loaderContext: { resourcePath: './a.js' }
}, 'hello!', null, function(err) {
assert.equal(err, 'teehee!');
done();
});
Expand All @@ -85,7 +94,10 @@ describe("applyLoaders", function() {
});

it('propagates it', function(done) {
Subject({ loaders: FIXTURES.singleLoader }, 'hello!', null, './a.js', function(err) {
Subject({
loaders: FIXTURES.singleLoader,
loaderContext: { resourcePath: './a.js' }
}, 'hello!', null, function(err) {
assert.equal(err, 'teehee!');
done();
});
Expand All @@ -106,7 +118,10 @@ describe("applyLoaders", function() {
sandbox.spy(AnotherLoader, '__impl__');
sandbox.spy(IdentityLoader, '__impl__');

Subject({ loaders }, 'hello!', null, 'a.js', function(err, result) {
Subject({
loaders,
loaderContext: { resourcePath: './a.js' }
}, 'hello!', null, function(err, result) {
assert.calledWith(AnotherLoader.__impl__, 'hello!');
assert.calledWith(IdentityLoader.__impl__, 'hello!5');

Expand All @@ -121,7 +136,10 @@ describe("applyLoaders", function() {
sandbox.stub(AnotherLoader, '__impl__', () => { throw 'teehee!' });
sandbox.spy(IdentityLoader, '__impl__');

Subject({ loaders }, fixture('a.js'), null, 'a.js', function(err) {
Subject({
loaders,
loaderContext: { resourcePath: './a.js' }
}, fixture('a.js'), null, function(err) {
assert.called(AnotherLoader.__impl__);
assert.notCalled(IdentityLoader.__impl__);

Expand Down
72 changes: 56 additions & 16 deletions lib/applyLoaders.js
Original file line number Diff line number Diff line change
@@ -1,41 +1,81 @@
var HappyFakeLoaderContext = require('./HappyFakeLoaderContext');

module.exports = function(runContext, source, inputSourceMap, sourcePath, done) {
/**
* @param {Object} runContext
* @param {HappyFakeCompiler} runContext.compiler
* @param {Array.<Object>} runContext.loaders
* @param {Object} runContext.loaderContext
*
* @param {String} runContext.loaderContext.remoteLoaderId
* The ID of the HappyLoader instance that initiated this compilation
* request.
*
* @param {String} runContext.loaderContext.request
* The full request for the resource including the loader chain string.
* Something like:
* '/path/to/style-loader.js!/path/to/css-loader.js!/path/to/resource.css'
*
* @param {String} runContext.loaderContext.context
* The directory of the resource, useful for resolving siblings.
*
* @param {String} runContext.loaderContext.resource
* The resource path without the loader chain.
*
* @param {String} runContext.loaderContext.resourcePath
* The resource path without the query fragment.
*
* @param {String} runContext.loaderContext.resourceQuery
* The query fragment of the resource path.
*
* @param {Object} runContext.compilerOptions
*
* @param {String} sourceCode
* @param {String} sourceMap
* @param {Function} done
*/
module.exports = function(runContext, sourceCode, sourceMap, done) {
var cursor = 0;
var result = { code: source, map: inputSourceMap };
var loaders = runContext.loaders;
var loaderContext = runContext.loaderContext || {};
var result = { code: sourceCode, map: sourceMap };

if (process.env.VERBOSE) {
console.log('applying %d loaders (%s) against %s', loaders.length,
JSON.stringify(
loaders
), sourcePath);
console.log('applying %d loaders (%s) against %s',
runContext.loaders.length,
JSON.stringify(runContext.loaders),
runContext.loaderContext.resourcePath
);
}

function apply() {
var loader = loaders[cursor++];
var loader = runContext.loaders[cursor++];

if (!loader) {
return done(null, result);
}

// TODO: this is probably not the best place to create the context, and it
// also should be cached at some layer
var context = new HappyFakeLoaderContext(source, sourcePath);
var context = new HappyFakeLoaderContext(runContext.loaderContext.resourcePath);
var transform = require(loader.path);

context._compiler = runContext.compiler; // for compiler RPCs
context._remoteLoaderId = loaderContext.remoteLoaderId; // for loader RPCs
context._remoteLoaderId = runContext.loaderContext.remoteLoaderId; // for loader RPCs
context.query = loader.query;
context.options = runContext.compilerOptions;
context.context = loaderContext.context;

context.request = runContext.loaderContext.request;
context.resource = runContext.loaderContext.resource;
context.resourcePath = runContext.loaderContext.resourcePath;
context.resourceQuery = runContext.loaderContext.resourceQuery;
context.context = runContext.loaderContext.context;

context.loaders = runContext.loaders;
context.loaderIndex = cursor - 1;

if (transform.pitch) {
throw new Error('pitch loaders are not supported!')
}

applyAsync(transform, context, [ result.code, result.map ], acceptResultAndApplyNext);
applySyncOrAsync(transform, context, result, acceptResultAndApplyNext);
}

function acceptResultAndApplyNext(err, code, map) {
Expand All @@ -52,13 +92,13 @@ module.exports = function(runContext, source, inputSourceMap, sourcePath, done)
process.nextTick(apply);
}

function applyAsync(fn, context, args, done) {
function applySyncOrAsync(fn, context, previousResult, done) {
// sync/async this.callback() style
context.callback = done;

try {
// synchronus return style
var result = fn.apply(context, args);
var result = fn.call(context, previousResult.code, previousResult.map);

if (result) {
done(null, result);
Expand All @@ -83,7 +123,7 @@ function applyAsync(fn, context, args, done) {
// var data = {};
// var remainingRequest =

// applyAsync(transform.pitch, context, [ remainingRequest, precedingRequest, data ], function(err) {
// applySyncOrAsync(transform.pitch, context, [ remainingRequest, precedingRequest, data ], function(err) {
// if (err) {
// return done(err);
// }
Expand Down

0 comments on commit e0ac462

Please sign in to comment.