Firebase Auth + Electron = failure? - firebase

I'm trying to get firebase auth working with electron. I already have it working with iOS and Android and would like to use the same for the desktop version of the app.
What I'm mainly trying with is the google sign in. Using firebase's web version ends up with a failure where localhost isn't accepted for signing in. I have tried the node.js version of the code but I can't get that working either.
Google this: https://www.google.com/search?q=firebase+auth+electron
And you'll see all I have tried and all stackoverflow questions I have looked through. Some people say they have it working but I have found no working examples. Is this a lost cause or could someone point me in the right direction?
A lot of people seems to have the same issue but no answers.

you will have to set nativeWindowOpen to true inside webPreferences in your main windows. Like so:
mainWindow = new BrowserWindow(
{
width: 1280,
height: 720,
webPreferences: {
nodeIntegration: false,
preload: path.join(__dirname, 'preload.js'),
nativeWindowOpen: true
}
}
);

One way to make this work is to run a local server which serves the page you want to display. Then in your electron window load that local server url.
Because the Firebase libraries will complain if loaded directly in an electron window, but you can get around it using a local server like this:
import {
app,
BrowserWindow
} from 'electron'
import ex from 'express'
import path from 'path'
const express = ex()
let win
const port = 12345
const appPath = app.getAppPath()
express.use(require('express').static(path.join(appPath, '/')))
express.get('/', (_, res) => res.sendFile(path.join(appPath, '/index.html')))
express.listen(port, () => console.log('Running on ' + port))
function getWindow () {
if (win === undefined) {
// Create the browser window.
win = new BrowserWindow({
frame: false,
transparent: true,
alwaysOnTop: true,
width: 1280,
height: 768,
center: true
})
win.loadURL('http://localhost:' + port)
}
return win
}
app.on('ready', () => {
getWindow().show()
})
The above code would be your index.js which you'd run when you run electron. Then in index.html which is served over the local webserver you load the firebase web libraries.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title>Example</title>
</head>
<body>
<script src="/__/firebase/6.3.0/firebase-app.js"></script>
<script src="/__/firebase/6.3.0/firebase-auth.js"></script>
</body>
</html>

what you could look into is something that achieves what you need but not exactly what you want. Whilst the google sign in module is iffy to say the least with electron, I've found success using the createUserWithEmailAndPassword function with Firebase auth, check that out

I was facing the same problem when connecting firebase and electron.js with React.js but there's a simple way that allows you to use firebase popup authentication. Inside the main process when creating a new browserWindow. Under webPreferences object add or set the property nativeWindowOpen to true. Make sure that your webPreferences object has the property nativeWindowOpen set to true.
Example
window = new electron.BrowserWindow({
width: 1200,
height: 650,
webPreferences:{
nodeIntegration: true,
enableRemoteModule: true,
nativeWindowOpen: true, // this allows you to use popups when doing authentication using firebase in an electron app
}
})
Good luck ✔✔✨✨

Related

How to export script and execute it with next/script

Salutations!
I am working on a Tailwind-css-Next.js-Typescript project trying to implement a theme toggler. It works fine except for the on-load flicker.
In the past I implemented a solution similar to https://github.com/vercel/next.js/discussions/12533 but now that only next/script is accepted, when using Typescript you can't export a script without export which paradoxically returns an Uncaught SyntaxError: Unexpected token 'export' error.Also scripts like this won't execute anyway if you add them in the Head instead of inside the body. Which in turn is a problem because tailwind wants the script in the head.
This is my current script (note that I must use export{} and create a module otherwise the Typescript linter doesn't let me save the file):
var theme = localStorage.getItem("dark-theme") || "light";
if (theme === "dark") {
document.documentElement.classList.add("dark");
}
export {};
And I try to use it like so:
import "./globals.css";
import Script from "next/script";
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
{/*
<head /> will contain the components returned by the nearest parent
head.tsx. Find out more at https://beta.nextjs.org/docs/api-reference/file-conventions/head
*/}
<head />
<body>
<Script
type="module"
strategy="beforeInteractive"
src="themeScript.tsx"
/>
{children}
</body>
</html>
);
}
But this causes a Uncaught SyntaxError: Unexpected token 'export' (at themeScript.tsx:1:1)
I have also tried adding the following both in the Head and in the body. It doesn't return an error but doesn't produce a result.
<Script id="find-dark-mode">{localStorage.getItem("dark-theme") === true ? document.documentElement.classList.add('dark') : document.documentElement.classList.remove('dark')}</Script>
This question is similar to Next 13 & Tailwind Darkmode Flickering but I am asking about next 13 scripts in general.
I appreciate your time in advance.

Botframework with WordPress

I want to implement BotFramework in a WordPress but in any way or form, it's not working properly.
I used different scripts but got to the same wrong result.
one:
<script>
(function () {
var div = document.createElement("div");
document.getElementsByTagName('body')[0].appendChild(div);
div.outerHTML = "<div id='botDiv' style='height: 38px; position: fixed;
bottom: 0; z-index: 1000; background-color: red'>
<div id='botTitleBar' style='height: 38px; width: 400px;
position:fixed; cursor: pointer;'></div>
[advanced_iframe src="https://webchat.botframework.com/embed/..."
width="100%" height="600"]</div>";
document.querySelector('body').addEventListener('click', function (e) {
e.target.matches = e.target.matches || e.target.msMatchesSelector;
if (e.target.matches('#botTitleBar')) {
var botDiv = document.querySelector('#botDiv');
botDiv.style.height = botDiv.style.height == '600px' ? '38px' : '600px';
};
});
}());
</script>
it's giving me the banner but not opening the chat when pressed.
in other case the script:
<!DOCTYPE html>
<html>
<body>
<div id="webchat" role="main"></div>
<script src="https://cdn.botframework.com/botframework-webchat/latest/webchat.js"></script>
<script>
window.WebChat.renderWebChat({
directLine: window.WebChat.createDirectLine({ token: 'key' }),
userID: 'YOUR_USER_ID',
username: 'Web Chat User',
locale: 'en-US',
botAvatarInitials: 'WC',
userAvatarInitials: 'WW'
}, document.getElementById('webchat'));
</script>
</body>
</html>
but in this case, it's doing nothing.
help, please :(
I don't know how your environment is structured, so hopefully, this translates but I was able to accomplish this. I'm running this locally having spun up a WP site on a WAMP server.
First, I generate a token by making an API call to
https://directline.botframework.com/v3/directline/tokens/generate.
If you're already generating a token, then skip to the next section. If not, you can reference this code, found here (if of interest).
On WP, I am using a plugin called 'WP Coder' This allows you to enter in the necessary components while letting the plugin 'make it work' in the page. I tried hand-coding it in, but the WP page wasn't playing nice and this plugin was.
Once the plugin is installed, put this in the 'HTML code' section:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>WebChat</title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<div id="webchat" role="main"></div>
</body>
</html>
Followed by this in the 'CSS code' section:
html,
body {
height: 100%
}
body {
margin: 0
}
#webchat,
#webchat>* {
height: 500px;
width: 100%;
}
Btw, if you set the height to 100% for '#webchat' the chat will continuously scroll down the page, as entries are made, forcing the user to have to 'scroll after it'. Outside of that, adjust it as you will.
Under 'JS Code', add the following. Please note, that I'm generating a token locally. You will need to update this to match your method of token generation:
( async function () {
const res = await fetch( 'http://localhost:3979/directline/token', { method: 'POST' } );
const { token } = await res.json();
window.WebChat.renderWebChat( {
directLine: window.WebChat.createDirectLine( { token } )
}, document.getElementById( 'webchat' ) );
} )();
Next, under 'Include files' enter the two following JS files as URLs (individually):
https://unpkg.com/markdown-it/dist/markdown-it.min.js
https://cdn.botframework.com/botframework-webchat/master/webchat.js
Lastly, take the Publish 'shortcode' (mine looks like this [WP-Coder id="1"]) and place it on your page. This is found in the WP Coder plugin.
At this point, it should work for you. If not, I would look closely at how you are generating and passing the token.
Hope of help!

Webpack-React with server-side-rendering: linking to css file in server template with hash name

I'm preparing a starter for react from scratch, here is the code: https://github.com/antondc/react-starter
I managed to set up bundling for client and server, with css modules and less, and now I'm with server side rendering. I'm doing that with a js template:
// src/server/views/index.ejs
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>INDEX.EJS</title>
<link rel="stylesheet" type="text/css" href="assets/index.css">
</head>
<body>
<div id="app"></div>
<script src="/assets/bundle.js"></script>
</body>
</html>
As you see, the link to the css file is harcoded there. But in my Webpack configuration I have this file name hashed, because I want to prevent caching from browsers when I update the code on development.
I am wondering how can I link the css file there. Now in the template I have href="assets/index.css, but the css file is in /dist/assets/d47e.css.
It would be great if would be possible to do something like href="assets/*.css, but is not possible, so what is the common approach for a problem like this one?
Thanks!
It depends.
Step 1: Get the current asset name
To get the current name of the generated webpack css/js files, you can use the assets-webpack-plugin. This will (with default config) generate an assets.json file in your output folder with essentially this structure:
{
"bundle_name": {
"asset_kind": "/public/path/to/asset"
}
}
Step 2a: Your html is rendered from a template (pug/jade/what ever)
// in your render code
const assets = require('<webpack-output-folder>/assets.json');
// ...
res.render('template', {
scripts: [{src: `${WEBPACK_PUBLIC_PATH}/${assets.myEntryPointName.js}` }],
links: [{href: `${WEBPACK_PUBLIC_PATH}/${assets.myEntryPointName.css}` rel: 'stylesheet' }],
});
// in your template (example for pug)
// ...
each link in links
link(rel=link.rel href=link.href)
// ...
each script in scripts
script(src=script.src)
// ...
Step 2b: Your html is static
You need to update the html (using a script) with the information from the asset.json file. This script needs to be run after webpack. Something like
const assets = require('<webpack-output-folder>/assets.json');
const fs = require('fs');
const css = /assets\/[a-z0-9]*\.css/i;
const js = /assets\/[a-z0-9]*\.js/i;
fs.readFile('<yourhtml>.html', (err, data) => {
// ... (error handling)
const updatedCss = data.replace(css, assets.myEntryPointName.css);
const updatedJs = updatedCss.replace(js, assets.myEntryPointName.js);
fs.writeFile('<yourhtml>.html', updated, (err) => {
// ... (error handling)
});
});
You can use HTMLWebpackPlugin to generate an HTML file that will have your JS and CSS output inserted.

How can I contain the styles of a Chrome Extension content script?

I'm working on a Chrome extension that injects some UI react components into a page.
The UI components come from react-mdl. Using them requires me to include a css file in the top of my project.
Unfortunately, once the css is injected into the page, the entire page's font is changed.
Is there a way to limit the scope of the css used by react-mdl such that it doesn't affect the page into which I'm injecting?
Just posting this for posterity as accepted answer deserves credit, but if anyone finds themselves in a similar predicament, here is a snippet of the code that worked for me:
// my injected code
window.addEventListener('load', () => {
const injectDiv = document.createElement('div')
const shadowRoot = injectDiv.attachShadow({ mode: 'open' })
// note inline use of webpack raw-loader, so that the css
// file gets inserted as raw text, instead of attached to <head>
// as with the webpack style-loader
shadowRoot.innerHTML = // just using template string
`
<style>${require('raw-loader!app/styles/extension-material.css')}</style>
<div id='shadowReactRoot' />
`
document.body.appendChild(injectDiv)
ReactDOM.render(
<App />,
// note you have to start your query in the shadow DOM
// in order to find your root
shadowRoot.querySelector('#shadowReactRoot')
)
})
Then, sure enough:
I think you should use the Shadow DOM API. It is good practice for those cases when you just need to append your UI component to a webpage.
https://developers.google.com/web/fundamentals/getting-started/primers/shadowdom
As mentioned in this other SO post, <link> tag is also supported, so one can simply do as follows:
const injectedDiv = document.createElement('div');
const shadowRoot = injectedDiv.attachShadow({ mode: 'open' });
shadowRoot.innerHTML = `\
<link rel="stylesheet" type="text/css" href="${chrome.extension.getURL("bootstrap.min.css")}"></link>\
<link rel="stylesheet" type="text/css" href="${chrome.extension.getURL("whatever.css")}"></link>\
`;
document.body.appendChild(injectedDiv);
Notes:
Using chrome.extension.getURL is required for getting an extension's local resource url, see e.g. in this answer.
The linked .css resources must be declared under the web_accessible_resources property in your manifest.json (otherwise, you'll get this error)

Enyo error: "Uncaught referenceError: App is not defined"

I am getting the error: "Uncaught referenceError: App is not defined" in my JS console when loading this Enyo app on my localhost. I am brand new to Enyo so I am still trying to learn the concepts of kinds and components.
app.js (in source folder):
enyo.kind({
name: "App",
kind: "FittableRows",
classes: "enyo-fit enyo-unselectable",
components: [
{
kind: "onyx.Toolbar",
layoutKind:"FittableColumnsLayout",
components: [
{
kind:onyx.Button,
style:"width:80px;background:green;",
ontap:"handleBtnBack",
content:"Back"
},
{
content:"Header",
style:"text-align:center;",
fit:true
},
{
kind:onyx.Button,
style:"width:80px;background:red;",
ontap:"handleBtnNext",
content:"Next"
}
]
},
{
kind: "Scroller",
horizontal:"hidden",
touch:true,
fit:true,
thumb:true,
components:[
{
tag:"h1",
//This is how we insert css class.
classes:"padding15px",
content:"This is content area...Hello World!!!"
}
]
},
{
kind: "onyx.Toolbar",
// The footer
layoutKind:"FittableColumnsLayout",
components:[
{
kind:"onyx.Button",
content:"Go Next Page",
ontap:"handleBtnNextPage",
fit:true
}
]
}
],
create: function(){
this.inherited(arguments);
console.log("App is created in memory");
},
rendered : function(){
this.inherited(arguments);
console.log("App is created in rendered into DOM");
},
handleBtnNextPage : function(inSender,inEvent){
new Page2().renderInto(document.body);
},
handleBtnNext: function(inSender,inEvent){
new Page2().renderInto(document.body);
},
handleBtnBack: function(inSender,inEvent){
//For each enyo event handler comes with inSender, the control that sends the event and the inEvent the actual event itself.
alert("Back Button");
}
});
package.js (in source folder):
enyo.depends(
// Layout library
"$lib/layout",
// Onyx UI library
"$lib/onyx", // To theme Onyx using Theme.less, change this line to $lib/onyx/source,
//"Theme.less", // uncomment this line, and follow the steps described in Theme.less
// CSS/LESS style files
"../assets/css/app.css",
// Include our default entry point
"App.js",
"Page2.js"
);
index.html (in root folder):
<!--My Copy-->
<!DOCTYPE html>
<html>
<head>
<title>IsGoodStuff.com Tutorial #2</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<link rel="shortcut icon" href="assets/favicon.ico"/>
<script src="enyo/enyo.js" type="text/javascript"></script>
<!-- -->
<script src="package.js" type="text/javascript"> </script>
</head>
<body>
<script type="text/javascript">
new App().renderInto(document.body);
</script>
</body>
</html>
If your index.html is in your root folder, but the main package.js is in the source folder, it's probably your script tag that loads package.js. Try:
<script src="source/package.js" type="text/javascript"> </script>
You haven't supplied Page2 but it appears the code would work as-is.
Here's a fiddle showing the working page: http://jsfiddle.net/kgxvg7Lw/1/
Some thoughts:
1) Are you using a case-sensitive file system? You show app.js but your package.js has App.js (capitalized).
2) Are you certain there are no parse errors in the console?
Now, that said... You probably don't want to reload a new app for every 'page' switch. Usually, you would use something like Panels to allow the app to control the content that appears on the screen and just navigate among the panels as needed.

Resources