From ae49aa44bb17c8488ee8e08f66fcbbf30d0d1699 Mon Sep 17 00:00:00 2001 From: zodern Date: Fri, 3 Mar 2023 17:07:23 -0600 Subject: [PATCH 1/4] Use __meteor_bootstrap__ to check if fibers enabled --- packages/meteor/asl-helpers-client.js | 2 ++ packages/meteor/asl-helpers.js | 4 +++- tools/isobuild/isopack.js | 15 +++++++++++++-- tools/static-assets/server/boot.js | 4 ++-- tools/tool-env/isopackets.js | 5 ++++- 5 files changed, 24 insertions(+), 6 deletions(-) diff --git a/packages/meteor/asl-helpers-client.js b/packages/meteor/asl-helpers-client.js index 688ae22205..1026afcb80 100644 --- a/packages/meteor/asl-helpers-client.js +++ b/packages/meteor/asl-helpers-client.js @@ -1,3 +1,5 @@ +Meteor.fibersDisabled = true; + Meteor._isPromise = (r) => { return r && typeof r.then === 'function'; }; diff --git a/packages/meteor/asl-helpers.js b/packages/meteor/asl-helpers.js index f140cc9a3c..1ae0571e7f 100644 --- a/packages/meteor/asl-helpers.js +++ b/packages/meteor/asl-helpers.js @@ -2,7 +2,9 @@ const getAslStore = () => (Meteor.isServer && global?.asyncLocalStorage?.getStor const getValueFromAslStore = key => getAslStore()[key]; const updateAslStore = (key, value) => getAslStore()[key] = value; -Meteor._isFibersEnabled = !process.env.DISABLE_FIBERS && Meteor.isServer; +Meteor.fibersDisabled = !!__meteor_bootstrap__.fibersDisabled; +Meteor._isFibersEnabled = !Meteor.fibersDisabled; + Meteor._getAslStore = getAslStore; Meteor._getValueFromAslStore = getValueFromAslStore; Meteor._updateAslStore = updateAslStore; diff --git a/tools/isobuild/isopack.js b/tools/isobuild/isopack.js index b1925feaf4..e366afd1b2 100644 --- a/tools/isobuild/isopack.js +++ b/tools/isobuild/isopack.js @@ -472,8 +472,19 @@ Object.assign(Isopack.prototype, { // case right.) }, async function () { // Make a new Plugin API object for this plugin. - var Plugin = self._makePluginApi(name); - await plugin.load({ Plugin: Plugin, Profile: Profile }); + const Plugin = self._makePluginApi(name); + const __meteor_bootstrap__ = { + fibersDisabled: true, + // Set to null to tell Meteor.startup to call hooks immediately + // XXX: should we fully support startup hooks in build plugins? + startupHooks: null + }; + + await plugin.load({ + Plugin, + Profile, + __meteor_bootstrap__ + }); }); } diff --git a/tools/static-assets/server/boot.js b/tools/static-assets/server/boot.js index ca6f586c25..453d30e779 100644 --- a/tools/static-assets/server/boot.js +++ b/tools/static-assets/server/boot.js @@ -33,7 +33,8 @@ var starJson = JSON.parse(fs.readFileSync(path.join(buildDir, "star.json"))); __meteor_bootstrap__ = { startupHooks: [], serverDir: serverDir, - configJson: configJson + configJson: configJson, + fibersDisabled: true }; __meteor_runtime_config__ = { @@ -504,4 +505,3 @@ var runMain = Profile("Run main()", async function () { }); }); })().catch(e => console.log('error on boot.js', e)); - diff --git a/tools/tool-env/isopackets.js b/tools/tool-env/isopackets.js index d2c21afd6d..acd59e7a40 100644 --- a/tools/tool-env/isopackets.js +++ b/tools/tool-env/isopackets.js @@ -303,7 +303,10 @@ var loadIsopacketFromDisk = async function (isopacketName) { // An incredibly minimalist version of the environment from // tools/server/boot.js. Kind of a hack. var env = { - __meteor_bootstrap__: { startupHooks: [] }, + __meteor_bootstrap__: { + startupHooks: [], + fibersDisabled: true + }, __meteor_runtime_config__: { meteorRelease: "ISOPACKET" } }; env.Profile = Profile; From 6a304c66c185f0999d19e6ce70ee9141ef0e18fe Mon Sep 17 00:00:00 2001 From: zodern Date: Fri, 3 Mar 2023 17:07:42 -0600 Subject: [PATCH 2/4] Re-add async-await plugin --- .../meteor-babel/plugins/async-await.js | 74 +++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 npm-packages/meteor-babel/plugins/async-await.js diff --git a/npm-packages/meteor-babel/plugins/async-await.js b/npm-packages/meteor-babel/plugins/async-await.js new file mode 100644 index 0000000000..ffd97d28af --- /dev/null +++ b/npm-packages/meteor-babel/plugins/async-await.js @@ -0,0 +1,74 @@ +"use strict"; + +module.exports = function (babel) { + const t = babel.types; + + return { + name: "transform-meteor-async-await", + visitor: { + Function: { + exit: function (path) { + const node = path.node; + if (!node.async) { + return; + } + + // The original function becomes a non-async function that + // returns a Promise. + node.async = false; + + // The inner function should inherit lexical environment items + // like `this`, `super`, and `arguments` from the outer + // function, and arrow functions provide exactly that behavior. + const innerFn = t.arrowFunctionExpression( + // The inner function has no parameters of its own, but can + // refer to the outer parameters of the original function. + [], + node.body, + // The inner function called by Promise.asyncApply should be + // async if we have native async/await support. + !!this.opts.useNativeAsyncAwait + ); + + const promiseResultExpression = t.callExpression( + t.memberExpression( + t.identifier("Promise"), + t.identifier("asyncApply"), + false + ), [innerFn] + ); + + // Calling the async function with Promise.asyncApply is + // important to ensure that the part before the first await + // expression runs synchronously in its own Fiber, even when + // there is native support for async/await. + if (node.type === "ArrowFunctionExpression") { + node.body = promiseResultExpression; + } else { + node.body = t.blockStatement([ + t.returnStatement(promiseResultExpression) + ]); + } + } + }, + + AwaitExpression: function (path) { + if (this.opts.useNativeAsyncAwait) { + // No need to transform await expressions if we have native + // support for them. + return; + } + + const node = path.node; + path.replaceWith(t.callExpression( + t.memberExpression( + t.identifier("Promise"), + t.identifier(node.all ? "awaitAll" : "await"), + false + ), + [node.argument] + )); + } + } + }; +}; From 8babb0c8deb1db64cff65b7d3957ba53c605ab02 Mon Sep 17 00:00:00 2001 From: zodern Date: Fri, 3 Mar 2023 17:09:19 -0600 Subject: [PATCH 3/4] Use features to configure async-await plugin --- npm-packages/meteor-babel/options.js | 9 ++++----- packages/babel-compiler/babel-compiler.js | 2 ++ tools/isobuild/builder.js | 3 ++- tools/tool-env/install-babel.js | 3 ++- 4 files changed, 10 insertions(+), 7 deletions(-) diff --git a/npm-packages/meteor-babel/options.js b/npm-packages/meteor-babel/options.js index 7f3db27945..7ff86ac842 100644 --- a/npm-packages/meteor-babel/options.js +++ b/npm-packages/meteor-babel/options.js @@ -188,16 +188,15 @@ function getDefaultsForNode8(features) { ); // TODO [fibers]: instead of removing the code below, consider this comment: // https://github.com/meteor/meteor/pull/12471/files#r1089610144 - const isFiberDisabled = process.env.DISABLE_FIBERS === '1'; const ignoreAsyncPlugin = process.env.IGNORE_ASYNC_PLUGIN === '1'; - if (!ignoreAsyncPlugin) { + if (!features.useNativeAsyncAwait && !ignoreAsyncPlugin) { combined.plugins.push([ require('./plugins/async-await.js'), { - // Do not transform `await x` to `Promise.await(x)`, since Node - // 8 has native support for await expressions. - useNativeAsyncAwait: isFiberDisabled, + // Even though Node 8 supports native async/await, it is not + // compatible with fibers. + useNativeAsyncAwait: false, }, ]); } diff --git a/packages/babel-compiler/babel-compiler.js b/packages/babel-compiler/babel-compiler.js index 879b6b302e..cacf9ebe95 100644 --- a/packages/babel-compiler/babel-compiler.js +++ b/packages/babel-compiler/babel-compiler.js @@ -96,6 +96,8 @@ BCp.processOneFileForTarget = function (inputFile, source) { features.topLevelAwait = arch.startsWith('os.') || enableClientTLA + features.useNativeAsyncAwait = Meteor.fibersDisabled; + if (! features.hasOwnProperty("jscript")) { // Perform some additional transformations to improve compatibility // in older browsers (e.g. wrapping named function expressions, per diff --git a/tools/isobuild/builder.js b/tools/isobuild/builder.js index 98f74a1a19..563d47bf01 100644 --- a/tools/isobuild/builder.js +++ b/tools/isobuild/builder.js @@ -369,7 +369,8 @@ Previous builder: ${previousBuilder.outputPath}, this builder: ${outputPath}` const babel = require("@meteorjs/babel"); const commonBabelOptions = babel.getDefaultOptions({ nodeMajorVersion: parseInt(process.versions.node), - typescript: true + typescript: true, + useNativeAsyncAwait: true }); commonBabelOptions.sourceMaps = true; diff --git a/tools/tool-env/install-babel.js b/tools/tool-env/install-babel.js index fb79789846..a49bcb6a7b 100644 --- a/tools/tool-env/install-babel.js +++ b/tools/tool-env/install-babel.js @@ -11,7 +11,8 @@ function babelRegister() { const cacheDir = path.join(meteorPath, ".babel-cache"); const babelOptions = meteorBabel.getDefaultOptions({ nodeMajorVersion: parseInt(process.versions.node), - typescript: true + typescript: true, + useNativeAsyncAwait: true }); // Make sure that source maps are included in the generated code for From c727788332842f63d43107763ae46f82a0a5fa44 Mon Sep 17 00:00:00 2001 From: zodern Date: Mon, 6 Mar 2023 10:45:29 -0600 Subject: [PATCH 4/4] Rename fibersDisabled to isFibersDisabled --- packages/babel-compiler/babel-compiler.js | 2 +- packages/meteor/asl-helpers-client.js | 2 +- packages/meteor/asl-helpers.js | 4 ++-- tools/isobuild/isopack.js | 2 +- tools/static-assets/server/boot.js | 2 +- tools/tool-env/isopackets.js | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/babel-compiler/babel-compiler.js b/packages/babel-compiler/babel-compiler.js index cacf9ebe95..2b7e2e8301 100644 --- a/packages/babel-compiler/babel-compiler.js +++ b/packages/babel-compiler/babel-compiler.js @@ -96,7 +96,7 @@ BCp.processOneFileForTarget = function (inputFile, source) { features.topLevelAwait = arch.startsWith('os.') || enableClientTLA - features.useNativeAsyncAwait = Meteor.fibersDisabled; + features.useNativeAsyncAwait = Meteor.isFibersDisabled; if (! features.hasOwnProperty("jscript")) { // Perform some additional transformations to improve compatibility diff --git a/packages/meteor/asl-helpers-client.js b/packages/meteor/asl-helpers-client.js index 1026afcb80..4780867f3a 100644 --- a/packages/meteor/asl-helpers-client.js +++ b/packages/meteor/asl-helpers-client.js @@ -1,4 +1,4 @@ -Meteor.fibersDisabled = true; +Meteor.isFibersDisabled = true; Meteor._isPromise = (r) => { return r && typeof r.then === 'function'; diff --git a/packages/meteor/asl-helpers.js b/packages/meteor/asl-helpers.js index 1ae0571e7f..bd9271b7cb 100644 --- a/packages/meteor/asl-helpers.js +++ b/packages/meteor/asl-helpers.js @@ -2,8 +2,8 @@ const getAslStore = () => (Meteor.isServer && global?.asyncLocalStorage?.getStor const getValueFromAslStore = key => getAslStore()[key]; const updateAslStore = (key, value) => getAslStore()[key] = value; -Meteor.fibersDisabled = !!__meteor_bootstrap__.fibersDisabled; -Meteor._isFibersEnabled = !Meteor.fibersDisabled; +Meteor.isFibersDisabled = !!__meteor_bootstrap__.isFibersDisabled; +Meteor._isFibersEnabled = !Meteor.isFibersDisabled; Meteor._getAslStore = getAslStore; Meteor._getValueFromAslStore = getValueFromAslStore; diff --git a/tools/isobuild/isopack.js b/tools/isobuild/isopack.js index e366afd1b2..31be03ed33 100644 --- a/tools/isobuild/isopack.js +++ b/tools/isobuild/isopack.js @@ -474,7 +474,7 @@ Object.assign(Isopack.prototype, { // Make a new Plugin API object for this plugin. const Plugin = self._makePluginApi(name); const __meteor_bootstrap__ = { - fibersDisabled: true, + isFibersDisabled: true, // Set to null to tell Meteor.startup to call hooks immediately // XXX: should we fully support startup hooks in build plugins? startupHooks: null diff --git a/tools/static-assets/server/boot.js b/tools/static-assets/server/boot.js index 453d30e779..1d2d7210f5 100644 --- a/tools/static-assets/server/boot.js +++ b/tools/static-assets/server/boot.js @@ -34,7 +34,7 @@ __meteor_bootstrap__ = { startupHooks: [], serverDir: serverDir, configJson: configJson, - fibersDisabled: true + isFibersDisabled: true }; __meteor_runtime_config__ = { diff --git a/tools/tool-env/isopackets.js b/tools/tool-env/isopackets.js index acd59e7a40..14f4700791 100644 --- a/tools/tool-env/isopackets.js +++ b/tools/tool-env/isopackets.js @@ -305,7 +305,7 @@ var loadIsopacketFromDisk = async function (isopacketName) { var env = { __meteor_bootstrap__: { startupHooks: [], - fibersDisabled: true + isFibersDisabled: true }, __meteor_runtime_config__: { meteorRelease: "ISOPACKET" } };