How / where does one define AudioWorkletProcessor - javascript

I have just started playing with the Web Audio API. I have been pouring over the API docs and see several examples. My issue is probably trivial and I am probably missing something fundamental.
I have the worker javascript file below. It came from an example whoes URL I have misplaced. I am using PyCharm as my IDE, if that matters, and it flags "AudioWorkletProcessor" as undefined. I have looked at a lot of pages at this point and I do not see any import or require statements that might define this interface.
I have just tried running the code in Firefox and Chrome and both throw exceptions on the undefined AudioWorkletProcessor line.
Should this be a "builtin"? Is it part of a library/module that I just haven't seen referenced yet?
class AudioRecorder extends AudioWorkletProcessor {
static get parameterDescriptors() {
return [
{
name: 'isRecording',
defaultValue: 0,
minValue: 0,
maxValue: 1,
},
]
}
process(inputs, outputs, parameters) {
const buffer = []
const channel = 0
for (let t = 0; t < inputs[0][channel].length; t += 1) {
if (parameters.isRecording[0] === 1) { // <2>
buffer.push(inputs[0][channel][t])
}
}
if (buffer.length >= 1) {
this.port.postMessage({buffer})
}
return true
}
}
registerProcessor('audio-recorder', AudioRecorder)

The AudioWorkletProcessor base class and the registerProcessor() function are both available as globals in the AudioWorkletGlobalScope.
It's not possible to evaluate that code in the console. You need to load your JavaScript file like that:
audioContext.audioWorklet.addModule('path/to/your/file.js');
I guess your IDE is just not aware of the fact that you are editing something that is meant to be evaluated in that scope.

Related

"process is not defined" when used in a function (Vue/Quasar)

The following snippet represents a Pinia store in my Vue 3 / Quasar 2 application. This store uses the environment variable VUE_APP_BACKEND_API_URL which shall be read from either the window object or process.env.
However I don't understand why the first variant is wokring but the second is not. Using the getEnv function always results in a Uncaught (in promise) ReferenceError: process is not defined error.
import { defineStore } from 'pinia';
function getEnv(name) {
return window?.appConfig?.[name] || process.env[name];
}
// 1. this is working
const backendApiUrl = window?.appConfig?.VUE_APP_BACKEND_API_URL || process.env.VUE_APP_BACKEND_API_URL;
// 2. this is NOT working
const backendApiUrl = getEnv('VUE_APP_BACKEND_API_URL');
export const useAppConfigStore = defineStore('appConfig', {
state: () => ({
authorizationUrl: new URL(
'/oauth2/authorization/keycloak',
backendApiUrl,
).toString(),
logoutUrl: new URL('/logout', backendApiUrl).toString(),
backendApiUrl: new URL(backendApiUrl).toString(),
}),
});
NodeJS-specific stuff like process doesn't exist in the browser environments. Both Webpack and Vite implementations work by replacing process.env.XYZ expressions with their values on build time. So, just process.env, or process.env[name] will not be replaced, which will lead to the errors you are experiencing. See the caveats section and related Webpack/Vite docs and resources. So, unfortunately, the only easy way seems to be the first long and repetitive way you've tried(const backendApiUrl = window?.appConfig?.VUE_APP_BACKEND_API_URL || process.env.VUE_APP_BACKEND_API_URL;). You can try embedding this logic in a single object, then use the function to access it.
const config = {
VUE_APP_BACKEND_API_URL: window?.appConfig?.VUE_APP_BACKEND_API_URL || process.env.VUE_APP_BACKEND_API_URL
}
export function getEnv(name) {
return config[name];
}
This way it will be longer and more repetitive to define it the first time, but at least you will be able to use it easily through the code base.
This is late, but it might help someone, I was able to resolve this by adding below to my quasar.conf.js
build: {
vueRouterMode: 'hash', // available values: 'hash', 'history'
env: {
API_ENDPOINT: process.env.API_ENDPOINT ? process.env.API_ENDPOINT : 'http://stg.....com',
API_ENDPOINT_PORT: process.env.API_ENDPOINT_PORT ? process.env.API_ENDPOINT_PORT : '0000',
...env
},
}
For more information ge here: https://github.com/quasarframework/quasar/discussions/9967

How do You Deal with Reference Errors in Flutter Web?

The Problem and What I've Done So Far
Abstract: I'm getting a reference error, probably from a package I've imported, that I'd like to know if I can fix on my own. I'm building/testing with flutter-web
I'm writing a flutter app that processes some markdown/LaTeX using the flutter_tex package. Unfortunately when I add a TeXView() widget to my app and try to reload I get:
ReferenceError: OnPageLoaded is not defined
at http://localhost:40111/assets/packages/flutter_tex/js/katex/index.html:50:5
new-447 old-750
It seems to me that there isn't anything in my code that could have caused this error and that it is something wrong with the way that my code gets compiled for the web. I have added this line:
<script src="assets/packages/flutter_tex/js/flutter_tex.js"></script>
to my project's index.html as advised in the installation instructions.
The developer of this package has not responded to issues on GitHub for nearly half a year and someone else has come across this problem before but, I need the features that this package offers so it really isn't an option for me to try a different package.
What I want to know is if there is a general way that I can deal with this. I am new to dart and I'm not even sure where to find most of these files or if any changes that I make will persist after reloading. I do know from the question How do you use onPageLoad in Javascript? that onPageLoad may be replaceable with window.onload but I'm not sure if this is related to my issue.
The Code
import 'package:flutter_tex/flutter_tex.dart';
// <!--Snip--!>
class CardView extends StatefulWidget {
final String deck;
final TeXViewRenderingEngine renderingEngine;
CardView(
{this.deck, this.renderingEngine = const TeXViewRenderingEngine.katex()});
#override
State<CardView> createState() => _CardViewState(deck: deck);
}
class _CardViewState extends State<CardView> {
final String deck;
var _card = jsonDecode('{}');
var _cardId = 0;
var _testString = r"""
*This should be bold*
# This should be a title.
$x=3$
\(x=3\)
$$x=3$$
Hello $x=3$ \(x=3\)""";
_CardViewState({this.deck});
// <!--Snip--!>
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Decks > Deck')),
body: Center(
// child: RichText(
// text: TextSpan(
// text: _card.toString(),
// style: TextStyle(color: Colors.black, fontSize: 18)))
child: TeXView(child: TeXViewMarkdown(_testString.toString()))));
}
}

What is the difference between mwc.js and mwc.esm.js?

I created a StencilJS project that has a bunch of web components bundled in my mwc project. From within Stencil, I can execute npm run start and see my components working as expected.
I created an Electron project and in it I'm importing the stencil mwc package using :
<script src="dist/mwc/mwc.js"></script>
When I do this I've noticed the stencil generated code fails to run any for-loops that iterate over a Map or Set. Basically the for-loop exits and never iterates.
For example, in one of my components I have a class that defines a variable this way:
private _groupedItems : Map<string, Item[]> = new Map();
This variable gets populated and when the following code tries to run, it always fails:
#Method()
async updateItemAsync( arg : { value : string, data : UpdateSelectItem } ) {
//find where the item value is located
let item : Item | undefined = undefined;
for( const key of this._groupedItems.keys() ) {
const groupedItems = this._groupedItems.get( key );
if( groupedItems ) {
item = groupedItems.find( item => item.value === arg.value );
if( item ) {
break;
}
}
}
if( item === undefined ) {
console.error( 'Could not find item to update with value=', arg.value );
return;
}
//NEVER GETS HERE!
//more code below snipped out
}
In Chrome devTools I can see that the generated JavaScript that is trying to run looks like this:
e.prototype.updateItemAsync = function(e) {
return __awaiter(this, void 0, void 0, function() {
var t, i, n, r, s;
return __generator(this, function(a) {
t = undefined;
for (i = 0,
n = this._groupedItems.keys(); i < n.length; i++) {
r = n[i];
s = this._groupedItems.get(r);
if (s) {
t = s.find(function(t) {
return t.value === e.value
});
if (t) {
break
}
}
}
if (t === undefined) {
console.error("Could not find item to update with value=", e.value);
return [2]
}
I discovered if instead of using the aforementioned script, I use this instead :
<script type="module" src="dist/mwc/mwc.esm.js"></script>
Then everything works fine (sort of). Basically when I fire up my Electron package using webpack all the code works as expected and my for-loops are now working. The problem with this solution is that when I package my Electron application using electron-webpack, I can't run the resulting standalone EXE because I get an error message when the application starts up. Chrome gives me an error when it tries to load the mwc.esm.js file:
Failed to load module script: The server responded with a non-JavaScript MIME type of "". Strict MIME type checking is enforced for module scripts per HTML spec.
What is the difference between the mwc.js and mwc.esm.js files? Why won't the mwc.js file run my for-loops properly?
The esm.js file is a Javascript Module which will be served to browsers that support it.
When you use the old way of including a Stencil component (/dist/mwc.js) you will get a console warning about how to properly include it, which is also documented in the breaking changes for version 1:
[mwc] Deprecated script, please remove: <script src="/dist/mwc.js"></script>
To improve performance it is recommended to set the differential scripts in the head as follows:
<script type="module" src="/dist/mwc/mwc.esm.js"></script>
<script nomodule src="/dist/mwc/mwc.js"></script>
I don't know why Map and Set loops would not work with the non-module file but the module is the recommended way of importing in Chrome.
The MIME type error seems to be a known issue in Electron which seems to be because Electron uses the file:// protocol by default which doesn't allow including modules, as per spec.

Jest import of plain javascript results in unexpected token

Firstly: as far as I can tell, this is not a duplicate. The other questions with similar problems are all slightly different, e.g. use a transformation like babel or have problems with transitive imports. In my case I have no transformation, I have one test file and one file imported file that will be tested. I just started using jest and use the default setting, so there is no configuration file to post.
When I try to run my tests I get the error message:
Test suite failed to run
Jest encountered an unexpected token
This usually means that you are trying to import a file which Jest cannot parse, e.g. it's not plain JavaScript.
The tested file:
export function showTooltip(x, y, content) {
const infoElement = document.getElementById('info');
infoElement.style.left = `${x}px`;
infoElement.style.top = `${y}px`;
infoElement.style.display = 'block';
infoElement.innerText = createTooltipText(content);
}
function createTooltipText(object) {
return Object.keys(object)
.filter(key => key != 'id')
.map(key => `${key} : ${object[key]}`)
.join('\n');
}
export function hideTooltip() {
const infoElement = document.getElementById('info');
infoElement.style.display = 'none';
}
The test:
import {showTooltip, hideTooltip} from '../../../src/public/javascripts/tooltip.js';
const TOOLTIP_DUMMY = {
style: {
left: 0,
top: 0,
display: '',
innerText: ''
}
};
test('showTooltip accesses the element with the id \'info\'', () => {
const getElementByIdMock = jest.fn(() => TOOLTIP_DUMMY);
document.getElementById = getElementByIdMock;
showTooltip(0, 0, {});
expect(getElementByIdMock).toHaveBeenCalledWith('info');
});
test('hideTooltip accesses the element with the id \'info\'', () => {
const getElementByIdMock = jest.fn(() => TOOLTIP_DUMMY);
document.getElementById = getElementByIdMock;
hideTooltip();
expect(getElementByIdMock).toHaveBeenCalledWith('info');
});
As you can see I am using plain javascript so I am not sure what to do here. The error message gives further hints about Babel which does not really apply to my case.
Sidenote: My test might be flawed. I am currently trying to figure out how to use mocks to avoid interaction with the document and I am not sure if that is the way. However this is not the point of this question as it should not affect the ability of the tests to run, but I am very open for suggestions.
EDIT: Why this is not a duplicate to this question: It kind of is, but I feel that question and the accepted answer were not really helpful for me and hopefully someone will profit from this one.
I have found the solution to my problem:
As suggested in this answer, you need to use Babel. This can be done as suggested here, but I used #babel/env-preset as it is suggested on the Babel website.
This left me with the problem that jest internally uses babel-core#6.26.3, but at least babel 7 was required. This problem is described here. I used the temporary fix of manually copying and overwriting babel-core from my node-modules directory to the node-modules directories of jest-config and jest-runtime. This dirty fix is also described in the previous link.
I have yet to find a clean solution, but at least this works.
Use global.document.getElementById = getElementByIdMock; In some configurations Jest doesn't have access to document object directly.

Using code in both Actionscript3 and Javascript

Here's an interesting architectural query. I have a piece of code that needs to run on the server (under Node.js) and on the client (in a Flash 10 app written with Actionscript 3). The code is mostly fairly intricate object manipulation, it doesn't make any API calls, and works fine in both contexts.
So far the project is just a demo, so I've been happy to copy and paste the code into both places. But it might be quite interesting to move forward with this.
So how would you do it?
I assume there is no easy way to get the Flash SDK (has to build without an IDE) to read and do something useful with a .js file.
My only thought is that I could write a code-generator that takes the .js file and places it in an ActionScript wrapper.
Are there any obvious approaches that I've missed?
Just to pre-empt an obvious answer, I know about cross-platform languages like Haxe.
A possible way is using include in your wrapper Actionscript code. Just a quick and very simple test:
package {
import flash.display.Sprite;
import flash.text.TextField;
public class Main extends Sprite {
private var _alertTxt:TextField;
include "some.js"
public function Main() {
_alertTxt = new TextField();
_alertTxt.multiline = true;
_alertTxt.height = 400;
_alertTxt.width = 400;
addChild(_alertTxt);
run();
}
public function alert(msg) {
_alertTxt.text += msg + "\n";
}
}
}
some.js
function run() {
alert("run");
var obj = {
a : 'hello',
b : 4.5,
c : false
};
loop(obj);
}
function loop(obj) {
for (var field in obj) {
alert(obj[field]);
}
}
To compile from command-line (you might want to add other options):
mxmlc -strict=false Main.as
If you don't set strict to false, it won't compile because of the lack of type declarations.

Categories