Background:
I'm loading my entire AngularJS Cordova/Ionic web-app from the server. This is amazing. I can change the app without going through Apple.
Questions:
Q1) How can I use js-files.zip, loaded from server, in my index.html file?
Q2) How can I effectively load index.html startup logic from my server?
Problems:
On some older devices, loading time is too high if I load all my .js files from my server, so I want to be able to configure that logic (in index.html) also from the server.
The only thing I'm not loading from the server is the content of index.html
So, how can I essentially load index.html from a server?
If i try to do that
1) Pulling, say, indexfromserver.html using ajax and doing html rewrite of index.html with document.write(res), then there are AngularJS problems:
E.g., module missing errors (*1 below), because the following isn't in index.html until after the ajax response rewrites index.html:
<body ng-app="myapp" ng-controller="MainCtrl">
1.1) I can include the necessary modules in the initial local index.html, but then if I rewrite index.html, I'll get these errors/warnings about classList null in ionic (ask me for details), deviceready not fired, and angularjs loading more than once
2) I can redirect index.html to, say, indexfromserver.html, but then all my $http responses are rejected promises.
Regarding 2) I've been told I should be able to add a controller for indexfromserver.html or specify $urlRouterProvider.otherwise('/app/indexfromserver');
This hasn't fixed the $http requests from being rejected.
I don't understand exactly how index.html is involved in making $http work correctly, as it doesn't have a controller and isn't the 'otherwise' route provided. I only see mention of index.html in config.xml so far.
Request:
Can someone please post a snippet of a typical example how an AngularJS Cordova/Ionic app could effectively use index.html logic that's loaded from a server?
Otherwise, can someone show/explain if/how I can use js-files.zip from server, and uncompress and use in index.html?
Details/Notes:
(*1)
Uncaught Error: [$injector:modulerr] Failed to instantiate module myapp due to:
Error: [$injector:nomod] Module 'myapp' is not available! You either misspelled the module name or forgot to load it. If registering a module ensure that you specify the dependencies as the second argument.
http://errors.angularjs.org/1.2.17/$injector/nomod?p0=myapp
It was pointed out that you can use JavaScript in certain situations to unzip an archive, but that is not very common. The web does not work like that, Ionic runs inside of a browser so you should use the same processes as you would to optimize a website.
You would build the app instead like any website. Take the following steps to create a more optimized app for loading quickly. If you aren't familiar with build tools, take a look at http://yeoman.io/, and this specific generator for Ionic https://github.com/diegonetto/generator-ionic.
Here is a very basic list of some steps you can take, though the generator provides a few more options and other things could be added as well.
Concat and minimize your app's JavaScript into single file.
Concat and minimize your app's CSS into a single file.
Compress your angular templates with a tool like this https://www.npmjs.org/package/grunt-angular-templates into a single JS file.
Deploy static assets to server.
Link to above assets in index.html.
Ultimately the goal is to optimize the assets so you don't have to load a lot of files, and each file is as compressed as possible.
If you want to go the zip file route, and you assume your users aren't always connected to the internet, probably the best way is to:
Check if the version is new via a server call, and if so, download the zip file, extract it (maybe via stuk.github.io/jszip/), and use a Cordova interface to write the new JS code to the phone's memory, and run the code by adding some script tags in your loader.
Related
Our React app is served from a static hosting using S3 and CloudFront.
We configured S3 and CloudFront to add CloudFront-Viewer-Country in the return header of each request made to resources in it. So for instance, our index.html makes a call to get the .js bundle from CloudFront, the returned header would include: cloudfront-viewer-country: US in my case.
My goal is to have the React app "wake up to life" already knowing the location of its user. I realize I can probably add some javascript to the index.html to keep/store it somehow so that the React root component can pick up on that and pass it on to wherever it needs to be (probably the redux state). But then I ask myself, how do I tap into the response header received when the <script> tag finished loading the bundle in order to extract the custom header from it?
the index.html is pretty straightforward. Its body looks like this:
<body>
<div id=root></div>
<script type="text/javascript" src="/myBundle.ac9cf87295a8f1239929.js"></script>
</body>
What do you recommend?
It isn't possible to access the headers from the page load or script load. You will have to make a separate request to access the headers.
You could also use browser's locale (navigator.languages) if you need this information for localization.
I have a react app which works perfectly fine.
However we are pushing code after NPM BUILD and deploying the code manually via SFTP
We can see the JS and CSS files have different names.
However the browser keeps downloading css and js files form cache, even if I disable cache in the browser.
I tried deleting all files in FTP, and magically the website keeps working? so it looks all the files are retrieved from the browser cache even if nothing exists in the server
I tried stopping and starting the azure website, but didnt make any difference
I tried cleaning the browser, cache, history, etc, no difference.
I wonder if I need to setup something in web.config, or in Azure website settings to make this works
This seems to be not an issue with Azure app service (Web app), you need to remove the caching of the react app with the following steps
Step 1: adding the following to in index.html
<meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="Expires" content="0" />
Step 2: inserting the following to the js
import { unregister } from './registerServiceWorker';
and call
unregister()
Reference Answer
It depends on how your app is configured, but I would not recommend disabling cache on the JS & CSS. Instead, it's best to add some version-dependent information to the file name so every time the JS or CSS update the file name changes.
Last time I worked on a web project we had it such that our JS & CSS had a content hash at the end. Something along the lines of main.205199ab45963f6a62ec.js instead of just main.js. Also note that you don't even have to manage that hash yourself, as there are ways to get ASP.NET or webpack (etc...) to update the reference in the HTML/JSX for you.
Here's webpack's page about it: https://webpack.js.org/guides/caching/
We have a SPA built with React and bundled with Webpack.
The server only has the index.html and javascript bundle files located.
Behaviour Chrome/Firefox/Opera
Loads index.html
Fetches bundles
Boots React page
Behaviour Edge
Loads index.html
Fetches bundles
Boots React page
Starts loading every module and component as an independent file using HTTP requests (they are not even on the server, the response is index.html)
The bundle does not have this information. This information must be fetched from the source map. But why does Edge do this?
This is similar like SAP application, those JavaScript library has their own logic to preload source codes to optimize the performance/network requests. It's a compatibility issue with React library for Edge browser.
The next version of Edge browser don't have this issue. Maybe you want to try this: https://www.microsoftedgeinsider.com/en-us/
Coming from a PHP background, I used to have an index.php which does two things:
serve the webpage if no parameters were set;
or serve JSON data when a specific POST parameter was included in the request.
Something like this:
// -- index.php
<?php
if ($_POST["some_parameter"]) {
...
echo json_encode(someArrayData);
exit(0);
}
?>
<html>
...
</html>
I have built the complete frontend application with npm, webpack, webpack-dev-server, and react. Having completed the first part, how can I effectively serve JSON data instead of HTML when a request includes a specific POST parameter?
I can see 2 ways of doing this:
Build the frontend as usual and everytime I build the bundle, modify index.html, inject my PHP code in it, and rename it to index.php. I then would have to run this folder via apache or nginx, so I'd be able to run the index.php script. This method is downright ugly and is probably the worst way to do it.
Run a separate PHP server which just serves data or redirects to the static webpack-generated build. All requests should then start from this server, and this server determines whether to serve data or redirect to the frontend. The problem comes to neatly passing the POST data received from the request to the static react app. As far as I know, the only way to do this would be to include a URL (GET) parameter to the redirect and manually parse it with javascript on the frontend. This is a dirty solution, in my opinion.
So, to summarize:
I need an efficient way to get POST data in a react/webpack/webpack-dev-server environment.
It should work with my hot-module-replacement dev setup.
I'm fine with switching to a node-based backend like express.
There shouldn't be any ajax involved in the static react app.
Any ideas? There has to be a way to do this properly.
UPDATE: I solved this by simply copying an index.php from my source directory to my build directory via the webpack config. I serve the build folder to a PHP server and keep a webpack --watch building my source.
I lose built-in features like auto-reload and css injection, but it's worth the convenience of not having to implement SSR for a very simple task (getting a single POST variable).
For anyone interested, I also added 2 npm scripts:
npm run start runs my original webpack-dev-server with hot-reload, serving static content including a static index.html file
npm run static runs the webpack --watch which copies the index.php file to the build directory
This lets me have hot-reloading when developing frontend, and allows POST data fetching when programming logic.
It's easy, convenient, and works on most web hosting providers.
Need some experienced eyes to tell me what's going on.
I got this nice message.
so when I dutifully click on mainCtrl.js:1, devTools show me this.
How in the world did my browser decide that my index.html is now mainCtrl.js ?
You can already see my index.html in the window above... It is a direct copy of this.
...and here is just one of the script tags causing me this grief (they all give this same Syntax error)...
<script src="app/controllers/mainCtrl.js"></script>
There is no minifying or grunt/gulp action happening at all, so what could be causing this confusion?
all the js files are loading fine too, according to my nice morgan log
This happens because you have an error in your (presumably Express) routes.
You probably have a catchall that is serving the index.html file. Further up in your route definitions you need a route to serve your .js file.
Just for the record (answered in the comments): Some express middlewares can be the reason for such rewrites, especially when using the html5 history api for client side routing. (for example https://github.com/bripkens/connect-history-api-fallback - which by default only responds to urls not containing a dot.)