Playing state dependent audio files in React - javascript

I am trying to create a new state-dependent Audio instance in React. When using require(), I receive the warning, "Critical dependency: the request of a dependency is an expression." I cannot simply import the file since the audio's source is state-dependent. How can I work around this?
The following code gives the error:
playSong = () => {
this.setState(this.state, function(){
let source = require(this.state.songList[this.state.songIndex].src);
let audio = new Audio(source);
audio.play();
});
}
The require() function only seems to work if given a literal.

You cannot require dynamic values, sadly.
You could import all your files into the songList array statically first, and pick the correct one from that:
const songList = [
require('./path/to/song1.mp3'),
require('./path/to/song2.mp3')
];
class MyComponent extends React.Component {
playSong = () => {
let source = songList[this.state.songIndex].src;
let audio = new Audio(source);
audio.play();
};
render () {
// ...
}
}

Related

new Function() inside of AudioWorklet

I want to create an audio editor where you can connect nodes together to create custom audio components. Every time the nodes change, they get compiled into javascript and then will be run by a new Function() to get better performance. I just read up that there is the possibility to create an AudioWorklet, which runs on a separate thread. Now I am wondering if there is a possibility of combining both ideas in a way where my algorithm gets passed to the AudioWorklet as a string of javascript code, where it then gets put into a function using new Function(codeString) inside of the constructor. Then the audioworklet's process() function will call the custom function somehow.
Is this possible in some way, or am I asking for too much? I would like to get a "yes, that's possible" or a "no, sorry" before I spend hours trying to get it to work...
Thanks for your help,
dogefromage
With the help of #AKX's comment, I crafted together this solution. The code inside the string will later be replaced by a compiler.
function generateProcessor()
{
return (`
class TestProcessor extends AudioWorkletProcessor
{
process(inputs, outputs)
{
const input = inputs[0];
const output = outputs[0];
for (let channel = 0; channel < output.length; ++channel) {
for (let i = 0; i < output[channel].length; i++) {
output[channel][i] = 0.01 * Math.acos(input[channel][i]);
}
}
return true;
}
}
registerProcessor('test-processor', TestProcessor);
`);
}
const button = document.querySelector('#button');
button.addEventListener('click', async (e) =>
{
const audioContext = new AudioContext();
await audioContext.audioWorklet.addModule(
URL.createObjectURL(new Blob([
generateProcessor()
], {type: "application/javascript"})));
const oscillator = new OscillatorNode(audioContext);
const testProcessor = new AudioWorkletNode(audioContext, 'test-processor');
oscillator.connect(testProcessor).connect(audioContext.destination);
oscillator.start();
});

Uncaught ReferenceError: Cannot access '__WEBPACK_DEFAULT_EXPORT__' before initialization

I have a problem with my webpack project, so I was trying to import one class to another and instantiate it but suddenly an error appear in my console and my program stopped working, it was this:
Uncaught ReferenceError: Cannot access '__WEBPACK_DEFAULT_EXPORT__' before initialization
This is the code of the class were I am trying to import my another class (that is PopUpPlugin):
import PopupPlugin from './popupPlugin.js';
export const addSearchBtnEvent = (weatherUI) => {
const searchBtn = document.querySelector('.weather__search');
searchBtn.addEventListener('click', () => {
weatherUI.style.opacity = '1';
weatherUI.style.visibility = 'visible';
})
}
export const addSearchExitEvent = (weatherUI) => {
const weatherExit = document.querySelector('.weather__search-exit');
weatherExit.addEventListener('click', () => {
weatherUI.style.opacity = '0';
weatherUI.style.visibility = 'hidden';
})
}
const popupObj = new PopupPlugin();
class searchDashboard {
constructor() {
}
setInputEvent() {
const inputSearch = document.querySelector('.weather__city-search');
const inputSearchBtn = document.querySelector('.weather__search-btn');
inputSearchBtn.addEventListener('click', () => {
const inputSearchVal = inputSearch.value;
this.validateStr(inputSearchVal);
});
}
validateStr() {
const onlyLettersAndSpaces = /^[a-zA-Z][a-zA-Z\s]*$/;
if(str.trim().length > 0 && str.match(onlyLettersAndSpaces)) {
const strValue = str.toLowerCase().trim().replace(' ', '+');
this.popupObj.searchCoincidences(strValue, 'weather__search-ui');
}
}
}
export default searchDashboard;
I don't actually know why this is happening, I also tried to instantiate it inside the constructor and it worked but it sended me the error of an stack overflow.
PD: If someone needs it here is the code of the PopupPlugin. (Here is what was working to me that was instantiating the class inside the constructor until the stack overflow error appeared)
import ManageWeatherDashboard from './manageWeatherDashboard.js';
import { getFetch, repeatAppend } from './weatherHelpers.js';
class popupPlugin {
constructor() {
this.manageWeatherDashboardObj = new ManageWeatherDashboard();
}
validateStr(str) {
const onlyLettersAndSpaces = /^[a-zA-Z][a-zA-Z\s]*$/;
if(str.trim().length > 0 && str.match(onlyLettersAndSpaces)) {
const strValue = str.toLowerCase().trim().replace(' ', '+');
return strValue;
}
}
searchCoincidences(val, parent) {
getFetch(`https://www.metaweather.com/api/location/search/?query=${val}`)
.then(res => res.text())
.then(data => {
const parentResults = document.querySelector('.'+parent);
parentResults.innerHTML = '';
const dataArr = JSON.parse(data)
if(dataArr.length >= 15) {
let resVal;
for(let i = 0; i <= 15; i++) {
resVal = this.addDOMResultCoincidences(parent, dataArr[i].title,
dataArr[i].woeid);
}
this.whenClickCoincidence(resVal);
} else {
let resVal;
dataArr.forEach(el => {
resVal = this.addDOMResultCoincidences(parent, el.title, el.woeid);
})
this.whenClickCoincidence(resVal);
}
})
}
addDOMResultCoincidences(parentBlock, name, id) {
const args = Array.from(arguments);
if(args[0] === 'popup__results') {
const popupResults = document.querySelector('.popup__results');
const divResult = document.createElement('div');
divResult.className = 'popup__result';
divResult.setAttribute('data-woeid', id);
const spanResultName = document.createElement('span');
spanResultName.className = 'popup__result-name';
const cityReturn = document.createTextNode(args[1]);
spanResultName.appendChild(cityReturn);
divResult.appendChild(spanResultName);
popupResults.prepend(divResult);
return divResult;
}
if(args[0] === 'weather__search-ui') {
const weatherUI = document.querySelector('.weather__search-ui');
const divResult = document.createElement('div');
divResult.className = 'weather__search-result';
divResult.setAttribute('data-woeid', id);
const spanResultName = document.createElement('span');
const spanResultNameText = document.createTextNode(args[1]);
spanResultName.className = 'weather__city-result';
spanResultName.appendChild(spanResultNameText);
const iconResult = document.createElement('i');
iconResult.className = 'fa fa-arrow-right weather__go-result';
repeatAppend([spanResultName, iconResult], divResult);
weatherUI.appendChild(divResult);
return divResult;
}
}
// When click a coincidence in search field
whenClickCoincidence(el) {
const woeId = el.getAttribute('data-woeid');
el.addEventListener('click', () => {
let handler = 0;
if(handler === 0) {
getFetch(`https://www.metaweather.com/api/location/${woeId}/`)
.then(res => res.json())
.then(data => {
const popup = document.querySelector('.popup');
const weatherNext6Days = data.consolidated_weather;
this.manageWeatherDashboardObj.changeWeatherBar(weatherNext6Days[0], data.title);
weatherNext6Days.slice(1, 6).forEach(el => {
this.manageWeatherDashboardObj.nextFiveDays(el);
})
this.manageWeatherDashboardObj.updateStadistics(weatherNext6Days[0]);
popup.style.opacity = '0';
popup.style.visibility = 'hidden';
})
}
handler += 1;
})
}
}
export default popupPlugin;
This might be caused by a cyclic dependencies (i.e. moduleA imports module B and vice versa at the same time). Take a deeper look at your code.
I faced the same issue when I moved the import statement for the redux store below some import of a local module that was dealing with some reducer reference from of the store. Moving the import store from ./store upwards resolved this issue for me.
Try fixing the order of imports in your files.
Had this problem, after upgrading from webpack 4 to webpack 5, and, yes, it was a circular dependency in my case.
Furthermore I found this blog How to Eliminate Circular Dependencies from Your JavaScript Project which led me to https://github.com/aackerman/circular-dependency-plugin
Plopped the plugin into my webpack dev config, as per sample on github, then spent some time reading its output figuring out where I went wrong. Fixing things was pretty easy once I knew the problem - it had been a pretty basic error.
circular-dependency-plugin#5.2.2 works on webpack 4 apparently, and I can confirm it works on webpack#5.73.0 as well. Saved me lots of time :-) You can take it out of webpack dev config after it's done its work.
In my case, it was due to circular import. Meaning, that two modules are exporting and importing contents form each other
For anyone whose issue is not a circular dependency, it could also be a missing import.
In my case, using Material UI 5, I forgot the line import { styled } from "#mui/styles";, which gave me this error:
Uncaught ReferenceError: Cannot access '__WEBPACK_DEFAULT_EXPORT__' before initialization
instead of the usual ReferenceError: MyModule is not defined missing import error.
Using my IDE auto import I had something like:
import useStore, { useCart } from "../lib/store"
Everything was working fine for awhile! But then I got the same error until I changed my import to be like this:
import { useStore, useCart } from "../lib/store"
in my case, I was just trying to call the dispatch function before the store had fully loaded - i.e. store.dispatch()
Have same issue in nextjs project.
Switching to previous versions or reinstalling node_modules/ - did not help.
Solution - remove build/ directory and restart build.
In my case, it was the entry-point file that used the following syntax:
export default <symbol>;
Maybe because you used circle import.
For me, I used encapsulated axios to request in mobx store, and I also used some data from mobx store in encapsulated axios.
This isn't exactly what's causing the same error to occur for me.
Mine were caused by calling things like useState, useEffect and firebase() outside the main functional Component Block. This is very dumb but I somehow completely missed it.
Hope it helps anyone from the future who had the same problem as mine.

Websockets in Sapper

I have a readable store in Svelte that looks like this:
const state = {};
export const channels = readable(state, set => {
let st = state;
let socket = new WebSocket("ws://127.0.0.1:5999");
socket.onmessage = function (event) {
var datastr = event.data.split(':');
st[datastr[0]].value = datastr[1];
st[datastr[0]].timestamp = Date.now();
set(st)
};
return () => {
socket.close()
}
});
When I import it to my Svelte App works. But if I put that App.svelte as my index.svelte running on Sapper, it doesnt work at first. It says error 500 websocket is not defined. Once I reload the page in the browser start to work...
I have try to parse a function that creates the store instead:
export const getChannel = () => {
// here my store
return {...store}
}
and then creating the store inside a onMount() like this:
onMount( ()=> {
const channel = getChannel();
});
But doesnt seem to do the trick... What do I miss?
Note: If a just replace the store by a simple writable, and create the websocket onMount(), it works without any problem. I just only wanted to put all the communication inside the store as a readable...
In Sapper, code in components (or imported into components) is executed in Node during server-side rendering unless it's put inside onMount (which doesn't run on the server, because there's no 'mounting' happening) or an if (process.browser) {...} block, or something equivalent.
That includes things like references to $channels causing channels.subscribe(...) to be called during initialisation.
Since there's no WebSocket global in Node, creating that subscription will fail. The simplest workaround is probably a simple feature check:
const state = {};
export const channels = readable(state, (set) => {
if (typeof WebSocket === 'undefined') return;
let st = state;
let socket = new WebSocket("ws://127.0.0.1:5999");
socket.onmessage = function (event) {
var datastr = event.data.split(":");
st[datastr[0]].value = datastr[1];
st[datastr[0]].timestamp = Date.now();
set(st);
};
return () => {
socket.close();
};
});

Integrate guacamole-common-js in my react application

I wanna use guacamole-common-js in my React application and already set up guaca in docker and guacamole client by guacamole-lite. I have successfully seen the view from plain HTML and javascript. However, I could not render it in React JSX.
Here is my code:
import Guacamole from "guacamole-common-js";
let guaca = new Guacamole.Client(new Guacamole.WebSocketTunnel(webSocketFullUrl));
guaca.onerror = function (error) {
alert(error);
};
guaca.connect();
// Disconnect on close
window.onunload = function () {
guaca.disconnect();
}
let display = document.getElementById("display");
display.appendChild(guaca.getDisplay().getElement());
And to render it:
React.createElement("div", {id, "display"})
I also try with Ref like follow but still not works:
constructor(props) {
super(props);
this.displayRef = React.createRef();
this.guacaRef = React.createRef();
}
this.guacaRef.current = new Guacamole.Client(new Guacamole.WebSocketTunnel(webSocketFullUrl));
this.guacaRef.current.onerror = function (error) {
alert(error);
};
this.guacaRef.current.connect();
// Disconnect on close
window.onunload = function () {
this.guacaRef.current.disconnect();
}
this.displayRef.current.appendChild(this.guacaRef.current.getDisplay().getElement());
To render it:
<div ref={displayRef}/>
I'm new to it and any help will be appreciated.
Seems like the reason is kind of stupid... the default style for guacamole canvas rendering is {z-index: -1}. When adding up to 1, it renders properly.
As #Ivana stated, necessary to change z-index
const element = guaca.getDisplay().getElement();
const canvas = $(element).find(`canvas`);
for(let c of canvas) {
$(c).css(`z-index`, 10)
};

how to work with list of elements in page object model

In the below code snippet, how can I use osList and featureList using typescript can you please help me with this. I need to know how to work with a list of elements in the page object model like submitName function.
import { Selector, t } from 'testcafe';
const label = Selector('label');
class Feature {
constructor (text) {
this.label = label.withText(text);
this.checkbox = this.label.find('input[type=checkbox]');
}
}
class OperatingSystem {
constructor (text) {
this.label = label.withText(text);
this.radioButton = this.label.find('input[type=radio]');
}
}
export default class Page {
constructor () {
this.nameInput = Selector('#developer-name');
this.triedTestCafeCheckbox = Selector('#tried-test-cafe');
this.populateButton = Selector('#populate');
this.submitButton = Selector('#submit-button');
this.results = Selector('.result-content');
this.commentsTextArea = Selector('#comments');
this.featureList = [
new Feature('Support for testing on remote devices'),
new Feature('Re-using existing JavaScript code for testing'),
new Feature('Running tests in background and/or in parallel in multiple browsers'),
new Feature('Easy embedding into a Continuous integration system'),
new Feature('Advanced traffic and markup analysis')
];
this.osList = [
new OperatingSystem('Windows'),
new OperatingSystem('MacOS'),
new OperatingSystem('Linux')
];
this.slider = {
handle: Selector('.ui-slider-handle'),
tick: Selector('.slider-value')
};
this.interfaceSelect = Selector('#preferred-interface');
this.interfaceSelectOption = this.interfaceSelect.find('option');
this.submitButton = Selector('#submit-button');
}
async submitName (name) {
await t
.typeText(this.nameInput, name)
.click(this.submitButton);
}
}
I can describe this to you based on the TestCafe's basic example. First, you need to change the page-model file extension to ts and create this file according to the TypeScript rules (for example, see my gist). Then, you can change the test file extension to ts and start test execution like you do it for any js tests, e. g. testcafe chrome test.ts.

Categories

Resources