Astro transforming async generator functions is not supported yet - javascript

I want to support old browsers for my website. I am currently trying to use #vitejs/plugin-legacy. But while building I get this error,
[vite:esbuild-transpile] Transform failed with 9 errors:
entry.mjs:551:0: ERROR: Transforming async generator functions to the configured target environment ("chrome64", "edge79", "es2020", "firefox67", "safari11.1" + 2 overrides) is not supported yet
entry.mjs:683:2: ERROR: Transforming async generator functions to the configured target environment ("chrome64", "edge79", "es2020", "firefox67", "safari11.1" + 2 overrides) is not supported yet
entry.mjs:696:0: ERROR: Transforming async generator functions to the configured target environment ("chrome64", "edge79", "es2020", "firefox67", "safari11.1" + 2 overrides) is not supported yet
entry.mjs:1256:2: ERROR: Transforming async generator functions to the configured target environment ("chrome64", "edge79", "es2020", "firefox67", "safari11.1" + 2 overrides) is not supported yet
entry.mjs:1295:0: ERROR: Transforming async generator functions to the configured target environment ("chrome64", "edge79", "es2020", "firefox67", "safari11.1" + 2 overrides) is not supported yet
...
Transforming async generator functions to the configured target environment ("chrome64", "edge79", "es2020", "firefox67", "safari11.1" + 2 overrides) is not supported yet
548| function markHTMLBytes(bytes) {
549| return new HTMLBytes(bytes);
550| }
| ^
551| async function* unescapeChunksAsync(iterable) {
| ^
552| for await (const chunk of iterable) {
Transforming async generator functions to the configured target environment ("chrome64", "edge79", "es2020", "firefox67", "safari11.1" + 2 overrides) is not supported yet
681| return "AstroComponent";
682| }
683| async *[Symbol.asyncIterator]() {
| ^
684| const { htmlParts, expressions } = this;
685| for (let i = 0; i < htmlParts.length; i++) {
Transforming async generator functions to the configured target environment ("chrome64", "edge79", "es2020", "firefox67", "safari11.1" + 2 overrides) is not supported yet
693| function isRenderTemplateResult(obj) {
694| return typeof obj === "object" && !!obj[renderTemplateResultSym];
695| }
| ^
696| async function* renderAstroTemplateResult(component) {
| ^
697| for await (const value of component) {
Transforming async generator functions to the configured target environment ("chrome64", "edge79", "es2020", "firefox67", "safari11.1" + 2 overrides) is not supported yet
1254| return this.returnValue;
1255| }
1256| async *render() {
| ^
1257| if (this.returnValue === void 0) {
1258| await this.init();
Transforming async generator functions to the configured target environment ("chrome64", "edge79", "es2020", "firefox67", "safari11.1" + 2 overrides) is not supported yet
1292| return typeof obj === "object" && !!obj[astroComponentInstanceSym];
1293| }
1294|
| ^
1295| async function* renderChild(child) {
| ^
1296| child = await child;
Transforming async generator functions to the configured target environment ("chrome64", "edge79", "es2020", "firefox67", "safari11.1" + 2 overrides) is not supported yet
1987| }
1988| if (!hydration) {
1989| return async function* () {
| ^
1990| if (slotInstructions) {
1991| yield* slotInstructions;
Transforming async generator functions to the configured target environment ("chrome64", "edge79", "es2020", "firefox67", "safari11.1" + 2 overrides) is not supported yet
2029| island.props["await-children"] = "";
2030| }
2031| async function* renderAll() {
| ^
2032| if (slotInstructions) {
2033| yield* slotInstructions;
Transforming async generator functions to the configured target environment ("chrome64", "edge79", "es2020", "firefox67", "safari11.1" + 2 overrides) is not supported yet
2086| const children = item.children;
2087| return index === all.findIndex((i) => JSON.stringify(i.props) === props && i.children == children);
2088| };
| ^
2089| async function* renderExtraHead(result, base) {
| ^
2090| yield base;
Transforming async generator functions to the configured target environment ("chrome64", "edge79", "es2020", "firefox67", "safari11.1" + 2 overrides) is not supported yet
2111| return renderAllHeadContent.bind(null, result);
2112| }
2113| const renderHead = createRenderHead;
| ^
2114| async function* maybeRenderHead(result) {
| ^
2115| if (result._metadata.hasRenderedHead) {
error Transforming async generator functions to the configured target environment ("chrome64", "edge79", "es2020", "firefox67", "safari11.1" + 2 overrides) is not supported yet
File:
entry.mjs
Reproduction: https://stackblitz.com/edit/typescript-ry3189
How do I fix this?

Try running 'npm install' again, then run 'npm run build'
I always feel that it is because the initialization is not completed

Related

Unexpected synchronous behaviour when using nodejs events module

I am using Node Events module for executing my function asynchronously.
var events = require('events');
var eventEmitter = new events.EventEmitter();
eventEmitter.on('myEvent', f2);
function f1(x, y) {
console.log('got', x, y)
eventEmitter.emit('myEvent', x, y);
eventEmitter.emit('myEvent', x, y);
eventEmitter.emit('myEvent', x, y);
console.log('done')
}
var count = 0
function f2(x, y) {
count++;
console.log('from f2', x, y, count)
}
f1(1, 2)
Its output is
alok#alok-HP-Laptop-14s-cf3xxx:~/tmp/test-node$ node alok.js
got 1 2
from f2 1 2 1
from f2 1 2 2
from f2 1 2 3
done
My expected output is
got 1 2
done
from f2 1 2 1
from f2 1 2 2
from f2 1 2 3
Why console.log('done') is running in last. or Why execution is synchronous?
Because that's how it works:
When the EventEmitter object emits an event, all of the functions attached to that specific event are called synchronously.
[..]
Asynchronous vs. synchronous
The EventEmitter calls all listeners synchronously in the order in which they were registered. This ensures the proper sequencing of events and helps avoid race conditions and logic errors. When appropriate, listener functions can switch to an asynchronous mode of operation using the setImmediate() or process.nextTick() methods:
const myEmitter = new MyEmitter();
myEmitter.on('event', (a, b) => {
setImmediate(() => {
console.log('this happens asynchronously');
});
});
myEmitter.emit('event', 'a', 'b');
https://nodejs.dev/en/api/v19/events

Why does a global array in Node.js cause a Memory Leak?

I am trying to understand how the garbage collection in Node.js works.
A big array is created and stored globally. When tracking the Heap Usage, I saw that once the array is created, the Heap Usage goes up drastically. No wonder, since the array is huge.
But it seems like the garbage collector does not remove the array - no matter how long I wait, the Heap Usage stays the same. Does the garabge collector think, the array is still needed?
let bigArray
setTimeout(function() {
bigArray = new Array(9999999)
}, 5000)
setInterval(function () {
const used = process.memoryUsage().heapUsed / 1024 / 1024;
console.log(`Usage: ${Math.round(used * 100) / 100} MB`);
}, 1000)
```
The array is still referenced in the module functions closure so can't be garbage collected:
// Implicit closure created by nodejs
(function(exports, require, module, __filename, __dirname) {
let bigArray
setTimeout(function() {
bigArray = new Array(9999999)
}, 5000);
setInterval(function () {
// `bigArray` is still in scope here so cannot be garbage collected
// If you set bigArray to undefined it will get GC'd
const used = process.memoryUsage().heapUsed / 1024 / 1024;
console.log(`Usage: ${Math.round(used * 100) / 100} MB`);
}, 1000);
});
If you were to declare the variable only inside the setTimeout function scope it would be GC'd without having to remove the reference yourself, e.g.
// Implicit closure created by nodejs
(function(exports, require, module, __filename, __dirname) {
setTimeout(function() {
let bigArray = new Array(9999999)
}, 5000);
setInterval(function () {
// `bigArray` is not in scope here so it will be GC'd
const used = process.memoryUsage().heapUsed / 1024 / 1024;
console.log(`Usage: ${Math.round(used * 100) / 100} MB`);
}, 1000);
});
Additionally, be aware that V8 could be behaving lazily when it's not constrained for memory.
You can try running your script with --expose-gc and force gc:
node --expose-gc index.js
const forceGC = () => {
if (global.gc) {
global.gc();
} else {
console.warn('No GC hook! Start your program as `node --expose-gc file.js`.');
}
}
let bigArray
setTimeout(function() {
bigArray = new Array(9999999)
}, 5000)
setInterval(function () {
bigArray = undefined;
forceGC();
const used = process.memoryUsage().heapUsed / 1024 / 1024;
console.log(`Usage: ${Math.round(used * 100) / 100} MB`);
}, 1000)
Also, you can give node less memory to work with to test how it behaves when it's running low on memory:
node --max-old-space-size=100 index.js // Give node just 100MB (defaults to 2GB)
The garbage collector does not collect all the time. Only when your computer is running out of memory.
Try this post and trigger the garbage collector by hand. Will it still have the memory leak?
How to request the Garbage Collector in node.js to run?
Also the array is still referenced, if you set it to null somewhere it might get collected.

Consume async iterable without variable declaration

With a synchronous JavaScript generator I can iterate over it as follows:
(() => {
function * syncGenerator () {
yield 1
yield 2
yield 3
console.log('done')
}
Array.from(syncGenerator())
})()
This will simply iterate over the whole generator without having to initialise a variable. I would like to do the same with async generators. The closest solution I could come up with is as follows:
(async () => {
async function * asyncGenerator () {
yield Promise.resolve(1)
yield Promise.resolve(2)
yield Promise.resolve(3)
console.log('done')
}
for await (const num of asyncGenerator()) {}
})()
Unfortunately I had to instantiate the variable num in the above code snippet. This causes StandardJS to give an error on that line, because the variable isn't used. Is there any way I can iterate over an async generator without having to create a variable?
Current solution
Based on the comments to the question and my own research my preferred solution to the problem at the time of writing is the following:
(async () => {
async function * asyncGenerator () {
yield Promise.resolve(1)
yield Promise.resolve(2)
yield Promise.resolve(3)
console.log('done')
}
// eslint-disable-next-line no-unused-vars
for await (const num of asyncGenerator()) {}
})()
Note the // eslint-disable-next-line no-unused-vars comment which suppresses the warning generated by StandardJS for that one line.
Future solution
Once the Iterator Helpers proposal matures and becomes available one could do something like the following for both synchronous and asynchronous generators:
function * syncGenerator () {
yield 1
yield 2
yield 3
console.log('sync done')
}
syncGenerator().forEach(() => {}) // Logs 'sync done'
async function * asyncGenerator () {
yield Promise.resolve(1)
yield Promise.resolve(2)
yield Promise.resolve(3)
console.log('async done')
}
asyncGenerator().forEach(() => {}) // Logs 'async done'
Here's another method
async function * asyncGenerator(): AsyncIterableIterator<number> {
yield Promise.resolve(1)
yield Promise.resolve(2)
yield Promise.resolve(3)
console.log('async done')
}
const it: AsyncIterableIterator<number> = asyncGenerator()
while (true) {
const result: IteratorResult<number> = await it.next();
if (result.done) break;
}
(TypeScript types added for documentation purposes)
Of course, this does declare the variable it, but it's not unused, which I believe is what your actual problem was.
That said, my ESLint did complain about the use of while (true) (with config eslint:recommended), which I personally find a bit stupid, but may or may not be a problem for you.

Regarding generator function send() javascript

I was viewing generator functions in Mozilla Dev page.
There was an example code which is having send() function.
function* fibonacci() {
var a = yield 1;
yield a * 2;
}
var it = fibonacci();
console.log(it); // "Generator { }"
console.log(it.next()); // 1
console.log(it.send(10)); // 20
console.log(it.close()); // undefined
console.log(it.next()); // throws StopIteration (as the generator is now closed)
But, both chrome and Firefox (Latest version) are throwing error on send() function.
Any views on this? Is it not supported?
.send is part of the Legacy generator objects which are specific to the SpiderMonkey engine. It will be removed in some future release. They have already started removing/replacing the legacy generator objects with ES6 generators in parts of their code (Bug 1215846, Bug 1133277)
For the moment you can still use legacy generators in Firefox (current version as of this answer: 43.0.4). Just leave off the * when defining, and as long as the function body uses a yield statement the legacy generator will be used.
function fibonacci() {
var a = yield 1;
yield a * 2;
}
var it = fibonacci();
console.log(it);
console.log(it.next());
console.log(it.send(10));
console.log(it.close());
console.log(it.next());
Interesting that in ESNext might be function.sent()
var result;
function* generator() {
result = function.sent;
}
var iter = generator();
iter.next('tromple');
return result === 'tromple';
https://github.com/allenwb/ESideas/blob/master/Generator%20metaproperty.md

Passing variables to callbacks in Node.js

I'm quite new to node and am trying to create something that gets some server info. But here's my problem. I setup a config object (this will, in time, become updated dynamically by events that occur) and then later in, in a function, I try and access a value in this object. (See code below)
So First, I setup my vars:
var util = require('util'),
child = require('child_process'),
config = {};
which works okay. Then I load my config:
function loadConfig( )
{
// Add some code for auto-loading of args
config = {
"daemons": [
["Apache", "apache2"],
["MySQL", "mysqld"],
["SSH", "sshd"]
]
};
}
and init that calling the function
loadConfig();
After that, I run my check on daemons.
function getDaemonStatus( )
{
for(var i=0; i<config.daemons.length; i++)
{
child.exec( 'ps ax -o \'%c %P\' | awk \'{if (($2 == 1) && ($1 == "\'' +
config.daemons[i][1] + '\'")) print $0}\'',
function( error, stdout, stderr )
{
console.log(config.daemons[i]);
});
}
}
The response I get is:
undefined
undefined
undefined
I don't really want to use a GLOBAL variable, so can you guys think of another way to solve my problem?
Thanks! =]
This is a gotcha that lots of people run into because of the asynchronous ordering of execution.
Your for loop will look from 0-3, and then exit when 'i' is four, obviously. The tough part to remember here is that your callback for exec won't run immediately. In only runs once the process has started, and by the time that happens, the for loop will be done.
That means that essentially, all three times that your callback function is running, you are essentially doing this:
console.log(config.daemons[4]);
That's why it prints 'undefined'.
You need to capture the 'i' value in a new scope, by wrapping the loop contents in an anonymous, self-executing function.
function getDaemonStatus( ) {
for(var i=0; i<config.daemons.length; i++) {
(function(i) {
child.exec( 'ps ax -o \'%c %P\' | awk \'{if (($2 == 1) && ($1 == "\'' +
config.daemons[i][1] + '\'")) print $0}\'',
function( error, stdout, stderr ) {
console.log(config.daemons[i]);
});
})(i);
}
}
Also, I see that your function is called 'getDaemonStatus'. Just remember that, since that exec callback is asyncronous, that also means that you can't collect the results of each callback, and then return them from the getDaemonStatus. Instead, you will need to pass a your own callback, and call the it from inside your exec callback.
Updated
Note though, the easiest way to have a scope per-iteration is to use forEach, e.g.
function getDaemonStatus( ) {
config.daemons.forEach(function(daemon, i){
child.exec( 'ps ax -o \'%c %P\' | awk \'{if (($2 == 1) && ($1 == "\'' +
daemon[1] + '\'")) print $0}\'',
function( error, stdout, stderr ) {
console.log(daemon);
});
}
}

Categories