diff --git a/History.md b/History.md index 6f2ca1ce55..99af701950 100644 --- a/History.md +++ b/History.md @@ -1,17 +1,51 @@ ## v.NEXT -* The `accounts-facebook` and `facebook-oauth` packages have been updated to - use the v2.9 of the Facebook Graph API for the Login Dialog since the v2.2 - version will be deprecated by Facebook in July. There shouldn't be a problem - regardless since Facebook simply rolls over to the next active version - (v2.3, in this case) however this should assist in avoiding deprecation - warnings and should enable any new functionality which has become available. - [PR #8858](https://github.com/meteor/meteor/pull/8858) +## v1.5.1, 2017-07-12 -* `observe`/`observeChanges` callbacks are now bound using `Meteor.bindEnvironment`. - The same `EnvironmentVariable`s that were present when `observe`/`observeChanges` - was called are now available inside the callbacks. - [PR #8734](https://github.com/meteor/meteor/pull/8734) +* Node has been upgraded to version 4.8.4. + +* A new core Meteor package called `server-render` provides generic + support for server-side rendering of HTML, as described in the package's + [`README.md`](https://github.com/meteor/meteor/blob/release-1.5.1/packages/server-render/README.md). + [PR #8841](https://github.com/meteor/meteor/pull/8841) + +* To reduce the total number of file descriptors held open by the Meteor + build system, native file watchers will now be started only for files + that have changed at least once. This new policy means you may have to + [wait up to 5000ms](https://github.com/meteor/meteor/blob/6bde360b9c075f1c78c3850eadbdfa7fe271f396/tools/fs/safe-watcher.js#L20-L21) + for changes to be detected when you first edit a file, but thereafter + changes will be detected instantaneously. In return for that small + initial waiting time, the number of open file descriptors will now be + bounded roughly by the number of files you are actively editing, rather + than the number of files involved in the build (often thousands), which + should help with issues like + [#8648](https://github.com/meteor/meteor/issues/8648). If you need to + disable the new behavior for any reason, simply set the + `METEOR_WATCH_PRIORITIZE_CHANGED` environment variable to `"false"`, as + explained in [PR #8866](https://github.com/meteor/meteor/pull/8866). + +* All `observe` and `observeChanges` callbacks are now bound using + `Meteor.bindEnvironment`. The same `EnvironmentVariable`s that were + present when `observe` or `observeChanges` was called are now available + inside the callbacks. [PR #8734](https://github.com/meteor/meteor/pull/8734) + +* A subscription's `onReady` is now fired again during a re-subscription, even + if the subscription has the same arguments. Previously, when subscribing + to a publication the `onReady` would have only been called if the arguments + were different, creating a confusing difference in functionality. This may be + breaking behavior if an app uses the firing of `onReady` as an assumption + that the data was just received from the server. If such functionality is + still necessary, consider using + [`observe`](https://docs.meteor.com/api/collections.html#Mongo-Cursor-observe) + or + [`observeChanges`](https://docs.meteor.com/api/collections.html#Mongo-Cursor-observeChanges) + [PR #8754](https://github.com/meteor/meteor/pull/8754) + [Issue #1173](https://github.com/meteor/meteor/issues/1173) + +* The `minimongo` and `mongo` packages are now compliant with the upsert behavior + of MongoDB 2.6 and higher. **As a result support for MongoDB 2.4 has been dropped.** + This mainly changes the effect of the selector on newly inserted documents. + [PR #8815](https://github.com/meteor/meteor/pull/8815) * `reactive-dict` now supports setting initial data when defining a named `ReactiveDict`. No longer run migration logic when used on the server, @@ -26,6 +60,14 @@ proper domain in all applications. [PR #8760](https://github.com/meteor/meteor/issues/8760) +* The `accounts-facebook` and `facebook-oauth` packages have been updated to + use the v2.9 of the Facebook Graph API for the Login Dialog since the v2.2 + version will be deprecated by Facebook in July. There shouldn't be a problem + regardless since Facebook simply rolls over to the next active version + (v2.3, in this case) however this should assist in avoiding deprecation + warnings and should enable any new functionality which has become available. + [PR #8858](https://github.com/meteor/meteor/pull/8858) + * Add `DDP._CurrentPublicationInvocation` and `DDP._CurrentMethodInvocation`. `DDP._CurrentInvocation` remains for backwards-compatibility. This change allows method calls from publications to inherit the `connection` from the @@ -52,7 +94,14 @@ context and with its `EnvironmentVariable`s bound. [PR #8629](https://github.com/meteor/meteor/pull/8629) -* The `reify` npm package has been upgraded to version 0.11.22. +* The `minifier-js` package will now replace `process.env.NODE_ENV` with + its string value (or `"development"` if unspecified). + +* The `meteor-babel` npm package has been upgraded to version 0.22.0. + +* The `reify` npm package has been upgraded to version 0.11.24. + +* The `uglify-js` npm package has been upgraded to version 3.0.18. * Illegal characters in paths written in build output directories will now be replaced with `_`s rather than removed, so that file and directory @@ -61,7 +110,7 @@ * Additional "extra" packages (packages that aren't saved in `.meteor/packages`) can be included temporarily using the `--extra-packages` - option. For example: `meteor run --extra-packages "bundle-visualizer"`. + option. For example: `meteor run --extra-packages bundle-visualizer`. Both `meteor test` and `meteor test-packages` also support the `--extra-packages` option and commas separate multiple package names. [PR #8769](https://github.com/meteor/meteor/pull/8769) @@ -72,6 +121,22 @@ * The `coffeescript` package has been updated to use CoffeeScript version 1.12.6. [PR #8777](https://github.com/meteor/meteor/pull/8777) +* It's now possible to pipe a series of statements to `meteor shell`, + whereas previously the input had to be an expression; for example: + ```sh + > echo 'import pkg from "babel-runtime/package.json"; + quote> pkg.version' | + pipe> meteor shell + "6.23.0" + ``` + [Issue #8823](https://github.com/meteor/meteor/issues/8823) + [PR #8833](https://github.com/meteor/meteor/pull/8833) + +* Any `Error` thrown by a DDP method with the `error.isClientSafe` + property set to `true` will now be serialized and displayed to the + client, whereas previously only `Meteor.Error` objects were considered + client-safe. [PR #8756](https://github.com/meteor/meteor/pull/8756) + ## v1.5, 2017-05-30 * The `meteor-base` package implies a new `dynamic-import` package, which diff --git a/meteor b/meteor index 1314849223..ef8749df65 100755 --- a/meteor +++ b/meteor @@ -1,6 +1,6 @@ #!/usr/bin/env bash -BUNDLE_VERSION=4.8.18 +BUNDLE_VERSION=4.8.21 # OS Check. Put here because here is where we download the precompiled # bundles that are arch specific. @@ -132,4 +132,7 @@ fi # the script take precedence over $NODE_PATH; it used to be that users would # screw up their meteor installs by have a ~/node_modules -exec "$DEV_BUNDLE/bin/node" ${TOOL_NODE_FLAGS} "$METEOR" "$@" +exec "$DEV_BUNDLE/bin/node" \ + --expose-gc \ + ${TOOL_NODE_FLAGS} \ + "$METEOR" "$@" diff --git a/packages/accounts-base/package.js b/packages/accounts-base/package.js index 80ac334d76..9f52c7a6f9 100644 --- a/packages/accounts-base/package.js +++ b/packages/accounts-base/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "A user account system", - version: "1.3.0" + version: "1.3.1" }); Package.onUse(function (api) { diff --git a/packages/accounts-password/package.js b/packages/accounts-password/package.js index 28b305e829..b8960d0472 100644 --- a/packages/accounts-password/package.js +++ b/packages/accounts-password/package.js @@ -1,6 +1,10 @@ Package.describe({ summary: "Password support for accounts", - version: "2.0.0" + // This version was bumped to 2.0.0 temporarily during the Meteor 1.5.1 + // release process, so versions 2.0.0-beta.2 through -beta.5 and -rc.0 + // have already been published. The next time this package reaches 2.x + // territory, I would recommend jumping straight to 2.1.0. + version: "1.4.0" }); Package.onUse(function(api) { diff --git a/packages/allow-deny/package.js b/packages/allow-deny/package.js index 4f84375323..56d9402c5b 100644 --- a/packages/allow-deny/package.js +++ b/packages/allow-deny/package.js @@ -1,6 +1,6 @@ Package.describe({ name: 'allow-deny', - version: '1.0.5', + version: '1.0.6', // Brief, one-line summary of the package. summary: 'Implements functionality for allow/deny and client-side db operations', // URL to the Git repository containing the source code for this package. diff --git a/packages/babel-compiler/.npm/package/npm-shrinkwrap.json b/packages/babel-compiler/.npm/package/npm-shrinkwrap.json index 066a3e4bae..0aa725dbc9 100644 --- a/packages/babel-compiler/.npm/package/npm-shrinkwrap.json +++ b/packages/babel-compiler/.npm/package/npm-shrinkwrap.json @@ -21,14 +21,14 @@ "from": "babel-code-frame@>=6.22.0 <7.0.0" }, "babel-core": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.24.1.tgz", + "version": "6.25.0", + "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.25.0.tgz", "from": "babel-core@>=6.22.1 <7.0.0" }, "babel-generator": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.24.1.tgz", - "from": "babel-generator@>=6.24.1 <7.0.0" + "version": "6.25.0", + "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.25.0.tgz", + "from": "babel-generator@>=6.25.0 <7.0.0" }, "babel-helper-builder-react-jsx": { "version": "6.24.1", @@ -138,8 +138,8 @@ } }, "babel-plugin-minify-dead-code-elimination": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/babel-plugin-minify-dead-code-elimination/-/babel-plugin-minify-dead-code-elimination-0.1.6.tgz", + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/babel-plugin-minify-dead-code-elimination/-/babel-plugin-minify-dead-code-elimination-0.1.7.tgz", "from": "babel-plugin-minify-dead-code-elimination@>=0.1.3 <0.2.0" }, "babel-plugin-minify-flip-comparisons": { @@ -280,8 +280,8 @@ "from": "babel-plugin-transform-es2015-modules-commonjs@>=6.22.0 <7.0.0" }, "babel-plugin-transform-es2015-modules-reify": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-reify/-/babel-plugin-transform-es2015-modules-reify-0.11.0.tgz", + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-reify/-/babel-plugin-transform-es2015-modules-reify-0.11.2.tgz", "from": "babel-plugin-transform-es2015-modules-reify@>=0.11.0 <0.12.0" }, "babel-plugin-transform-es2015-object-super": { @@ -340,13 +340,13 @@ "from": "babel-plugin-transform-inline-consecutive-adds@>=0.0.2 <0.0.3" }, "babel-plugin-transform-member-expression-literals": { - "version": "6.8.3", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-member-expression-literals/-/babel-plugin-transform-member-expression-literals-6.8.3.tgz", + "version": "6.8.4", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-member-expression-literals/-/babel-plugin-transform-member-expression-literals-6.8.4.tgz", "from": "babel-plugin-transform-member-expression-literals@>=6.8.1 <7.0.0" }, "babel-plugin-transform-merge-sibling-variables": { - "version": "6.8.4", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-merge-sibling-variables/-/babel-plugin-transform-merge-sibling-variables-6.8.4.tgz", + "version": "6.8.5", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-merge-sibling-variables/-/babel-plugin-transform-merge-sibling-variables-6.8.5.tgz", "from": "babel-plugin-transform-merge-sibling-variables@>=6.8.2 <7.0.0" }, "babel-plugin-transform-minify-booleans": { @@ -360,13 +360,13 @@ "from": "babel-plugin-transform-object-rest-spread@>=6.22.0 <7.0.0" }, "babel-plugin-transform-property-literals": { - "version": "6.8.3", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-property-literals/-/babel-plugin-transform-property-literals-6.8.3.tgz", + "version": "6.8.4", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-property-literals/-/babel-plugin-transform-property-literals-6.8.4.tgz", "from": "babel-plugin-transform-property-literals@>=6.8.1 <7.0.0" }, "babel-plugin-transform-react-display-name": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-display-name/-/babel-plugin-transform-react-display-name-6.23.0.tgz", + "version": "6.25.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-display-name/-/babel-plugin-transform-react-display-name-6.25.0.tgz", "from": "babel-plugin-transform-react-display-name@>=6.23.0 <7.0.0" }, "babel-plugin-transform-react-jsx": { @@ -395,13 +395,13 @@ "from": "babel-plugin-transform-regexp-constructors@>=0.0.5 <0.0.6" }, "babel-plugin-transform-remove-console": { - "version": "6.8.3", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-remove-console/-/babel-plugin-transform-remove-console-6.8.3.tgz", + "version": "6.8.4", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-remove-console/-/babel-plugin-transform-remove-console-6.8.4.tgz", "from": "babel-plugin-transform-remove-console@>=6.8.0 <7.0.0" }, "babel-plugin-transform-remove-debugger": { - "version": "6.8.3", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-remove-debugger/-/babel-plugin-transform-remove-debugger-6.8.3.tgz", + "version": "6.8.4", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-remove-debugger/-/babel-plugin-transform-remove-debugger-6.8.4.tgz", "from": "babel-plugin-transform-remove-debugger@>=6.8.0 <7.0.0" }, "babel-plugin-transform-remove-undefined": { @@ -415,8 +415,8 @@ "from": "babel-plugin-transform-runtime@>=6.22.0 <7.0.0" }, "babel-plugin-transform-simplify-comparison-operators": { - "version": "6.8.3", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-simplify-comparison-operators/-/babel-plugin-transform-simplify-comparison-operators-6.8.3.tgz", + "version": "6.8.4", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-simplify-comparison-operators/-/babel-plugin-transform-simplify-comparison-operators-6.8.4.tgz", "from": "babel-plugin-transform-simplify-comparison-operators@>=6.8.1 <7.0.0" }, "babel-plugin-transform-strict-mode": { @@ -460,33 +460,33 @@ "from": "babel-runtime@>=6.22.0 <7.0.0" }, "babel-template": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.24.1.tgz", + "version": "6.25.0", + "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.25.0.tgz", "from": "babel-template@>=6.22.0 <7.0.0" }, "babel-traverse": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.24.1.tgz", + "version": "6.25.0", + "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.25.0.tgz", "from": "babel-traverse@>=6.22.1 <7.0.0" }, "babel-types": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.24.1.tgz", + "version": "6.25.0", + "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.25.0.tgz", "from": "babel-types@>=6.22.0 <7.0.0" }, "babylon": { - "version": "6.17.2", - "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.17.2.tgz", + "version": "6.17.4", + "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.17.4.tgz", "from": "babylon@>=6.15.0 <7.0.0" }, "balanced-match": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz", - "from": "balanced-match@>=0.4.1 <0.5.0" + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "from": "balanced-match@>=1.0.0 <2.0.0" }, "brace-expansion": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.7.tgz", + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", "from": "brace-expansion@>=1.1.7 <2.0.0" }, "chalk": { @@ -530,8 +530,8 @@ "from": "esutils@>=2.0.2 <3.0.0" }, "globals": { - "version": "9.17.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-9.17.0.tgz", + "version": "9.18.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", "from": "globals@>=9.0.0 <10.0.0" }, "has-ansi": { @@ -555,8 +555,8 @@ "from": "is-finite@>=1.0.0 <2.0.0" }, "js-tokens": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.1.tgz", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", "from": "js-tokens@>=3.0.0 <4.0.0" }, "jsesc": { @@ -590,9 +590,9 @@ "from": "loose-envify@>=1.0.0 <2.0.0" }, "meteor-babel": { - "version": "0.21.4", - "resolved": "https://registry.npmjs.org/meteor-babel/-/meteor-babel-0.21.4.tgz", - "from": "meteor-babel@0.21.4" + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/meteor-babel/-/meteor-babel-0.22.0.tgz", + "from": "meteor-babel@0.22.0" }, "meteor-babel-helpers": { "version": "0.0.3", @@ -610,8 +610,8 @@ "from": "minimist@0.0.8" }, "minipass": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.0.2.tgz", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.2.1.tgz", "from": "minipass@>=2.0.0 <3.0.0" }, "minizlib": { @@ -692,8 +692,8 @@ } }, "reify": { - "version": "0.11.22", - "resolved": "https://registry.npmjs.org/reify/-/reify-0.11.22.tgz", + "version": "0.11.24", + "resolved": "https://registry.npmjs.org/reify/-/reify-0.11.24.tgz", "from": "reify@>=0.11.18 <0.12.0" }, "repeating": { diff --git a/packages/babel-compiler/babel.js b/packages/babel-compiler/babel.js index 13306f306b..90f88704aa 100644 --- a/packages/babel-compiler/babel.js +++ b/packages/babel-compiler/babel.js @@ -1,12 +1,15 @@ +var meteorBabel = null; +function getMeteorBabel() { + return meteorBabel || (meteorBabel = Npm.require("meteor-babel")); +} + /** * Returns a new object containing default options appropriate for */ function getDefaultOptions(extraFeatures) { - var meteorBabel = Npm.require('meteor-babel'); - // See https://github.com/meteor/babel/blob/master/options.js for more // information about what the default options are. - var options = meteorBabel.getDefaultOptions(extraFeatures); + var options = getMeteorBabel().getDefaultOptions(extraFeatures); // The sourceMap option should probably be removed from the default // options returned by meteorBabel.getDefaultOptions. @@ -22,22 +25,24 @@ Babel = { validateExtraFeatures: Function.prototype, parse: function (source) { - return Npm.require('meteor-babel').parse(source); + return getMeteorBabel().parse(source); }, compile: function (source, options) { - var meteorBabel = Npm.require('meteor-babel'); options = options || getDefaultOptions(); - return meteorBabel.compile(source, options); + return getMeteorBabel().compile(source, options); }, setCacheDir: function (cacheDir) { - Npm.require('meteor-babel').setCacheDir(cacheDir); + getMeteorBabel().setCacheDir(cacheDir); }, - minify: function(source, options) { - var meteorBabel = Npm.require('meteor-babel'); - var options = options || meteorBabel.getMinifierOptions(); - return meteorBabel.minify(source, options); + minify: function (source, options) { + var options = options || getMeteorBabel().getMinifierOptions(); + return getMeteorBabel().minify(source, options); + }, + + getMinifierOptions: function (extraFeatures) { + return getMeteorBabel().getMinifierOptions(extraFeatures); } }; diff --git a/packages/babel-compiler/package.js b/packages/babel-compiler/package.js index 4e8beea419..8b8731b79a 100644 --- a/packages/babel-compiler/package.js +++ b/packages/babel-compiler/package.js @@ -6,11 +6,11 @@ Package.describe({ // isn't possible because you can't publish a non-recommended // release with package versions that don't have a pre-release // identifier at the end (eg, -dev) - version: '6.19.2' + version: '6.19.4' }); Npm.depends({ - 'meteor-babel': '0.21.4' + 'meteor-babel': '0.22.0' }); Package.onUse(function (api) { diff --git a/packages/boilerplate-generator-tests/.npm/package/.gitignore b/packages/boilerplate-generator-tests/.npm/package/.gitignore new file mode 100644 index 0000000000..3c3629e647 --- /dev/null +++ b/packages/boilerplate-generator-tests/.npm/package/.gitignore @@ -0,0 +1 @@ +node_modules diff --git a/packages/boilerplate-generator-tests/.npm/package/README b/packages/boilerplate-generator-tests/.npm/package/README new file mode 100644 index 0000000000..3d492553a4 --- /dev/null +++ b/packages/boilerplate-generator-tests/.npm/package/README @@ -0,0 +1,7 @@ +This directory and the files immediately inside it are automatically generated +when you change this package's NPM dependencies. Commit the files in this +directory (npm-shrinkwrap.json, .gitignore, and this README) to source control +so that others run the same versions of sub-dependencies. + +You should NOT check in the node_modules directory that Meteor automatically +creates; if you are using git, the .gitignore file tells git to ignore it. diff --git a/packages/boilerplate-generator-tests/.npm/package/npm-shrinkwrap.json b/packages/boilerplate-generator-tests/.npm/package/npm-shrinkwrap.json new file mode 100644 index 0000000000..dff9c18125 --- /dev/null +++ b/packages/boilerplate-generator-tests/.npm/package/npm-shrinkwrap.json @@ -0,0 +1,9 @@ +{ + "dependencies": { + "parse5": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-3.0.2.tgz", + "from": "parse5@3.0.2" + } + } +} diff --git a/packages/boilerplate-generator-tests/README.md b/packages/boilerplate-generator-tests/README.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/boilerplate-generator-tests/package.js b/packages/boilerplate-generator-tests/package.js new file mode 100644 index 0000000000..ff30ae3ce1 --- /dev/null +++ b/packages/boilerplate-generator-tests/package.js @@ -0,0 +1,13 @@ +Npm.depends({'parse5': '3.0.2'}); +Package.describe({ + // These tests are in a separate package so that we can Npm.depend on parse5, a html parsing library + summary: "Tests for the boilerplate-generator package", + version: '1.0.0' +}); + +Package.onTest(function (api) { + api.use('ecmascript'); + api.use(['tinytest', 'boilerplate-generator'], 'server'); + api.addFiles('web.browser-tests.js', 'server'); + api.addFiles('web.cordova-tests.js', 'server'); +}); diff --git a/packages/boilerplate-generator-tests/test-lib.js b/packages/boilerplate-generator-tests/test-lib.js new file mode 100644 index 0000000000..1084396018 --- /dev/null +++ b/packages/boilerplate-generator-tests/test-lib.js @@ -0,0 +1,54 @@ +export function generateHTMLForArch(arch) { + // Use a dummy manifest. None of these paths will be read from the filesystem, but css / js should be handled differently + const manifest = [ + { + path: 'packages/bootstrap/css/bootstrap-responsive.css', + where: 'client', + type: 'css', + cacheable: true, + url: '/packages/bootstrap/css/bootstrap-responsive.css?hash=785760fc5ad665d7b54d56a3c2522797bb2cc150&v="1"', + size: 22111, + hash: '785760fc5ad665d7b54d56a3c2522797bb2cc150' + }, + { + path: 'packages/templating-runtime.js', + where: 'client', + type: 'js', + cacheable: true, + url: '/packages/templating-runtime.js?hash=c18de19afda6e9f0db7faf3d4382a4c953cabe18&v="1"', + size: 24132, + hash: 'c18de19afda6e9f0db7faf3d4382a4c953cabe18' + }, + ]; + + // Set some extra options for boilerplate data. + // webapp_server usually constructs a Boilerplate object similarly + const inline = true; + const inlineScriptsAllowed = true; + const additionalStaticJs = []; + const meteorRuntimeConfig = 'config123'; + const rootUrlPathPrefix = 'rootUrlPathPrefix'; + const htmlAttributes = { + foo: 'foobar', + gems: '&"', + }; + + // A dummy rewrite hook to test ampersands + function bundledJsCssUrlRewriteHook(url) { + return url + '+rewritten_url=true'; + } + + const boilerplate = new Boilerplate(arch, manifest, { + baseDataExtension: { + htmlAttributes, + additionalStaticJs, + meteorRuntimeConfig, + rootUrlPathPrefix, + bundledJsCssUrlRewriteHook, + inlineScriptsAllowed, + inline + }, + }); + + return boilerplate.toHTML(); +}; diff --git a/packages/boilerplate-generator-tests/web.browser-tests.js b/packages/boilerplate-generator-tests/web.browser-tests.js new file mode 100644 index 0000000000..afe5287393 --- /dev/null +++ b/packages/boilerplate-generator-tests/web.browser-tests.js @@ -0,0 +1,41 @@ +import { parse, serialize } from 'parse5'; +import { generateHTMLForArch } from './test-lib'; + +const html = generateHTMLForArch('web.browser'); + +Tinytest.add("boilerplate-generator-tests - web.browser - well-formed html", function (test) { + const formatted = serialize(parse(html)); + test.isTrue(formatted.replace(/\s/g, '') === html.replace(/\s/g, '')); +}); + +Tinytest.add("boilerplate-generator-tests - web.browser - include htmlAttributes", function (test) { + test.matches(html, /foo="foobar"/); +}); + +Tinytest.add("boilerplate-generator-tests - web.browser - escape htmlAttributes", function (test) { + test.matches(html, /gems="&""/); +}); + +Tinytest.add("boilerplate-generator-tests - web.browser - include js", function (test) { + test.matches(html, /]*src="[^<>]*templating[^<>]*">/); +}); + +Tinytest.add("boilerplate-generator-tests - web.browser - escape js", function (test) { + test.matches(html, /]*src="[^<>]*templating[^<>]*&v="1"[^<>]*">/); +}); + +Tinytest.add("boilerplate-generator-tests - web.browser - include css", function (test) { + test.matches(html, /]*href="[^<>]*bootstrap[^<>]*">/); +}); + +Tinytest.add("boilerplate-generator-tests - web.browser - escape css", function (test) { + test.matches(html, /]*href="[^<>]*bootstrap[^<>]*&v="1"[^<>]*">/); +}); + +Tinytest.add("boilerplate-generator-tests - web.browser - call rewriteHook", function (test) { + test.matches(html, /\+rewritten_url=true/); +}); + +Tinytest.add("boilerplate-generator-tests - web.browser - include runtime config", function (test) { + test.matches(html, /]*>[^<>]*__meteor_runtime_config__ =.*decodeURIComponent\(config123\)/); +}); diff --git a/packages/boilerplate-generator-tests/web.cordova-tests.js b/packages/boilerplate-generator-tests/web.cordova-tests.js new file mode 100644 index 0000000000..a924019c58 --- /dev/null +++ b/packages/boilerplate-generator-tests/web.cordova-tests.js @@ -0,0 +1,33 @@ +import { parse, serialize } from 'parse5'; +import { generateHTMLForArch } from './test-lib'; + +const html = generateHTMLForArch('web.cordova'); + +Tinytest.add("boilerplate-generator-tests - web.cordova - well-formed html", function (test) { + const formatted = serialize(parse(html)); + test.isTrue(formatted.replace(/\s/g, '') === html.replace(/\s/g, '')); +}); + +Tinytest.add("boilerplate-generator-tests - web.cordova - include js", function (test) { + test.matches(html, /]*src="[^<>]*templating[^<>]*">/); +}); + +Tinytest.add("boilerplate-generator-tests - web.cordova - escape js", function (test) { + test.matches(html, /]*src="[^<>]*templating[^<>]*&v="1"[^<>]*">/); +}); + +Tinytest.add("boilerplate-generator-tests - web.cordova - include css", function (test) { + test.matches(html, /]*href="[^<>]*bootstrap[^<>]*">/); +}); + +Tinytest.add("boilerplate-generator-tests - web.cordova - escape css", function (test) { + test.matches(html, /]*href="[^<>]*bootstrap[^<>]*&v="1"[^<>]*">/); +}); + +Tinytest.add("boilerplate-generator-tests - web.cordova - do not call rewriteHook", function (test) { + test.notMatches(html, /\+rewritten_url=true/); +}); + +Tinytest.add("boilerplate-generator-tests - web.cordova - include runtime config", function (test) { + test.matches(html, /]*>[^<>]*\n[^<>]*__meteor_runtime_config__ =[^<>]*decodeURIComponent\(config123\)\)/); +}); diff --git a/packages/boilerplate-generator/boilerplate-generator.js b/packages/boilerplate-generator/boilerplate-generator.js deleted file mode 100644 index 041b21f527..0000000000 --- a/packages/boilerplate-generator/boilerplate-generator.js +++ /dev/null @@ -1,106 +0,0 @@ -var fs = Npm.require('fs'); -var path = Npm.require('path'); - -// Copied from webapp_server -var readUtf8FileSync = function (filename) { - return Meteor.wrapAsync(fs.readFile)(filename, 'utf8'); -}; - -Boilerplate = function (arch, manifest, options) { - var self = this; - options = options || {}; - self.template = _getTemplate(arch); - self.baseData = null; - self.func = null; - - self._generateBoilerplateFromManifestAndSource( - manifest, - self.template, - options - ); -}; - -// The 'extraData' argument can be used to extend 'self.baseData'. Its -// purpose is to allow you to specify data that you might not know at -// the time that you construct the Boilerplate object. (e.g. it is used -// by 'webapp' to specify data that is only known at request-time). -Boilerplate.prototype.toHTML = function (extraData) { - var self = this; - - if (! self.baseData || ! self.func) - throw new Error('Boilerplate did not instantiate correctly.'); - - return "\n" + - Blaze.toHTML(Blaze.With(_.extend({}, self.baseData, extraData), - self.func)); -}; - -// XXX Exported to allow client-side only changes to rebuild the boilerplate -// without requiring a full server restart. -// Produces an HTML string with given manifest and boilerplateSource. -// Optionally takes urlMapper in case urls from manifest need to be prefixed -// or rewritten. -// Optionally takes pathMapper for resolving relative file system paths. -// Optionally allows to override fields of the data context. -Boilerplate.prototype._generateBoilerplateFromManifestAndSource = - function (manifest, boilerplateSource, options) { - var self = this; - // map to the identity by default - var urlMapper = options.urlMapper || _.identity; - var pathMapper = options.pathMapper || _.identity; - - var boilerplateBaseData = { - css: [], - js: [], - head: '', - body: '', - meteorManifest: JSON.stringify(manifest) - }; - - // allow the caller to extend the default base data - _.extend(boilerplateBaseData, options.baseDataExtension); - - _.each(manifest, function (item) { - var urlPath = urlMapper(item.url); - var itemObj = { url: urlPath }; - - if (options.inline) { - itemObj.scriptContent = readUtf8FileSync( - pathMapper(item.path)); - itemObj.inline = true; - } - - if (item.type === 'css' && item.where === 'client') { - boilerplateBaseData.css.push(itemObj); - } - if (item.type === 'js' && item.where === 'client' && - // Dynamic JS modules should not be loaded eagerly in the - // initial HTML of the app. - ! item.path.startsWith('dynamic/')) { - boilerplateBaseData.js.push(itemObj); - } - if (item.type === 'head') { - boilerplateBaseData.head = - readUtf8FileSync(pathMapper(item.path)); - } - if (item.type === 'body') { - boilerplateBaseData.body = - readUtf8FileSync(pathMapper(item.path)); - } - }); - var boilerplateRenderCode = SpacebarsCompiler.compile( - boilerplateSource, { isBody: true }); - - // Note that we are actually depending on eval's local environment capture - // so that UI and HTML are visible to the eval'd code. - // XXX the template we are evaluating relies on the fact that UI is globally - // available. - global.UI = UI; - self.func = eval(boilerplateRenderCode); - self.baseData = boilerplateBaseData; -}; - -var _getTemplate = _.memoize(function (arch) { - var filename = 'boilerplate_' + arch + '.html'; - return Assets.getText(filename); -}); diff --git a/packages/boilerplate-generator/boilerplate_web.browser.html b/packages/boilerplate-generator/boilerplate_web.browser.html deleted file mode 100644 index fb03a57027..0000000000 --- a/packages/boilerplate-generator/boilerplate_web.browser.html +++ /dev/null @@ -1,28 +0,0 @@ - - -{{#each css}} {{/each}} -{{{head}}} -{{{dynamicHead}}} - - -{{{body}}} -{{{dynamicBody}}} -{{#if inlineScriptsAllowed}} - -{{else}} - -{{/if}} -{{#each js}} -{{/each}} -{{#each additionalStaticJs}} - {{#if ../inlineScriptsAllowed}} - - {{else}} - - {{/if}} -{{/each}} - - diff --git a/packages/boilerplate-generator/boilerplate_web.cordova.html b/packages/boilerplate-generator/boilerplate_web.cordova.html deleted file mode 100644 index 5cb90f70f9..0000000000 --- a/packages/boilerplate-generator/boilerplate_web.cordova.html +++ /dev/null @@ -1,46 +0,0 @@ - - - - - - - - -{{! We are explicitly not using bundledJsCssUrlRewriteHook: in cordova we serve assets up directly from disk, so rewriting the URL does not make sense }} - -{{#each css}} {{/each}} - - - - -{{#each js}} -{{/each}} -{{#each additionalStaticJs}} - {{#if ../inlineScriptsAllowed}} - - {{else}} - - {{/if}} -{{/each}} - {{{head}}} - - - - {{{body}}} - - diff --git a/packages/boilerplate-generator/generator.js b/packages/boilerplate-generator/generator.js new file mode 100644 index 0000000000..7ce1b7eaf3 --- /dev/null +++ b/packages/boilerplate-generator/generator.js @@ -0,0 +1,102 @@ +import { readFile } from 'fs'; + +import WebBrowserTemplate from './template-web.browser'; +import WebCordovaTemplate from './template-web.cordova'; + +// Copied from webapp_server +const readUtf8FileSync = filename => Meteor.wrapAsync(readFile)(filename, 'utf8'); + +export class Boilerplate { + constructor(arch, manifest, options = {}) { + this.template = _getTemplate(arch); + this.baseData = null; + + this._generateBoilerplateFromManifest( + manifest, + options + ); + } + + // The 'extraData' argument can be used to extend 'self.baseData'. Its + // purpose is to allow you to specify data that you might not know at + // the time that you construct the Boilerplate object. (e.g. it is used + // by 'webapp' to specify data that is only known at request-time). + toHTML(extraData) { + if (!this.baseData || !this.template) { + throw new Error('Boilerplate did not instantiate correctly.'); + } + + return "\n" + + this.template({ ...this.baseData, ...extraData }); + } + + // XXX Exported to allow client-side only changes to rebuild the boilerplate + // without requiring a full server restart. + // Produces an HTML string with given manifest and boilerplateSource. + // Optionally takes urlMapper in case urls from manifest need to be prefixed + // or rewritten. + // Optionally takes pathMapper for resolving relative file system paths. + // Optionally allows to override fields of the data context. + _generateBoilerplateFromManifest(manifest, { + urlMapper = _.identity, + pathMapper = _.identity, + baseDataExtension, + inline, + } = {}) { + + const boilerplateBaseData = { + css: [], + js: [], + head: '', + body: '', + meteorManifest: JSON.stringify(manifest), + ...baseDataExtension, + }; + + _.each(manifest, item => { + const urlPath = urlMapper(item.url); + const itemObj = { url: urlPath }; + + if (inline) { + itemObj.scriptContent = readUtf8FileSync( + pathMapper(item.path)); + itemObj.inline = true; + } + + if (item.type === 'css' && item.where === 'client') { + boilerplateBaseData.css.push(itemObj); + } + + if (item.type === 'js' && item.where === 'client' && + // Dynamic JS modules should not be loaded eagerly in the + // initial HTML of the app. + !item.path.startsWith('dynamic/')) { + boilerplateBaseData.js.push(itemObj); + } + + if (item.type === 'head') { + boilerplateBaseData.head = + readUtf8FileSync(pathMapper(item.path)); + } + + if (item.type === 'body') { + boilerplateBaseData.body = + readUtf8FileSync(pathMapper(item.path)); + } + }); + + this.baseData = boilerplateBaseData; + } +}; + +// Returns a template function that, when called, produces the boilerplate +// html as a string. +const _getTemplate = arch => { + if (arch === 'web.browser') { + return WebBrowserTemplate; + } else if (arch === 'web.cordova') { + return WebCordovaTemplate; + } else { + throw new Error('Unsupported arch: ' + arch); + } +}; diff --git a/packages/boilerplate-generator/package.js b/packages/boilerplate-generator/package.js index c045189553..23fb12dcbb 100644 --- a/packages/boilerplate-generator/package.js +++ b/packages/boilerplate-generator/package.js @@ -1,24 +1,13 @@ Package.describe({ summary: "Generates the boilerplate html from program's manifest", - version: '1.1.1' + version: '1.1.2' }); -Package.onUse(function (api) { +Package.onUse(api => { + api.use('ecmascript'); api.use([ 'underscore', - 'spacebars-compiler', - 'spacebars', - 'htmljs', - 'ui', - ], 'server'); - api.addFiles(['boilerplate-generator.js'], 'server'); - api.export(['Boilerplate'], 'server'); - // These are spacebars templates, but we process them manually with the - // spacebars compiler rather than letting the 'templating' package (which - // isn't fully supported on the server yet) handle it. That also means that - // they don't contain the outer "