Meteor "--mobile-settings" being overriden by server values? - javascript

I'm trying to provide some per-build configuration for a Meteor mobile app. The --mobile-settings option looked to be ideal for this task - it allows you to pass configuration (JSON) to mobile clients at build time - in the same way that the --settings option does for the server.
However, I'm seeing some unexpected behaviour... anything passed to the mobile clients via --mobile-settings looks to be being overridden when the client refreshes from the server.
Here's what I did....
Wrote a very simple app which reads a settings value from Meteor.settings.public.blah and displays it on-screen.
Deployed this app to the meteor servers (without any mobile-settings file).
Built the same app for android, pointing to the server above and with the --mobile-settings option set - pointing to a settings file which declared the 'blah' property. Installed it on a device.
When I ran the app on the device, the app started and the screen correctly displayed the blah setting.
However, after a couple of seconds the app refreshed and the setting disappeared.
On refresh, why would a mobile-specific, build-time value be overridden from the server? Does the mobile-settings file need to exist on the server too?
Thanks in advance.
Update
Ok, going by a discussion below, I think I need to clarify my question a little...
What I've described above is the behaviour I'm seeing. However, I find this behaviour confusing and I'm struggling to find any documentation on this feature to detail what the expected behaviour is.
The best I could find was a thread where one of the original devs commented (https://groups.google.com/forum/#!msg/meteor-talk/Jbfnk5kCvW4/6qvccun2dQ0J). He said...
You just build your mobile apps twice with different json passed to --mobile-settings.
This does not seem to support the behaviour I'm seeing - where the json passed to --mobile-settings would be overwritten by whatever was deployed to the server. Hence my confusion.
I would appreciate it if anyone could point me to any documentation or confirm this behaviour either way.

In short
Let's look at
meteor build --help
It reads:
--mobile-settings Set optional data for the initial value of Meteor.settings
in your mobile application. A new value for
Meteor.settings can be set later by the server as part of
hot code push.
So it looks like the settings you provide for the server with the METEOR_SETTINGS environment variable always takes precedence. The "mobile settings" are only there as a fallback/defaults values if there are no server setting yet.
Let's look at Meteor source code :)
Still, it may not be clear what's the purpose of having another settings object for a mobile device. I am not an expert on Cordova, but I guess the problem here is how the application gets bootstrapped.
Normally, when you request the initial page from meteor server the Meteor.settings object is - of course - up-to-date with your server config. This is taken care of by the webapp package here:
https://github.com/meteor/meteor/blob/devel/packages/webapp/webapp_server.js#L352
Note that it becomes a bit more complicated when you install the application on your mobile device. Of course the installation process has nothing to do with your server current state, hence there's no way to get the initial values for settings unless they're know in advance during the mobile build process. That's the only reason you need that --mobile-settings option. They're not there to alter your settings for a mobile device but to provide initial values before the up-to-date settings object can be loaded from your server during the hot-code-push.
And it will always happen if the two settings objects are different, because as you can see in the code here the PUBLIC_SETTINGS value is taken into account while computing the hash which is used to tell if the the client code is up-to-date.
Conclusion
So the conclusion is: your "mobile settings" - or at least the public part of it - should reflect the current server configuration as close as possible. Every time you change your public settings you should also rebuild your mobile application and publish the update to make sure your new customers have the up-to-date version of settings out-of-the-box.
Ideally, the client application should not depend on Meteor.settings to startup properly. Even if the object is empty there should be some default behavior that does not break the user experience.

Related

Routes being cached by service worker in react

We are in the process of building a new website for the company I work for which is written in React using CRA. Browser push notifications and a PWA are both required so a service worker is essential, however I beleive the service worker is responsible for some fairly major caching issues.
The website is not yet in production however I added a new page yesterday (and this has happened a few times before) and once deployed to our dev environment nobody in the office was able to access it - they were simply redirected to the homepage (as if the route didn't exist) until they cleared their cache then the route loaded with no issues.
I've read a little bit on semantic versioning however the articles all seem to use NPM rather than yarn and are versioned locally (which isn't great with a team of 8 working on this project) using npm version patch etc.
We are using MS Azure as the build and release pipeline which I assume would be the best place to set versions if this is required.
My question is what are the steps to aviod this problem and am I on the correct lines thinking versioning will mitigate?
Semantic versioning in this context doesn't make any sense, you've been reading most likely about packages (libraries, frameworks) that are published into NPM for the world to use. In CRA projects, and most other web projects too, versioning of your app happens by the build tools as they name the files based on their contents. The filenames include the hash of the contents and are versioned automatically when contents change, eg. app.iue9234980s.js becomes app.92384oujiuoisdf.js etc.
--
If you're using the default Service Worker setup provided by CRA, then you should look at src/serviceWorker.js. In the comments of that file it says
// This lets the app load faster on subsequent visits in production, and gives
// it offline capabilities. However, it also means that developers (and users)
// will only see deployed updates on subsequent visits to a page, after all the
// existing tabs open on the page have been closed, since previously cached
// resources are updated in the background.
What happens here is that the SW and the build process use Workbox SW library that is configured to use precache policy. In this policy, users get the last version that was previously cached from the browser's cache even if there's a new version available, then in the background SW updates the caches, and on another visit users get the newer version. This of course means that users might always be one version "late".
If this behaviour is not what you want, then you need to change src/serviceWorker.js and probably some configuration somewhere in CRA files. You should google something like "custom service workers with cra" for examples.
To better grasp what is happening – and especially what is correct and intended behaviour in differently configured cases – I really recommend (everyone) to read Google's primer on SWs themselves, here: https://developers.google.com/web/fundamentals/primers/service-workers
With understanding of the SWs basic principles, it is then probably useful to checkout the Workbox library https://developers.google.com/web/tools/workbox to see what it can offer for your app.
Reading and understanding the different aspects of SW is key here – it is excruciatinly easy to shoot yourself in the foot with SWs :)

Forcing refresh on client side browser whenever java script is out dated

When we deploy new versions of our application, there is a chance that our users might still be using old front end java script code that may cause errors.
Our app is a single page app, so people do not refresh it a lot, and users sometimes leave it up for a while. So this problem is really prone to happening whenever we push new code.
We were thinking maybe putting up a popup with a refresh button that will force them reload the front end cached code.
How do you trigger that normally? There are lots of ways I can think to do it, but maybe there is a standard way of doing it?
You effectively have two independent problems.
API version mismatch between client and server
Accelerating the release of new versions of the code.
API version mismatch
Typically, you'll want to use a versioned API. Each API request should somehow indicate which version the request corresponds to. This is often done in the path of the request, which makes routing to different API servers very easy to do. For example:
http://api.example.com/1.0/foo/bar
Your web server can match on /1.0/ and route to the appropriate application server for your API.
This gives you some flexibility, allowing a rolling release process and not forcing clients to reload every single time you do a release. (You may some day want to release 50 times a day, and your clients won't be too happy about that. No need to force a reload unless you have a specific reason to.)
The easiest way to do this is make new versions of your API backwards compatible as much as possible. But, breaking changes do occur. When this happens, run two instances of your API server simultaneously. If you have a major underlying data structure change, or some other huge change that prevents this, you will need to stop the old versions at the same time as starting the new, and force a reload.
New client code releases
You'll have to decide based on your app and business conditions whether or not it's a requirement to reload each time you have a release. Again, you might some day want 50 releases in a day, most of those for minor issues that most of your customers will never see. It's common to let the user know that a new version is available and let them reload when they feel like it. You can always force a reload if you absolutely have to (due to critical security issue, or major breaking changes).
Implementation
The specifics of how you do this are up to you, but one simple way is to have a basic JSON file available, indicating the latest versions:
{
"apiVersion": "1.0.5"
"appVersion": "1.1.352"
}
More creatively, you could have this file indicate whether or not specific versions need to be killed, and thus a reload forced.
I would add ?<version> to the script's src.
<script src="myFile.js?1"></script>
You can change this version with a code push for instance, so the client's forced to take a new version, because of the querystring.
You could use a Web Worker to periodically ping a server for a new code change or version number (say from a database) and force a refresh if there's something new. That will give you more on-demand possibilities than if you are just using say, a setTimeout.
This is a case where semver really comes in handy. You want to have an automated process that updates the client code. To make sure the update is compatible, you should ensure that there is a way to compare the version strings of the new and old code and determine if it's a "major" update or not. For "minor" or "patch" updates, you can probably update on-the-fly. But for major updates, it would be smart to force a full reload, after helping the user save their work.
In terms of a process for on-the-fly updates, you could use something like AMD modules for this. You would expire the module cache, download the new code, and reinitialize relevant parts of the system (carried out by the new code).
There is also the matter of knowing when updates are available. I would recommend looking at Server Sent Events for this. But if you need Internet Explorer support, you may have to resort to a setTimeout-based polling mechanism, or similar.

Sending data SAP Fiori launchpad webapp/SAPUI5 webapp from client side javascript

This is a general question I have as I am exploring the world of automating some tasks in my workplace.
We have a portal/launchpad environment on our businesses website which has apps shown as tiles.
One of these apps when opened has a homepage that has a bunch of search fields and selectors to interface with (I assume) SAP data.
Ultimately my goal is to be able to send a number to a specific search field on a client-side local webapp (just plain old HTML/jquery stuff) and execute a search for that number in the sapui webapp.
I am getting to an competent level with javascript/HTML/CSS but am completely lost as to where to start with this type of issue as the MVC stuff is completely alien to me.
All my experience has been in creating completely client-side web apps with mostly interface with a local MS Access database.
Is what I am suggesting even possible?
So far I can open the homepage by executing the following code that someone else in the organization used:
window.open('https://fiori.mycompany.com/sap/bc/ui5_ui5/sap/z_cs_ch/index.html
Is it possible to add some form of string after a ?.... at the end of the url?
Again I am completely new to this and looking at the development guides in sapui website isn't shedding any light on it either. Possibly because I don't really know exactly what I am looking for!
Any help /guidance is greatly appreciated.
EDIT:
After comments below I can see the request sent to server is in the following format:
Request GET /sap/opu/odata/sap/someotherlocation/SearchTerm('<variable to search for>')?$format=json HTTP/1.1
Am I right in thinking I could potentially send an ajax request to do something similar? If so, how do I go about it?
Thanks again
There are possibilties to achieve that but i think it's not a real good solution, to fill fields in another web application and to trigger the search.
It would be better if you know the backend service which is used by this Fiori App, and to integrate directly the service. If it's an Fiori App i might be an OData /REST Service. Odata/REST Service also can be called by HTML/jquery JavaScript stuff too.
In order to determine the Service URL and the payload which is used by the web app with the search field, just use Chrome Debugger Tools (or other Browser Debug Tools) and check under Network which server address and which payload parameters are sent to the server, when you trigger the search manually. Hope that helps you little bit.
In the whole Fiori concept, it is definitely possible to have applications to call other applications and to get them to open up exactly at the point the user expects it. E.g. from a order click on a product to be brought to the material master, and have the material master app exactly show the product the user clicked on.
As you mentioned, this would indeed require the target application (that is navigated to) to support some parameters. You mentioned in your question already that you wondered if it would be possible to add a "?...." section to the URL. Fiori apps definitely support this concept, but how it is implemented depends very much on the app itself. In my previous example it could be as easy as e.g. adding ?product_id=abcde though.
Fiori also has very nice extensibility concepts built-in. So if your target app doesn't exactly support the parameters you intend to pass, you could easily extend the app to support it, without having to rewrite of copy the entire app (which would be a disaster when you receive updated from the original developer).
To navigate from one Fiori app to the other, it is advised to use the toExternal method of the CrossApplicationNavigation service, which comes with the Fiori launchpad. This service allows you to specify parameters such as the app you'd like to navigate to, the intent (display, create etc), parameters (such as product ID) and a app specific route (e.g. /supplierdetails to see the supplier details of a product).
The CrossApplicationNavigation service is officially documented in the SAPUI5 SDK, but I'm afraid that the SDK doesn't contain a very elaborate description. However, if you Google for it, you'll find extensive information and examples on SCN and Stackoverflow on this topic as well.
As promised here is what I got to work - actually got the overall method from an answer on here somewhere else.
This will send back enough detail that I can at least show the user some updates however after searching around I believe what I really need to be able to do is batch requests... I'm looking into Apache Olingo to see if that's possible.
function orderSmmary(SO) {
var uri = "https://fiori.<company>.com/sap/opu/odata/sap/<environment>/Details('"+ SO + "')?$format=json";
var http_request = new XMLHttpRequest();
http_request.onreadystatechange = function() {
if (http_request.readyState == 4 ) {
var data = JSON.parse(http_request.responseText);
// Do lots of awesome stuff with response
}
}
http_request.open('GET',uri, true);
http_request.setRequestHeader("Authorization", "Negotiate");
http_request.send();
}
Again this is an entirely clientside solution from completely outside any flori environment so I am hoping to stay completely javascript based.

How can I debug javascript between client and server seamlessly

Question regarding javascript debugging:
We have a mobile app, made with JavaScript and HTML. This app is running on the mobile platform (BlackBerry 10, Android, iOS) inside a web container.
There is another part of this application running on the remote server. This part is implemented also with JavaScript running on Node.js.
Assume there is some communication established between the client (JS on mobile) and the server (JS on Node.js) sides using e.g. REST.
The question I would like to know is if it is possible to seamlessly debug both sides at the same time.
E.g. if I have a breakpoint on the mobile app client side, how would I be able to debug all the way to JS on the server side, if it’s possible at all.
Any suggestions would help.
You can use node-inspector on the server, then you'll have TWO instances, but the same debugger toolset.
If you're stepping through code client, and want to debug "into" the server, you must place a breakpoint in the server debugger before making the GET/POST from the client.
TIP: Get a three (at least two) monitor setup.
Using the node inspector is a good strategy for doing debugging, but it would also be good to supplement the debugger with logging.
Debugging will let you step through an event chain and examine values of variables and output of functions in that chain, but in production it won't give you insight into the steps or production conditions that lead to errors users are experiencing (i.e. Why do I have a null variable? Why is my response message wrong?) If you use debugging without logging you'll be trying to replicate the conditions in production that are causing an error, which is an inefficient (and usually futile) way of doing things.
I'd say the best way to implement what you want to do (solve issues taking into account client & server events that happen concurrently) is to implement an open source logging library like Log4j on both your server and your client and configure an appender to send the logs to a log aggregator like Loggly which gives you tools to analyze both client & server logs in the same place (rather than extracting log files from both devices manually).
Once you've done this, you'll be able to distribute your application out to testers and you'll be able to see what actions, application logs, and hardware/network conditions surround certain issues. With this data in hand you'll know a lot better what leads to certain bugs and can use that information to much more effectively use node-inspector to debug them.

what are the major steps required to create multiple instances of a meteor.js application running on a single server?

I have designed a meteor.js application and it works great on localhost and even when deployed to the internet. Now I want create a sign-up site that will spin up new instances of the application for each client who signs up on the back-end. Assuming a meteor.js application and python or javascript for the sign-up site, what high level steps need to be taken to implement this?
I am looking for a more correct and complete answer that takes the form of my poorly imagined version of this:
Use something like node or python to call a shell script that may or may not run as sudo
That script might create a new folder to hold instance specific stuff (like client files, config, and or that instances database).
The script or python code would deploy an instance of the application to that folder and on a specific port
Python might add configuration information to a tool like Pound to forward a subdomain to a port
Other things....!?
I don't really understand the high level steps that need to be taken here so if someone could provide those steps and maybe even some useful tools or tutorials for doing so I'd be extremely grateful.
I have a similar situation to you but ended up solving it in a completely different way. It is now available as a Meteor smart package:
https://github.com/mizzao/meteor-partitioner
The problem we share is that we wanted to write a meteor app as if only one client (or group of clients, in my case) exists, but that it needs to handle multiple sets of clients without them knowing about each other. I am doing the following:
Assume the Meteor app is programmed for just a single instance
Using a smart package, hook the collections on server (and possibly client) so that all operations are 'scoped' only to the instance of the user that is calling them. One way to do this is to automatically attach an 'instance' or 'group' field to each document that is being added.
Doing this correctly requires a lot of knowledge about the internals of Meteor, which I've been learning. However, this approach is a lot cleaner and less resource-intensive than trying to deploy multiple meteor apps at once. It means that you can still code the app as if only one client exists, instead of explicitly doing so for multiple clients. Additionally, it allows you to share resources between the instances that can be shared (i.e. static assets, shared state, etc.)
For more details and discussions, see:
https://groups.google.com/forum/#!topic/meteor-talk/8u2LVk8si_s
https://github.com/matb33/meteor-collection-hooks (the collection-hooks package; read issues for additional discussions)
Let me remark first that I think spinning up multiple instances of the same app is a bad design choice. If it is a stop gap measure, here's what I would suggest:
Create an archive that can be readily deployed. (Bundle the app, reinstall fibers if necessary, rezip). Deploy (unzip) the archive to a new folder when a new instance is created using a script.
Create a template of an init script and use forever or daemonize or jesus etc to start the site on reboot and keep the sites up during normal operation. See Meteor deploying to a VM by installing meteor or How does one start a node.js server as a daemon process? for examples. when a new instance is deployed populate the template with new values (i.e. port number, database name, folder). Copy the filled out template to init.d and link to the runlevel. Alternatively, create one script in init.d that executes other scripts to bring up the site.
Each instance should be listening to its own port, so you'll need a reverse proxy. AFAIK, Apache and Nginx require restarts when you change the configuration, so you'll probably want to look at Hipache https://github.com/dotcloud/hipache. Hipache uses redis to store the configuration information. Adding the new instance requires to add a key to redis. There is an experimental port of Hipache that brings the functionality to Nginx https://github.com/samalba/hipache-nginx
What about DNS updates? Once you create a new instance, do you need to add a new record to your DNS configuration?
I don't really have an answer to your question... but I just want to remind you of another potential problem that you may run into cuz I see you mentioned python, in other words, you may be running another web app on Apache/Nginx, etc... the problem is Meteor is not very friendly when it comes to co-exist with another http server, the project I'm working on was troubled by this issue and we had to move it to a stand alone server after days of hassle with guys from Meteor... I did not work on the issue, so I'm not able to give you more details, but I just looked up online and found something similar: https://serverfault.com/questions/424693/serving-meteor-on-main-domain-and-apache-on-subdomain-independently.
Just something to keep in mind...

Categories