Fix hot code push client-side reloads.

We were overwriting the server directory when a client-side file changed,
which made all process calls fail, such as process.cwd() and fs.*. We
abstracted out some of the builder code so that only the client targets
are "rebuilt" when a client side file changes.
This commit is contained in:
Matthew Arbesfeld
2014-07-25 17:16:37 -07:00
parent 3aff2199cc
commit 55fe8a8aae
3 changed files with 80 additions and 58 deletions

View File

@@ -1452,6 +1452,27 @@ var writeFile = function (file, builder) {
builder.write(file.targetPath, { data: file.contents() });
};
// Writes a target a path in 'programs'
var writeTargetToPath = function (name, target, outputPath, options) {
var builder = new Builder({
outputPath: path.join(outputPath, 'programs', name),
symlink: options.includeNodeModulesSymlink
});
var relControlFilePath =
target.write(builder, {
includeNodeModulesSymlink: options.includeNodeModulesSymlink,
getRelativeTargetPath: options.getRelativeTargetPath });
builder.complete();
return {
name: name,
arch: target.mostCompatibleArch(),
path: path.join('programs', name, relControlFilePath)
};
};
///////////////////////////////////////////////////////////////////////////////
// writeSiteArchive
///////////////////////////////////////////////////////////////////////////////
@@ -1495,51 +1516,6 @@ var writeSiteArchive = function (targets, outputPath, options) {
meteorRelease: options.releaseName
};
// Pick a path in the bundle for each target
var paths = {};
_.each(targets, function (target, name) {
var p = path.join('programs', name);
builder.reserve(p, { directory: true });
paths[name] = p;
});
// Hack to let servers find relative paths to clients. Should find
// another solution eventually (probably some kind of mount
// directive that mounts the client bundle in the server at runtime)
var getRelativeTargetPath = function (options) {
var pathForTarget = function (target) {
var name;
_.each(targets, function (t, n) {
if (t === target)
name = n;
});
if (! name)
throw new Error("missing target?");
if (! (name in paths))
throw new Error("missing target path?");
return paths[name];
};
return path.relative(pathForTarget(options.relativeTo),
pathForTarget(options.forTarget));
};
// Write out each target
_.each(targets, function (target, name) {
var relControlFilePath =
target.write(builder.enter(paths[name]), {
includeNodeModulesSymlink: options.includeNodeModulesSymlink,
getRelativeTargetPath: getRelativeTargetPath });
json.programs.push({
name: name,
arch: target.mostCompatibleArch(),
path: path.join(paths[name], relControlFilePath)
});
});
// Tell Galaxy what version of the dependency kit we're using, so
// it can load the right modules. (Include this even if we copied
// or symlinked a node_modules, since that's probably enough for
@@ -1589,6 +1565,10 @@ var writeSiteArchive = function (targets, outputPath, options) {
}
});
_.each(targets, function (target, name) {
json.programs.push(writeTargetToPath(name, target, builder.buildPath, options));
});
// We did it!
builder.complete();
@@ -1750,9 +1730,11 @@ exports.bundle = function (options) {
targets.client = client;
// Server
var server = options.cachedServerTarget || makeServerTarget(app, client);
server.clientTarget = client;
targets.server = server;
if (! options.hasCachedBundle) {
var server = makeServerTarget(app, client);
server.clientTarget = client;
targets.server = server;
}
}
// Pick up any additional targets in /programs
@@ -1902,15 +1884,47 @@ exports.bundle = function (options) {
if (! (controlProgram in targets))
controlProgram = undefined;
// Hack to let servers find relative paths to clients. Should find
// another solution eventually (probably some kind of mount
// directive that mounts the client bundle in the server at runtime)
var getRelativeTargetPath = function (options) {
var pathForTarget = function (target) {
var name;
_.each(targets, function (t, n) {
if (t === target)
name = n;
});
if (! name)
throw new Error("missing target?");
return path.join('programs', name);
};
return path.relative(pathForTarget(options.relativeTo),
pathForTarget(options.forTarget));
};
// Write to disk
starResult = writeSiteArchive(targets, outputPath, {
var writeOptions = {
includeNodeModulesSymlink: includeNodeModulesSymlink,
builtBy: builtBy,
controlProgram: controlProgram,
releaseName: releaseName
});
serverWatchSet.merge(starResult.serverWatchSet);
clientWatchSet.merge(starResult.clientWatchSet);
releaseName: releaseName,
getRelativeTargetPath: getRelativeTargetPath
};
if (options.hasCachedBundle) {
// XXX If we already have a cached bundle, just recreate the new targets.
// This might make the contents of "star.json" out of date.
_.each(targets, function (target, name) {
writeTargetToPath(name, target, outputPath, options);
clientWatchSet.merge(target.getWatchSet());
});
} else {
starResult = writeSiteArchive(targets, outputPath, writeOptions);
serverWatchSet.merge(starResult.serverWatchSet);
clientWatchSet.merge(starResult.clientWatchSet);
}
success = true;
});
@@ -1922,8 +1936,7 @@ exports.bundle = function (options) {
errors: success ? false : messages,
serverWatchSet: serverWatchSet,
clientWatchSet: clientWatchSet,
starManifest: starResult && starResult.starManifest,
serverTarget: targets.server
starManifest: starResult && starResult.starManifest
};
};

View File

@@ -423,7 +423,7 @@ _.extend(AppRunner.prototype, {
// Cache the server target because the server will not change inside
// a single invocation of _runOnce().
var cachedServerTarget = null;
var cachedBundle;
var bundleApp = function () {
if (! self.firstRun)
packageCache.packageCache.refresh(true); // pick up changes to packages
@@ -432,10 +432,17 @@ _.extend(AppRunner.prototype, {
outputPath: bundlePath,
includeNodeModulesSymlink: true,
buildOptions: self.buildOptions,
cachedServerTarget: cachedServerTarget
hasCachedBundle: !! cachedBundle
});
cachedServerTarget = bundle.serverTarget;
// Overwrite the null elements in the new bundle with the elements from
// the cached bundle. However, we make sure to keep the serverWatchSet
// from the original cached bundle.
if (cachedBundle) {
bundle.serverWatchSet = cachedBundle.serverWatchSet;
}
cachedBundle = _.defaults(bundle, cachedBundle);
return bundle;
};

View File

@@ -9,6 +9,8 @@ if (Meteor.isServer) {
Meteor.methods({
clientLoad: function (jsVar) {
// Make sure that the process still has the correct working directories.
process.cwd();
console.log("client connected: " + clientConnections++);
console.log("jsVar: " + jsVar);
}