Write (but don't use) sourceMaps (but not sources) for client programs.

Add builder.writeToGeneratedFilename helper and use it a lot.
This commit is contained in:
David Glasser
2013-07-09 10:42:25 -07:00
parent 5b8e1c17f3
commit f786fd6fa5
3 changed files with 96 additions and 61 deletions

View File

@@ -272,6 +272,19 @@ _.extend(Builder.prototype, {
return relPath;
},
// Convenience wrapper around generateFilename and write.
//
// (Note that in the object returned by builder.enter, this method
// is patched through directly rather than rewriting its inputs and
// outputs. This is only valid because it does nothing with its inputs
// and outputs other than send pass them to other methods.)
writeToGeneratedFilename: function (relPath, writeOptions) {
var self = this;
var generated = self.generateFilename(relPath);
self.write(generated, writeOptions);
return generated;
},
// Recursively copy a directory and all of its contents into the
// bundle. But if the symlink option was passed to the Builder
// constructor, then make a symlink instead, if possible.
@@ -377,11 +390,11 @@ _.extend(Builder.prototype, {
var self = this;
var methods = ["write", "writeJson", "reserve", "generateFilename",
"copyDirectory", "enter"];
var ret = {};
var subBuilder = {};
var relPathWithSep = relPath + path.sep;
_.each(methods, function (method) {
ret[method] = function (/* arguments */) {
subBuilder[method] = function (/* arguments */) {
var args = _.toArray(arguments);
if (method !== "copyDirectory") {
@@ -412,7 +425,14 @@ _.extend(Builder.prototype, {
};
});
return ret;
// Methods that don't have to fix up arguments or return values, because
// they are implemented purely in terms of other methods which do.
var passThroughMethods = ["writeToGeneratedFilename"];
_.each(passThroughMethods, function (method) {
subBuilder[method] = self[method];
});
return subBuilder;
},
// Move the completed bundle into its final location (outputPath)

View File

@@ -70,6 +70,8 @@
// parameter when used
// - size: size of file in bytes
// - hash: sha1 hash of the file contents
// - sourceMap: optional path to source map file (relative to program.json)
// - sources: same as in native format (see below)
// Additionally there will be an entry with where equal to
// "internal", path equal to page (above), and hash equal to the
// sha1 of page (before replacements.) Currently this is used to
@@ -200,6 +202,13 @@ var rejectBadPath = function (p) {
throw new Error("bad path: " + p);
};
var stripLeadingSlash = function (p) {
if (p.charAt(0) !== '/')
throw new Error("bad path: " + p);
return p.slice(1);
};
///////////////////////////////////////////////////////////////////////////////
// NodeModulesDirectory
///////////////////////////////////////////////////////////////////////////////
@@ -643,9 +652,7 @@ _.extend(Target.prototype, {
if (resource.type === "static")
relPath = path.join("static", resource.servePath);
else {
if (resource.servePath.charAt(0) !== '/')
throw new Error("bad servePath: " + resource.servePath);
relPath = resource.servePath.slice(1);
relPath = stripLeadingSlash(resource.servePath);
}
f.setTargetPathFromRelPath(relPath);
if (resource.type === "js")
@@ -868,26 +875,50 @@ _.extend(ClientTarget.prototype, {
// the target
write: function (builder) {
var self = this;
var manifest = [];
builder.reserve("program.json");
builder.reserve("app.html");
// Resources served via HTTP
_.each(["js", "css", "static"], function (type) {
_.each(self[type], function (file) {
writeFile(file, builder);
manifest.push({
path: file.targetPath,
where: "client",
type: type,
cacheable: file.cacheable,
url: file.url,
size: file.size(),
hash: file.hash()
// Helper to iterate over all resources that we serve over HTTP.
var eachResource = function (f) {
_.each(["js", "css", "static"], function (type) {
_.each(self[type], function (file) {
f(file, type);
});
});
};
// Reserve all file names from the manifest, so that interleaved
// generateFilename calls don't overlap with them.
eachResource(function (file, type) {
builder.reserve(file.targetPath);
});
// Build up a manifest of all resources served via HTTP.
var manifest = [];
eachResource(function (file, type) {
writeFile(file, builder);
var manifestItem = {
path: file.targetPath,
where: "client",
type: type,
cacheable: file.cacheable,
url: file.url,
size: file.size(),
hash: file.hash()
};
if (file.sourceMap) {
manifestItem.sourceMap = builder.writeToGeneratedFilename(
stripLeadingSlash(file.targetPath + '.map'), {
data: new Buffer(file.sourceMap.toString(), 'utf8')
});
// XXX write sources too
}
manifest.push(manifestItem);
});
// HTML boilerplate (the HTML served to make the client load the
@@ -1078,8 +1109,9 @@ _.extend(JsImage.prototype, {
if (! item.targetPath)
throw new Error("No targetPath?");
var loadPath = builder.generateFilename(item.targetPath);
builder.write(loadPath, { data: new Buffer(item.source, 'utf8') });
var loadPath = builder.writeToGeneratedFilename(
item.targetPath,
{ data: new Buffer(item.source, 'utf8') });
var loadItem = {
path: loadPath,
node_modules: item.nodeModulesDirectory ?
@@ -1089,26 +1121,22 @@ _.extend(JsImage.prototype, {
};
if (item.sourceMap) {
// XXX this code is very similar to saveAsUnipackage.
// Write the source map.
var mapFilename = builder.generateFilename(item.targetPath + '.map');
loadItem.sourceMap = mapFilename;
builder.write(mapFilename, {
data: new Buffer(item.sourceMap.toString(), 'utf8')
});
// XXX this code is very similar to saveAsUnipackage.
loadItem.sourceMap = builder.writeToGeneratedFilename(
item.targetPath + '.map',
{ data: new Buffer(item.sourceMap.toString(), 'utf8') }
);
// Now write the sources themselves.
loadItem.sources = {};
_.each(item.sources, function (x, pathForSourceMap) {
var savedFilename = builder.generateFilename(
path.join('sources', pathForSourceMap));
builder.write(savedFilename, {
data: x.source
});
loadItem.sources[pathForSourceMap] = {
package: x.package,
sourcePath: x.sourcePath,
source: savedFilename
source: builder.writeToGeneratedFilename(
path.join('sources', pathForSourceMap),
{ data: x.source })
};
});
}

View File

@@ -2065,13 +2065,11 @@ _.extend(Package.prototype, {
if (_.contains(["head", "body"], resource.type))
return; // already did this one
var resourcePath = builder.generateFilename(
path.join(sliceDir, resource.servePath));
builder.write(resourcePath, { data: resource.data });
sliceJson.resources.push({
type: resource.type,
file: resourcePath,
file: builder.writeToGeneratedFilename(
path.join(sliceDir, resource.servePath),
{ data: resource.data }),
length: resource.data.length,
offset: 0,
servePath: resource.servePath || undefined
@@ -2080,17 +2078,11 @@ _.extend(Package.prototype, {
// Output prelink resources
_.each(slice.prelinkFiles, function (file) {
var resourcePath = builder.generateFilename(
path.join(sliceDir, file.servePath));
var data = new Buffer(file.source, 'utf8');
builder.write(resourcePath, {
data: data
});
var resource = {
type: 'prelink',
file: resourcePath,
file: builder.writeToGeneratedFilename(
path.join(sliceDir, file.servePath),
{ data: new Buffer(file.source, 'utf8') }),
length: data.length,
offset: 0,
servePath: file.servePath || undefined
@@ -2098,25 +2090,20 @@ _.extend(Package.prototype, {
if (file.sourceMap) {
// Write the source map.
var mapFilename = builder.generateFilename(
path.join(sliceDir, file.servePath + '.map'));
resource.sourceMap = mapFilename;
builder.write(mapFilename, {
data: new Buffer(file.sourceMap.toString(), 'utf8')
});
resource.sourceMap = builder.writeToGeneratedFilename(
path.join(sliceDir, file.servePath + '.map'),
{ data: new Buffer(file.sourceMap.toString(), 'utf8') }
);
// Now write the sources themselves.
resource.sources = {};
_.each(file.sources, function (x, pathForSourceMap) {
var savedFilename = builder.generateFilename(
path.join(sliceDir, 'sources', x.sourcePath));
builder.write(savedFilename, {
data: x.source
});
resource.sources[pathForSourceMap] = {
package: x.package,
sourcePath: x.sourcePath,
source: savedFilename
source: builder.writeToGeneratedFilename(
path.join(sliceDir, 'sources', x.sourcePath),
{ data: x.source })
};
});
}