I've successfully instantiated a simple AudioWorklet in React and wish to start a simple oscillator like in Google's example. In order to test run it, I am rendering a button whose onClick event calls the following:
src/App.jsx:
userGesture(){
//create a new AudioContext
this.context = new AudioContext();
//Add our Processor module to the AudioWorklet
this.context.audioWorklet.addModule('worklet/processor.js').then(() => {
//Create an oscillator and run it through the processor
let oscillator = new OscillatorNode(this.context);
let bypasser = new MyWorkletNode(this.context, 'my-worklet-processor');
//Connect to the context's destination and start
oscillator.connect(bypasser).connect(this.context.destination);
oscillator.start();
})
.catch((e => console.log(e)))
}
The problem is, on every click, addModule method is returning the following error:
DOMException: The user aborted a request.
I am running Chrome v66 on Ubuntu v16.0.4.
src/worklet/worklet-node.js:
export default class MyWorkletNode extends window.AudioWorkletNode {
constructor(context) {
super(context, 'my-worklet-processor');
}
}
src/worklet/processor.js
class MyWorkletProcessor extends AudioWorkletProcessor {
constructor() {
super();
}
process(inputs, outputs) {
let input = inputs[0];
let output = outputs[0];
for (let channel = 0; channel < output.length; ++channel) {
output[channel].set(input[channel]);
}
return true;
}
}
registerProcessor('my-worklet-processor', MyWorkletProcessor);
My code is straight JavaScript, not React, but I got the same error because the path provided to addModule was incorrect. In my case, both the script that calls addModule and the script provided as the argument to addModule reside in the same directory ("js"). In spite of that, I still had to include this directory in the path to eliminate the error:
...addModule('js/StreamTransmitter.js')...
I hope this helps. Good luck!
For anyone else getting this mysterious error, swallow your pride and check the following:
The processor doesn't have any errors.
The processor is calling external modules with proper path to the external file(s).
The external modules don't have any errors.
The promise will abort when external modules that are loaded via "import" have errors, or the paths to the modules can't be resolved (e.g. the path's to the modules are wrong and don't point to existing files).
This worked for me: serve your worklet files from public folder instead of src. The addModule(url) function points there by default, so addModule('worklets/foo.js') references file public\worklets\foo.js
Source: https://hackernoon.com/implementing-audioworklets-with-react-8a80a470474
This seems to be a bug in the Chromium module loader, it parses the worklet/processor.js file by removing whitespace, which in turn causes it to have JavaScript syntax errors everywhere, which then finally causes this generic non-explanatory error message to show up.
The solution is to serve your worklet-processors (e.g. worklet/processor.js in your case) with:
Content-Type: application/javascript
or
Content-Type: text/javascript
I also experienced this error but due to a Webpack issue.
Turns out webpack doesn't support worklets like it supports web workers (see this issue).
I would recommend using worker-url with webpack.
Install worker-url
npm i --save-dev worker-url
Update your webpack config to include the WorkerUrl plugin.
const WorkerUrlPlugin = require('worker-url/plugin');
module.exports = {
// ...
plugins: [new WorkerUrlPlugin()],
// ...
};
Use WorkerUrl like so:
import { WorkerUrl } from 'worker-url';
const workletUrl = new WorkerUrl(
new URL('./random-noise-processor', import.meta.url),
{ name: 'worklet' },
);
await context.audioWorklet.addModule(workletUrl);
The Error "DOMException: The user aborted a request." happens when the AudioWorklet.addModule() function cannot load the file from the path or URL you provided. Refer to this MDN page
The api AudioWorklet.addModule() expects a String containing the URL of a JavaScript file with the module to add.
It can be an internal URL that points to your public folder where the browser loads your static files in this case -> 'worklet/processor.js if the worklet folder is inside the public directory of your React app.
You can modify your code as below.
this.context.audioWorklet.addModule('worklet/processor.js')
In this case the audioWorklet.addModule() method expects the path to point to your public folder. It can also be an external URL for example a link to Github repository that loads the JS file.
Changing:
this.context.audioWorklet.addModule('worklet/processor.js')
with
this.context.audioWorklet.addModule('../worklet/processor.js')
worked for me.
Related
How does fix this Warning: DEP_WEBPACK_DEV_SERVER_ON_AFTER_SETUP_MIDDLEWARE
in simple Create React App and when I don't use Webpack
This problem is in WebStorm only. If you start in Visual Studio Code you can see this warning near one second and then everything is ok.
simple solution is here
In file: node_modules/react-scripts/config/webpackDevServer.config.js
change this code
onBeforeSetupMiddleware(devServer) { // Keep evalSourceMapMiddleware// middlewares beforeredirectServedPath` otherwise will not have any effect
// This lets us fetch source contents from webpack for the error overlay
devServer.app.use(evalSourceMapMiddleware(devServer));
if (fs.existsSync(paths.proxySetup)) {
// This registers user provided middleware for proxy reasons
require(paths.proxySetup)(devServer.app);
}
},
onAfterSetupMiddleware(devServer) {
// Redirect to PUBLIC_URL or homepage from package.json if url not match
devServer.app.use(redirectServedPath(paths.publicUrlOrPath));
// This service worker file is effectively a 'no-op' that will reset any
// previous service worker registered for the same host:port combination.
// We do this in development to avoid hitting the production cache if
// it used the same host and port.
// https://github.com/facebook/create-react-app/issues/2272#issuecomment-302832432
devServer.app.use(noopServiceWorkerMiddleware(paths.publicUrlOrPath));
}
from
setupMiddlewares: (middlewares, devServer) => {
if (!devServer) {
throw new Error('webpack-dev-server is not defined')
}
if (fs.existsSync(paths.proxySetup)) {
require(paths.proxySetup)(devServer.app)
}
middlewares.push(
evalSourceMapMiddleware(devServer),
redirectServedPath(paths.publicUrlOrPath),
noopServiceWorkerMiddleware(paths.publicUrlOrPath)
)
return middlewares;
}
I'm using Webpack Module Federation to create 2 React applications: host and child.
In the host, I create atoms.ts and selector.ts filed and I expose them via the plugin under the expose section:
exposes: {
"./atoms": "./src/recoil/atoms.ts",
"./selectors": "./src/recoil/selectors.ts",
}
Inside the child, I just consume that via the remotes section:
remotes: {
host: "host#http://localhost:3000/remoteEntry.js",
}
Then, in the code of the child I use that like that:
import {someSelector} from "host/selectors"
const val = useRecoilValue(someSelector);
It's working fine but I got this warning in the console:
Duplicate atom key "userAuthState". This is a FATAL ERROR in
production. But it is safe to ignore this warning if it occurred because of
hot module replacement.
Does anyone face that issue and know if it's really a problem or how we could hide the warning?
Another related q:
Is it ok that the host will contain <RecoilRoot> and also the child will contain <RecoilRoot> ? because I want both will manage their own state but also share atom/selectors.
Thanks!
Regarding your second question:
Yes, this is totally fine. The nested <RecoilRoot> will create its own context and every atom referenced below the second root will be independent from the upper root. This is also explained in the docs.
Regarding the first question: As the log states this is fine as long as it occurs during development. Sometimes during the hot module replacement recoil throws away atoms and reinstantiates them causing this duplication to happen internally.
But as long as this warning doesn't pop up in your production code, everything is fine.
Are you importing the atoms or the selectors in your host application using a local path?
You need to include in your host webpack config its own entrypoint as remote and import your atoms from 'host/atoms'
I think this could solve your issue.
You can ignore the warning output (if you can bare it), functionality is not affected.
Also, you can install the intercept-stdout package and add the following to next.config.js (outside of the exported configuration):
const intercept = require("intercept-stdout")
// safely ignore recoil warning messages in dev (triggered by HMR)
function interceptStdout(text) {
if (text.includes("Duplicate atom key")) {
return "";
}
return text;
}
if (process.env.NODE_ENV === "development") {
intercept(interceptStdout);
}
This way can omit the annoying warning in console.
I'm trying to embed Pdf tron to my React application. I'm receiving this error when I'm clicking on the tab I want to filter to find the relative pdf file.
const handleFilteredDocs = (id)=>{
const filteredDoc = props.location.documents && props.location.documents.filter(doc=>{
return doc.controlId === id
})
setFileteredDoc(filteredDoc)
setPdfPath(filteredDoc[0].filePath)
WebViewer(
{
path: 'lib',
initialDoc: `lib/pdf/${pdfPath}`,
extension: "pdf"
},
viewer.current,
).then((instance) => {
const { docViewer, Annotations } = instance;
const annotManager = docViewer.getAnnotationManager();
docViewer.on('documentLoaded', () => {
const rectangleAnnot = new Annotations.RectangleAnnotation();
rectangleAnnot.PageNumber = 1;
// values are in page coordinates with (0, 0) in the top left
rectangleAnnot.X = 100;
rectangleAnnot.Y = 150;
rectangleAnnot.Width = 200;
rectangleAnnot.Height = 50;
rectangleAnnot.Author = annotManager.getCurrentUser();
annotManager.addAnnotation(rectangleAnnot);
// need to draw the annotation otherwise it won't show up until the page is refreshed
annotManager.redrawAnnotation(rectangleAnnot);
});
});
}
I'm thinking is because the ref component didn't receive in time the pdfPath state and then throw the error. I've tried to place a separate button to load the pdf with the pdfPath correctly updated and in that case worked. What can i do make it render correctly there?
this is the error I get from the console:
(index)
Value
UI version "7.3.0"
Core version "7.3.0"
Build "Mi8yMi8yMDIxfDZmZmNhOTdmMQ=="
WebViewer Server false
Full API false
Object
CoreControls.js:189 Could not use incremental download for url /lib/pdf/. Reason: The file is not linearized.
CoreControls.js:189
{message: "The file is not linearized."}
CoreControls.js:189 There may be some degradation of performance. Your server has not been configured to serve .gz. and .br. files with the expected Content-Encoding. See http://www.pdftron.com/kb_content_encoding for instructions on how to resolve this.
CoreControls.js:189 There may be some degradation of performance. Your server has not been configured to serve .gz. and .br. files with the expected Content-Encoding. See http://www.pdftron.com/kb_content_encoding for instructions on how to resolve this.
CoreControls.js:189 There may be some degradation of performance. Your server has not been configured to serve .gz. and .br. files with the expected Content-Encoding. See http://www.pdftron.com/kb_content_encoding for instructions on how to resolve this.
81150ece-4c18-41b0-b551-b92f332bd17f:1
81150ece-4c18-41b0-b551-b92f332bd17f:1 PDFNet is running in demo mode.
81150ece-4c18-41b0-b551-b92f332bd17f:1 Permission: read
CoreControls.js:922 Uncaught (in promise)
{message: "Exception: ↵ Message: PDF header not found. The f… Function : SkipHeader↵ Linenumber : 1139↵", type: "InvalidPDF"}
Thank you guys for any help I will get on this!
The value of "pdfPath" isn't set to "filteredDoc[0].filePath" yet after you call "setPdfPath" (it'll still be the initial state till the next render). One thing you can do is pass a callback function when using "setState" to call "WebViewer()" after "pdfPath" has been updated
https://reactjs.org/docs/react-component.html#setstate
Also there is a guide on how to add PDFtron to a React project in the following link
https://www.pdftron.com/documentation/web/get-started/react/
One thing to note, is it's does the following
useEffect(() => {
// will only run once
WebViewer()
}, [])
By doing the above, "WebViewer" is only initialized once. It might be a good idea to do something similar and use "loadDocument" (https://www.pdftron.com/documentation/web/guides/best-practices/#loading-documents-with-loaddocument) when switching between documents instead of reinitializing WebViewer each time the state changes
So, I looked for a few authentication options for Next.js that wouldn't require any work on the server side of things. My goal was to block users from entering the website without a password.
I've set up a few tests with NextAuth (after a few other tries) and apparently I can block pages with sessions and cookies, but after a few hours of research I still can't find how I would go about blocking assets (e.g. /image.png from the /public folder) from non-authenticated requests.
Is that even possible without a custom server? Am I missing some core understanding here?
Thanks in advance.
I did stumble upon this problem too. It took my dumbass a while but i figured it out in the end.
As you said - for auth you can just use whatever. Such as NextAuth.
And for file serving: I setup new api endpoint and used NodeJS magic of getting the file and serving it in pipe. It's pretty similar to what you would do in Express. Don't forget to setup proper head info in your response.
Here is little snippet to demonstrate (typescript version):
import { NextApiRequest, NextApiResponse } from 'next'
import {stat} from "fs/promises"
import {createReadStream, existsSync} from "fs"
import path from "path"
import mime from "mime"
//basic nextjs api
export default async function getFile (req: NextApiRequest, res: NextApiResponse) {
// Dont forget to auth first!1!!!
// for this i created folder in root folder (at same level as normal nextjs "public" folder) and the "somefile.png" is in it
const someFilePath = path.resolve('./private/somefile.png');
// if file is not located in specified folder then stop and end with 404
if (! existsSync(someFilePath)) return res.status(404);
// Create read stream from path and now its ready to serve to client
const file = createReadStream(path.resolve('./private/somefile.png'))
// set cache so its proper cached. not necessary
// 'private' part means that it should be cached by an invidual(= is intended for single user) and not by single cache. More about in https://stackoverflow.com/questions/12908766/what-is-cache-control-private#answer-49637255
res.setHeader('Cache-Control', `private, max-age=5000`);
// set size header so browser knows how large the file really is
// im using native fs/promise#stat here since theres nothing special about it. no need to be using external pckages
const stats = await stat(someFilePath);
res.setHeader('Content-Length', stats.size);
// set mime type. in case a browser cant really determine what file its gettin
// you can get mime type by lot if varieties of methods but this working so yay
const mimetype = mime.getType(someFilePath);
res.setHeader('Content-type', mimetype);
// Pipe it to the client - with "res" that has been given
file.pipe(res);
}
Cheers
I'm trying to import multiple files with a certain extension in a folder:
const allEntries = require.context('../static/blog', true, '/\.md/')
but I'm getting:
Unhandled Rejection (TypeError): __webpack_require__(...).context is not a function
I'm using Nextjs and require the files in one of the pages. Something seems off here?
Edit: I don't necessarily need to do it via require I just want to be able to import/require multiple files at once without knowing the filename or how many of the files are in a folder.
You can give the following a try in webpack:
const glob = require('glob');
const allEntries = glob.sync("../static/blog/*.md");
The glob will return an array of files. The array will contain all files with .md extension in the ../static/blog/ folder. Eventough there is a package it shouldn't be required to install the package.
Try using require context npm library.
$ npm i --save require-context
In your file:
// Load globally into all modules.
require('require-context/register')
// Load locally as a function.
var requireContext = require('require-context');
function requireAll(r) { r.keys().forEach(r); }
requireAll(requireContext('../static/blog', true, /\.md$/));
From what I understand you are very close, from the error you are using webpack's require.context
const allEntries = require.context('../static/blog', true, '/\.md/')
console.log(allEntries.keys()) // all the files found in the context
allEntries.keys().forEach(allEntries) // require them all
const imageDirectory = path.join(process.cwd(), '/public/dirname');
const imageFilenames = await fs.readdir(imageDirectory)
// Store the file names in an array and use it.
webpack.require is basically using webpack, make sure what you're using is webpack in fact