Loading local file inside an iframe in Electron - iframe

I've tried different approaches but all are problematic.
So first of all I was using webview, but as per electron documentation, this tag is undergoing major architectural changes and it's recommended to use iframe or other alternatives. Furthermore, the webview tag gives me a warning while used alongside VueJS that the component is not registered. I understand this component doesn't exist within HTML standards and is something specific to electron, so I am not sure how to tell Vue to ignore or recognize it in the use case of an electron app.
Coming to the iframe problem, approach one of loading the file directly via src, gives me the obvious error Not allowed to load local resource:. Turning off webSecurity though allows the file to load but I read it's not recommended to turn it off. I am not sure if there are specific use case where it's safe to turn it off or shouldn't be at all.
I decided to try via file protocol as I already have it in place. The protocol code:
protocol.registerFileProtocol('downloads', (request, callback) => {
const url = request.url.substring('downloads:///'.length)
const location = path.normalize(paths.downloads(url))
callback({ path: location })
})
Though when I load the file this way, the renderer process crash without errors. Is there something in addition to the above which would help loading local files via iframe?
Edit 1
My use case is the following: I have a typical entry point to an index.html which contains code for a VueJS app.
if (app.isPackaged) {
window.loadFile(join(__dirname, '../renderer/index.html'))
} else {
// 🚧 Use ['ENV_NAME'] avoid vite:define plugin
const url = `http://${process.env['VITE_DEV_SERVER_HOST']}:${process.env['VITE_DEV_SERVER_PORT']}`
window.loadURL(url)
window.webContents.openDevTools()
}
Inside that VueJS app, I require to list html files from a directory. I am able to achieve so via webview but I have tried to move away from it for the reason mentioned above. I tried using iframe but encountered issues as well. If there's a setting that doesn't turn off all security and allows me to load the file via iframe, that would be ideal.

This is kind of the reverse of this question where they're using an iframe, running into the "not allowed to load local resource" and being told to use a <webview> instead.
The <webview> docs list BrowserView as another alternative which is what I would recommend here. That should be much easier to work with than an iframe.
const { app, BrowserView, BrowserWindow } = require('electron')
app.whenReady().then(() => {
const win = new BrowserWindow()
const view = new BrowserView()
win.setBrowserView(view)
view.setBounds({ x: 0, y: 0, width: 300, height: 300 })
view.webContents.loadFile('<yourFile>')
})

Even though it is not recommended to use webview tag, I decided to go forward as it's the only thing that works for me. The only issue then was this error where Vue does not recognize the tag. To work around that error/warning, I had to update my vite.js config:
plugins: [
vue({
template: {
compilerOptions: {
isCustomElement: (tag) => tag === 'webview'
}
}
}),
// ...

Related

Next JS Version 12+: Static Site Generation

I'm using Next.js version 12.0.4 on a new project, having used Next.js version 10 on a prior one.
Has something changed with Static Site Rendering at build time? It's rendering all my output pages when I do an npm run build (which in turn executes "next build and next export") with html files that include a ton of .js files and no native text "content" which I'd expect.
That is, the output doesn't have any of the standard HTML <h1>, <h2> etc. in it, just a bunch of javascript for the client to hydrate.
Prior versions of Next.js (or perhaps it was my configuration?) seemed to render pure, finalized HTML just fine.
I'm trying to render a simple About page (no dynamic routes, no dynamic props for this route) and, while it properly renders a page in the "/about/index.html" output location, that page has a bunch of .js files and a JSON payload. That page does indeed display properly, but I'd really like the output in the "out" directory to be actual .html files with HTML pre-rendered, for SEO and other reasons.
In my next.config.js, I've specified:
module.exports = {
exportPathMap: function () {
return {
"/": { page: "/" },
"/about": { page: "/about" },
};
},
};
I've also specified getStaticProps on the about page conponent (about.tsx). (I'm using typescript if that matters.)
The rendered /about/index.html file has a ton of .js includes and no real HTML "content".
Have I missed a configuration setting? What can I do to make it render pure HTML where I'd like?
AHA! Ok, so this error was of course a coding error on my side.
In _app.tsx, I had a wrapper for Authentication that I had written. By (bad) design, it was deliberately NOT rendering children for it if the user wasn't authenticated. Therefore, the pre-renderer wouldn't render the "regular" html elements, because the pre-renderer of course does not sign in.
If this same problem happens to you, make sure you're not wrapping all views up in some provider element which conditionally renders children.

How to remove __NEXT_DATA__ from dom in NextJs?

Because of NEXT_DATA element dom size is getting very high and it is affecting to the performance. Can anyone plz help me to remove NEXT_DATA from dom?
I am using full server-side rendering with dynamic routes in next Js.
TLDR: If you would(/could) remove the __NEXT_DATA__ script tag, React wouldn't be able to hydrate. You either hardcode the data in the page or try to reduce your pageProps payload, returned from getServerSideProps.
I came upon this issue also recently, where I asked myself, why would there be a need for the content to be included in the HTML 2 times.
As the content itself - when your NextJS renders the appropriate HTML and sends it to the client
As JSON in <script> tag - This is because of the need for rehydration on the client side.
"Solutions"
Returning only necessary data from data-fetching method - I can recommend reading up on this article Reducing HTML payload with NextJS, in which they talk about formatting / aggravating the necessary data and returning only the needed fields.
Not using the data-fetching method and hardcoding static content - The idea behind using static data fetching, if not using revalidate option, is that the content shouldn't be changing (maybe ever). So in that case, why couldn't we hardcode the data in the page itself. Althought downside of this of course is, having to write it all out manually / download the required content to some JSON / object and then use it in the page like so.
Reading
Here's a github link with related discussion in next in which you might be interested.
Blog post about reducing the size of __NEXT_DATA__ - by Liran Cohen.
To remove the rehydration data regex: <script id="__NEXT_DATA__((.|n)*)script> from all pages of the static website run the following command after the build has finished:
find out -name '*.html' | xargs perl -0777 -pi -e 's/<script id="__NEXT_DATA__.*?script>//sg;'
If you come across this issue, make sure you don't have any conditional rendering. This is how I solved this issue myself !
You can do this to not show __NEXT_DATA__:
export const config = {
unstable_runtimeJS: false,
};
But all JavaScript functionality will not work in frontend.
Sometimes you might not require some of the __NEXT_DATA__ props during client side rendering.
To drop those props, you can mutate the NextScript.getInlineScriptSource function in the _document.tsx file. Here is an example:
// _document.tsx
const nextInlineScriptSource = NextScript.getInlineScriptSource;
NextScript.getInlineScriptSource = (props) => {
if (props?.__NEXT_DATA__?.foo) {
props.__NEXT_DATA__.foo = 'bar';
}
return nextInlineScriptSource(props);
};

Gatsby wrapRootElement/wrapPageElement works on localhost, but not once deployed to shared hosting

I'm using Gatsby for the first time on a simple website project. I'm accustomed with traditional React apps where there is a root file component, typically "App.js" that one attaches Providers and other global level functionality.
Gatsby doesn't offer a root App.js, but it does offer wrapRootElement and wrapPageElement, which, after a bit of wrangling, worked just fine on my localhost.
export const wrapRootElement = ({ element }) => {
return (
<ThemeProvider theme={theme}>
{element}
</ThemeProvider>
)
}
and
export const wrapPageElement = ({ element, props }) => {
return <Layout {...props}>{element}</Layout>
}
inside of gatsby-browser.js (and with appropriate local imports and such)
(using Root for my Theme Provider and Page for my Layout wrapper, which includes header and footer elements)
I used 'gatsby clean' then 'gatsby build' to generate the deployable public folder, but upon upload to my shared host, only the inner portion showed up, not the header or footer, nor did my theme colors show up.
On a whim, I downloaded Gatsby and pulled out their "using-redux" example, built, and deployed it to the same shared host with similar results — that is, it doesn't behave as expected.
What am I missing? Since it fails on the Gatsby example, I'm presuming it as something to do with my server side setup (recall, it works fine on localhost). I have Node installed, but I'm not using it as part of this app; it's intended to be completely static and I'm just trying to use the wrappers to clean up my code.
After toying around with it some more, I replicated the code in gatsby-browser.js into gatsby-ssr.js. Voila, it worked.
This article is what inspired me, sort of: https://www.gatsbyjs.org/docs/api-files-gatsby-browser/. It states:
If you use one of them, consider if you should implement it in both
gatsby-ssr.js and gatsby-browser.js.
I had read the article earlier, but didn't take the gatsby-ssr.js file as being a requirement. Apparently, I should have interpreted the word "should" a bit more forcefully.

Phonegap: InAppBrowser insertCSS file

I'm trying to create an app that loads a website and then adds some custom CSS to adjust it to a mobile device.
I'm using window.open to load the page successfully, and I have a callback on loadstop where I'm calling browser.insertCSS, this is where the problem is.
If I do something like this:
browser.insertCSS({code:"body{background-color:red;}");
The style is applied correctly. However if I do this:
browser.insertCSS({file:"mobile-style.css");
And add the same CSS to the file, it doesn't get loaded
I have tried different paths (putting the file in the www folder, in the css folder, in the same folder as the JS file, and referencing it with "./mobile-style.css", "mobile-style.css", "/www/mobile-style.css", "/mobile-style.css" but none of them seem to load the file correctly.
I saw another post What should file paths fed to insertCSS() be relative to? where this same question was asked, but there is no accepted answer (I have tried the suggestion there and it doesn't work).
Any help would be greatly appreciated.
Thanks
Will
you have to wait until your inAppBrowser page loading finishes.
You must add an event listener:
var inApp = window.open('mypage.html', '_blank', 'location=no');
inApp.addEventListener('loadstop', function(){
inApp.insertCSS({
file: 'inAppStyle.css'
},onSuccess);
});
EDITED
Use this path for your android projects file:///android_asset/{your folder}
INFO: https://github.com/apache/cordova-plugin-file/blob/master/doc/index.md#android-file-system-layout
I couldn't find the right local path. Instead, I just uploaded the css file to the web and provided a regular URL
file: 'http://mywebsite.com/path-if-needed/my.css'
Not ideal to have an external dependency, but not a big deal since InAppBrowser itself requires internet access.
I probably know why it won't work, it is because your path isn't right, this css file should not put in www folder, neither the cordova project folder, u should put it into the server, for example, if ur browser is to visit http://192.168.1.1/admin, then the cordova only fetch this file when the browser is under the 192.168.1.1/admin, it fetch the file under the server directory.I don't know if u use any debug tool , if u use one, it's easy to find out what went wrong, ur console will log the error which path it fetch the css file and didn't get it.
If you want to add an external CSS file stored locally in the APP's sandbox and not around in the Internet, this is the only way, that is, you get the external file, you store it into a string variable, and then you insert such code into the Browser.
var inAppBrowserRef = cordova.InAppBrowser.open(url, "_blank", "location=no");
//when load stops call loadedCallbackFunction
inAppBrowserRef.addEventListener('loadstop', loadedCallbackFunction);
function loadedCallbackFunction() {
console.log("InAppBrowser Window loaded");
$.ajax({
type: "GET",
url: cordova.file.applicationDirectory + "www/css/myExternalCSS.css",
dataType: "text",
success: function (CSScode) {
inAppBrowserRef.insertCSS(
{ code: JScode},
function(){
console.log("CSS code Inserted Succesfully into inApp Browser Window");
});
},
error: function () {
console.error("Ajax Error");
}
});
}
You need the cordova-plugin-inappbrowser

How can I apply GA download tracking with Sitecore?

I'm posting this question to Stackflow b/c after doing much research into an answer to this very question online, I did not come across a straight forward answer and had to do my own sleuthwork to resolve this.
Basically, Sitecore uses a handler file .ASHX for all files uploaded to the Media Library. Since the 3rd party GA tracking tool I was using (entourage.js or gatags.js) does not recognize .ashx as a whitelisted download file, it was not adding the appropriate GA tracking syntax to the GA pixel tracker (__utm.gif).
So the solution turns out to be simple but sadly, not retroactive, meaning all files previously uploaded to the Media Library in the Sitecore content tree will continue to use the ashx extension unless you reupload the image. In your web.config file, search for the "Media.RequestExtension" setting. If you change the value associated with this setting from "ashx" to a blank string, this will force Sitecore to use the originalextension of the file and image in the Sitecore Media Library.
Aside from interfering with GA analytics, this method of turning every downloadable file extension into an ashx file is poor SEO practice. AND, Sitecore will not point you in the right direction of getting around this other than a round-about way (google Sitecore dynamic linking and configuration) because they want you to use their Sitecore OMS download tracking capability. And that's it! Two days of research led me to this conclusion.
So the solution turns out to be simple but sadly, not retroactive,
meaning all files previously uploaded to the Media Library in the
Sitecore content tree will continue to use the ashx extension unless
you reupload the image.
Not sure where you got this information, but it's incorrect. You can blank out the Media.RequestExtension setting and all existing files will use their original extension. In IIS7 Integrated Mode, you should be able to make this change without having to make other server configuration changes.
Edit: More Info
If you analyze Sitecore.Configuration.Settings.Media.RequestExtension (the API equivalent to this settings) in a decompiler, you can see that it's only used by the MediaProvider when constructing the Media URL. Sitecore should remember the original extension of the media and can serve it with its original URL, regardless of what this setting was when it was uploaded. That's my experience, anyway, and it seems to be validated by looking into Sitecore.Kernel.
You could use this script to track download events via Google Analytics.
if (typeof jQuery != 'undefined') {
jQuery(document).ready(function($) {
var filetypes = /\.(zip|pdf|doc*|xls*|ppt*|jpg|ashx)$/i;
var baseHref = '';
if (jQuery('base').attr('href') != undefined) baseHref = jQuery('base').attr('href');
jQuery('a').each(function() {
var href = jQuery(this).attr('href');
if (href) {
if (href.indexOf('?') != '-1') {
href = href.substring(0, href.indexOf('?'));
}
if (href.match(filetypes)) {
jQuery(this).click(function() {
var extension = String((/[.]/.exec(href)) ? /[^.]+$/.exec(href) : undefined);
var filePath = String(href);
_gaq.push(['_trackEvent', 'Download', extension, filePath]);
if (jQuery(this).attr('target') != undefined && jQuery(this).attr('target').toLowerCase() != '_blank') {
setTimeout(function() {
location.href = baseHref + href;
}, 200);
return false;
}
});
}
}
});
});
}
Just add in the required file types here at this line -
var filetypes = /.(zip|pdf|doc*|xls*|ppt*|jpg|ashx)$/i;
Having done a quick google for gatags.js, I can see that you can add an extension to the whitelist on line 24:
var isDoc = path.match(/\.(?:doc|eps|jpg|png|svg|xls|ppt|pdf|xls|zip|txt|vsd|vxd|js|css|rar|exe|wma|mov|avi|wmv|mp3)($|\&|\?)/);
Change it to:
var isDoc = path.match(/\.(?:ashx|doc|eps|jpg|png|svg|xls|ppt|pdf|xls|zip|txt|vsd|vxd|js|css|rar|exe|wma|mov|avi|wmv|mp3)($|\&|\?)/);
Alternatively, you could attach the Google Analytics _trackEvent yourself with a dom selector and a click event.
Either way, I think OMS can track media library files regardless of extension - removing the default ashx extension doesn't stop the file being handled by Sitecore.

Resources