ServiceWorker multiple SCSS files for dynamic require in React - javascript

I have been searching around but can't find an answer to this. I managed to dynamically load the required scss files for the create-react-app dynamically, so as to have a light and dark modes. I use the vanilla framework with React.js, and am doing the following in app.js
useEffect(
() => {
console.log('use effect')
if (cookies['mode'] === 'light' || cookies['mode'] === 'dark') {
console.log('cookies_mode: '+cookies['mode'])
setUiMode(cookies['mode'])
} else {
console.log('cookies_mode: light')
setUiMode('light')
}
if (uiMode === 'light') {
require('./app.scss')
setNavBgColor('#FFF')
setNavFgColor('#111')
} else {
require('./app-dark.scss')
setNavBgColor('#080808')
setNavFgColor('#FFF')
}
},
[cookies, uiMode]
)
and upon reload the correct stylesheet is used. This is working perfectly in the development server (i.e npm start) but when I build it with npm run build and then serve it, all the site works fine, except for the ability to switch modes, so it stays in dark mode always... super strange because the cookies are being set correctly.. Could this be because of having enabled the service worker and it is caching my stylesheet even if it has different name?
Code in my github: https://github.com/averageflow/joes-software
Don't know if it helps but here is the way it switches themes:
function toggleUIMode () {
if (uiMode === 'dark') {
setCookie('mode', 'light', { path: '/' })
setUiMode('light')
window.location.reload(false)
} else {
setCookie('mode', 'dark', { path: '/' })
setUiMode('dark')
window.location.reload(false)
}
console.log('set ui mode to')
console.log(uiMode)
}

Related

How to use proxy with vite (vue frontend) and django rest framework

So, you know when you access a view with django rest api on the browser, you get an html page, and when you send something like an ajax request, you get the json? I'm trying to figure out how to mess with the proxy setting for vite, but I can't find a single decent documentation around it. I want to redirect '/' to 'http://localhost:8000/api', but there's really weird behavior going on.
If I have a route on localhost:8000/api, I can do:
//vite.config.js
export default defineConfig({
plugins: [vue()],
server: {
proxy: {
//Focus here
'/api': {
target: 'http://localhost:8000',
changeOrigin: true,
rewrite: (path) => { console.log(path); return path.replace('/^\/api/', '') }
}
}
}
})
//todo-component.vue
export default {
data() {
return {
todos: []
}
},
components: {
TodoElement
},
beforeCreate() {
//Focus here as well
this.axios.get('/api').then((response) => {
this.todos = response.data
})
.catch((e) => {
console.error(e)
})
}
}
This will return the json response as expected. However, if I try to make it so that '/' routes to 'localhost:8000/api/', like this:
export default defineConfig({
plugins: [vue()],
server: {
proxy: {
//change here
'/': {
target: 'http://localhost:8000/api',
changeOrigin: true,
rewrite: (path) => { console.log(path); return path.replace('/^\/api/', '') }
}
}
}
})
import TodoElement from "./todo-element.vue"
export default {
data() {
return {
todos: []
}
},
components: {
TodoElement
},
beforeCreate() {
//change here
this.axios.get('/').then((response) => {
this.todos = response.data
})
.catch((e) => {
console.error(e)
})
}
}
It just spews out the html version of the api view, but with no styling, with a bunch of errors
No idea what to do. If someone could explain how this proxy works, i'd really love it. I don't want to keep writing "api/", and it'd be really valuable if I can manage to understand how this works.
You are a bit confusing things and I will try to show you why.
If you redirect root path / to /api, every request sent to your app running at http://localhost:3000 will be forwarded to http://localhost:8000/api. It mean that you will not be able to serve anything from the running app, but you will get an answer from the configured endpoint (localhost:8000/api) for every request.
To understand easily what is going on, keep in mind that this vite config option (server.proxy) act like a reverse proxy. As example, I take the favicon.ico resource of your app.
With your current configuration, when from your browser you try to access your app, the /favicon.ico (and all other resources) is then loaded from http://localhost:8000/api/favicon.ico and not anymore from your app running at http://localhost:3000/favicon.ico.
This explain all the errors in the console. Again, for example, /static/rest_framework is loaded from http://localhost:8000/api/ and not http://localhost:3000/.
The documentation is quite clear, it's just a matter of understanding what a http-proxy is. To get more information you can head to https://github.com/http-party/node-http-proxy#core-concept

Display full folder path in console using electron and Javascript

Im using electron with a python backend (for a stand alone desktop application) and I need to supply the python script with a directory. With the following code I can get a dialog to open however, it will not output the folder path to the console.
const OpenBtn = document.getElementById('OpenBtn')
OpenBtn.addEventListener('click', function(event) {
const { dialog } = require('electron').remote;
//Synchronous
let dir = dialog.showOpenDialog({properties:["openDirectory"]})
console.log(dir)
})
I am new to the frontend aspects of creating apps and I am trying to understand what is contained in dir. I see it produces a "promise" (I've tried various ways of accessing the filePaths string, but without success.
There is an HTML button with id=OpenBtn, and I have
webPreferences: {
nodeIntegration: true,
enableRemoteModule: true
}
in my main.js file.
Either use the synchronous showOpenDialogSync:
let dirs = dialog.showOpenDialogSync({properties:["openDirectory"]})
if (typeof dirs !== "undefined") {
console.log("Selected paths:");
console.log(dirs);
}
Or the asynchronous showOpenDialog:
dialog.showOpenDialog({properties: ["openDirectory"]}).then(result => {
if (result.canceled === false) {
console.log("Selected paths:");
console.log(result.filePaths);
}
}).catch(err => {
console.log(err);
})

Vue CLI Plugin Electron Builder shows complete blank screen on build

When I build my electron app with this plugin, all I get when installing the package is a blank, white, screen. I've configured the window to open dev tools in the built version, but when I look at the inspect menu, the only content on the page are the <html>, <head> and <body> tags, and there are no errors; the console is completely empty:
Elements:
Console:
I've looked just about everywhere online, but none of the solutions there worked.
I have tried changing the router mode from history to hash and also running vue invoke electron-builder, but they didn't help.
From what I can tell, this is failing:
win.loadURL('app://index.html')
because the path is incorrect. But I don't know if that's the case or if it's something else, since there are no errors reported.
Here's my background.js file:
'use strict'
import { app, protocol, BrowserWindow } from 'electron'
import { createProtocol } from 'vue-cli-plugin-electron-builder/lib'
import installExtension, { VUEJS_DEVTOOLS } from 'electron-devtools-installer'
const isDevelopment = process.env.NODE_ENV !== 'production'
// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let win
// Scheme must be registered before the app is ready
protocol.registerSchemesAsPrivileged([
{ scheme: 'app', privileges: { secure: true, standard: true } }
])
function createWindow() {
// Create the browser window.
win = new BrowserWindow({
width: 1500,
height: 845,
webPreferences: {
// Use pluginOptions.nodeIntegration, leave this alone
// See nklayman.github.io/vue-cli-plugin-electron-builder/guide/security.html#node-integration for more info
nodeIntegration: true,
enableRemoteModule: true
}
})
win.removeMenu()
win.webContents.openDevTools();
if (process.env.WEBPACK_DEV_SERVER_URL) {
// Load the url of the dev server if in development mode
win.loadURL(process.env.WEBPACK_DEV_SERVER_URL)
// if (!process.env.IS_TEST) win.webContents.openDevTools();
} else {
createProtocol('app')
// Load the index.html when not in development
win.loadURL('app://index.html')
}
win.once('ready-to-show', () => {
win.show();
})
win.on('closed', () => {
win = null
})
}
// Quit when all windows are closed.
app.on('window-all-closed', () => {
// On macOS it is common for applications and their menu bar
// to stay active until the user quits explicitly with Cmd + Q
if (process.platform !== 'darwin') {
app.quit()
}
})
app.on('activate', () => {
// On macOS it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (win === null) {
createWindow()
}
})
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on('ready', async () => {
if (isDevelopment && !process.env.IS_TEST) {
// Install Vue Devtools
try {
await installExtension(VUEJS_DEVTOOLS)
} catch (e) {
console.error('Vue Devtools failed to install:', e.toString())
}
}
createWindow()
})
// Exit cleanly on request from parent process in development mode.
if (isDevelopment) {
if (process.platform === 'win32') {
process.on('message', (data) => {
if (data === 'graceful-exit') {
app.quit()
}
})
} else {
process.on('SIGTERM', () => {
app.quit()
})
}
}
How can I fix this problem?
I found that solution is to change router mode from "history" to "hash". So in router config set:
mode: process.env.IS_ELECTRON ? 'hash' : 'history',
Problem solution source
So after more Googling, I stumbled upon this site which suggested to do this:
Replace your default win.loadURL() (which might look like this:
win.loadURL(formatUrl({
pathname: path.join(__dirname, 'index.html');,
protocol: 'file',
slashes: true
}))
or it could be different; it doesn't matter), with this:
win.loadURL(path.join(__dirname, 'index.html'));
Basically, the difference is that this just removes the formatUrl which seems to screw things up.
I replaced mine, which was:
win.loadURL("app://./index.html");
with this, and it works fine now.
Also make sure you don't delete createProtocol('app') if that is there too, (it was a few lines above win.loadUrl()), because you could break your app :).
if you are using vue-router, make sure to set it on "hash mode".
source: https://nklayman.github.io/vue-cli-plugin-electron-builder/guide/commonIssues.html

what features of Google Analytics can be used in Electron-Vue application

I have created an education application with electron-vue js and now I have decided to implement Google Analytics in this desktop application. I have googled for some packages but could not find what exactly I can get from Google Analytics i.e., what features of google analytics I should use to improve my study-based desktop application( electron-vue js platform).
Here is a little bit description about it:
a) the application is totally offline.
b) it includes study stuff like audios,videos,etc.,.
c) it also provides features like printing study material.
Even a single idea can help me figuring out what to do with Google analytics and can be a good head start.
Thanking you in advance!
Google analytics will consider Electron a website.
I use this plugin https://github.com/MatteoGabriele/vue-analytics
And set it up like this in your main entry for Vue in your renderer
import VueAnalytics, { set } from 'vue-analytics'
Vue.use(VueAnalytics, {
id: 'UA-idnumber',
router,
// debug: {
// enabled: true,
// trace: true // help you find problems
// },
fields: {
cookieDomain: 'none' // no domain
},
autoTracking: {
pageviewTemplate (route) {
// allow custom page titles in the router meta
let title = route.meta.title
if (!title) {
title = route.name
}
return {
page: route.name,
title: title,
location: route.path
}
}
}
})
set('allowAdFeatures', false) // no ads
set('checkProtocolTask', null) // ignore electron protocols
set('checkStorageTask', null) // ignore electrons cache solution, assume it works
Then I have directives like this
import { event } from 'vue-analytics'
Vue.directive('gaClick',
{
inserted: (el, binding, vnode) => {
let routeName = vnode.context.$route.meta.title
if (!routeName) {
routeName = vnode.context.$route.name
}
el.addEventListener('click', async e => {
const category = binding.value && binding.value.category ? binding.value.category : 'button Click'
const action = binding.value && binding.value.action ? binding.value.action : 'Click'
const label = binding.value && binding.value.label ? binding.value.label : `${e.target.innerText} (${routeName})`
const value = binding.value && binding.value.value ? binding.value.value : 0
event(category, action, label, value)
})
}
})
To be used on buttons and links like this
<router-link
:to="{name:'status-page'}}"
v-ga-click="{label:'Status Page'}"
>
Status Page
</router-link>
This will give you nearly all the features google analytics has. Unless they decide to change things again and break it. Like they did in their push to firebase analytics for "apps"

Expo IntentLauncher can't open Application_Details_Settings

I want to open the details settings of my application from the app itself.
I use the IntentLauncher from Expo itself: https://docs.expo.io/versions/latest/sdk/intent-launcher
The code I use that I assume should work is:
IntentLauncher.startActivityAsync(IntentLauncher.ACTION_APPLICATION_DETAILS_SETTINGS)
But this gives me this error:
[Unhandled promise rejection: Error: Encountered an exception while calling native method: Exception occurred while executing exported method startActivity on module ExpoIntentLauncher: null]
I'm not sure if I should give some kind of parameter with it so it links to my app?
Opening all other settings does work, ex:
IntentLauncher.startActivityAsync(IntentLauncher.ACTION_APPLICATION_SETTINGS)
This does open a list off all apps, I just need to get the detailed screen of the app itself, not the list.
I found this solution by bodolsog working.
Complete solution
import * as IntentLauncher from "expo-intent-launcher";
import Constants from "expo-constants";
const pkg = Constants.manifest.releaseChannel
? Constants.manifest.android.package // When published, considered as using standalone build
: "host.exp.exponent"; // In expo client mode
IntentLauncherAndroid.startActivityAsync(
IntentLauncherAndroid.ACTION_APPLICATION_DETAILS_SETTINGS,
{ data: 'package:' + pkg },
)
Hope this helps someone
import { startActivityAsync, ActivityAction } from 'expo-intent-launcher';
import * as Linking from 'expo-linking';
import Constants from 'expo-constants';
const pkg = Constants.manifest.releaseChannel
? Constants.manifest.android.package // When published, considered as using standalone build
: 'host.exp.exponent'; // In expo client mode
openSettings = async () => {
try {
if (Platform.OS === 'android') {
// console.log(Constants);
startActivityAsync(ActivityAction.APPLICATION_DETAILS_SETTINGS, {
data: 'package:' + pkg,
});
}
if (Platform.OS === 'ios') {
Linking.openSettings();
}
} catch (error) {
console.log(error);
}
};

Categories

Resources