From 0244680131eeab8ebb5045094e3e3faaa6b84afb Mon Sep 17 00:00:00 2001 From: Adriaan Callaerts Date: Thu, 7 Jun 2018 15:41:21 +0200 Subject: [PATCH 01/40] Allow dynamic import() requests from any origin on any device. (#9954) A tweak to the change introduced in c4b5707747ce3c5bf339b62940da84628680a1d3 to fix #9952. This will allow clients that don't support the * value in `Access-Control-Allow-Headers`, but do specify the `Access-Control-Request-Headers` (such as electron 2.0.2) to use dynamic import. --- packages/dynamic-import/server.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/dynamic-import/server.js b/packages/dynamic-import/server.js index 0bdbeb8e69..ee35c0e3fd 100644 --- a/packages/dynamic-import/server.js +++ b/packages/dynamic-import/server.js @@ -66,7 +66,12 @@ function middleware(request, response) { response.setHeader("Access-Control-Allow-Origin", "*"); if (request.method === "OPTIONS") { - response.setHeader("Access-Control-Allow-Headers", "*"); + const requestedHeaders = request.headers["access-control-request-headers"]; + if (requestedHeaders !== undefined) { + response.setHeader("Access-Control-Allow-Headers", requestedHeaders); + } else { + response.setHeader("Access-Control-Allow-Headers", "*"); + } response.setHeader("Access-Control-Allow-Methods", "POST"); response.end(); } else if (request.method === "POST") { From 43211a0526502c19276881425c44f3b38c9f5205 Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Thu, 7 Jun 2018 11:11:48 -0400 Subject: [PATCH 02/40] Style tweaks for access-control-request-headers echoing. --- packages/dynamic-import/server.js | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/packages/dynamic-import/server.js b/packages/dynamic-import/server.js index ee35c0e3fd..ed29b51767 100644 --- a/packages/dynamic-import/server.js +++ b/packages/dynamic-import/server.js @@ -66,12 +66,11 @@ function middleware(request, response) { response.setHeader("Access-Control-Allow-Origin", "*"); if (request.method === "OPTIONS") { - const requestedHeaders = request.headers["access-control-request-headers"]; - if (requestedHeaders !== undefined) { - response.setHeader("Access-Control-Allow-Headers", requestedHeaders); - } else { - response.setHeader("Access-Control-Allow-Headers", "*"); - } + const acrh = request.headers["access-control-request-headers"]; + response.setHeader( + "Access-Control-Allow-Headers", + typeof acrh === "string" ? acrh : "*" + ); response.setHeader("Access-Control-Allow-Methods", "POST"); response.end(); } else if (request.method === "POST") { From f0e04facd286cc8e38b0a82fc8e0169db0c6ea24 Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Thu, 7 Jun 2018 11:31:28 -0400 Subject: [PATCH 03/40] Update dynamic-import test app to Meteor 1.7.0.1. --- .../.meteor/.finished-upgraders | 1 + .../apps/dynamic-import/.meteor/packages | 17 +- .../tests/apps/dynamic-import/.meteor/release | 2 +- .../apps/dynamic-import/.meteor/versions | 82 +++++ .../apps/dynamic-import/package-lock.json | 290 +++++++++--------- tools/tests/apps/dynamic-import/package.json | 2 +- 6 files changed, 239 insertions(+), 155 deletions(-) create mode 100644 tools/tests/apps/dynamic-import/.meteor/versions diff --git a/tools/tests/apps/dynamic-import/.meteor/.finished-upgraders b/tools/tests/apps/dynamic-import/.meteor/.finished-upgraders index 910574ce2d..4538749ab8 100644 --- a/tools/tests/apps/dynamic-import/.meteor/.finished-upgraders +++ b/tools/tests/apps/dynamic-import/.meteor/.finished-upgraders @@ -15,3 +15,4 @@ notices-for-facebook-graph-api-2 1.4.1-add-shell-server-package 1.4.3-split-account-service-packages 1.5-add-dynamic-import-package +1.7-split-underscore-from-meteor-base diff --git a/tools/tests/apps/dynamic-import/.meteor/packages b/tools/tests/apps/dynamic-import/.meteor/packages index d705b9dbce..c99031ebff 100644 --- a/tools/tests/apps/dynamic-import/.meteor/packages +++ b/tools/tests/apps/dynamic-import/.meteor/packages @@ -4,23 +4,24 @@ # 'meteor add' and 'meteor remove' will edit this file for you, # but you can also edit it by hand. -meteor-base@1.3.0 # Packages every Meteor app needs to have +meteor-base@1.4.0 # Packages every Meteor app needs to have mobile-experience@1.0.5 # Packages for a great mobile UX -mongo@1.4.2 # The database Meteor supports right now +mongo@1.5.0 # The database Meteor supports right now blaze-html-templates@1.0.4 # Compile .html files into Meteor Blaze views reactive-var@1.0.11 # Reactive variable for tracker jquery@1.11.10 # Helpful client-side library -tracker@1.1.3 # Meteor's client-side reactive programming library +tracker@1.2.0 # Meteor's client-side reactive programming library -standard-minifier-css@1.4.0 # CSS minifier run for production mode -standard-minifier-js@2.3.1 # JS minifier run for production mode -es5-shim@4.7.0 # ECMAScript 5 compatibility for older browsers. -ecmascript@0.10.0 # Enable ECMAScript2015+ syntax in app code +standard-minifier-css@1.4.1 # CSS minifier run for production mode +standard-minifier-js@2.3.4 # JS minifier run for production mode +es5-shim@4.8.0 # ECMAScript 5 compatibility for older browsers. +ecmascript@0.11.0 # Enable ECMAScript2015+ syntax in app code shell-server@0.3.1 # Server-side component of the `meteor shell` command autopublish@1.0.7 # Publish all data to the clients (for prototyping) insecure@1.0.7 # Allow all DB writes from clients (for prototyping) -dynamic-import@0.3.0 +dynamic-import@0.4.0 lazy-test-package helper-package user:colon-name +underscore diff --git a/tools/tests/apps/dynamic-import/.meteor/release b/tools/tests/apps/dynamic-import/.meteor/release index d502dc0d92..7f956de292 100644 --- a/tools/tests/apps/dynamic-import/.meteor/release +++ b/tools/tests/apps/dynamic-import/.meteor/release @@ -1 +1 @@ -METEOR@1.6.1 +METEOR@1.7.0.1 diff --git a/tools/tests/apps/dynamic-import/.meteor/versions b/tools/tests/apps/dynamic-import/.meteor/versions new file mode 100644 index 0000000000..0d014bc9d2 --- /dev/null +++ b/tools/tests/apps/dynamic-import/.meteor/versions @@ -0,0 +1,82 @@ +allow-deny@1.1.0 +autopublish@1.0.7 +autoupdate@1.4.0 +babel-compiler@7.1.0 +babel-runtime@1.2.2 +base64@1.0.11 +binary-heap@1.0.10 +blaze@2.3.2 +blaze-html-templates@1.1.2 +blaze-tools@1.0.10 +boilerplate-generator@1.5.0 +caching-compiler@1.1.12 +caching-html-compiler@1.1.2 +callback-hook@1.1.0 +check@1.3.1 +coffeescript@2.2.1_1 +coffeescript-compiler@2.2.1_1 +ddp@1.4.0 +ddp-client@2.3.2 +ddp-common@1.4.0 +ddp-server@2.2.0 +deps@1.0.12 +diff-sequence@1.1.0 +dynamic-import@0.4.0 +ecmascript@0.11.0 +ecmascript-runtime@0.7.0 +ecmascript-runtime-client@0.7.1 +ecmascript-runtime-server@0.7.0 +ejson@1.1.0 +es5-shim@4.8.0 +geojson-utils@1.0.10 +helper-package@0.0.1 +hot-code-push@1.0.4 +html-tools@1.0.11 +htmljs@1.0.11 +http@1.4.1 +id-map@1.1.0 +insecure@1.0.7 +jquery@1.11.11 +launch-screen@1.1.1 +lazy-test-package@0.0.1 +livedata@1.0.18 +logging@1.1.20 +meteor@1.9.0 +meteor-base@1.4.0 +minifier-css@1.3.1 +minifier-js@2.3.5 +minimongo@1.4.4 +mobile-experience@1.0.5 +mobile-status-bar@1.0.14 +modern-browsers@0.1.1 +modules@0.12.0 +modules-runtime@0.10.0 +mongo@1.5.0 +mongo-dev-server@1.1.0 +mongo-id@1.0.7 +npm-mongo@3.0.7 +observe-sequence@1.0.16 +ordered-dict@1.1.0 +promise@0.11.1 +random@1.1.0 +reactive-var@1.0.11 +reload@1.2.0 +retry@1.1.0 +routepolicy@1.0.13 +shell-server@0.3.1 +socket-stream-client@0.2.1 +spacebars@1.0.15 +spacebars-compiler@1.1.3 +standard-minifier-css@1.4.1 +standard-minifier-js@2.3.4 +templating@1.3.2 +templating-compiler@1.3.3 +templating-runtime@1.3.2 +templating-tools@1.1.2 +tracker@1.2.0 +ui@1.0.13 +underscore@1.0.10 +url@1.2.0 +user:colon-name@0.0.1 +webapp@1.6.0 +webapp-hashing@1.0.9 diff --git a/tools/tests/apps/dynamic-import/package-lock.json b/tools/tests/apps/dynamic-import/package-lock.json index 704e1aac5a..042c6308d7 100644 --- a/tools/tests/apps/dynamic-import/package-lock.json +++ b/tools/tests/apps/dynamic-import/package-lock.json @@ -4,12 +4,12 @@ "lockfileVersion": 1, "dependencies": { "@babel/runtime": { - "version": "7.0.0-beta.46", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.0.0-beta.46.tgz", - "integrity": "sha512-/3a3USMKk54BEHhDgY8rtxtaQOs4bp4aQwo6SDtdwmrXmgSgEusWuXNX5oIs/nwzmTD9o8wz2EyAjA+uHDMmJA==", + "version": "7.0.0-beta.49", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.0.0-beta.49.tgz", + "integrity": "sha1-A7O/B+uYIHLI6FHdLd1RECguYb8=", "requires": { - "core-js": "2.5.6", - "regenerator-runtime": "0.11.1" + "core-js": "^2.5.6", + "regenerator-runtime": "^0.11.1" } }, "acorn": { @@ -28,9 +28,9 @@ "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=" }, "core-js": { - "version": "2.5.6", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.6.tgz", - "integrity": "sha512-lQUVfQi0aLix2xpyjrrJEvfuYCqPc/HwmTKsC/VNf8q0zsjX7SQZtp4+oRONN5Tsur9GDETPjj+Ub2iDiGZfSQ==" + "version": "2.5.7", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.7.tgz", + "integrity": "sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw==" }, "encoding": { "version": "0.1.12", @@ -110,28 +110,28 @@ "resolved": "https://registry.npmjs.org/meteor-node-stubs/-/meteor-node-stubs-0.4.1.tgz", "integrity": "sha512-UO2OStvLOKoApmOdIP5eCqoLaa/ritMXRg4ffJVdkNLEsczzPvTjgC0Mxk4cM4R8MZkwll90FYgjDf5qUTJdMA==", "requires": { - "assert": "1.4.1", - "browserify-zlib": "0.1.4", - "buffer": "4.9.1", - "console-browserify": "1.1.0", - "constants-browserify": "1.0.0", - "crypto-browserify": "3.12.0", - "domain-browser": "1.2.0", - "events": "1.1.1", + "assert": "^1.4.1", + "browserify-zlib": "^0.1.4", + "buffer": "^4.9.1", + "console-browserify": "^1.1.0", + "constants-browserify": "^1.0.0", + "crypto-browserify": "^3.11.0", + "domain-browser": "^1.1.7", + "events": "^1.1.1", "https-browserify": "0.0.1", - "os-browserify": "0.2.1", + "os-browserify": "^0.2.1", "path-browserify": "0.0.0", - "process": "0.11.10", - "punycode": "1.4.1", - "querystring-es3": "0.2.1", - "readable-stream": "2.3.6", - "stream-browserify": "2.0.1", - "stream-http": "2.8.1", - "string_decoder": "1.1.1", - "timers-browserify": "1.4.2", + "process": "^0.11.9", + "punycode": "^1.4.1", + "querystring-es3": "^0.2.1", + "readable-stream": "^2.3.6", + "stream-browserify": "^2.0.1", + "stream-http": "^2.8.0", + "string_decoder": "^1.1.0", + "timers-browserify": "^1.4.2", "tty-browserify": "0.0.0", - "url": "0.11.0", - "util": "0.10.3", + "url": "^0.11.0", + "util": "^0.10.3", "vm-browserify": "0.0.4" }, "dependencies": { @@ -139,9 +139,9 @@ "version": "4.10.1", "bundled": true, "requires": { - "bn.js": "4.11.8", - "inherits": "2.0.1", - "minimalistic-assert": "1.0.1" + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" } }, "assert": { @@ -167,67 +167,67 @@ "version": "1.2.0", "bundled": true, "requires": { - "buffer-xor": "1.0.3", - "cipher-base": "1.0.4", - "create-hash": "1.2.0", - "evp_bytestokey": "1.0.3", - "inherits": "2.0.1", - "safe-buffer": "5.1.2" + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" } }, "browserify-cipher": { "version": "1.0.1", "bundled": true, "requires": { - "browserify-aes": "1.2.0", - "browserify-des": "1.0.1", - "evp_bytestokey": "1.0.3" + "browserify-aes": "^1.0.4", + "browserify-des": "^1.0.0", + "evp_bytestokey": "^1.0.0" } }, "browserify-des": { "version": "1.0.1", "bundled": true, "requires": { - "cipher-base": "1.0.4", - "des.js": "1.0.0", - "inherits": "2.0.1" + "cipher-base": "^1.0.1", + "des.js": "^1.0.0", + "inherits": "^2.0.1" } }, "browserify-rsa": { "version": "4.0.1", "bundled": true, "requires": { - "bn.js": "4.11.8", - "randombytes": "2.0.6" + "bn.js": "^4.1.0", + "randombytes": "^2.0.1" } }, "browserify-sign": { "version": "4.0.4", "bundled": true, "requires": { - "bn.js": "4.11.8", - "browserify-rsa": "4.0.1", - "create-hash": "1.2.0", - "create-hmac": "1.1.7", - "elliptic": "6.4.0", - "inherits": "2.0.1", - "parse-asn1": "5.1.1" + "bn.js": "^4.1.1", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "create-hmac": "^1.1.2", + "elliptic": "^6.0.0", + "inherits": "^2.0.1", + "parse-asn1": "^5.0.0" } }, "browserify-zlib": { "version": "0.1.4", "bundled": true, "requires": { - "pako": "0.2.9" + "pako": "~0.2.0" } }, "buffer": { "version": "4.9.1", "bundled": true, "requires": { - "base64-js": "1.3.0", - "ieee754": "1.1.11", - "isarray": "1.0.0" + "base64-js": "^1.0.2", + "ieee754": "^1.1.4", + "isarray": "^1.0.0" } }, "buffer-xor": { @@ -242,15 +242,15 @@ "version": "1.0.4", "bundled": true, "requires": { - "inherits": "2.0.1", - "safe-buffer": "5.1.2" + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" } }, "console-browserify": { "version": "1.1.0", "bundled": true, "requires": { - "date-now": "0.1.4" + "date-now": "^0.1.4" } }, "constants-browserify": { @@ -265,48 +265,48 @@ "version": "4.0.3", "bundled": true, "requires": { - "bn.js": "4.11.8", - "elliptic": "6.4.0" + "bn.js": "^4.1.0", + "elliptic": "^6.0.0" } }, "create-hash": { "version": "1.2.0", "bundled": true, "requires": { - "cipher-base": "1.0.4", - "inherits": "2.0.1", - "md5.js": "1.3.4", - "ripemd160": "2.0.2", - "sha.js": "2.4.11" + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" } }, "create-hmac": { "version": "1.1.7", "bundled": true, "requires": { - "cipher-base": "1.0.4", - "create-hash": "1.2.0", - "inherits": "2.0.1", - "ripemd160": "2.0.2", - "safe-buffer": "5.1.2", - "sha.js": "2.4.11" + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" } }, "crypto-browserify": { "version": "3.12.0", "bundled": true, "requires": { - "browserify-cipher": "1.0.1", - "browserify-sign": "4.0.4", - "create-ecdh": "4.0.3", - "create-hash": "1.2.0", - "create-hmac": "1.1.7", - "diffie-hellman": "5.0.3", - "inherits": "2.0.1", - "pbkdf2": "3.0.16", - "public-encrypt": "4.0.2", - "randombytes": "2.0.6", - "randomfill": "1.0.4" + "browserify-cipher": "^1.0.0", + "browserify-sign": "^4.0.0", + "create-ecdh": "^4.0.0", + "create-hash": "^1.1.0", + "create-hmac": "^1.1.0", + "diffie-hellman": "^5.0.0", + "inherits": "^2.0.1", + "pbkdf2": "^3.0.3", + "public-encrypt": "^4.0.0", + "randombytes": "^2.0.0", + "randomfill": "^1.0.3" } }, "date-now": { @@ -317,17 +317,17 @@ "version": "1.0.0", "bundled": true, "requires": { - "inherits": "2.0.1", - "minimalistic-assert": "1.0.1" + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" } }, "diffie-hellman": { "version": "5.0.3", "bundled": true, "requires": { - "bn.js": "4.11.8", - "miller-rabin": "4.0.1", - "randombytes": "2.0.6" + "bn.js": "^4.1.0", + "miller-rabin": "^4.0.0", + "randombytes": "^2.0.0" } }, "domain-browser": { @@ -338,13 +338,13 @@ "version": "6.4.0", "bundled": true, "requires": { - "bn.js": "4.11.8", - "brorand": "1.1.0", - "hash.js": "1.1.3", - "hmac-drbg": "1.0.1", - "inherits": "2.0.1", - "minimalistic-assert": "1.0.1", - "minimalistic-crypto-utils": "1.0.1" + "bn.js": "^4.4.0", + "brorand": "^1.0.1", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.0" } }, "events": { @@ -355,24 +355,24 @@ "version": "1.0.3", "bundled": true, "requires": { - "md5.js": "1.3.4", - "safe-buffer": "5.1.2" + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" } }, "hash-base": { "version": "3.0.4", "bundled": true, "requires": { - "inherits": "2.0.1", - "safe-buffer": "5.1.2" + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" } }, "hash.js": { "version": "1.1.3", "bundled": true, "requires": { - "inherits": "2.0.3", - "minimalistic-assert": "1.0.1" + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.0" }, "dependencies": { "inherits": { @@ -385,9 +385,9 @@ "version": "1.0.1", "bundled": true, "requires": { - "hash.js": "1.1.3", - "minimalistic-assert": "1.0.1", - "minimalistic-crypto-utils": "1.0.1" + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" } }, "https-browserify": { @@ -414,16 +414,16 @@ "version": "1.3.4", "bundled": true, "requires": { - "hash-base": "3.0.4", - "inherits": "2.0.1" + "hash-base": "^3.0.0", + "inherits": "^2.0.1" } }, "miller-rabin": { "version": "4.0.1", "bundled": true, "requires": { - "bn.js": "4.11.8", - "brorand": "1.1.0" + "bn.js": "^4.0.0", + "brorand": "^1.0.1" } }, "minimalistic-assert": { @@ -446,11 +446,11 @@ "version": "5.1.1", "bundled": true, "requires": { - "asn1.js": "4.10.1", - "browserify-aes": "1.2.0", - "create-hash": "1.2.0", - "evp_bytestokey": "1.0.3", - "pbkdf2": "3.0.16" + "asn1.js": "^4.0.0", + "browserify-aes": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.0", + "pbkdf2": "^3.0.3" } }, "path-browserify": { @@ -461,11 +461,11 @@ "version": "3.0.16", "bundled": true, "requires": { - "create-hash": "1.2.0", - "create-hmac": "1.1.7", - "ripemd160": "2.0.2", - "safe-buffer": "5.1.2", - "sha.js": "2.4.11" + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" } }, "process": { @@ -480,11 +480,11 @@ "version": "4.0.2", "bundled": true, "requires": { - "bn.js": "4.11.8", - "browserify-rsa": "4.0.1", - "create-hash": "1.2.0", - "parse-asn1": "5.1.1", - "randombytes": "2.0.6" + "bn.js": "^4.1.0", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "parse-asn1": "^5.0.0", + "randombytes": "^2.0.1" } }, "punycode": { @@ -503,28 +503,28 @@ "version": "2.0.6", "bundled": true, "requires": { - "safe-buffer": "5.1.2" + "safe-buffer": "^5.1.0" } }, "randomfill": { "version": "1.0.4", "bundled": true, "requires": { - "randombytes": "2.0.6", - "safe-buffer": "5.1.2" + "randombytes": "^2.0.5", + "safe-buffer": "^5.1.0" } }, "readable-stream": { "version": "2.3.6", "bundled": true, "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "2.0.0", - "safe-buffer": "5.1.2", - "string_decoder": "1.1.1", - "util-deprecate": "1.0.2" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" }, "dependencies": { "inherits": { @@ -537,8 +537,8 @@ "version": "2.0.2", "bundled": true, "requires": { - "hash-base": "3.0.4", - "inherits": "2.0.1" + "hash-base": "^3.0.0", + "inherits": "^2.0.1" } }, "safe-buffer": { @@ -549,41 +549,41 @@ "version": "2.4.11", "bundled": true, "requires": { - "inherits": "2.0.1", - "safe-buffer": "5.1.2" + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" } }, "stream-browserify": { "version": "2.0.1", "bundled": true, "requires": { - "inherits": "2.0.1", - "readable-stream": "2.3.6" + "inherits": "~2.0.1", + "readable-stream": "^2.0.2" } }, "stream-http": { "version": "2.8.1", "bundled": true, "requires": { - "builtin-status-codes": "3.0.0", - "inherits": "2.0.1", - "readable-stream": "2.3.6", - "to-arraybuffer": "1.0.1", - "xtend": "4.0.1" + "builtin-status-codes": "^3.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.3.3", + "to-arraybuffer": "^1.0.0", + "xtend": "^4.0.0" } }, "string_decoder": { "version": "1.1.1", "bundled": true, "requires": { - "safe-buffer": "5.1.2" + "safe-buffer": "~5.1.0" } }, "timers-browserify": { "version": "1.4.2", "bundled": true, "requires": { - "process": "0.11.10" + "process": "~0.11.0" } }, "to-arraybuffer": { diff --git a/tools/tests/apps/dynamic-import/package.json b/tools/tests/apps/dynamic-import/package.json index 8fc888807b..6cfb8ecbe7 100644 --- a/tools/tests/apps/dynamic-import/package.json +++ b/tools/tests/apps/dynamic-import/package.json @@ -6,7 +6,7 @@ "test": "meteor test --full-app --driver-package dispatch:mocha-browser" }, "dependencies": { - "@babel/runtime": "^7.0.0-beta.46", + "@babel/runtime": "^7.0.0-beta.49", "acorn": "^4.0.11", "arson": "^0.2.3", "meteor-node-stubs": "^0.4.1", From ab87f48f1bc851323177459f26f6494a8be4b143 Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Thu, 7 Jun 2018 11:38:44 -0400 Subject: [PATCH 04/40] Bump dynamic-import package version before republishing. --- packages/dynamic-import/package.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/dynamic-import/package.js b/packages/dynamic-import/package.js index c622aa1c76..dd99bbd177 100644 --- a/packages/dynamic-import/package.js +++ b/packages/dynamic-import/package.js @@ -1,6 +1,6 @@ Package.describe({ name: "dynamic-import", - version: "0.4.0", + version: "0.4.1", summary: "Runtime support for Meteor 1.5 dynamic import(...) syntax", documentation: "README.md" }); From 0a336175c4a47cd264060891b5f66893b945afe4 Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Thu, 7 Jun 2018 16:20:38 -0400 Subject: [PATCH 05/40] Let any client request any static resource. (#9965) Fixes #9953. --- packages/webapp/legacy_test_asset.js | 1 + packages/webapp/modern_test_asset.js | 1 + packages/webapp/package.js | 5 +- packages/webapp/webapp_server.js | 20 +++++-- packages/webapp/webapp_tests.js | 78 ++++++++++++++++++++++++++++ 5 files changed, 99 insertions(+), 6 deletions(-) create mode 100644 packages/webapp/legacy_test_asset.js create mode 100644 packages/webapp/modern_test_asset.js diff --git a/packages/webapp/legacy_test_asset.js b/packages/webapp/legacy_test_asset.js new file mode 100644 index 0000000000..e889f09131 --- /dev/null +++ b/packages/webapp/legacy_test_asset.js @@ -0,0 +1 @@ +console.log("LEGACY"); diff --git a/packages/webapp/modern_test_asset.js b/packages/webapp/modern_test_asset.js new file mode 100644 index 0000000000..c30017283a --- /dev/null +++ b/packages/webapp/modern_test_asset.js @@ -0,0 +1 @@ +console.log("MODERN"); diff --git a/packages/webapp/package.js b/packages/webapp/package.js index 6e71c856dd..c65234f9e7 100644 --- a/packages/webapp/package.js +++ b/packages/webapp/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Serves a Meteor app over HTTP", - version: '1.6.0' + version: '1.6.1' }); Npm.depends({"basic-auth-connect": "1.0.0", @@ -57,4 +57,7 @@ Package.onTest(function (api) { api.addFiles('webapp_tests.js', 'server'); api.addFiles('webapp_client_tests.js', 'client'); api.addFiles('socket_file_tests.js', 'server'); + + api.addAssets('modern_test_asset.js', 'web.browser'); + api.addAssets('legacy_test_asset.js', 'legacy'); }); diff --git a/packages/webapp/webapp_server.js b/packages/webapp/webapp_server.js index 700b12c8fd..870b31c96b 100644 --- a/packages/webapp/webapp_server.js +++ b/packages/webapp/webapp_server.js @@ -484,23 +484,33 @@ function getStaticFileInfo(originalPath, browser) { return null; } - if (hasOwn.call(staticFilesByArch, arch)) { + // Get a list of all available static file architectures, with arch + // first in the list if it exists. + const staticArchList = Object.keys(staticFilesByArch); + const archIndex = staticArchList.indexOf(arch); + if (archIndex > 0) { + staticArchList.unshift(staticArchList.splice(archIndex, 1)[0]); + } + + let info = null; + + staticArchList.some(arch => { const staticFiles = staticFilesByArch[arch]; // If staticFiles contains originalPath with the arch inferred above, // use that information. if (hasOwn.call(staticFiles, originalPath)) { - return staticFiles[originalPath]; + return info = staticFiles[originalPath]; } // If getArchAndPath returned an alternate path, try that instead. if (path !== originalPath && hasOwn.call(staticFiles, path)) { - return staticFiles[path]; + return info = staticFiles[path]; } - } + }); - return null; + return info; } function getArchAndPath(path, browser) { diff --git a/packages/webapp/webapp_tests.js b/packages/webapp/webapp_tests.js index b8fe5201bd..722583b334 100644 --- a/packages/webapp/webapp_tests.js +++ b/packages/webapp/webapp_tests.js @@ -2,6 +2,7 @@ const url = require("url"); const crypto = require("crypto"); const http = require("http"); const streamToString = require("stream-to-string"); +import { isModern } from "meteor/modern-browsers"; const additionalScript = "(function () { var foo = 1; })"; WebAppInternals.addStaticJs(additionalScript); @@ -68,6 +69,83 @@ Tinytest.add("webapp - content-type header", function (test) { "application/javascript; charset=utf-8"); }); +const modernUserAgent = + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) " + + "AppleWebKit/537.36 (KHTML, like Gecko) " + + "Chrome/68.0.3440.15 Safari/537.36"; + +const legacyUserAgent = "legacy"; + +Tinytest.addAsync("webapp - modern/legacy static files", test => { + test.equal(isModern(WebAppInternals.identifyBrowser(modernUserAgent)), true); + test.equal(isModern(WebAppInternals.identifyBrowser(legacyUserAgent)), false); + + const promises = []; + + Object.keys(WebAppInternals.staticFilesByArch).forEach(arch => { + const staticFiles = WebAppInternals.staticFilesByArch[arch]; + + Object.keys(staticFiles).forEach(path => { + const { type } = staticFiles[path]; + if (type !== "asset") { + return; + } + + const pathMatch = /\/(modern|legacy)_test_asset\.js$/.exec(path); + if (! pathMatch) { + return; + } + + const absUrl = url.resolve(Meteor.absoluteUrl(), path); + + [ // Try to request the modern/legacy assets with both modern and + // legacy User Agent strings. (#9953) + modernUserAgent, + legacyUserAgent, + ].forEach(ua => promises.push(new Promise((resolve, reject) => { + HTTP.get(absUrl, { + headers: { + "User-Agent": ua + } + }, (error, response) => { + if (error) { + reject(error); + return; + } + + if (response.statusCode !== 200) { + reject(new Error(`Bad status code ${ + response.statusCode + } for ${path}`)); + return; + } + + const contentType = response.headers["content-type"]; + if (! contentType.startsWith("application/javascript")) { + reject(new Error(`Bad Content-Type ${contentType} for ${path}`)); + return; + } + + const expectedText = pathMatch[1].toUpperCase(); + const index = response.content.indexOf(expectedText); + if (index < 0) { + reject(new Error(`Missing ${ + JSON.stringify(expectedText) + } text in ${path}`)); + return; + } + + resolve(path); + }); + }))); + }); + }); + + test.isTrue(promises.length > 0); + + return Promise.all(promises); +}); + Tinytest.addAsync( "webapp - additional static javascript", async function (test) { From a52b462f557f07d79583792211c289c1c34344ce Mon Sep 17 00:00:00 2001 From: Rob Fallows Date: Mon, 11 Jun 2018 14:15:39 +0100 Subject: [PATCH 06/40] Update default and --minimal app skeletons. Fixes #9961 (#9977) --- tools/static-assets/skel-minimal/package.json | 2 +- tools/static-assets/skel-minimal/{test => tests}/main.js | 0 tools/static-assets/skel/package.json | 2 +- tools/static-assets/skel/{test => tests}/main.js | 0 4 files changed, 2 insertions(+), 2 deletions(-) rename tools/static-assets/skel-minimal/{test => tests}/main.js (100%) rename tools/static-assets/skel/{test => tests}/main.js (100%) diff --git a/tools/static-assets/skel-minimal/package.json b/tools/static-assets/skel-minimal/package.json index bd24b879b6..ddd1e7cd2d 100644 --- a/tools/static-assets/skel-minimal/package.json +++ b/tools/static-assets/skel-minimal/package.json @@ -16,6 +16,6 @@ "client": "client/main.js", "server": "server/main.js" }, - "testModule": "test/main.js" + "testModule": "tests/main.js" } } diff --git a/tools/static-assets/skel-minimal/test/main.js b/tools/static-assets/skel-minimal/tests/main.js similarity index 100% rename from tools/static-assets/skel-minimal/test/main.js rename to tools/static-assets/skel-minimal/tests/main.js diff --git a/tools/static-assets/skel/package.json b/tools/static-assets/skel/package.json index bd24b879b6..ddd1e7cd2d 100644 --- a/tools/static-assets/skel/package.json +++ b/tools/static-assets/skel/package.json @@ -16,6 +16,6 @@ "client": "client/main.js", "server": "server/main.js" }, - "testModule": "test/main.js" + "testModule": "tests/main.js" } } diff --git a/tools/static-assets/skel/test/main.js b/tools/static-assets/skel/tests/main.js similarity index 100% rename from tools/static-assets/skel/test/main.js rename to tools/static-assets/skel/tests/main.js From ff82847cd6dfa31cb88f0e512a08c0935e5b500f Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Sat, 9 Jun 2018 15:55:50 -0400 Subject: [PATCH 07/40] Replace async.eachLimit usage in caching-compiler with Promises. --- .../.npm/package/npm-shrinkwrap.json | 5 -- packages/caching-compiler/caching-compiler.js | 29 +++++------ .../multi-file-caching-compiler.js | 50 +++++++++---------- packages/caching-compiler/package.js | 1 - 4 files changed, 38 insertions(+), 47 deletions(-) diff --git a/packages/caching-compiler/.npm/package/npm-shrinkwrap.json b/packages/caching-compiler/.npm/package/npm-shrinkwrap.json index f0ac52d443..6b16d0b092 100644 --- a/packages/caching-compiler/.npm/package/npm-shrinkwrap.json +++ b/packages/caching-compiler/.npm/package/npm-shrinkwrap.json @@ -1,11 +1,6 @@ { "lockfileVersion": 1, "dependencies": { - "async": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/async/-/async-1.4.0.tgz", - "integrity": "sha1-Nfhvg8WeBCHQmc2akdgnj7V4wA0=" - }, "lru-cache": { "version": "2.6.4", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.6.4.tgz", diff --git a/packages/caching-compiler/caching-compiler.js b/packages/caching-compiler/caching-compiler.js index 6c4abd335f..57f943e436 100644 --- a/packages/caching-compiler/caching-compiler.js +++ b/packages/caching-compiler/caching-compiler.js @@ -2,9 +2,7 @@ const fs = Plugin.fs; const path = Plugin.path; const createHash = Npm.require('crypto').createHash; const assert = Npm.require('assert'); -const Future = Npm.require('fibers/future'); const LRU = Npm.require('lru-cache'); -const async = Npm.require('async'); // Base class for CachingCompiler and MultiFileCachingCompiler. CachingCompilerBase = class CachingCompilerBase { @@ -283,14 +281,12 @@ CachingCompiler = class CachingCompiler extends CachingCompilerBase { const cacheMisses = []; const arches = this._cacheDebugEnabled && Object.create(null); - const future = new Future; - async.eachLimit(inputFiles, this._maxParallelism, (inputFile, cb) => { + return Promise.all(inputFiles.map(async (inputFile) => { if (arches) { arches[inputFile.getArch()] = 1; } - let error = null; - try { + const getResult = () => { const cacheKey = this._deepHash(this.getCacheKey(inputFile)); let compileResult = this._cache.get(cacheKey); @@ -316,17 +312,18 @@ CachingCompiler = class CachingCompiler extends CachingCompilerBase { this._writeCacheAsync(cacheKey, compileResult); } - this.addCompileResult(inputFile, compileResult); - } catch (e) { - error = e; - } finally { - cb(error); - } - }, future.resolver()); - future.wait(); + return compileResult; + }; + + this.addCompileResult(inputFile, getResult()); + + })).then(() => { + if (! this._cacheDebugEnabled) { + return; + } - if (this._cacheDebugEnabled) { cacheMisses.sort(); + this._cacheDebug( `Ran (#${ ++this._callCount @@ -336,7 +333,7 @@ CachingCompiler = class CachingCompiler extends CachingCompilerBase { JSON.stringify(Object.keys(arches).sort()) }` ); - } + }); } _cacheFilename(cacheKey) { diff --git a/packages/caching-compiler/multi-file-caching-compiler.js b/packages/caching-compiler/multi-file-caching-compiler.js index 6cb698cb34..0b79652dde 100644 --- a/packages/caching-compiler/multi-file-caching-compiler.js +++ b/packages/caching-compiler/multi-file-caching-compiler.js @@ -1,7 +1,5 @@ const path = Plugin.path; -const Future = Npm.require('fibers/future'); const LRU = Npm.require('lru-cache'); -const async = Npm.require('async'); // MultiFileCachingCompiler is like CachingCompiler, but for implementing // languages which allow files to reference each other, such as CSS @@ -92,20 +90,12 @@ extends CachingCompilerBase { cacheKeyMap.set(importPath, this._getCacheKeyWithPath(inputFile)); }); - const allProcessedFuture = new Future; - async.eachLimit(inputFiles, this._maxParallelism, (inputFile, cb) => { + return Promise.all(inputFiles.map(async (inputFile) => { if (arches) { arches[inputFile.getArch()] = 1; } - let error = null; - try { - // If this isn't a root, skip it (and definitely don't waste time - // looking for a cache file that won't be there). - if (!this.isRoot(inputFile)) { - return; - } - + const getResult = () => { const absoluteImportPath = this.getAbsoluteImportPath(inputFile); const cacheKey = cacheKeyMap.get(absoluteImportPath); let cacheEntry = this._cache.get(cacheKey); @@ -122,10 +112,14 @@ extends CachingCompilerBase { const compileOneFileReturn = this.compileOneFile(inputFile, allFiles); if (! compileOneFileReturn) { // compileOneFile should have called inputFile.error. - // We don't cache failures for now. + // We don't cache failures for now. return; } - const {compileResult, referencedImportPaths} = compileOneFileReturn; + + const { + compileResult, + referencedImportPaths, + } = compileOneFileReturn; cacheEntry = { compileResult, @@ -148,17 +142,22 @@ extends CachingCompilerBase { this._writeCacheAsync(cacheKey, cacheEntry); } - this.addCompileResult(inputFile, cacheEntry.compileResult); - } catch (e) { - error = e; - } finally { - cb(error); - } - }, allProcessedFuture.resolver()); - allProcessedFuture.wait(); + return cacheEntry.compileResult; + }; + + if (this.isRoot(inputFile)) { + // If this isn't a root, skip it (and definitely don't waste time + // looking for a cache file that won't be there). + this.addCompileResult(inputFile, getResult()); + } + + })).then(() => { + if (! this._cacheDebugEnabled) { + return; + } - if (this._cacheDebugEnabled) { cacheMisses.sort(); + this._cacheDebug( `Ran (#${ ++this._callCount @@ -166,8 +165,9 @@ extends CachingCompilerBase { JSON.stringify(cacheMisses) } ${ JSON.stringify(Object.keys(arches).sort()) - }`); - } + }` + ); + }); } // Returns a hash that incorporates both this.getCacheKey(inputFile) and diff --git a/packages/caching-compiler/package.js b/packages/caching-compiler/package.js index 37b38bfde1..3d7cb0b083 100644 --- a/packages/caching-compiler/package.js +++ b/packages/caching-compiler/package.js @@ -7,7 +7,6 @@ Package.describe({ Npm.depends({ 'lru-cache': '2.6.4', - 'async': '1.4.0' }); Package.onUse(function(api) { From 2bd67f334f31cc142399780fabef624c8fb6e7ae Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Sat, 9 Jun 2018 16:28:25 -0400 Subject: [PATCH 08/40] Use the lru-cache package from dev_bundle in caching-compiler. --- packages/caching-compiler/.npm/package/.gitignore | 1 - packages/caching-compiler/.npm/package/README | 7 ------- .../caching-compiler/.npm/package/npm-shrinkwrap.json | 10 ---------- packages/caching-compiler/package.js | 4 ---- scripts/dev-bundle-tool-package.js | 2 +- 5 files changed, 1 insertion(+), 23 deletions(-) delete mode 100644 packages/caching-compiler/.npm/package/.gitignore delete mode 100644 packages/caching-compiler/.npm/package/README delete mode 100644 packages/caching-compiler/.npm/package/npm-shrinkwrap.json diff --git a/packages/caching-compiler/.npm/package/.gitignore b/packages/caching-compiler/.npm/package/.gitignore deleted file mode 100644 index 3c3629e647..0000000000 --- a/packages/caching-compiler/.npm/package/.gitignore +++ /dev/null @@ -1 +0,0 @@ -node_modules diff --git a/packages/caching-compiler/.npm/package/README b/packages/caching-compiler/.npm/package/README deleted file mode 100644 index 3d492553a4..0000000000 --- a/packages/caching-compiler/.npm/package/README +++ /dev/null @@ -1,7 +0,0 @@ -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/caching-compiler/.npm/package/npm-shrinkwrap.json b/packages/caching-compiler/.npm/package/npm-shrinkwrap.json deleted file mode 100644 index 6b16d0b092..0000000000 --- a/packages/caching-compiler/.npm/package/npm-shrinkwrap.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "lockfileVersion": 1, - "dependencies": { - "lru-cache": { - "version": "2.6.4", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.6.4.tgz", - "integrity": "sha1-JnUZDM0bBwHsL2UqTQ09QA12wN0=" - } - } -} diff --git a/packages/caching-compiler/package.js b/packages/caching-compiler/package.js index 3d7cb0b083..1ae94aa309 100644 --- a/packages/caching-compiler/package.js +++ b/packages/caching-compiler/package.js @@ -5,10 +5,6 @@ Package.describe({ documentation: 'README.md' }); -Npm.depends({ - 'lru-cache': '2.6.4', -}); - Package.onUse(function(api) { api.use(['ecmascript', 'random']); api.addFiles(['caching-compiler.js'], 'server'); diff --git a/scripts/dev-bundle-tool-package.js b/scripts/dev-bundle-tool-package.js index e564b87bb0..e0bef526ae 100644 --- a/scripts/dev-bundle-tool-package.js +++ b/scripts/dev-bundle-tool-package.js @@ -53,7 +53,7 @@ var packageJson = { multipipe: "2.0.1", pathwatcher: "7.1.1", optimism: "0.6.3", - 'lru-cache': '4.1.1' + 'lru-cache': '4.1.3' } }; From 9cc739078c12fe473260a950c62da712d1b95c0a Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Sat, 9 Jun 2018 16:02:10 -0400 Subject: [PATCH 09/40] Support lazy compilation of inputFile.add{JavaScript,Stylesheet,...} resources. One limitation of Meteor's current compiler plugins system is that every file we *might* use must be compiled before we know whether it *will* be used by the application (which is something we only find out when we later run the `ImportScanner`). More specifically, when inputFile.addJavaScript is called, any information relevant to the current file must already have been computed, even if the file will never be used. This commit begins the process of supporting a lazy version of the `inputFile.addJavaScript` method. For consistency, this interface is supported by other methods like `inputFile.addStylesheet`, though it may not make as much sense for non-JavaScript resources. In this very basic initial implementation, the `lazyFinalizer` function is called immediately, so that subsequent code can keep pretending that all relevant information was eagerly provided. The next step will be waiting to call `lazyFinalizer` until the last possible moment, so that we can skip a potentially huge amount of unnecessary compilation time. --- tools/isobuild/compiler-plugin.js | 71 ++++++++++++++++++++++++++----- 1 file changed, 60 insertions(+), 11 deletions(-) diff --git a/tools/isobuild/compiler-plugin.js b/tools/isobuild/compiler-plugin.js index 023a7c03e4..e6818f1cab 100644 --- a/tools/isobuild/compiler-plugin.js +++ b/tools/isobuild/compiler-plugin.js @@ -221,6 +221,11 @@ class InputFile extends buildPluginModule.InputFile { // Map from imported module identifier strings (possibly relative) to // fully require.resolve'd module identifiers. this._resolveCache = Object.create(null); + + // Communicate to compiler plugins that methods like addJavaScript + // accept a lazy finalizer function as a second argument, so that + // compilation can be avoided until/unless absolutely necessary. + this.supportsLazyCompilation = true; } getContentsAsBuffer() { @@ -445,16 +450,26 @@ class InputFile extends buildPluginModule.InputFile { * @param {String|Object} options.sourceMap A stringified JSON * sourcemap, in case the stylesheet was generated from a different * file. + * @param {Function} lazyFinalizer Optional function that can be called + * to obtain any remaining options that may be + * expensive to compute, and thus should only be + * computed if/when we are sure this CSS will be used + * by the application. * @memberOf InputFile * @instance */ - addStylesheet(options) { - var self = this; + addStylesheet(options, lazyFinalizer) { + if (typeof lazyFinalizer === "function") { + // For now, just call the lazyFinalizer function immediately. + Object.assign(options, lazyFinalizer()); + } + if (options.sourceMap && typeof options.sourceMap === 'string') { // XXX remove an anti-XSSI header? ")]}'\n" options.sourceMap = JSON.parse(options.sourceMap); } - self._resourceSlot.addStylesheet(options); + + this._resourceSlot.addStylesheet(options); } /** @@ -470,16 +485,26 @@ class InputFile extends buildPluginModule.InputFile { * @param {String|Object} options.sourceMap A stringified JSON * sourcemap, in case the JavaScript file was generated from a * different file. + * @param {Function} lazyFinalizer Optional function that can be called + * to obtain any remaining options that may be + * expensive to compute, and thus should only be + * computed if/when we are sure this JavaScript will + * be used by the application. * @memberOf InputFile * @instance */ - addJavaScript(options) { - var self = this; + addJavaScript(options, lazyFinalizer) { + if (typeof lazyFinalizer === "function") { + // For now, just call the lazyFinalizer function immediately. + Object.assign(options, lazyFinalizer()); + } + if (options.sourceMap && typeof options.sourceMap === 'string') { // XXX remove an anti-XSSI header? ")]}'\n" options.sourceMap = JSON.parse(options.sourceMap); } - self._resourceSlot.addJavaScript(options); + + this._resourceSlot.addJavaScript(options); } /** @@ -493,12 +518,24 @@ class InputFile extends buildPluginModule.InputFile { * file. * @param {String} [options.hash] Optionally, supply a hash for the output * file. + * @param {Function} lazyFinalizer Optional function that can be called + * to obtain any remaining options that may be + * expensive to compute, and thus should only be + * computed if/when we are sure this asset will be + * used by the application. * @memberOf InputFile * @instance */ - addAsset(options) { - var self = this; - self._resourceSlot.addAsset(options); + addAsset(options, lazyFinalizer) { + if (typeof lazyFinalizer === "function") { + // For now, just call the lazyFinalizer function immediately. Since + // assets typically are not compiled, this immediate invocation is + // probably permanently appropriate for addAsset, whereas methods + // like addJavaScript benefit from waiting to call lazyFinalizer. + Object.assign(options, lazyFinalizer()); + } + + this._resourceSlot.addAsset(options); } /** @@ -508,12 +545,24 @@ class InputFile extends buildPluginModule.InputFile { * @param {String} options.section Which section of the document should * be appended to. Can only be "head" or "body". * @param {String} options.data The content to append. + * @param {Function} lazyFinalizer Optional function that can be called + * to obtain any remaining options that may be + * expensive to compute, and thus should only be + * computed if/when we are sure this HTML will be used + * by the application. * @memberOf InputFile * @instance */ addHtml(options) { - var self = this; - self._resourceSlot.addHtml(options); + if (typeof lazyFinalizer === "function") { + // For now, just call the lazyFinalizer function immediately. Since + // HTML is not compiled, this immediate invocation is probably + // permanently appropriate for addHtml, whereas methods like + // addJavaScript benefit from waiting to call lazyFinalizer. + Object.assign(options, lazyFinalizer()); + } + + this._resourceSlot.addHtml(options); } _reportError(message, info) { From c28065aedc6995e7d1bc17818b8c1df320312f36 Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Sat, 9 Jun 2018 16:03:00 -0400 Subject: [PATCH 10/40] Let CachingCompiler subclasses implement compileOneFileLater. If you're subclassing `CachingCompiler` or `MultiFileCachingCompiler`, you can now implement a `compileOneFileLater` (emphasis on `Later`) to opt into the new lazy compilation strategy. If you implement this method, and `inputFile.supportsLazyCompilation` is true, then the `addCompileResult` will not be called, though it is probably a good idea to keep any existing `addCompileResult` methods, just in case `inputFile.supportsLazyCompilation` is not truthy. This will be an important part of a proper solution to the issues I described (but failed to fix) in my broken PR #9968. --- packages/caching-compiler/caching-compiler.js | 10 +++++++++- .../multi-file-caching-compiler.js | 16 ++++++++++++---- packages/less/plugin/compile-less.js | 12 ++++++++++++ 3 files changed, 33 insertions(+), 5 deletions(-) diff --git a/packages/caching-compiler/caching-compiler.js b/packages/caching-compiler/caching-compiler.js index 57f943e436..e7165f5840 100644 --- a/packages/caching-compiler/caching-compiler.js +++ b/packages/caching-compiler/caching-compiler.js @@ -315,7 +315,15 @@ CachingCompiler = class CachingCompiler extends CachingCompilerBase { return compileResult; }; - this.addCompileResult(inputFile, getResult()); + if (this.compileOneFileLater && + inputFile.supportsLazyCompilation) { + this.compileOneFileLater(inputFile, getResult); + } else { + const result = getResult(); + if (result) { + this.addCompileResult(inputFile, result); + } + } })).then(() => { if (! this._cacheDebugEnabled) { diff --git a/packages/caching-compiler/multi-file-caching-compiler.js b/packages/caching-compiler/multi-file-caching-compiler.js index 0b79652dde..85af3e13ff 100644 --- a/packages/caching-compiler/multi-file-caching-compiler.js +++ b/packages/caching-compiler/multi-file-caching-compiler.js @@ -145,10 +145,18 @@ extends CachingCompilerBase { return cacheEntry.compileResult; }; - if (this.isRoot(inputFile)) { - // If this isn't a root, skip it (and definitely don't waste time - // looking for a cache file that won't be there). - this.addCompileResult(inputFile, getResult()); + if (this.compileOneFileLater && + inputFile.supportsLazyCompilation) { + // TODO Remove this isRoot check once compileOneFileLater no + // longer immediately compiles the file. + if (this.isRoot(inputFile)) { + this.compileOneFileLater(inputFile, getResult); + } + } else if (this.isRoot(inputFile)) { + const result = getResult(); + if (result) { + this.addCompileResult(inputFile, result); + } } })).then(() => { diff --git a/packages/less/plugin/compile-less.js b/packages/less/plugin/compile-less.js index 4b428d2f51..10b57035eb 100644 --- a/packages/less/plugin/compile-less.js +++ b/packages/less/plugin/compile-less.js @@ -45,6 +45,18 @@ class LessCompiler extends MultiFileCachingCompiler { /\.lessimport$/.test(pathInPackage)); } + compileOneFileLater(inputFile, getResult) { + inputFile.addStylesheet({ + path: inputFile.getPathInPackage(), + }, () => { + const result = getResult(); + return result && { + data: result.css, + sourceMap: result.sourceMap, + }; + }); + } + compileOneFile(inputFile, allFiles) { const importPlugin = new MeteorImportLessPlugin(allFiles); From a5751003a7f29b45f81a96fa942541b288fe3eca Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Sat, 9 Jun 2018 16:08:22 -0400 Subject: [PATCH 11/40] Use lazyFinalizer function when calling addJavaScript in BabelCompiler. --- packages/babel-compiler/babel-compiler.js | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/packages/babel-compiler/babel-compiler.js b/packages/babel-compiler/babel-compiler.js index 7c9e5a7c8e..b3c91795bb 100644 --- a/packages/babel-compiler/babel-compiler.js +++ b/packages/babel-compiler/babel-compiler.js @@ -21,15 +21,29 @@ var hasOwn = Object.prototype.hasOwnProperty; var isMeteorPre144 = semver.lt(process.version, "4.8.1"); BCp.processFilesForTarget = function (inputFiles) { + var compiler = this; + // Reset this cache for each batch processed. this._babelrcCache = null; inputFiles.forEach(function (inputFile) { - var toBeAdded = this.processOneFileForTarget(inputFile); - if (toBeAdded) { - inputFile.addJavaScript(toBeAdded); + var fileOptions = inputFile.getFileOptions(); + + if (inputFile.supportsLazyCompilation) { + inputFile.addJavaScript({ + path: inputFile.getPathInPackage(), + hash: inputFile.getSourceHash(), + bare: !! fileOptions.bare + }, function () { + return compiler.processOneFileForTarget(inputFile); + }); + } else { + var toBeAdded = compiler.processOneFileForTarget(inputFile); + if (toBeAdded) { + inputFile.addJavaScript(toBeAdded); + } } - }, this); + }); }; // Returns an object suitable for passing to inputFile.addJavaScript, or From 98d853551fd390038bb839c4c7c9904eefa077da Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Sat, 9 Jun 2018 16:08:48 -0400 Subject: [PATCH 12/40] Bump minor version of caching-compiler package to 1.2.0. --- packages/caching-compiler/package.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/caching-compiler/package.js b/packages/caching-compiler/package.js index 1ae94aa309..987d9b7651 100644 --- a/packages/caching-compiler/package.js +++ b/packages/caching-compiler/package.js @@ -1,6 +1,6 @@ Package.describe({ name: 'caching-compiler', - version: '1.1.12', + version: '1.2.0', summary: 'An easy way to make compiler plugins cache', documentation: 'README.md' }); From 7cfba6e002aac4029a61d4f1c2ab433c6c773c17 Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Sat, 9 Jun 2018 16:09:06 -0400 Subject: [PATCH 13/40] Bump minor version of babel-compiler package to 7.2.0. --- packages/babel-compiler/package.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/babel-compiler/package.js b/packages/babel-compiler/package.js index 2d863bb6da..8450906c82 100644 --- a/packages/babel-compiler/package.js +++ b/packages/babel-compiler/package.js @@ -6,7 +6,7 @@ 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: '7.1.0' + version: '7.2.0' }); Npm.depends({ From 7ec5d446d180599c6d17008e4a136875a9468281 Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Sat, 9 Jun 2018 16:10:01 -0400 Subject: [PATCH 14/40] Bump minor version of less package to 2.8.0. We should really update to the latest version of the less npm package (3.0.4 at the time this commit message was written). --- packages/less/package.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/less/package.js b/packages/less/package.js index 4246551c39..363b4c6926 100644 --- a/packages/less/package.js +++ b/packages/less/package.js @@ -1,6 +1,6 @@ Package.describe({ name: 'less', - version: '2.7.12', + version: '2.8.0', summary: 'Leaner CSS language', documentation: 'README.md' }); From 98ed7675226cffb973bdd6c4b7a300ce0469d3ed Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Mon, 11 Jun 2018 15:21:31 -0400 Subject: [PATCH 15/40] Use custom JsOutputResource class in ResourceSlot#addJavaScript. --- tools/isobuild/compiler-plugin.js | 171 ++++++++++++++++++++---------- 1 file changed, 113 insertions(+), 58 deletions(-) diff --git a/tools/isobuild/compiler-plugin.js b/tools/isobuild/compiler-plugin.js index e6818f1cab..26cb22d3cd 100644 --- a/tools/isobuild/compiler-plugin.js +++ b/tools/isobuild/compiler-plugin.js @@ -23,6 +23,8 @@ import { import { isTestFilePath } from './test-files.js'; +const hasOwn = Object.prototype.hasOwnProperty; + // This file implements the new compiler plugins added in Meteor 1.2, which are // registered with the Plugin.registerCompiler API. // @@ -494,17 +496,7 @@ class InputFile extends buildPluginModule.InputFile { * @instance */ addJavaScript(options, lazyFinalizer) { - if (typeof lazyFinalizer === "function") { - // For now, just call the lazyFinalizer function immediately. - Object.assign(options, lazyFinalizer()); - } - - if (options.sourceMap && typeof options.sourceMap === 'string') { - // XXX remove an anti-XSSI header? ")]}'\n" - options.sourceMap = JSON.parse(options.sourceMap); - } - - this._resourceSlot.addJavaScript(options); + this._resourceSlot.addJavaScript(options, lazyFinalizer); } /** @@ -752,29 +744,26 @@ class ResourceSlot { // file is lazy, add it as a lazy JS module instead of adding it // unconditionally as a CSS resource, so that it can be imported // when needed. - resource.type = "js"; - resource.data = - Buffer.from(cssToCommonJS(data, resource.hash), "utf8"); - - self.jsOutputResources.push(resource); + self.addJavaScript({ + ...resource, + data: Buffer.from(cssToCommonJS(data, resource.hash), "utf8"), + }); } else { // Eager CSS is added unconditionally to a combined