diff --git a/.circleci/config.yml b/.circleci/config.yml index 7dfe7f968c..eae8da0cea 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -128,8 +128,9 @@ jobs: - package-npm-deps-cache-group2-v3- - restore_cache: keys: - - v2-other-deps-cache-{{ .Branch }}-{{ .Revision }} - - v2-other-deps-cache-{{ .Branch }}- + - v3-other-deps-cache-{{ .Branch }}-{{ checksum "meteor" }}-{{ .Revision }} + - v3-other-deps-cache-{{ .Branch }}-{{ checksum "meteor" }}- + - v3-other-deps-cache-{{ .Branch }}- - restore_cache: keys: - v1-test-groups-{{ .Branch }} @@ -768,7 +769,7 @@ jobs: - packages/fetch/.npm/package/node_modules - packages/non-core/mongo-decimal/.npm/package/node_modules - save_cache: - key: v2-other-deps-cache-{{ .Branch }}-{{ .Revision }} + key: v3-other-deps-cache-{{ .Branch }}-{{ checksum "meteor" }}-{{ .Revision }} paths: - ".babel-cache" - ".meteor" diff --git a/History.md b/History.md index 30ce819cb2..8b9a3574bc 100644 --- a/History.md +++ b/History.md @@ -60,6 +60,19 @@ N/A [fork](https://github.com/meteor/pacote/tree/v9.5.8-meteor) of its `pacote` dependency has been updated to version 9.5.8. +* New Meteor applications now include an official `typescript` package, + supporting TypeScript compilation of `.ts` and `.tsx` modules, which can + be added to existing apps by running `meteor add typescript`. + +* New TypeScript-based Meteor applications can be created by running + ```sh + meteor create --typescript new-typescript-app + ``` + This app skeleton contains a recommended tsconfig.json file, and should + serve as a reference for how to make TypeScript and Meteor work together + (to the best of our current knowledge). + [PR #10695](https://github.com/meteor/meteor/pull/10695) + * When bundling client code, the Meteor module system now prefers the `"module"` field in `package.json`, if defined. [PR #10541](https://github.com/meteor/meteor/pull/10541) @@ -87,20 +100,24 @@ N/A * The `mongodb` npm package used by the `npm-mongo` Meteor package has been updated to version 3.2.7. -* The `meteor-babel` npm package has been updated to version 7.6.0, +* The `meteor-babel` npm package has been updated to version 7.6.1, enabling compilation of the `meteor/tools` codebase with TypeScript (specifically, version 3.6.2 of the `typescript` npm package). * The `reify` npm package has been updated to version 0.20.12. * The `core-js` npm package used by `ecmascript-runtime-client` and - `ecmascript-runtime-server` has been updated to version 3.1.4. + `ecmascript-runtime-server` has been updated to version 3.2.1. + +* The `terser` npm package used by `minifier-js` (and indirectly by + `standard-minifier-js`) has been updated to version 4.3.1. * The `node-gyp` npm package has been updated to version 5.0.1, and `node-pre-gyp` has been updated to 0.13.0. -* The `optimism` npm package has been updated to version 0.10.2, which - enables caching of thrown exceptions, as well as ordinary results. +* The `optimism` npm package has been updated to version 0.11.2, which + enables caching of thrown exceptions as well as ordinary results, in + addition to performance improvements. * The `pathwatcher` npm package has been updated to version 8.1.0. diff --git a/appveyor.yml b/appveyor.yml index 28290ec4c6..7c1ca47fdd 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -43,5 +43,5 @@ on_failure: cache: - dev_bundle -> meteor - - .babel-cache + - .babel-cache -> meteor - .meteor diff --git a/packages/babel-compiler/.npm/package/npm-shrinkwrap.json b/packages/babel-compiler/.npm/package/npm-shrinkwrap.json index 9b2cff8a65..e027e1cbf9 100644 --- a/packages/babel-compiler/.npm/package/npm-shrinkwrap.json +++ b/packages/babel-compiler/.npm/package/npm-shrinkwrap.json @@ -11,11 +11,6 @@ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.6.0.tgz", "integrity": "sha512-FuRhDRtsd6IptKpHXAa+4WPZYY2ZzgowkbLBecEDDSje1X/apG7jQM33or3NdOmjXBKWGOg4JmSiRfUfuTtHXw==", "dependencies": { - "@babel/parser": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.6.0.tgz", - "integrity": "sha512-+o2q111WEx4srBs7L9eJmcwi655eD8sXniLqMB93TBK9GrNzGrxDWSjiqz2hLU0Ha8MTXFIP0yd9fNdP+m43ZQ==" - }, "json5": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.0.tgz", @@ -144,9 +139,9 @@ "integrity": "sha512-7dV4eu9gBxoM0dAnj/BCFDW9LFU0zvTrkq0ugM7pnHEgguOEeOz1so2ZghEdzviYzQEED0r4EAgpsBChKy1TRQ==" }, "@babel/parser": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.5.5.tgz", - "integrity": "sha512-E5BN68cqR7dhKan1SfqgPGhQ178bkVKpXTPEXnFJBrEt8/DKRZlybmy+IgYLTeN7tp1R5Ccmbm2rBk17sHYU3g==" + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.6.0.tgz", + "integrity": "sha512-+o2q111WEx4srBs7L9eJmcwi655eD8sXniLqMB93TBK9GrNzGrxDWSjiqz2hLU0Ha8MTXFIP0yd9fNdP+m43ZQ==" }, "@babel/plugin-proposal-async-generator-functions": { "version": "7.2.0", @@ -158,11 +153,26 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.5.5.tgz", "integrity": "sha512-AF79FsnWFxjlaosgdi421vmYG6/jg79bVD0dpD44QdgobzHKuLZ6S3vl8la9qIeSwGi8i1fS0O1mfuDAAdo1/A==" }, + "@babel/plugin-proposal-nullish-coalescing-operator": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.4.4.tgz", + "integrity": "sha512-Amph7Epui1Dh/xxUxS2+K22/MUi6+6JVTvy3P58tja3B6yKTSjwwx0/d83rF7551D6PVSSoplQb8GCwqec7HRw==" + }, "@babel/plugin-proposal-object-rest-spread": { "version": "7.5.5", "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.5.5.tgz", "integrity": "sha512-F2DxJJSQ7f64FyTVl5cw/9MWn6naXGdk3Q3UhDbFEEHv+EilCPoeRD3Zh/Utx1CJz4uyKlQ4uH+bJPbEhMV7Zw==" }, + "@babel/plugin-proposal-optional-catch-binding": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.2.0.tgz", + "integrity": "sha512-mgYj3jCcxug6KUcX4OBoOJz3CMrwRfQELPQ5560F70YQUBZB7uac9fqaWamKR1iWUzGiK2t0ygzjTScZnVz75g==" + }, + "@babel/plugin-proposal-optional-chaining": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.6.0.tgz", + "integrity": "sha512-kj4gkZ6qUggkprRq3Uh5KP8XnE1MdIO0J7MhdDX8+rAbB6dJ2UrensGIS+0NPZAaaJ1Vr0PN6oLUgXMU1uMcSg==" + }, "@babel/plugin-syntax-async-generators": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.2.0.tgz", @@ -188,11 +198,26 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.2.0.tgz", "integrity": "sha512-VyN4QANJkRW6lDBmENzRszvZf3/4AXaj9YR7GwrWeeN9tEBPuXbmDYVU9bYBN0D70zCWVwUy0HWq2553VCb6Hw==" }, + "@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.2.0.tgz", + "integrity": "sha512-lRCEaKE+LTxDQtgbYajI04ddt6WW0WJq57xqkAZ+s11h4YgfRHhVA/Y2VhfPzzFD4qeLHWg32DMp9HooY4Kqlg==" + }, "@babel/plugin-syntax-object-rest-spread": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.2.0.tgz", "integrity": "sha512-t0JKGgqk2We+9may3t0xDdmneaXmyxq0xieYcKHxIsrJO64n1OiMWNUtc5gQK1PA0NpdCRrtZp4z+IUaKugrSA==" }, + "@babel/plugin-syntax-optional-catch-binding": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.2.0.tgz", + "integrity": "sha512-bDe4xKNhb0LI7IvZHiA13kff0KEfaGX/Hv4lMA9+7TEc63hMNvfKo6ZFpXhKuEp+II/q35Gc4NoMeDZyaUbj9w==" + }, + "@babel/plugin-syntax-optional-chaining": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.2.0.tgz", + "integrity": "sha512-HtGCtvp5Uq/jH/WNUPkK6b7rufnCPLLlDAFN7cmACoIjaOOiXxUt3SswU5loHqrhtqTsa/WoLQ1OQ1AGuZqaWA==" + }, "@babel/plugin-transform-arrow-functions": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.2.0.tgz", @@ -341,26 +366,12 @@ "@babel/template": { "version": "7.6.0", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.6.0.tgz", - "integrity": "sha512-5AEH2EXD8euCk446b7edmgFdub/qfH1SN6Nii3+fyXP807QRx9Q73A2N5hNwRRslC2H9sNzaFhsPubkS4L8oNQ==", - "dependencies": { - "@babel/parser": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.6.0.tgz", - "integrity": "sha512-+o2q111WEx4srBs7L9eJmcwi655eD8sXniLqMB93TBK9GrNzGrxDWSjiqz2hLU0Ha8MTXFIP0yd9fNdP+m43ZQ==" - } - } + "integrity": "sha512-5AEH2EXD8euCk446b7edmgFdub/qfH1SN6Nii3+fyXP807QRx9Q73A2N5hNwRRslC2H9sNzaFhsPubkS4L8oNQ==" }, "@babel/traverse": { "version": "7.6.0", "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.6.0.tgz", - "integrity": "sha512-93t52SaOBgml/xY74lsmt7xOR4ufYvhb5c5qiM6lu4J/dWGMAfAh6eKw4PjLes6DI6nQgearoxnFJk60YchpvQ==", - "dependencies": { - "@babel/parser": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.6.0.tgz", - "integrity": "sha512-+o2q111WEx4srBs7L9eJmcwi655eD8sXniLqMB93TBK9GrNzGrxDWSjiqz2hLU0Ha8MTXFIP0yd9fNdP+m43ZQ==" - } - } + "integrity": "sha512-93t52SaOBgml/xY74lsmt7xOR4ufYvhb5c5qiM6lu4J/dWGMAfAh6eKw4PjLes6DI6nQgearoxnFJk60YchpvQ==" }, "@babel/types": { "version": "7.6.1", @@ -533,9 +544,9 @@ "integrity": "sha1-viQcqBQEAwZ4t0hxcyK4nQyP4oA=" }, "babel-preset-meteor": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/babel-preset-meteor/-/babel-preset-meteor-7.6.0.tgz", - "integrity": "sha512-YEuDJ3F8s8eLtv0Rpg9gD6xRa9gLYw6KiaZmYGyhj6VoyhEVAHFfzLd7aqE2KVlYYFowr/hi4BcqTE7hcu0ECQ==" + "version": "7.6.1", + "resolved": "https://registry.npmjs.org/babel-preset-meteor/-/babel-preset-meteor-7.6.1.tgz", + "integrity": "sha512-MtFTa3g7cF+lepxY+XraKMTXBKdY5iNrSC2vcnp/cSC3rLwhWfc8WCxIS+qFU7dTen0u2IB3GIWI8cjqCIMOsA==" }, "babel-preset-minify": { "version": "0.5.1", @@ -628,9 +639,9 @@ "integrity": "sha512-6QK0OpF/phMz0Q2AxILkX2mFhi7m+WMwTRg0LQKq/WBB0cDP4rYH3Wp4/d3OTXlrPLVJT/RFqj8tFeAR4nk8AA==" }, "meteor-babel": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/meteor-babel/-/meteor-babel-7.6.0.tgz", - "integrity": "sha512-LOFO4R6qoujjalVafJfSk/io9Mydj1tgAd8+b2f8a3f4dtaFxOp3ey99SrpDEjMdztOa1vMEEJbtGJ8ozoyENg==" + "version": "7.6.1", + "resolved": "https://registry.npmjs.org/meteor-babel/-/meteor-babel-7.6.1.tgz", + "integrity": "sha512-3gINjMYXgbBvkWs9x/rD4MInU2hOUTJ5dREEVcKQh48kvLa7WMKl28dkPFARTr0GmGVLqrlP8a01QCgEqk8+9A==" }, "meteor-babel-helpers": { "version": "0.0.3", @@ -688,9 +699,9 @@ "integrity": "sha512-flVuee02C3FKRISbxhXl9mGzdbWUVHubl1SMaknjxkFB1/iqpJhArQUvRxOOPEc/9tAiX0BaQ28FJH10E4isSQ==" }, "regexpu-core": { - "version": "4.5.5", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.5.5.tgz", - "integrity": "sha512-FpI67+ky9J+cDizQUJlIlNZFKual/lUkFr1AG6zOCpwZ9cLrg8UUVakyUQJD7fCDIe9Z2nwTQJNPyonatNmDFQ==" + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.6.0.tgz", + "integrity": "sha512-YlVaefl8P5BnFYOITTNzDvan1ulLOiXJzCNZxduTIosN17b87h3bvG9yHMoHaRuo88H4mQ06Aodj5VtYGGGiTg==" }, "regjsgen": { "version": "0.5.0", @@ -755,9 +766,9 @@ "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=" }, "typescript": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.6.2.tgz", - "integrity": "sha512-lmQ4L+J6mnu3xweP8+rOrUwzmN+MRAj7TgtJtDaXE5PMyX2kCrklhg3rvOsOIfNeAWMQWO2F1GPc1kMD2vLAfw==" + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.6.3.tgz", + "integrity": "sha512-N7bceJL1CtRQ2RiG0AQME13ksR7DiuQh/QehubYcghzv20tnh+MQnQIuJddTmsbqYj+dztchykemz0zFzlvdQw==" }, "unicode-canonical-property-names-ecmascript": { "version": "1.0.4", diff --git a/packages/babel-compiler/babel-compiler.js b/packages/babel-compiler/babel-compiler.js index f93790fc18..b88abe5a30 100644 --- a/packages/babel-compiler/babel-compiler.js +++ b/packages/babel-compiler/babel-compiler.js @@ -79,22 +79,22 @@ BCp.processOneFileForTarget = function (inputFile, source) { // compilation, give it the following file extension: .es5.js ! excludedFileExtensionPattern.test(inputFilePath)) { - const extraFeatures = { ...this.extraFeatures }; + const features = { ...this.extraFeatures }; const arch = inputFile.getArch(); if (arch.startsWith("os.")) { // Start with a much simpler set of Babel presets and plugins if // we're compiling for Node 8. - extraFeatures.nodeMajorVersion = parseInt(process.versions.node, 10); + features.nodeMajorVersion = parseInt(process.versions.node, 10); } else if (arch === "web.browser") { - extraFeatures.modernBrowsers = true; + features.modernBrowsers = true; } - if (! extraFeatures.hasOwnProperty("jscript")) { + if (! features.hasOwnProperty("jscript")) { // Perform some additional transformations to improve compatibility // in older browsers (e.g. wrapping named function expressions, per // http://kiro.me/blog/nfe_dilemma.html). - extraFeatures.jscript = true; + features.jscript = true; } if (shouldCompileModulesOnly(inputFilePath)) { @@ -102,12 +102,9 @@ BCp.processOneFileForTarget = function (inputFile, source) { // compiled to support ECMAScript modules syntax, but should *not* // be compiled in any other way (for more explanation, see my longer // comment in shouldCompileModulesOnly). - extraFeatures.compileModulesOnly = true; + features.compileModulesOnly = true; } - var babelOptions = Babel.getDefaultOptions(extraFeatures); - babelOptions.caller = { name: "meteor", arch }; - const cacheOptions = { cacheDirectory: this.cacheDirectory, cacheDeps: { @@ -115,6 +112,12 @@ BCp.processOneFileForTarget = function (inputFile, source) { }, }; + this.inferTypeScriptConfig( + features, inputFile, cacheOptions.cacheDeps); + + var babelOptions = Babel.getDefaultOptions(features); + babelOptions.caller = { name: "meteor", arch }; + this.inferExtraBabelOptions( inputFile, babelOptions, @@ -212,6 +215,20 @@ function profile(name, func) { } }; +BCp.inferTypeScriptConfig = function (features, inputFile, cacheDeps) { + if (features.typescript && inputFile.findControlFile) { + const tsconfigPath = inputFile.findControlFile("tsconfig.json"); + if (tsconfigPath) { + if (typeof features.typescript !== "object") { + features.typescript = Object.create(null); + } + Object.assign(features.typescript, { tsconfigPath }); + return true; + } + } + return false; +}; + BCp.inferExtraBabelOptions = function (inputFile, babelOptions, cacheDeps) { if (! inputFile.require || ! inputFile.findControlFile || diff --git a/packages/babel-compiler/package.js b/packages/babel-compiler/package.js index 86001c64b3..2b85362775 100644 --- a/packages/babel-compiler/package.js +++ b/packages/babel-compiler/package.js @@ -10,7 +10,7 @@ Package.describe({ }); Npm.depends({ - 'meteor-babel': '7.6.0', + 'meteor-babel': '7.6.1', 'json5': '2.1.0' }); diff --git a/packages/ecmascript-runtime-client/.npm/package/npm-shrinkwrap.json b/packages/ecmascript-runtime-client/.npm/package/npm-shrinkwrap.json index 79e8c3e339..c5366d30b1 100644 --- a/packages/ecmascript-runtime-client/.npm/package/npm-shrinkwrap.json +++ b/packages/ecmascript-runtime-client/.npm/package/npm-shrinkwrap.json @@ -2,9 +2,9 @@ "lockfileVersion": 1, "dependencies": { "core-js": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.1.4.tgz", - "integrity": "sha512-YNZN8lt82XIMLnLirj9MhKDFZHalwzzrL9YLt6eb0T5D0EDl4IQ90IGkua8mHbnxNrkj1d8hbdizMc0Qmg1WnQ==" + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.2.1.tgz", + "integrity": "sha512-Qa5XSVefSVPRxy2XfUC13WbvqkxhkwB3ve+pgCQveNgYzbM/UxZeu1dcOX/xr4UmfUd+muuvsaxilQzCyUurMw==" } } } diff --git a/packages/ecmascript-runtime-client/package.js b/packages/ecmascript-runtime-client/package.js index 07ed8241c8..17f1de7e4e 100644 --- a/packages/ecmascript-runtime-client/package.js +++ b/packages/ecmascript-runtime-client/package.js @@ -7,7 +7,7 @@ Package.describe({ }); Npm.depends({ - "core-js": "3.1.4" + "core-js": "3.2.1" }); Package.onUse(function(api) { diff --git a/packages/ecmascript-runtime-server/.npm/package/npm-shrinkwrap.json b/packages/ecmascript-runtime-server/.npm/package/npm-shrinkwrap.json index 79e8c3e339..c5366d30b1 100644 --- a/packages/ecmascript-runtime-server/.npm/package/npm-shrinkwrap.json +++ b/packages/ecmascript-runtime-server/.npm/package/npm-shrinkwrap.json @@ -2,9 +2,9 @@ "lockfileVersion": 1, "dependencies": { "core-js": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.1.4.tgz", - "integrity": "sha512-YNZN8lt82XIMLnLirj9MhKDFZHalwzzrL9YLt6eb0T5D0EDl4IQ90IGkua8mHbnxNrkj1d8hbdizMc0Qmg1WnQ==" + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.2.1.tgz", + "integrity": "sha512-Qa5XSVefSVPRxy2XfUC13WbvqkxhkwB3ve+pgCQveNgYzbM/UxZeu1dcOX/xr4UmfUd+muuvsaxilQzCyUurMw==" } } } diff --git a/packages/ecmascript-runtime-server/package.js b/packages/ecmascript-runtime-server/package.js index b33f346508..c3a906a24e 100644 --- a/packages/ecmascript-runtime-server/package.js +++ b/packages/ecmascript-runtime-server/package.js @@ -7,7 +7,7 @@ Package.describe({ }); Npm.depends({ - "core-js": "3.1.4" + "core-js": "3.2.1" }); Package.onUse(function(api) { diff --git a/packages/minifier-js/.npm/package/npm-shrinkwrap.json b/packages/minifier-js/.npm/package/npm-shrinkwrap.json index eec2ad9379..30e274a698 100644 --- a/packages/minifier-js/.npm/package/npm-shrinkwrap.json +++ b/packages/minifier-js/.npm/package/npm-shrinkwrap.json @@ -7,9 +7,9 @@ "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" }, "commander": { - "version": "2.17.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz", - "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==" + "version": "2.20.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz", + "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==" }, "source-map": { "version": "0.6.1", @@ -17,14 +17,14 @@ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" }, "source-map-support": { - "version": "0.5.10", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.10.tgz", - "integrity": "sha512-YfQ3tQFTK/yzlGJuX8pTwa4tifQj4QS2Mj7UegOu8jAz59MqIiMGPXxQhVQiIMNzayuUSF/jEuVnfFF5JqybmQ==" + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==" }, "terser": { - "version": "3.16.1", - "resolved": "https://registry.npmjs.org/terser/-/terser-3.16.1.tgz", - "integrity": "sha512-JDJjgleBROeek2iBcSNzOHLKsB/MdDf+E/BOAJ0Tk9r7p9/fVobfv7LMJ/g/k3v9SXdmjZnIlFd5nfn/Rt0Xow==" + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-4.3.1.tgz", + "integrity": "sha512-pnzH6dnFEsR2aa2SJaKb1uSCl3QmIsJ8dEkj0Fky+2AwMMcC9doMqLOQIH6wVTEKaVfKVvLSk5qxPBEZT9mywg==" } } } diff --git a/packages/minifier-js/package.js b/packages/minifier-js/package.js index e6c8fab292..fa319ae271 100644 --- a/packages/minifier-js/package.js +++ b/packages/minifier-js/package.js @@ -1,10 +1,10 @@ Package.describe({ summary: "JavaScript minifier", - version: "2.4.1" + version: "2.5.0-rc182.0" }); Npm.depends({ - terser: "3.16.1" + terser: "4.3.1" }); Package.onUse(function (api) { diff --git a/packages/standard-minifier-js/package.js b/packages/standard-minifier-js/package.js index 6f98cf77c3..0b3680082d 100644 --- a/packages/standard-minifier-js/package.js +++ b/packages/standard-minifier-js/package.js @@ -1,6 +1,6 @@ Package.describe({ name: 'standard-minifier-js', - version: '2.4.1', + version: '2.5.0-rc182.0', summary: 'Standard javascript minifiers used with Meteor apps by default.', documentation: 'README.md', }); diff --git a/scripts/dev-bundle-tool-package.js b/scripts/dev-bundle-tool-package.js index 934c280d92..f2dbf730e2 100644 --- a/scripts/dev-bundle-tool-package.js +++ b/scripts/dev-bundle-tool-package.js @@ -15,7 +15,7 @@ var packageJson = { "node-gyp": "5.0.1", "node-pre-gyp": "0.13.0", typescript: "3.6.2", - "meteor-babel": "7.6.0", + "meteor-babel": "7.6.1", // Keep the versions of these packages consistent with the versions // found in dev-bundle-server-package.js. "meteor-promise": "0.8.7", @@ -61,7 +61,7 @@ var packageJson = { pathwatcher: "8.1.0", // The @wry/context package version must be compatible with the // version constraint imposed by optimism/package.json. - optimism: "0.10.2", + optimism: "0.11.2", "@wry/context": "0.4.4", 'lru-cache': '4.1.3' } diff --git a/tools/cli/commands.js b/tools/cli/commands.js index 7648a2128c..2b4d2f5599 100644 --- a/tools/cli/commands.js +++ b/tools/cli/commands.js @@ -505,6 +505,7 @@ main.registerCommand({ minimal: { type: Boolean }, full: { type: Boolean }, react: { type: Boolean }, + typescript: { type: Boolean }, }, catalogRefresh: new catalog.Refresh.Never() }, function (options) { @@ -593,7 +594,7 @@ main.registerCommand({ return transform(f); }, transformContents: function (contents, f) { - if ((/(\.html|\.js|\.css)/).test(f)) { + if ((/(\.html|\.[jt]sx?|\.css)/).test(f)) { return Buffer.from(transform(contents.toString())); } else { return contents; @@ -757,6 +758,8 @@ main.registerCommand({ skelName += "-full"; } else if (options.react) { skelName += "-react"; + } else if (options.typescript) { + skelName += "-typescript"; } files.cp_r(files.pathJoin(__dirnameConverted, '..', 'static-assets', skelName), appPath, { @@ -764,7 +767,7 @@ main.registerCommand({ return transform(f); }, transformContents: function (contents, f) { - if ((/(\.html|\.js|\.css)/).test(f)) { + if ((/(\.html|\.[jt]sx?|\.css)/).test(f)) { return Buffer.from(transform(contents.toString())); } else { return contents; @@ -864,20 +867,20 @@ main.registerCommand({ if (! options.bare && ! options.minimal && ! options.full && - ! options.react) { - // Notify people about --bare, --minimal, --full, and --react. + ! options.react && + ! options.typescript) { + // Notify people about --bare, --minimal, --full, --react, and --typescript. Console.info([ "", "To start with a different app template, try one of the following:", "", ].join("\n")); - cmd("meteor create --bare # to create an empty app"); - cmd("meteor create --minimal # to create an app with as few " + - "Meteor packages as possible"); - cmd("meteor create --full # to create a more complete " + - "scaffolded app"); - cmd("meteor create --react # to create a basic React-based app"); + cmd("meteor create --bare # to create an empty app"); + cmd("meteor create --minimal # to create an app with as few Meteor packages as possible"); + cmd("meteor create --full # to create a more complete scaffolded app"); + cmd("meteor create --react # to create a basic React-based app"); + cmd("meteor create --typescript # to create an app using TypeScript and React"); } Console.info(""); diff --git a/tools/fs/files.ts b/tools/fs/files.ts index 3d51cb8cc5..d2fb10c8cd 100644 --- a/tools/fs/files.ts +++ b/tools/fs/files.ts @@ -11,6 +11,7 @@ import os from "os"; import { spawn, execFile } from "child_process"; import { EventEmitter } from "events"; import { Slot } from "@wry/context"; +import { dep } from "optimism"; const _ = require('underscore'); const Fiber = require("fibers"); @@ -1646,16 +1647,7 @@ export function withCache(fn: () => R): R { return cache ? fn() : withCacheSlot.withValue(Object.create(null), fn); } -let dependOnPathSalt = 0; -import { wrap } from "optimism"; -export const dependOnPath = wrap( - // Always return something different to prevent optimism from - // second-guessing the dirtiness of this function. - (_path: string) => ++dependOnPathSalt, - // This function is disposable because we don't care about its result, - // only its role in optimistic dependency tracking/dirtying. - { disposable: true } -); +export const dependOnPath = dep(); function wrapDestructiveFsFunc( fnName: string, diff --git a/tools/fs/optimistic.ts b/tools/fs/optimistic.ts index 4557474917..64e6dbf676 100644 --- a/tools/fs/optimistic.ts +++ b/tools/fs/optimistic.ts @@ -1,5 +1,5 @@ import assert from "assert"; -import { wrap, OptimisticWrapperFunction } from "optimism"; +import { wrap, OptimisticWrapperFunction, dep } from "optimism"; import ignore from "ignore"; import { Profile } from "../tool-env/profile"; import { watch, SafeWatcher } from "./safe-watcher"; @@ -15,6 +15,7 @@ import { readFile, readdir, dependOnPath, + findAppDir, } from "./files"; // When in doubt, the optimistic caching system can be completely disabled @@ -79,7 +80,12 @@ function makeOptimistic< return wrapper; } -export const shouldWatch = wrap((path: string) => { +// The Meteor application directory should never change during the lifetime +// of the build process, so it should be safe to cache findAppDir without +// subscribing to file changes. +const optimisticFindAppDir = wrap(findAppDir); + +const shouldWatch = wrap(Profile("shouldWatch", (path: string) => { const parts = path.split(pathSep); const nmi = parts.indexOf("node_modules"); @@ -88,6 +94,14 @@ export const shouldWatch = wrap((path: string) => { return true; } + const dotMeteorIndex = parts.lastIndexOf(".meteor", nmi); + if (dotMeteorIndex >= 0) { + // Watch nothing inside of .meteor, at least for the purposes of the + // optimistic caching system. Meteor watches files inside .meteor/local + // via the WatchSet abstraction, unrelatedly. + return false; + } + if (nmi < parts.length - 1) { const nmi2 = parts.indexOf("node_modules", nmi + 1); if (nmi2 > nmi) { @@ -97,6 +111,21 @@ export const shouldWatch = wrap((path: string) => { return false; } + const parentDirParts = parts.slice(0, nmi); + const parentDir = parentDirParts.join(pathSep); + const appDir = optimisticFindAppDir(parentDir); + if ( + appDir && + parentDir.startsWith(appDir) && + appDir.split(pathSep).length < parentDirParts.length + ) { + // If the given path is contained by the Meteor application directory, + // but the node_modules directory we're considering is not directly + // contained by the root application directory, watch the file. See + // discussion in issue https://github.com/meteor/meteor/issues/10664 + return true; + } + const packageDirParts = parts.slice(0, nmi + 2); if (parts[nmi + 1].startsWith("@")) { @@ -118,7 +147,7 @@ export const shouldWatch = wrap((path: string) => { // instead we rely on dependOnNodeModules to tell us when files in // node_modules directories might have changed. return false; -}); +})); function maybeDependOnPath(path: string) { if (typeof path === "string") { @@ -146,13 +175,7 @@ function maybeDependOnNodeModules(path: string) { } } -let dependOnDirectorySalt = 0; - -const dependOnDirectory = wrap((_dir: string) => { - // Always return something different to prevent optimism from - // second-guessing the dirtiness of this function. - return ++dependOnDirectorySalt; -}, { +const dependOnDirectory = dep({ subscribe(dir: string) { let watcher: SafeWatcher | null = watch( dir, @@ -166,10 +189,6 @@ const dependOnDirectory = wrap((_dir: string) => { } }; }, - - // This function is disposable because we don't care about its result, - // only its role in optimistic dependency tracking/dirtying. - disposable: true }); // Called when an optimistic function detects the given file does not @@ -191,20 +210,16 @@ function dependOnParentDirectory(path: string) { // Note that this strategy will not detect changes within subdirectories // of this node_modules directory, but that's ok because the use case we // care about is adding or removing npm packages. -const dependOnNodeModules = wrap((nodeModulesDir: string) => { +function dependOnNodeModules(nodeModulesDir: string) { assert(pathIsAbsolute(nodeModulesDir)); assert(nodeModulesDir.endsWith(pathSep + "node_modules")); - return dependOnDirectory(nodeModulesDir); -}, { - // This function is disposable because we don't care about its result, - // only its role in optimistic dependency tracking/dirtying. - disposable: true -}); + dependOnDirectory(nodeModulesDir); +} // Invalidate all optimistic results derived from paths involving the // given node_modules directory. export function dirtyNodeModulesDirectory(nodeModulesDir: string) { - dependOnNodeModules.dirty(nodeModulesDir); + dependOnDirectory.dirty(nodeModulesDir); } export const optimisticStatOrNull = makeOptimistic("statOrNull", (path: string) => { @@ -247,7 +262,7 @@ export const optimisticHashOrNull = makeOptimistic("hashOrNull", ( }); // A more tolerant implementation of JSON.parse. -import JSON from "json5"; +const { parse: jsonParse } = require("json5"); export const optimisticReadJsonOrNull = makeOptimistic("readJsonOrNull", ( @@ -257,7 +272,7 @@ makeOptimistic("readJsonOrNull", ( }, ) => { try { - return JSON.parse( + return jsonParse( optimisticReadFile(path, options) ) as Record; diff --git a/tools/static-assets/skel-react/imports/api/links.js b/tools/static-assets/skel-react/imports/api/links.js index 27352f85ff..872bb75c9c 100644 --- a/tools/static-assets/skel-react/imports/api/links.js +++ b/tools/static-assets/skel-react/imports/api/links.js @@ -1,3 +1,3 @@ import { Mongo } from 'meteor/mongo'; -export default Links = new Mongo.Collection('links'); +export default new Mongo.Collection('links'); diff --git a/tools/static-assets/skel-typescript/.gitignore b/tools/static-assets/skel-typescript/.gitignore new file mode 100644 index 0000000000..c2658d7d1b --- /dev/null +++ b/tools/static-assets/skel-typescript/.gitignore @@ -0,0 +1 @@ +node_modules/ diff --git a/tools/static-assets/skel-typescript/.meteor/.gitignore b/tools/static-assets/skel-typescript/.meteor/.gitignore new file mode 100644 index 0000000000..4083037423 --- /dev/null +++ b/tools/static-assets/skel-typescript/.meteor/.gitignore @@ -0,0 +1 @@ +local diff --git a/tools/static-assets/skel-typescript/.meteor/packages b/tools/static-assets/skel-typescript/.meteor/packages new file mode 100644 index 0000000000..3319ee0005 --- /dev/null +++ b/tools/static-assets/skel-typescript/.meteor/packages @@ -0,0 +1,22 @@ +# Meteor packages used by this project, one per line. +# Check this file (and the other files in this directory) into your repository. +# +# 'meteor add' and 'meteor remove' will edit this file for you, +# but you can also edit it by hand. + +meteor-base # Packages every Meteor app needs to have +mobile-experience # Packages for a great mobile UX +mongo # The database Meteor supports right now +reactive-var # Reactive variable for tracker + +standard-minifier-css # CSS minifier run for production mode +standard-minifier-js # JS minifier run for production mode +es5-shim # ECMAScript 5 compatibility for older browsers +ecmascript # Enable ECMAScript2015+ syntax in app code +typescript # Enable TypeScript syntax in .ts and .tsx modules +shell-server # Server-side component of the `meteor shell` command + +autopublish # Publish all data to the clients (for prototyping) +insecure # Allow all DB writes from clients (for prototyping) +static-html # Define static page content in .html files +react-meteor-data # React higher-order component for reactively tracking Meteor data diff --git a/tools/static-assets/skel-typescript/.meteor/platforms b/tools/static-assets/skel-typescript/.meteor/platforms new file mode 100644 index 0000000000..efeba1b50c --- /dev/null +++ b/tools/static-assets/skel-typescript/.meteor/platforms @@ -0,0 +1,2 @@ +server +browser diff --git a/tools/static-assets/skel-typescript/client/main.css b/tools/static-assets/skel-typescript/client/main.css new file mode 100644 index 0000000000..7f354f0fa7 --- /dev/null +++ b/tools/static-assets/skel-typescript/client/main.css @@ -0,0 +1,4 @@ +body { + padding: 10px; + font-family: sans-serif; +} diff --git a/tools/static-assets/skel-typescript/client/main.html b/tools/static-assets/skel-typescript/client/main.html new file mode 100644 index 0000000000..27c3712e54 --- /dev/null +++ b/tools/static-assets/skel-typescript/client/main.html @@ -0,0 +1,7 @@ + + ~name~ + + + +
+ diff --git a/tools/static-assets/skel-typescript/client/main.tsx b/tools/static-assets/skel-typescript/client/main.tsx new file mode 100644 index 0000000000..e3b8986233 --- /dev/null +++ b/tools/static-assets/skel-typescript/client/main.tsx @@ -0,0 +1,8 @@ +import React from 'react'; +import { Meteor } from 'meteor/meteor'; +import { render } from 'react-dom'; +import App from '/imports/ui/App' + +Meteor.startup(() => { + render(, document.getElementById('react-target')); +}); diff --git a/tools/static-assets/skel-typescript/imports/api/links.ts b/tools/static-assets/skel-typescript/imports/api/links.ts new file mode 100644 index 0000000000..f426a971d4 --- /dev/null +++ b/tools/static-assets/skel-typescript/imports/api/links.ts @@ -0,0 +1,10 @@ +import { Mongo } from 'meteor/mongo'; + +export interface Link { + _id?: string; + title: string; + url: string; + createdAt: Date; +} + +export const Links = new Mongo.Collection('links'); diff --git a/tools/static-assets/skel-typescript/imports/ui/App.tsx b/tools/static-assets/skel-typescript/imports/ui/App.tsx new file mode 100644 index 0000000000..e28430f56a --- /dev/null +++ b/tools/static-assets/skel-typescript/imports/ui/App.tsx @@ -0,0 +1,11 @@ +import React from 'react'; +import Hello from './Hello'; +import Info from './Info'; + +export default () => ( +
+

Welcome to Meteor!

+ + +
+); diff --git a/tools/static-assets/skel-typescript/imports/ui/Hello.tsx b/tools/static-assets/skel-typescript/imports/ui/Hello.tsx new file mode 100644 index 0000000000..a717944c0c --- /dev/null +++ b/tools/static-assets/skel-typescript/imports/ui/Hello.tsx @@ -0,0 +1,22 @@ +import React from 'react'; + +export default class Hello extends React.Component { + state = { + counter: 0, + } + + increment() { + this.setState({ + counter: this.state.counter + 1 + }); + } + + render() { + return ( +
+ +

You've pressed the button {this.state.counter} times.

+
+ ); + } +} diff --git a/tools/static-assets/skel-typescript/imports/ui/Info.tsx b/tools/static-assets/skel-typescript/imports/ui/Info.tsx new file mode 100644 index 0000000000..098df948ac --- /dev/null +++ b/tools/static-assets/skel-typescript/imports/ui/Info.tsx @@ -0,0 +1,34 @@ +import React from 'react'; +import { withTracker } from 'meteor/react-meteor-data'; +import { Links, Link } from '../api/links'; + +class Info extends React.Component<{ + links: Link[]; +}> { + render() { + const links = this.props.links.map( + link => this.makeLink(link) + ); + + return ( +
+

Learn Meteor!

+
    { links }
+
+ ); + } + + makeLink(link: Link) { + return ( +
  • + {link.title} +
  • + ); + } +} + +export default withTracker(() => { + return { + links: Links.find().fetch(), + }; +})(Info); diff --git a/tools/static-assets/skel-typescript/package.json b/tools/static-assets/skel-typescript/package.json new file mode 100644 index 0000000000..4fb03a4b66 --- /dev/null +++ b/tools/static-assets/skel-typescript/package.json @@ -0,0 +1,29 @@ +{ + "name": "~name~", + "private": true, + "scripts": { + "start": "meteor run", + "test": "meteor test --once --driver-package meteortesting:mocha", + "test-app": "TEST_WATCH=1 meteor test --full-app --driver-package meteortesting:mocha", + "visualize": "meteor --production --extra-packages bundle-visualizer" + }, + "dependencies": { + "@babel/runtime": "^7.6.0", + "meteor-node-stubs": "^1.0.0", + "react": "^16.9.0", + "react-dom": "^16.9.0" + }, + "devDependencies": { + "@types/meteor": "^1.4.30", + "@types/mocha": "^5.2.7", + "@types/react": "^16.9.0", + "@types/react-dom": "^16.9.0" + }, + "meteor": { + "mainModule": { + "client": "client/main.tsx", + "server": "server/main.ts" + }, + "testModule": "tests/main.ts" + } +} diff --git a/tools/static-assets/skel-typescript/server/main.ts b/tools/static-assets/skel-typescript/server/main.ts new file mode 100644 index 0000000000..9f8cf7abcc --- /dev/null +++ b/tools/static-assets/skel-typescript/server/main.ts @@ -0,0 +1,31 @@ +import { Meteor } from 'meteor/meteor'; +import { Links } from '/imports/api/links'; + +function insertLink(title: string, url: string) { + Links.insert({ title, url, createdAt: new Date() }); +} + +Meteor.startup(() => { + // If the Links collection is empty, add some data. + if (Links.find().count() === 0) { + insertLink( + 'Do the Tutorial', + 'https://www.meteor.com/tutorials/react/creating-an-app' + ); + + insertLink( + 'Follow the Guide', + 'http://guide.meteor.com' + ); + + insertLink( + 'Read the Docs', + 'https://docs.meteor.com' + ); + + insertLink( + 'Discussions', + 'https://forums.meteor.com' + ); + } +}); diff --git a/tools/static-assets/skel-typescript/tests/main.ts b/tools/static-assets/skel-typescript/tests/main.ts new file mode 100644 index 0000000000..7c3722128b --- /dev/null +++ b/tools/static-assets/skel-typescript/tests/main.ts @@ -0,0 +1,21 @@ +import { Meteor } from 'meteor/meteor'; +import assert from 'assert'; + +describe('~name~', function () { + it('package.json has correct name', async function () { + const { name } = await import('../package.json'); + assert.strictEqual(name, '~name~'); + }); + + if (Meteor.isClient) { + it('client is not server', function () { + assert.strictEqual(Meteor.isServer, false); + }); + } + + if (Meteor.isServer) { + it('server is not client', function () { + assert.strictEqual(Meteor.isClient, false); + }); + } +}); diff --git a/tools/static-assets/skel-typescript/tsconfig.json b/tools/static-assets/skel-typescript/tsconfig.json new file mode 100644 index 0000000000..4be740cec2 --- /dev/null +++ b/tools/static-assets/skel-typescript/tsconfig.json @@ -0,0 +1,40 @@ +{ + "compilerOptions": { + /* Basic Options */ + "target": "es2018", + "module": "esNext", + "lib": ["esnext", "dom"], + "allowJs": true, + "checkJs": false, + "jsx": "preserve", + "incremental": true, + "noEmit": true, + + /* Strict Type-Checking Options */ + "strict": true, + "noImplicitAny": true, + "strictNullChecks": true, + + /* Additional Checks */ + "noUnusedLocals": true, + "noUnusedParameters": true, + "noImplicitReturns": false, + "noFallthroughCasesInSwitch": false, + + /* Module Resolution Options */ + "baseUrl": ".", + "paths": { + /* Support absolute /imports/* with a leading '/' */ + "/*": ["*"] + }, + "moduleResolution": "node", + "resolveJsonModule": true, + "types": ["node", "mocha"], + "esModuleInterop": true, + "preserveSymlinks": true + }, + "exclude": [ + "./.meteor/**", + "./packages/**" + ] +} diff --git a/tools/tsconfig.json b/tools/tsconfig.json index 668d91e71b..ce0a729ba8 100644 --- a/tools/tsconfig.json +++ b/tools/tsconfig.json @@ -6,6 +6,7 @@ "lib": ["esnext"], "allowJs": true, "checkJs": false, + "jsx": "preserve", "incremental": true, "noEmit": true,