Can web workers have access to classes defined in Vue application? - javascript

I’m building an application that uses Vue for our front-end, specifically Vue 3 Composition API + Typescript. I need the ability to use web workers for long running processes in the background. I was able to get a vanillajs web worker to run alongside the Vue application no problem. My issue is that I need my web worker to have access to classes and functions that are written inside the Vue app. Both my web worker and my Vue app need to use the same classes and functions and I don’t want to have to write them in two places. Is there a way to share them? Any help is appreciated.

The answer is yes:
There is a way to let the web worker having access to the Vue.js framework through one single JavaScript file.
The library that will help you with this in your Vue.js project is vue-worker. This library uses the simple-web-worker package. (Inline Web Workers approach)
As you may know, a standard web worker requires an extra js file that will contain the code of the worker. For inline web workers it isn't necessary to use a helper method. That will inject a property into Vue (and pass it to every child component), with a default name of $worker. In total you can say it is behaving as an JavaScript promise but without really being a second JavaScript file.
Now your turn:
There is a really good documentation to follow along with this approach I described and additional a second "old-fashion" way. Try it out :)

I was able to figure out a solution using esbuild. I added a process to my npm run serve and npm run build commands so it runs node ./esbuild.js before the vue-cli commands. This compiles my typescript web worker to javascript and puts it in the public folder before compiling the Vue app. Now I can create a web worker like normal using:
const worker = new Worker('/worker.js', { type: 'module' })
And here is my esbuild.js file:
const esbuild = require('esbuild')
const { nodeExternalsPlugin } = require('esbuild-node-externals')
const config = {
entryPoints: ['./src/workers/worker.ts'],
outfile: 'public/worker.js',
bundle: true,
minify: false,
plugins: [nodeExternalsPlugin()]
}
esbuild.build(config).catch(() => process.exit(1))

Related

Check Production and Staging environment inside HTML file in a React App

I am trying to integrate a 3rd party app inside my React App. I have to use different keys for production and staging but I am unable to figure out how to achieve that in React and Node applications I can do it by process.env but in index.html I am unable to figure out how can I achieve that.
Here is my pseudocode which I am trying to pull for my index.html file for my React project
<script>
if(env === production){
some_app.init('TOKEN_FOR_PRODUCTION');
}
else{
some_app.init('TOKEN_FOR_STAGING_OR_DEV');
}
</script>
While I personally prefer to store all API keys on the server itself, this guide indicates that there are other ways to do it:
https://www.geeksforgeeks.org/how-to-hide-your-api-keys-from-public-in-reactjs/
Additionally, to define differences between prod and staging in the front end alone, I recommend defining plug in variables using webpack:
https://webpack.js.org/plugins/define-plugin/

How to use Node Modules in Electron React App

I am currently making a desktop application that is a ReactJS application bundled or built with Electron and I want to use node modules that come with electron in my app, specifically exec or spawn from the child process module. My goal is to have a button press that executes a set of commands from command prompt as a sub/side process and return the stdout.
My app follows the typical app creation process as the tutorials online for first making a react app, get some dependencies and package.json alterations, get electron, make an electron.js or main.js type of file with all the basic window configs in it.
In the main entry point file, for me that is electron.js, I have:
webPreferences: {
nodeIntegration: true
},
However, I cannot use the child process node module in my react code even though I have allowed it in the create window function on electron's side. In my react component, when I do
import { exec } from 'child_process';
react seems to recognize it and displays all the exec function information when hovered over (parameters, overloads, found in child_process module, etc).
However, if I run the this example command from a button click, I get the error:
"TypeError: Object(...) is not a function". Here the error is referring to exec.
import { exec } from 'child_process';
...
const run = () => {
exec('ls -lh', (error, stdout, stderr) => {
if (error) {
console.log(`error123: ${error.message}`);
return;
}
if (stderr) {
console.log(`stderr123: ${stderr}`);
return;
}
console.log(`stdout:\n${stdout}`);
})
};
....
return (
<div>
<button onClick={run}>Run Command!</button>
</div>
)
export ....
Does anybody know how to give the react side access to the node modules within the directory or how to import/access them correctly, either directly from the react side or maybe pass them from electron to react? Or maybe I am just running it incorrectly? I am new to javascript and stuff in general so understanding the issue and debugging is really hard for me.
Thanks to Badal for putting me in the right direction.
The answer I found involves setting contextisolation to false, nodeIntegration to true, and using the ipcMain handler (electron main process) and ipcRenderer handler (rendering, in this case react, process). The first link below shows how to use the handlers (look at the newer answers in the thread) and the second link is more detailed documentation on the inner workings. Note that if you search this 'node modules in react electron app' online, a lot of people are using remote, etc. but electron.remote is for the most deprecated at v12 or 13 and onwards, using it and other deprecated modules WILL NOT tell you its deprecated. Instead it will give the fs.filereadsync or wtvr error (I forgot) because it will not be able to understand it during building. The handlers for ipcMain and ipcRenderer handle all app internal communication and processes now, as the name ipc implies.
How to import ipcRenderer in react?
https://www.electronjs.org/docs/api/ipc-main
(new changes to electron) https://www.electronjs.org/docs/breaking-changes
With this, you can have a run button to execute a certain command and use ipcrenderer to send it to the electron side of things. In the electron side (defaults to sending to the main process file, so electron or main.js), you can import whatever node modules you want and use them. For me, I made a new file, did const {exec} = require('child process'), and then had a function which executed certain command line operations. The function call to exec was placed in the ipcMain handler.
This is insecure. For my purpose, security is not a concern, but for others it might be. Make sure to perform input cleaning and other precautions that prevent people from abusing the app and doing things like making calls without proper handles that can infiltrate the system. If you are using child process, OS subsystem modules, etc. this is especially important. As long as the front end can abstract the nature of how the internal communication is performed, that should be a good start.
Electron, as a framework, is highkey changing very fast. If you want to do well in creating applications with it, I highly recommend staying very attentive with version changes. I am new to it, and through my search on this matter and more, I have seen many small but major changes to how electron's internal process works and a lot of search results yield deprecated/outdated information.
It is preferred to access Node APIs from the Main process. Hence, you need to communicate from the Renderer to the Main process to execute such actions.
To access Node APIs from the Renderer process, you also need to set contextIsolation to false along with nodeIntegration set to true. This is again very insecure, to do because
..it helps prevent the website from accessing Electron internals or the powerful APIs your preload script has access to. [1]
So try to avoid doing in production, as for development you are free to experiment.
Reference:
[1] https://www.electronjs.org/docs/tutorial/context-isolation

Using GRPC-Web without NodeJS

How do you use GRPC-Web on the browser?
I mean, in pure browser code, without any NodeJS involved.
Official example from here: https://github.com/grpc/grpc-web/tree/master/net/grpc/gateway/examples/helloworld are mainly NodeJS oriented.
Is there way to use GRPC-Web in pure Javascript form without:
const {HelloRequest, HelloReply} = require('./helloworld_pb.js');
const {GreeterClient} = require('./helloworld_grpc_web_pb.js');
Meaning, just standard <script>-way of adding Javascript dependencies?
And be able to do: var client = new GreeterClient('http://localhost:8080');
Use grpc-web, not #grpc/grpc-js npm package.
The example provided in Write Client Code uses #grpc/grpc-js, which only works on NodeJS.
To use your protobufs and gRPC services defined in your .proto files, you need to generate your code using grpc-web. Then, import those generated files and use them.
Some things I learnt along the way:
You can't really use protobufjs with gprc-web in browsers, you need to use grpc-web and google-protobuf. If someone has an alternative solution, let me know please.
The generated code in grpc-web is not very nice - it is difficult to read and doesn't have all the features of protobufs. You need to have a lot of Javascript and bundling experience to use it.
grpc-web is more limited than gRPC. NodeJS runs gRPC, but in the browser, you have to use grpc-web, and must run a gRPC proxy to translate gRPC-web into/from gRPC.
Yes. You need to bundle your sources with webpack. This step is also described in the documentation you mentioned. At the bottom of the readme:
Just config your webpack to expose variable:
client.js
...
export function instantiateGreeterClient(...) {
return new GreeterClient(...)
};
webpack.config.js
module.exports = {
...
entry: './path/to/client.js',
output: {
path: './bundle/js/',
filename: 'grpc.js',
library: {
name: 'grpc',
type: 'umd',
},
...
}
And after that import your bundle as usual. Now you be able to use all defined variables in your script tag code as
<script src="path/to/grpc.js"></script>
<script>
const client = grpc.instantiateGreeterClient(...)
...
</script>
More information can be found in webpack documentation

ASP.NET Core - Running mutiple angular 2 applications

I'm facing some problems while trying to run multiple angular 2 application with ASP.NET Core. I'm using
JavaScriptServices with prerendering feature
in a Visual Studio 2015 template.
The structure of my solution is here.
The Core contians the ASP.NET application with server-side routing, and each ClientApp, once boundled, is copied inside the wwwroot.
The problem here is the prerendering feature, which rises:
Prerendering failed because of error: Error: Zone already loaded.
This happens when, after the first render of ClientApp1 I reload the page or when i try to switch between ClientApp1 and ClientApp2.
Can someone help me suggesting what is proper way to run multiple Angular2 applications using boot-server and boot-client style?
Any example/suggestion will be appreciated.
The issue is opened also in github at github.com/aspnet/JavaScriptServices/issues/566
The approach I'm using that seems to work is to simply define multiple entry points in webpack config.
const clientBundleConfig = {
entry: {
'front': './client/front/main.ts',
'admin': './client/admin/main.ts',
},
output: {
path: './www/dist',
filename: '[name].bundle.js'
}
...
}
Now the relevant angular app front or admin will update from a single HMR process. I couldn't get it to work with separate webpack config and HMR processes using the same dotnet server process, I found only the first app would update.
Update
I needed to perform a separate build for apps due to restrictions I ran into. I now follow SteveSandersonMS suggestion of calling UseWebpackDevMiddleware for each app in the Github issue you linked to, the only step missing from his suggestion is the need to specify a unique endpoint for each app:
app.UseWebpackDevMiddleware(new WebpackDevMiddlewareOptions
{
HotModuleReplacement = true,
ConfigFile = "webpack.front.js",
HotModuleReplacementEndpoint = "/__webpack_hmr_front"
});
app.UseWebpackDevMiddleware(new WebpackDevMiddlewareOptions
{
HotModuleReplacement = true,
ConfigFile = "webpack.admin.js",
HotModuleReplacementEndpoint = "/__webpack_hmr_admin"
});

How to handle window object on nodejs for server-side rendering of reactjs application

I am trying to implement server-side rendering for my reactjs application.
I am using webpack to build reactjs application, enhanced-resolve to handle importing of jsx files in nodejs.
My application depends on third party libraries like enquire.js.
When react application tries to import enquire.js on nodejs, it fails with error
ReferenceError: window is not defined
Since window object is not available nodejs
how to handle libraries that use window for server side rendering ?
I haven't used Webpack yet. However, I had similar issue using browserify and I solved it by creating two builds: one for browser one for node.js with list of modules to ignore. You could achieve the same effect by adding to webpack config:
{
plugins: [
new webpack.IgnorePlugin(/file\.js$/)
]
}
Then you have to make sure that you are not making any calls to enquire.js by checking if require() returned false value or object with module functions.
Well this is quite old question still if some one is looking at it.
Try
if (typeof window === 'undefined') {
global.window = {};
}

Categories

Resources