How to load webassembly file in Vue? - vue.js

I have compiled the C code using this command emcc add.c -o js_plumbing.js -s -s EXTRA_EXPORTED_RUNTIME_METHODS=['ccall','cwrap'] -s MODULARIZE=1
This is my Vue component code -
public instance:any = {
ready: new Promise(resolve => {
Module({
onRuntimeInitialized() {
this.instance = Object.assign(this, {
ready: Promise.resolve()
});
resolve();
}
});
})
};
public draw_outline() {
this.instance.ready
.then(_ => this.result_web = this.instance.addTwoNumbers(2,2));
}
draw_outline is getting called when I click on a text element.
And this is the error I'm getting -
So after this error I went to generate file and just added export to the module and this error disappears. but now my function in C "addTwoNumbers" is not getting called from instance.
if I print the value of instance I get
Does anyone know how to proceed from here?

I figured that when compiling I needed to use USE_ES6_IMPORT_META=0 flag so that WebAssembly module will use an older version of the import.meta.url line of code for systems that don't recognize the import style. so the command looks like emcc add.c -o js_plumbing.js -s EXTRA_EXPORTED_RUNTIME_METHODS=['ccall','cwrap'] -s ENVIRONMENT='web,worker' -s EXPORT_ES6=1 -s MODULARIZE=1 -s USE_ES6_IMPORT_META=0
This is my updated code -
Module().then(myModule => {
const result = myModule.ccall('addTwoNumbers',
'number',
['number', 'number'],
[4, 6]);
console.log("Value from wasm file", result);
});
My config file -
const path = require('path');
const contentBase = path.resolve(__dirname, '..', '..');
module.exports = {
configureWebpack: config => {
config.devServer = {
before(app) {
// use proper mime-type for wasm files
app.get('*.wasm', function (req, res, next) {
var options = {
root: contentBase,
dotfiles: 'deny',
headers: {
'Content-Type': 'application/wasm'
}
};
res.sendFile(req.url, options, function (err) {
if (err) {
next(err);
}
});
});
}
}
},
}
It is inside a function that I call on a click event . I can elaborate the whole process if someone is interested. It should not take this much time for anyone, I hope it helps others who have been looking for the solution. I realise I have not properly stated the problem in this post, I shall update everything here in a proper way soon.

Related

How can I configure Vite's dev server to give 404 errors?

Using Vite's dev server, if I try to access a non-existent URL (e.g. localhost:3000/nonexistent/index.html), I would expect to receive a 404 error. Instead I receive a 200 status code, along with the contents of localhost:3000/index.html.
How can I configure Vite so that it returns a 404 in this situation?
(This question: Serve a 404 page with app created with Vue-CLI, is very similar but relates to the Webpack-based Vue-CLI rather than Vite.)
Vite 3
Vite 3.x introduced appType, which can be used to enable/disable the history fallback. Setting it to 'mpa' disables the history fallback while keeping the index.html transform and the 404 handler enabled. The naming is somewhat misleading, as it implies the mode is only for MPAs, but on the contrary, you can use this mode for SPAs:
import { defineConfig } from 'vite'
export default defineConfig({
appType: 'mpa', // disable history fallback
})
Note the history fallback normally rewrites / to /index.html, so you'd have to insert your own middleware to do that if you want to keep that behavior:
import { defineConfig } from 'vite'
const rewriteSlashToIndexHtml = () => {
return {
name: 'rewrite-slash-to-index-html',
apply: 'serve',
enforce: 'post',
configureServer(server) {
// rewrite / as index.html
server.middlewares.use('/', (req, _, next) => {
if (req.url === '/') {
req.url = '/index.html'
}
next()
})
},
}
}
export default defineConfig({
appType: 'mpa', // disable history fallback
plugins: [
rewriteSlashToIndexHtml(),
],
})
Vite 2
Vite 2.x does not support disabling the history API fallback out of the box.
As a workaround, you can add a Vite plugin that removes Vite's history API fallback middleware (based on #ChrisCalo's answer):
// vite.config.js
import { defineConfig } from 'vite'
const removeViteSpaFallbackMiddleware = (middlewares) => {
const { stack } = middlewares
const index = stack.findIndex(({ handle }) => handle.name === 'viteSpaFallbackMiddleware')
if (index > -1) {
stack.splice(index, 1)
} else {
throw Error('viteSpaFallbackMiddleware() not found in server middleware')
}
}
const removeHistoryFallback = () => {
return {
name: 'remove-history-fallback',
apply: 'serve',
enforce: 'post',
configureServer(server) {
// rewrite / as index.html
server.middlewares.use('/', (req, _, next) => {
if (req.url === '/') {
req.url = '/index.html'
}
next()
})
return () => removeViteSpaFallbackMiddleware(server.middlewares)
},
}
}
export default defineConfig({
plugins: [
removeHistoryFallback(),
],
})
One disadvantage of this plugin is it relies on Vite's own internal naming of the history fallback middleware, which makes this workaround brittle.
You could modify fallback middleware to change the default behaves, or anything else you want. Here is an example. https://github.com/legend-chen/vite-404-redirect-plugin
Here's an approach that doesn't try to check what's on disk (which yielded incorrect behavior for me).
Instead, this approach:
removes Vite's SPA fallback middleware
it uses Vite's built-in HTML transformation and returns /dir/index.html (if it exists) for /dir or /dir/ requests
404s for everything else
// express not necessary, but its API does simplify things
const express = require("express");
const { join } = require("path");
const { readFile } = require("fs/promises");
// ADJUST THIS FOR YOUR PROJECT
const PROJECT_ROOT = join(__dirname, "..");
function removeHistoryFallback() {
return {
name: "remove-history-fallback",
configureServer(server) {
// returned function runs AFTER Vite's middleware is built
return function () {
removeViteSpaFallbackMiddleware(server.middlewares);
server.middlewares.use(transformHtmlMiddleware(server));
server.middlewares.use(notFoundMiddleware());
};
},
};
}
function removeViteSpaFallbackMiddleware(middlewares) {
const { stack } = middlewares;
const index = stack.findIndex(function (layer) {
const { handle: fn } = layer;
return fn.name === "viteSpaFallbackMiddleware";
});
if (index > -1) {
stack.splice(index, 1);
} else {
throw Error("viteSpaFallbackMiddleware() not found in server middleware");
}
}
function transformHtmlMiddleware(server) {
const middleware = express();
middleware.use(async (req, res, next) => {
try {
const rawHtml = await getIndexHtml(req.path);
const transformedHtml = await server.transformIndexHtml(
req.url, rawHtml, req.originalUrl
);
res.set(server.config.server.headers);
res.send(transformedHtml);
} catch (error) {
return next(error);
}
});
// named function for easier debugging
return function customViteHtmlTransformMiddleware(req, res, next) {
middleware(req, res, next);
};
}
async function getIndexHtml(path) {
const indexPath = join(PROJECT_ROOT, path, "index.html");
return readFile(indexPath, "utf-8");
}
function notFoundMiddleware() {
const middleware = express();
middleware.use((req, res) => {
const { method, path } = req;
res.status(404);
res.type("html");
res.send(`<pre>Cannot ${method} ${path}</pre>`);
});
return function customNotFoundMiddleware(req, res, next) {
middleware(req, res, next);
};
}
module.exports = {
removeHistoryFallback,
};
What's funny is that Vite seems to take the stance that:
it's a dev and build tool only, it's not to be used in production
built files are meant to be served statically, therefore, it doesn't come with a production server
However, for static file servers:
some configurations of static file servers will return index files when a directory is requested
they generally don't fallback to serving index.html when a file is not found and instead return a 404 in those situations
Therefore, it doesn't make much sense that Vite's dev server has this fallback behavior when it's targeting production environments that don't have it. It would be nice if there were a "correct" way to just turn off the history fallback while keeping the rest of the serving behavior (HTML transformation, etc).

Using ssh in cy.exe() always get timeout error

I use ssh command in cypress exec command. ssh command works properly but I get timeout error from exec() function always.
My code is :
cy.exec('ssh username#111.111.1.1 "\file.exe"')
Actually this code works properly and I can see that file.exe works on remote desktop but I get error on exec().
I think I have to put some options inside the ssh command like -q -w . I tried some of them but it did not work.
Could you please help me?
Maybe exec is too limited in the way you can interact with the command being called, you need a programmable API rather than just configuration options.
You can try using a task instead, there is a library node-ssh that will interface with a Cypress task.
I'm not familiar with ssh protocols, so you will have to fill in those details, but here is a basic example for Cypress task and the node-ssh library
cypress/plugins/index.js
module.exports = (on, config) => {
on('task', {
ssh(params) {
const {username, host, remoteCommand} = params // destructure the argument
const {NodeSSH} = require('node-ssh')
const ssh = new NodeSSH()
ssh.connect({
host: host,
username: username,
privateKey: '/home/steel/.ssh/id_rsa' // maybe parameterize this also
})
.then(function() {
ssh.execCommand(remoteCommand, { cwd:'/var/www' })
.then(function(result) {
console.log('STDOUT: ' + result.stdout)
console.log('STDERR: ' + result.stderr)
})
})
return null
},
})
}
Returning result
The above ssh code is just from the example page of node-ssh. If you want to return the result value, I think this will do it.
module.exports = (on, config) => {
on('task', {
ssh(params) {
const {username, host, remoteCommand} = params // destructure the argument
// returning promise, which is awaited by Cypress
return new Promise((resolve, reject) => {
const {NodeSSH} = require('node-ssh')
const ssh = new NodeSSH()
ssh.connect({
host: host,
username: username,
privateKey: '/home/steel/.ssh/id_rsa'
})
.then(function() {
ssh.execCommand(remoteCommand, { cwd:'/var/www' })
.then(function(result) {
resolve(result) // resolve to command result
})
})
})
},
})
}
In the test
cy.task('ssh', {username: 'username', host: '111.111.1.1', command: '\file.exe'})
.then(result => {
...
})
Only a single parameter is allowed for a task, so pass in an object and destructure it inside the task as shown above.

How to initialize manually next.js app (for testing purpose)?

I try to test my web services, hosted in my Next.js app and I have an error with not found Next.js configuration.
My web service are regular one, stored in the pages/api directory.
My API test fetches a constant ATTACKS_ENDPOINT thanks to this file:
/pages/api/tests/api.spec.js
import { ATTACKS_ENDPOINT } from "../config"
...
describe("endpoints", () => {
beforeAll(buildOptionsFetch)
it("should return all attacks for attacks endpoint", async () => {
const response = await fetch(API_URL + ATTACKS_ENDPOINT, headers)
config.js
import getConfig from "next/config"
const { publicRuntimeConfig } = getConfig()
export const API_URL = publicRuntimeConfig.API_URL
My next.config.js is present and is used properly by the app when started.
When the test is run, this error is thrown
TypeError: Cannot destructure property `publicRuntimeConfig` of 'undefined' or 'null'.
1 | import getConfig from "next/config"
2 |
> 3 | const { publicRuntimeConfig } = getConfig()
I looked for solutions and I found this issue which talks about _manually initialise__ next app.
How to do that, given that I don't test React component but API web service ?
I solved this problem by creating a jest.setup.js file and adding this line of code
First add jest.setup.js to jest.config.js file
// jest.config.js
module.exports = {
// Your config
setupFilesAfterEnv: ['<rootDir>/jest.setup.js'],
};
AND then
// jest.setup.js
jest.mock('next/config', () => () => ({
publicRuntimeConfig: {
YOUR_PUBLIC_VARIABLE: 'value-of-env' // Change this line and copy your env
}
}))
OR
// jest.setup.js
import { setConfig } from 'next/config'
import config from './next.config'
// Make sure you can use "publicRuntimeConfig" within tests.
setConfig(config)
The problem I faced with testing with Jest was that next was not being initialized as expected. My solution was to mock the next module... You can try this:
/** #jest-environment node */
jest.mock('next');
import next from 'next';
next.mockReturnValue({
prepare: () => Promise.resolve(),
getRequestHandler: () => (req, res) => res.status(200),
getConfig: () => ({
publicRuntimeConfig: {} /* This is where you import the mock values */
})
});
Read about manual mocks here: https://jestjs.io/docs/en/manual-mocks
In my case, I had to:
Create a jest.setup.js file and
setConfig({
...config,
publicRuntimeConfig: {
BASE_PATH: '/',
SOME_KEY: 'your_value',
},
serverRuntimeConfig: {
YOUR_KEY: 'your_value',
},
});
Then add this in your jest.config.js file:
setupFilesAfterEnv: ['<rootDir>/jest.setup.js'],

How do I seperate ipcMain.on() functions in different file from main.js

I'm creating an electron app with vuejs as frontend. How can I create all the ipcMain.on() functions in a separate file from the main.js. I want this for a more clean code structure.
The app has to work offline so I need to store the data in a local database. So when I create an object in the frontend, I send it with ipcMain to the electron side. Electron can then write it to the local database.
I want something like this:
main.js:
import { app, protocol, BrowserWindow } from "electron";
import {
createProtocol,
installVueDevtools
} from "vue-cli-plugin-electron-builder/lib";
require("./ipcListeners.js");
ipcListeners.js:
import { ipcMain } from "electron";
ipcMain.on("asynchronous-message", (event, arg) => {
console.log(arg);
event.reply("asynchronous-reply", "pong");
});
ipcMain.on("random-message", (event, arg) => {
console.log(arg);
event.reply("random-reply", "random");
});
The problem here is that only the first ipcMain.on() functions works but the second,... doesn't
What I did in my project is, I arranged all the IPCs in different folders according to their categories and in every file, I exported all the IPCs like the example below
products.js
module.exports = {
products: global.share.ipcMain.on('get-products', (event, key) => {
getProducts()
.then(products => {
event.reply('get-products-response', products)
})
.catch(err => {
console.log(err)
})
})
}
then I created a new file which imported all the exported IPCs
index.js
const {products} = require('./api/guestIpc/products')
module.exports = {
products
}
then finally I imported this file into the main.js file.
main.js
const { app, BrowserWindow, ipcMain } = require('electron')
global.share = {ipcMain} #this is only for limiting the number of ipcMain calls in all the IPC files
require('./ipc/index') #require the exported index.js file
That's it, now all the external IPCs are working as if they were inside the main.js file
i don't know this going to help any way i am going to post what i did. now your implementation worked for me but still i had problem if i am requiring 100 files now in all those requires i have to import ipcMain repeatedly so that's going to be a performances issue so what i did is created global object by inserting electon and IpcMain then it's worked perfectly
my Main.js file
const { app, BrowserWindow } = require('electron')
const electron = require('electron');
const { ipcMain } = require('electron')
global.share= {electron,ipcMain};
function createWindow () {
// Create the browser window.
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: true
}
})
// and load the index.html of the app.
win.loadFile('./views/index.html')
// Open the DevTools.
win.webContents.openDevTools()
}
app.whenReady().then(createWindow);
// Quit when all windows are closed.
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit()
}
})
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow()
}
})
require('./test.js');
test.js
global.share.ipcMain.on('synchronous-message', (event, arg) => {
console.log(arg) // prints "ping"
event.returnValue = 'pong'
})
this is my html call
const { ipcRenderer } = require('electron')
document.querySelector('.btn').addEventListener('click', () => {
console.log(ipcRenderer.sendSync('synchronous-message', 'ping')) // prints "pong"
})
Now this one worked me perfectly so no more messy and long main.js resources

What is the best approach to test a HapiJS plugin, with Lab?

What is the best way to test a HapiJS plugin, for example one plugin that add routes and handlers.
Since I have to create an instance of Hapi.Server to run the plugins, should I define all the tests from the app's root, for all the plugins ?
or
should I manage to get THE instance of Hapi.Server in my plugin's local tests ?
If I go for the second option, my server will have registered all the plugins, including those that the plugin to be tested doesn't depends on.
What is the best way to approach this ?
Thanks in advance.
If you're using Glue (and I highly recommend it), you can create a manifest variable for each test (or group of tests) you want to execute. The manifest only needs to include plugins required for that test to execute properly.
And expose some sort of init function to actually start your server. Small example:
import Lab = require("lab");
import Code = require('code');
import Path = require('path');
import Server = require('../path/to/init/server');
export const lab = Lab.script();
const it = lab.it;
const describe = lab.describe;
const config = {...};
const internals = {
manifest: {
connections: [
{
host: 'localhost',
port: 0
}
],
registrations: [
{
plugin: {
register: '../http_routes',
options: config
}
},
{
plugin: {
register: '../business_plugin',
options: config
}
}
]
},
composeOptions: {
relativeTo: 'some_path'
}
};
describe('business plugin', function () {
it('should do some business', function (done) {
Server.init(internals.manifest, internals.composeOptions, function (err, server) {
// run your tests here
});
});
});
init function:
export const init = function (manifest: any, composeOptions: any, next: (err?: any, server?: Hapi.Server) => void) {
Glue.compose(manifest, composeOptions, function (err: any, server: Hapi.Server) {
if (err) {
return next(err);
}
server.start(function (err: any) {
return next(err, server);
});
});
};