From fb61e884dbf4fa3edde6895385fac58339bf78b8 Mon Sep 17 00:00:00 2001 From: Avital Oliver Date: Tue, 23 Apr 2013 15:58:40 -0700 Subject: [PATCH 1/4] Don't create new var scope for js files in client/compatibility/ --- docs/client/concepts.html | 6 ++++++ packages/meteor/package.js | 5 +++-- tools/bundler.js | 25 +++++++++++++++++++------ tools/packages.js | 8 +++++++- 4 files changed, 35 insertions(+), 9 deletions(-) diff --git a/docs/client/concepts.html b/docs/client/concepts.html index cd26c5ef26..49c02bcfed 100644 --- a/docs/client/concepts.html +++ b/docs/client/concepts.html @@ -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 diff --git a/packages/meteor/package.js b/packages/meteor/package.js index dafe07c090..01946c1b9d 100644 --- a/packages/meteor/package.js +++ b/packages/meteor/package.js @@ -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 }); } ); diff --git a/tools/bundler.js b/tools/bundler.js index 5dbab04c24..c0f51ab055 100644 --- a/tools/bundler.js +++ b/tools/bundler.js @@ -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); diff --git a/tools/packages.js b/tools/packages.js index 8e98150976..4930b52f0f 100644 --- a/tools/packages.js +++ b/tools/packages.js @@ -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"); }); From 47ba95dfc4a0848c77d1a562d7c1f404e3de8657 Mon Sep 17 00:00:00 2001 From: Avital Oliver Date: Thu, 25 Apr 2013 10:58:27 -0700 Subject: [PATCH 2/4] wrapping --- tools/bundler.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tools/bundler.js b/tools/bundler.js index c0f51ab055..c9a7029260 100644 --- a/tools/bundler.js +++ b/tools/bundler.js @@ -345,10 +345,11 @@ 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. + // 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" From 4a32bb81f3d59195f9e52ba31fa4f97d307c164c Mon Sep 17 00:00:00 2001 From: Avital Oliver Date: Thu, 25 Apr 2013 13:47:03 -0700 Subject: [PATCH 3/4] options.compatibility -> options.raw --- packages/meteor/package.js | 2 +- tools/bundler.js | 8 ++++---- tools/packages.js | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/meteor/package.js b/packages/meteor/package.js index 01946c1b9d..805adff618 100644 --- a/packages/meteor/package.js +++ b/packages/meteor/package.js @@ -12,7 +12,7 @@ Package.register_extension( path: serve_path, source_file: source_path, where: where, - compatibility: opt.compatibility + raw: opt.raw }); } ); diff --git a/tools/bundler.js b/tools/bundler.js index c9a7029260..ae2de8d43b 100644 --- a/tools/bundler.js +++ b/tools/bundler.js @@ -189,7 +189,7 @@ _.extend(PackageBundlingInfo.prototype, { }, // opt {Object} - // - compatibility {Boolean} In case this is a JS file, don't wrap in a closure. + // - raw {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 || {}; @@ -307,7 +307,7 @@ 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 + * raw: (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. */ @@ -348,14 +348,14 @@ var Bundle = function () { // 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 + // `options.raw` 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" && !options.compatibility) { + if (w === "client" && !options.raw) { wrapped = Buffer.concat([ new Buffer("(function(){ "), data, diff --git a/tools/packages.js b/tools/packages.js index 4930b52f0f..8678652c88 100644 --- a/tools/packages.js +++ b/tools/packages.js @@ -238,12 +238,12 @@ _.extend(Package.prototype, { api.use(project.get_packages(app_dir)); // -- Source files -- - var inCompatibilityMode = function (filename) { + var shouldLoadRaw = 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(_.filter(clientFiles, shouldLoadRaw), "client", {raw: true}); + api.add_files(_.reject(clientFiles, shouldLoadRaw), "client"); api.add_files(sources_except(api, "client"), "server"); }); From c9e9c73da70d606716216216fea6220c12aa465e Mon Sep 17 00:00:00 2001 From: Avital Oliver Date: Thu, 25 Apr 2013 13:47:55 -0700 Subject: [PATCH 4/4] Update History.md --- History.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/History.md b/History.md index 5a26e1f5a1..2efcaa2549 100644 --- a/History.md +++ b/History.md @@ -1,6 +1,9 @@ ## vNEXT +* Files in the 'client/compatibility/' subdirectory of a Meteor app do + not get wrapped in a new variable scope. + * With `autopublish` on, publish many useful fields on `Meteor.users`. * When using the `http` package on the server synchronously, errors