Multiple importmap.json for different environments in single-spa - reactjs

In am converting the existing project into a single-spa. This application support different environments- dev,qa,prod. My requirement is to use the different import maps json based on the environment.
<% if (isLocal) { %>
<script type="systemjs-importmap">
{
"imports": {
"react": "https://cdn.jsdelivr.net/npm/react#16.13.1/umd/react.production.min.js",
"react-dom": "https://cdn.jsdelivr.net/npm/react-dom#16.13.1/umd/react-dom.production.min.js",
"#ppm-canvas/root-config": "//localhost:9000/ppm-canvas-root-config.js",
"#ppm-canvas/match-upload": "//localhost:8081/ppm-canvas-match-upload.js"
}
}
</script>
<% } else { %>
<script type="systemjs-importmap" src="https://cdn.cloudfront.net/import-map.json"></script>
<% } %>
Here, I want to use something like multiple else if condition to be able to load different import-map.json from remote cdn.
Can someone pls help me in achieving this.

You can achieve this in your root-config since it is simply an ejs template, which is processed by Webpack. If you peek at your root-config's webpack.config.js you'll find isLocal derived there. You can add your own templateParameters there. Lastly, import-map-deployer is a useful tool for managing multiple import maps, which can be good for multiple deployment environments.

Related

how to resolve Javascript issues when using 2sxc IRenderService to embed an App in a DNN Theme Layout

Im trying to embed my 2sxc App into a Theme layout page.
The App view html does render
<%-- This namespace provides this.GetScopedService<T>() --%>
<%# Import Namespace="ToSic.Sxc.Dnn" %>
<%-- This namespace provides all the common 2sxc services --%>
<%# Import Namespace="ToSic.Sxc.Services" %>
<%= this.GetScopedService<IRenderService>().Module(1041,3421) %>
, but its Javascript crashes.
The App uses its own API for searching.
1. // get the sxc-controller for this module
2. var sxc = $2sxc(3421);
3. // now get the data in the promise
4. sxc.webApi.get('app/auto/api/Forms/SearchForm')
5. .then(data => {
6. console.log(data)
7. });
originally line 2 crashed saying $2sxc is not recognised.
we resolved that by adding this script reference to our layout page
<script src="/desktopmodules/tosic_sexycontent/js/2sxc.api.min.js" type="text/javascript"></script>
And now it crashes on line 4 when trying to use sxc.webApi.get
Uncaught Can't find page - something went wrong, pls contact 2sxc.org
It seems I need to include another JS script.
I tried to also include
<script src="/desktopmodules/tosic_sexycontent/dist/inpage/inpage.min.js" type="text/javascript"></script>
but that made it worse
I resolved this by adding this
var page = GetService<ToSic.Sxc.Services.IPageService>();
page.Activate("2sxc.JsCore");
Update: to use the JS better in the theme, I've just pushed an update to 14.07.04.
Basically you can force a different context than the automatic one, using
var sxc = $2sxc({ pageId: 27, moduleId: 42, zoneId: 3, appId: 8});
sxc.webApi.fetchJson(...).then(...);
this uses the context identifier https://docs.2sxc.org/api/js/ContextIdentifier.html#Api_Js_SxcJs_ContextIdentifier which has existed for a few versions now, but there was a bug that was fixed in 14.07.04
See also https://docs.2sxc.org/api/js/SxcGlobal.html#Api_Js_SxcJs_SxcGlobal_get_3

Quasar assets vs statics directories

I am trying to understand the difference between assets and statics directories and when I should be using one or the other, especially in handling images.From the directory structure docs they seem to describe as
assets/ # dynamic assets (processed by webpack)
statics/ # pure static assets (directly copied)
Would really appreciate a simpler detailed explanation.
The docs explaining the difference for asset handling pretty straightforward:
Please note that whenever you bind “src” to a variable in your Vue scope, it must be one from the statics folder. The reason is simple: the URL is dynamic, so Webpack (which packs up assets at compile time) doesn’t know which file you’ll be referencing at runtime, so it won’t process the URL.
<template>
<div>
<q-img :src="thisImgDoesntWork" />
<q-img :src="thisImgWorks" />
<span class="thisCssImgFromAssetsWorks"></span>
</div>
</template>
<script>
export default {
data() {
return {
thisImgDoesntWork: '~assets/dummy.png',
thisImgWorks: '/statics/dummy.png'
}
}
}
</script>
<style lang="scss" scoped>
.thisCssImgFromAssetsWorks {
// ... because the URL can't change after compile time
background: url('~assets/dummy.png');
}
</style>

Backbone router working differently with utf-8 characters on Safari and Chrome

I have this example, using a route with an utf-8 non-ascii character:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Backbone Test</title>
</head>
<body>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script src="http://ajax.cdnjs.com/ajax/libs/underscore.js/1.3.1/underscore-min.js"></script>
<script src="http://ajax.cdnjs.com/ajax/libs/backbone.js/0.9.2/backbone-min.js"></script>
<script>
(function(){
window.App = {
Models: {},
Collections: {},
Views: {},
Router: {}
};
})();
App.Router = Backbone.Router.extend({
routes: {
'charñ': 'charChrome',
'char%C3%B1': 'charSafari'
},
charChrome: function(){
$(document.body).append("Chrome-compatible route triggered.<br/>");
},
charSafari: function(){
$(document.body).append("Safari-compatible route triggered.<br/>");
},
});
new App.Router;
Backbone.history.start();
</script>
<h1>HELLO THERE</h1>
</body>
</html>
When the page got called with something like:
file://localhost/whatever.html#charñ
...it trigger a different function on Safari and Chrome.
It's REALLY not easy for me to change backbone version.
Is there a way to avoid that difference?
Note: interesting enough, removing the meta tag breaks Chrome routing.
This shouldn't be seen as an answer to that makes every browsers works the same but prevent this from happening. As far as I know, there is no much control on what backone will trigger. It's not like you can really filter the url before it gets handled by the Router.
That said, you can create routes for both style. To make this easier, you can create a special object that will get a utf8 string and create a urlencoded version of the route. Both routes will have the same callback.
On other possibility is to avoid utf-8 symbols in the url and report a bug to backbonejs. Having both routes created with urlencoded/urldecoded will make the site work for possibly every browsers supporting javascript. The downside is that you'll have to create n*2 routes.
Have you tried decoding the URL when it's passed to your function? It may be that Chrome decodes the URL for you while Safari does not. 'char%C3%B1' will decode to 'charñ' just fine when using a URI decoder, and it should have no effect on already-decoded strings (assuming the encoding used was the correct one, of course).
decodeURIComponent('char%C3%B1')
/*
charñ
*/
decodeURIComponent('charñ')
/*
charñ
*/
Going by http://backbonejs.org/docs/backbone.html#section-156, you may be able to substitute _extractParameters with a version that calls decodeURI or decodeURIComponent on fragment before executing the regular expression.
Another possibility to try, as I just noticed that routes can be regular expressions (see http://backbonejs.org/docs/backbone.html#section-152): if you don't have many of them, you could use something like /char(ñ|%C3%B1)/g, or write a function to produce such a regular expression for the unencoded value, such that makeRegex('charñ') would produce /char(ñ|%C3%B1)/g, or whatever the regular expression would be.
I solved it by adding an additional line in the while loop, inside _bindRoutes, to bind the encoded routes as well:
_bindRoutes: function() {
if (!this.routes) return;
this.routes = _.result(this, 'routes');
var route, routes = _.keys(this.routes);
while ((route = routes.pop()) != null) {
this.route(route, this.routes[route]);
//add this line:
this.route(encodeURIComponent(route).replace(/%2F/g,'/').replace(/%3A/g,':'), this.routes[route]);
}
}

How to detect if browser supports file uploading? (Mobile + Desktop)

I'm developing an application for both mobile and desktop browsers. I'm wondering if there is anyway to detect if a browser supports file uploading. I'm looking specifically for feature detection and not browser detection. Is there any way to find out?
Server-side or client side is fine.
Thanks
client side javascript:
<input type="file" name="file" value="" id="fileUploadField1">
<script type="text/javascript" charset="utf-8">
if (document.getElementById('fileUploadField1').disabled)
{ document.write('your device does not allow uploads'); }
else
{ document.write('your device does allow uploads'); }
</script>
You might be interested to read this article about current input type=file support on mobile and how to detect it: http://viljamis.com/blog/2012/file-upload-support-on-mobile/ (the detection is currently tested to be working on ~120 different mobile browser/mobile OS combinations).
Basically, we are just using similar detection as Modernizr does, but use UA detection as a backup to filter out those mobile browsers that falsely report support (there really doesn’t seem to be any other way to detect it reliably than using these both, feature detection and browser detection).
You can use Modernizr framework with forms-fileinput extension. Give it a try.
if Modernizr.fileinput
// you can use file inputs
Visit the Modernizr download page and check the forms-fileinput extension (expand the "Non-core detects" section).
Modernizr now supports a check for whether or not file uploads are supported.
From: What is the best way to check if user can upload files?
if(Modernizr.fileinput) {
//file input available!
} else {
//No file input :(
}
If you're worried about the size of this library, you can always get one component at a time - http://modernizr.com/download/ ... or you can just copy the code they use: https://github.com/Modernizr/Modernizr/blob/master/feature-detects/forms/fileinput.js
if(navigator.userAgent.match(/(Android (1.0|1.1|1.5|1.6|2.0|2.1))|(Windows Phone (OS 7|8.0))|(XBLWP)|(ZuneWP)|(w(eb)?OSBrowser)|(webOS)|(Kindle\/(1.0|2.0|2.5|3.0))/)) {
return false;
}
var elem = createElement('input');
elem.type = 'file';
return !elem.disabled;

Local datastore not persisted between application restarts

I am running the GuestBook example from Google Developer CodeLab.
When adding an entry, it shows up in the list of greetings and in the local datastore
So far so good...
When I restart the application, however, only some of the entries still exist, while some disappear entirely, both from the list maintained by my app, and from the local datastore, as seen in above link.
I am using the google plugin for Eclipse to develop and test my application.
Can anyone point me in the right direction?
It's likely you're passing the --clear-datastore argument, either directly or through the launcher, to the dev_appserver. Another possibility is that something is erasing your temporary directory (such as on reboot), which is the default location for the dev_appserver's local datastore.
I don't know what would cause only some entities to disappear, and it's impossible to say without seeing your code. I also don't know what you mean by "the list maintained by [your] app".
Thank you for your answer.
I would think that a --clear-datastore argument, would erase ALL values, not just some.
The local datastore files, in the appengine-generated folder, are still there when I restart, and again, I would think that all values would disappear, if these files were erased.
The code is unmodified from the google codelab example (link provided in question).
The list maintained by my app, is just the list returned by the query and printed out:
<%
PersistenceManager pm = PMF.get().getPersistenceManager();
String query = "select from " + Greeting.class.getName();
List<Greeting> greetings = (List<Greeting>) pm.newQuery(query).execute();
if (greetings.isEmpty()) {
%>
<p>The guestbook has no messages.</p>
<%
} else {
for (Greetingg : greetings) {
if (g.getAuthor() == null) {
%>
<p>An anonymous person wrote:</p>
<%
} else {
%>
<p><b><%= g.getAuthor().getNickname() %></b> wrote:</p>
<%
}
%>
<blockquote><%= g.getContent() %></blockquote>
<%
}
}
pm.close();
%>

Resources