Configuring Pusher on Vue3 - vue.js

I have a project in Vue3 and want to implement a real time API or a web socket. So I attempted to use pusher using Vue third part libraries which are pusher-vue and vue-pusher. Using pusher-vue I am getting the error: Uncaught TypeError: e.prototype is undefined. Using vue-pusher I am getting the error: Uncaught TypeError: Vue.prototype is undefined. The following are the libraries' configurations:
PUSHER VUE
Component.vue
export default{
channels: {
applications_channel: {
subscribeOnMount: true,
subscribed(){
console.log("Some text")
},
bind:{
add_application_event(data){
console.log(data)
}
}
}
}
}
main.js
createApp(App)
.use(PusherVue, {
app_key: "MY_KEY",
cluster: 'MY_CLUSTER',
debug: true,
debugLevel: "all"
})
.mount("#app")
VUE PUSHER
Component.vue
export default{
read(){
var channel = this.$pusher.subscribe('applications-channel')
channel.bind('add-application-event', ({ log }) => {
console.log(log);
})
}
}
main.js
createApp(App)
.use(require("vue-pusher"), {
api_key: "MY_KEY",
options: {
cluster: 'MY_CLUSTER',
ecrypted: true,
}
})
.mount("#app")
May you please help with how can I configure this on Vue3 or recommend any beginner friendly alternatives to achieve the same functionality on Vue3.

Both pusher-vue and vue-pusher were built for Vue 2, so you need to use the Vue 3 migration build to make the library work in your project.
To setup your Vue CLI scaffolded project:
Install the Vue compatibility build and SFC compiler that matches your Vue build version (i.e., install #vue/compat#^3.1.0 and #vue/compiler-sfc#^3.1.0 if you have vue#^3.1.0 in package.json):
npm i -S #vue/compat#^3.1.0
npm i -S #vue/compiler-sfc#^3.1.0
Configure Webpack to alias vue to the #vue/compat build, and set vue-loader's compatibility mode to Vue 2:
// vue.config.js
module.exports = {
chainWebpack: config => {
config.resolve.alias.set('vue', '#vue/compat')
config.module
.rule('vue')
.use('vue-loader')
.tap(options => {
return {
...options,
compilerOptions: {
compatConfig: {
MODE: 2
}
}
}
})
}
}
demo: vue-pusher in Vue 3 w/migration build
However, vue-pusher 1.1.0 seems to only expose a new instance of Pusher (from pusher-js) as this.$pusher on the Vue instance. That code could easily be migrated to Vue 3 as a plugin:
// plugins/pusher.js
export default (app, { apiKey, ...options }) => {
const Pusher = require('pusher-js')
app.config.globalProperties.$pusher = new Pusher(apiKey, options)
}
// main.js
const { createApp } = require('vue')
import App from './App.vue'
import PusherPlugin from './plugins/pusher'
createApp(App)
.use(PusherPlugin, { apiKey: 'YOUR_API_KEY', cluster: 'YOUR_CLUSTER' })
.mount('#app')
demo: pusher-js in Vue 3

Related

How to enable reactivityTransform in Nuxt 3?

I want to enable Vue 3 experimental feature reactivityTransform in Nuxt 3 (3.0.0-rc.3). I've tried the solution provided here, but it did not work and I did get the following error:
Type '{ vue: { reactivityTransform: true; }; }' is not assignable to type 'UserConfig'.
Here is my nuxt.config.ts file:
import { defineNuxtConfig } from "nuxt";
export default defineNuxtConfig({
vite: {
vue: {
reactivityTransform: true
}
},
});
Any idea about what am I doing wrong? How can I enable reactivityTransform in Nuxt 3?
Apparently in the current version of Nuxt 3 (3.0.0-rc.3), instead of modifing the vite config in the nuxt.config file, we should add an experimental proprety; The following code enabled reactivityTransform in Nuxt 3:
// nuxt.config.ts
import { defineNuxtConfig } from "nuxt";
export default defineNuxtConfig({
experimental: {
reactivityTransform: true
},
});
Here is the related link.

using Nuxt 3 with Nest

Currently we are able to build nuxt as following. But are unable to handle routes. We basically want to serve nuxt app from Nestjs.
import { NestFactory } from '#nestjs/core';
import { AppModule } from './app.module.js';
import { loadNuxt } from 'nuxt3';
import { buildNuxt, Resolver } from '#nuxt/kit';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
// Check if we need to run Nuxt in development mode
const isDev = process.env.NODE_ENV !== 'production'
// Get a ready to use Nuxt instance
const nuxt = await loadNuxt({ rootDir: 'src/client-app/' })
// Enable live build & reloading on dev
if (isDev) {
buildNuxt(nuxt)
}
await app.listen(3001);
}
bootstrap();
Following is next (react) equivalent code which is working and trying to achieve in Nuxt 3.
https://github.com/hnviradiya/contact-list/blob/e38a72167d5710fcc9f3ed9718fa9bfe8ebb7d00/src/server/client-app/client-app.service.ts#L25
import { Injectable } from '#nestjs/common';
import { ConfigService } from '#nestjs/config';
import { IncomingMessage, ServerResponse } from 'http';
import createServer, { NextServer } from 'next/dist/server/next';
#Injectable()
export class ClientAppService {
private nextServer: NextServer;
constructor(private configService: ConfigService) {}
async onModuleInit(): Promise<void> {
try {
this.nextServer = createServer({
dev: this.configService.get<string>('NODE_ENV') !== 'production',
dir: './src/client',
});
await this.nextServer.prepare();
} catch (error) {
console.error(error);
}
}
handler(req: IncomingMessage, res: ServerResponse) {
return this.nextServer.getRequestHandler()(req, res);
}
}
In nuxt 2 there were nuxt.render(req, res) or nuxt.renderRoute(route, context). But these methods are not available in nuxt3.
https://nuxtjs.org/docs/internals-glossary/nuxt/
So how to serve nuxt app through NestJs.
Following is the repo where nuxt 3 code is there but it is not serving nuxt app.
https://github.com/hnviradiya/nest-nuxt
while Nestjs is a great server, it's angular style #decorators and modular setup is too unlike Nuxt3's scaffold simplicity.
This conception feels like a bad idea.

nuxt builder in nuxt3

Nuxt 2 was having builder which we used to build nuxt app.
But nuxt 3 is not having builder. Is that not part of nuxt 3? Following is what we were using in nuxt 2.
import { Builder } from '#nuxt/builder';
I am serving nuxt app from nestjs like following example of next.js.
https://github.com/hnviradiya/contact-list/blob/main/src/server/client-app/client-app.service.ts
Following is equivalent to Nuxt 2 code.
import { NestFactory } from '#nestjs/core';
import { AppModule } from './app.module.js';
import { loadNuxt } from 'nuxt3';
import { buildNuxt, Resolver } from '#nuxt/kit';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
// Check if we need to run Nuxt in development mode
const isDev = process.env.NODE_ENV !== 'production'
// Get a ready to use Nuxt instance
const nuxt = await loadNuxt({ rootDir: 'src/client-app/' })
// Enable live build & reloading on dev
if (isDev) {
buildNuxt(nuxt)
}
await app.listen(3001);
}
bootstrap();

How fix __dirname not defined when using electron events with Vue?

I used nklayman/vue-cli-plugin-electron-builder to create an electron app prepared with Vue/Vuex. It ships with files main.js, background.js including Vue component starting point. But I can't get the events to work. My attempt below yields Uncaught ReferenceError: __dirname is not defined when rendering (compile is fine).
Component: Splash.vue
<template>
<div #click="open">open</div>
</template>
<script>
const { ipcMain } = require('electron')
export default {
methods: {
open()
{
ipcMain.on('my-open-event', (event, arg) => {
console.log(event, arg)
})
}
}
}
</script>
background.js
import { app, protocol, BrowserWindow } from 'electron'
...
app.on('my-open-event', async () => {
try {
"Will call some executable here";
} catch (e) {
console.error(e)
}
})
main.js
import Vue from 'vue'
import App from './App.vue'
import store from './store'
Vue.config.productionTip = false
new Vue({
store,
render: h => h(App)
}).$mount('#app')
Full error:
Uncaught ReferenceError: __dirname is not defined
at eval (webpack-internal:///./node_modules/electron/index.js:4)
at Object../node_modules/electron/index.js (chunk-vendors.js:1035)
at __webpack_require__ (app.js:849)
at fn (app.js:151)
at eval (webpack-internal:///./node_modules/cache-loader/dist/cjs.js?!./node_modules/babel-loader/lib/index.js!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/components/Splash.vue?vue&type=script&lang=js&:6)
at Module../node_modules/cache-loader/dist/cjs.js?!./node_modules/babel-loader/lib/index.js!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/components/Splash.vue?vue&type=script&lang=js& (app.js:986)
at __webpack_require__ (app.js:849)
at fn (app.js:151)
at eval (webpack-internal:///./src/components/Splash.vue?vue&type=script&lang=js&:2)
at Module../src/components/Splash.vue?vue&type=script&lang=js& (app.js:1271)
Any ideas what I'm doing wrong?
To solve this I created a file vue.config.js in project root with content
module.exports = {
pluginOptions: {
electronBuilder: {
nodeIntegration: true
}
}
}
There are two processes in electron, the main process and the renderer process. Your Vue component is the renderer process. In order to communicate between these two processes, you need inter-processes communication. So in your case, you'd define a channel perhaps in background.js using ipcMain. You'd write something like:
ipcMain.on("my-custom-channel", (event, args) => handleEvent(event, args));
Then in your Vue component, you'd use the renderer process, ipcRendere, such as:
import { ipcRenderer } from "electron";
export default {
methods: {
open() {
ipcRenderer.send('my-custom-channel', "hello from Vue!")
}
}
}
Point is: you cannot use app.on for your custom events. app.on handles predefined electron events. Use ipcMain.on instead.
reference: https://www.electronjs.org/docs/api/ipc-main
You can apply the solution described on this post
How to import ipcRenderer in vue.js ? __dirname is not defined
In this way you can call window.ipcRenderer.send(channel, args...) from vue files.
Just make sure you configure preload.js on vue.config.js:
// vue.config.js - project root
module.exports = {
pluginOptions: {
electronBuilder: {
preload: 'src/preload.js' //make sure you have this line added
}
}
}
Another solution can be found here https://medium.com/swlh/how-to-safely-set-up-an-electron-app-with-vue-and-webpack-556fb491b83 and it use __static to refer to preload file instead of configure it on vue.config.js. To make it work you can disable preload es-lint warning inside of BrowserWindow constructor:
// eslint-disable-next-line no-undef
preload: path.resolve(__static, 'preload.js')
And make sure you added preload.js file on /public folder

aurealia-i18n and latest webpack typescript skeleton

I'm trying to use the aurelia-i18n plugin in with the latest typescript webpack skeleton.
So I have installed the needed npm packages
npm install aurelia-i18n --save
npm install i18next-xhr-backend --save
npm install i18next-browser-languagedetector --save
Then I have changed my main.ts
import { Aurelia } from 'aurelia-framework';
import { PLATFORM } from 'aurelia-pal';
import XHR from 'i18next-xhr-backend';
import LngDetector from 'i18next-browser-languagedetector';
export async function configure(aurelia: Aurelia) {
aurelia.use
.standardConfiguration()
.developmentLogging()
.plugin(PLATFORM.moduleName('aurelia-i18n'), (instance) => {
// register i18n plugins
instance.i18next
.use(XHR)
.use(LngDetector);
// adapt options to your needs (see http://i18next.com/docs/options/)
// make sure to return the promise of the setup method, in order to guarantee proper loading
return instance.setup({
backend: { // <-- configure backend settings
loadPath: './Locale/{{lng}}/{{ns}}.json', // <-- XHR settings for where to get the files from
},
detection: {
order: ['localStorage', 'cookie', 'navigator'],
lookupCookie: 'i18next',
lookupLocalStorage: 'i18nextLng',
caches: ['localStorage', 'cookie']
},
attributes: ['t', 'i18n'],
fallbackLng: 'en',
load: 'languageOnly',
debug: false,
ns: ['translation',
'StammAlbum',
'StammCategory',
'StammCategoryValue',
'StammPictureAdmin',
'StammPictureUpload',
'StammVideoUpload',
'StammVideoAdmin',
'VideoKonverter',
'Router',
'Datamappings',
'Toasts',
'Alerts',
'Controls',
'Metadata',
'Dialogs',
'AuthRegister',
'SecurityQuestions',
'Countries',
'Validation',
'AuthConfirmAccount',
'AuthLogin',
'AuthForgotPassword',
'AuthAdminAccount',
'AuthNewPassword',
'Messages'],
defaultNS: 'translation'
});
});
await aurelia.start();
await aurelia.setRoot(PLATFORM.moduleName('FamilieLaissApp'));
}
The webpack bundler shows no errors. But in the browser console I can see a 404 Error for every Translation-File.
So I have tried the solution that is documented on the aurelia hub for using the built in backend and changed the main.ts
import { Aurelia } from 'aurelia-framework';
import { PLATFORM } from 'aurelia-pal';
import {I18N, Backend} from 'aurelia-i18n';
import LngDetector from 'i18next-browser-languagedetector';
export async function configure(aurelia: Aurelia) {
aurelia.use
.standardConfiguration()
.developmentLogging()
.plugin(PLATFORM.moduleName('aurelia-i18n'), (instance) => {
// register i18n plugins
instance.i18next
.use(Backend.with(aurelia.loader))
.use(LngDetector);
// adapt options to your needs (see http://i18next.com/docs/options/)
// make sure to return the promise of the setup method, in order to guarantee proper loading
return instance.setup({
backend: { // <-- configure backend settings
loadPath: './Locale/{{lng}}/{{ns}}.json', // <-- XHR settings for where to get the files from
},
detection: {
order: ['localStorage', 'cookie', 'navigator'],
lookupCookie: 'i18next',
lookupLocalStorage: 'i18nextLng',
caches: ['localStorage', 'cookie']
},
attributes: ['t', 'i18n'],
fallbackLng: 'en',
load: 'languageOnly',
debug: false,
ns: ['translation',
'StammAlbum',
'StammCategory',
'StammCategoryValue',
'StammPictureAdmin',
'StammPictureUpload',
'StammVideoUpload',
'StammVideoAdmin',
'VideoKonverter',
'Router',
'Datamappings',
'Toasts',
'Alerts',
'Controls',
'Metadata',
'Dialogs',
'AuthRegister',
'SecurityQuestions',
'Countries',
'Validation',
'AuthConfirmAccount',
'AuthLogin',
'AuthForgotPassword',
'AuthAdminAccount',
'AuthNewPassword',
'Messages'],
defaultNS: 'translation'
});
});
await aurelia.start();
await aurelia.setRoot(PLATFORM.moduleName('FamilieLaissApp'));
}
But also no luck with this solution. The 404 Errors are gone but the localized strings are not shown in my application. I can only see the Localization.Identifiers not the localized text, and the browser shows no error in the console output.
So what I have to do to get this thing to work?
Here is my working config. I don't use typescript, but your problem is related to the bundling of locale files with webpack
var Promise = require('bluebird'); // Promise polyfill for IE11
Promise.config({
// Enable warnings
warnings: false,
// Enable long stack traces
longStackTraces: true,
// Enable cancellation
cancellation: false,
// Enable monitoring
monitoring: false
});
import 'intl';
import 'intl/locale-data/jsonp/en';
import 'intl/locale-data/jsonp/de';
import {bootstrap} from 'aurelia-bootstrapper-webpack';
import '../theme/assets/css/jquery-ui.css';
//import '-!style!css!../theme/assets/css/jquery-ui.css';
// note! import bootstrap styles after ace
import '../theme/assets/css/ace.css';
import '../theme/assets/css/bootstrap.css';
import '../styles/main.less';
import 'jquery-ui/jquery-ui';
// just js from bootstrap
import 'bootstrap-webpack/bootstrap-scripts!bootstrap-webpack/bootstrap.config.js';
// always import ace-theme after jquery-ui and bootsrap
import 'ace-theme/ace';
import 'ace-theme/ace-elements';
import 'font-awesome-webpack';
import XHR from 'i18next-xhr-backend';
function loadLocales(url, options, callback, data) {
try {
let waitForLocale = require('bundle!json!../locale/' + url + '.json');
waitForLocale((locale) => {
callback(locale, {status: '200'});
})
} catch (e) {
callback(null, {status: '404'});
}
}
bootstrap(function (aurelia) {
aurelia.use
.standardConfiguration()
.developmentLogging()
.plugin('aurelia-i18n', (instance) => {
// register backend plugin
instance.i18next.use(XHR);
// adapt options to your needs (see http://i18next.com/docs/options/)
return instance.setup({
backend: { // <-- configure backend settings
//loadPath: '/locale/{{lng}}/{{ns}}.json' // <-- XHR settings for where to get the files from
loadPath: '{{lng}}/{{ns}}',
parse: (data) => data,
ajax: loadLocales
},
lng: 'de',
attributes: ['t', 'i18n'],
fallbackLng: 'en',
debug: false,
//debug: true,
//compatibilityJSON: 'v1',
ns: ['translation', 'nav', 'secuident', 'validation']
});
})
.plugin('aurelia-validation')
.plugin('aurelia-dialog', config => {
config.useDefaults();
config.settings.startingZIndex = 5000;
});
aurelia.start().then(() => aurelia.setRoot('app-webpack', document.body));
});