Don't create new var scope for js files in client/compatibility/

This commit is contained in:
Avital Oliver
2013-04-23 15:58:40 -07:00
parent 37bc8491b8
commit fb61e884db
4 changed files with 35 additions and 9 deletions

View File

@@ -43,6 +43,12 @@ client. It minifies this bundle and serves it to each new client.
You're free to use a single JavaScript file for your entire application, or
create a nested tree of separate files, or anything in between.
Some JavaScript libraries only work when placed in the
`client/compatibility` subdirectory. Files in this directory are
executed without being wrapped in a new variable scope. This means
that each top-level `var` defines a global variable. In addition,
these files are executed before other client-side JavaScript files.
Files outside the `client`, `server` and `tests` subdirectories are loaded on
both the client and the server! That's the place for model definitions and
other functions. Meteor provides the variables [`isClient`](#meteor_isclient) and

View File

@@ -6,12 +6,13 @@ Package.describe({
});
Package.register_extension(
"js", function (bundle, source_path, serve_path, where) {
"js", function (bundle, source_path, serve_path, where, opt) {
bundle.add_resource({
type: "js",
path: serve_path,
source_file: source_path,
where: where
where: where,
compatibility: opt.compatibility
});
}
);

View File

@@ -115,7 +115,7 @@ var PackageBundlingInfo = function (pkg, bundle) {
});
},
add_files: function (paths, where) {
add_files: function (paths, where, opt) {
if (!(paths instanceof Array))
paths = paths ? [paths] : [];
if (!(where instanceof Array))
@@ -123,7 +123,7 @@ var PackageBundlingInfo = function (pkg, bundle) {
_.each(where, function (w) {
_.each(paths, function (rel_path) {
self.add_file(rel_path, w);
self.add_file(rel_path, w, opt);
});
});
},
@@ -188,8 +188,11 @@ _.extend(PackageBundlingInfo.prototype, {
return candidates[0];
},
add_file: function (rel_path, where) {
// opt {Object}
// - compatibility {Boolean} In case this is a JS file, don't wrap in a closure.
add_file: function (rel_path, where, opt) {
var self = this;
opt = opt || {};
if (self.files[where][rel_path])
return;
@@ -210,7 +213,8 @@ _.extend(PackageBundlingInfo.prototype, {
handler(self.bundle.api,
sourcePath,
path.join(self.pkg.serve_root, rel_path),
where);
where,
opt);
} else {
// If we don't have an extension handler, serve this file
// as a static resource.
@@ -302,6 +306,10 @@ var Bundle = function () {
*
* data: the data to send. overrides source_file if present. you
* must still set path (except for "head" and "body".)
*
* compatibility: (only for js files) when set, don't wrap code in
* a closure. used for client-side javascript libraries that use
* the `function foo()` or `var foo =` syntax to define globals.
*/
add_resource: function (options) {
var source_file = options.source_file || options.path;
@@ -337,11 +345,16 @@ var Bundle = function () {
// scope (eg, file-level vars are file-scoped). On the server, this
// is done in server/server.js to inject the Npm symbol.
//
// Some client-side Javascript libraries define globals with `var foo =` or
// `function bar()` which only work if loaded directly from a script tag. If
// `options.compatibility` is set, don't wrap in a closure to enable using
// such libraries.
//
// The ".call(this)" allows you to do a top-level "this.foo = "
// to define global variables when using "use strict"
// (http://es5.github.io/#x15.3.4.4); this is the only way to do
// it in CoffeeScript.
if (w === "client") {
if (w === "client" && !options.compatibility) {
wrapped = Buffer.concat([
new Buffer("(function(){ "),
data,
@@ -673,7 +686,7 @@ _.extend(Bundle.prototype, {
contents = self.files.client[file];
delete self.files.client[file];
self.files.client_cacheable[file] = contents;
url = file + '?' + sha1(contents)
url = file + '?' + sha1(contents);
}
else
throw new Error('unable to find file: ' + file);

View File

@@ -238,7 +238,13 @@ _.extend(Package.prototype, {
api.use(project.get_packages(app_dir));
// -- Source files --
api.add_files(sources_except(api, "server"), "client");
var inCompatibilityMode = function (filename) {
return filename.indexOf(path.sep + 'client' + path.sep + 'compatibility' + path.sep) !== -1;
};
var clientFiles = sources_except(api, "server");
api.add_files(_.filter(clientFiles, inCompatibilityMode), "client", {compatibility: true});
api.add_files(_.reject(clientFiles, inCompatibilityMode), "client");
api.add_files(sources_except(api, "client"), "server");
});