Posts tagged Web Apps

Azure Web App NPM Install Error

In a previous post I talked about using Gulp, Node and NPM to run automation during source code deployment to Windows Azure Web Apps. I recently encountered a new error standing up the Gulp/Node/NPM workflow on a new Azure Web App.

Here’s the bulk of the error:

> node postinstall
 npm ERR! Windows_NT 6.2.9200
npm ERR! argv "D:\\Program Files (x86)\\nodejs\\4.1.2\\node.exe" "D:\\Program Files (x86)\\npm\\2.14.4\\node_modules\\npm\\bin\\npm-cli.js" "install"
npm ERR! node v4.1.2
npm ERR! npm  v2.14.4
npm ERR! path D:\home\site\repository\node_modules\gulp-util\node_modules\dateformat\node_modules\meow\node_modules\normalize-package-data\node_modules\validate-npm-package-license\node_modules\spdx-correct\node_modules\spdx-license-ids\package.json.2216d6e92a8a6bf6068310c3c1b75618
npm ERR! code EINVAL
npm ERR! errno -4071
npm ERR! syscall rename
 npm ERR! EINVAL: invalid argument, rename 'D:\home\site\repository\node_modules\gulp-util\node_modules\dateformat\node_modules\meow\node_modules\normalize-package-data\node_modules\validate-npm-package-license\node_modules\spdx-correct\node_modules\spdx-license-ids\package.json.2216d6e92a8a6bf6068310c3c1b75618' -> 'D:\home\site\repository\node_modules\gulp-util\node_modules\dateformat\node_modules\meow\node_modules\normalize-package-data\node_modules\validate-npm-package-license\node_modules\spdx-correct\node_modules\spdx-license-ids\package.json'
npm ERR! 

The Key bit seems to be “npm ERR! errno –4071” and “npm ERR! syscall rename”. After quite a bit of messing around with the script the deploy.cmd and package.json I took a look at our existing Web App to see what were the differences then I found this under the config tab, but our existing apps were “0.10.32”

2015-11-13_15-12-14

Changing the setting to “0.10.32” fixed the error.

2015-11-13_15-13-13

I don’t know what other Node versions work, but it’s apparent 4.1.2 doesn’t work. I spent a few hours struggling with this issue, hopefully this helps someone resolve the issue quicker then I did.

Resgrid is a SaaS product utilizing Microsoft Azure, providing logistics, management and communication tools to first responder organizations like volunteer fire departments, career fire departments, EMS, search and rescue, CERT, public safety, disaster relief organizations, etc. It was founded in late 2012 by myself and Jason Jarrett (staxmanade).

Azure Web Apps Source Deployments with Gulp

In my last blog post “Ionic Framework as a Web Site” I detailed some changes I need to make to an Ionic app to utilize it as a web site. Step 2 of that process was trying to land my new Ionic Site somewhere. As Resgrid is a 100% cloud company we put it on Azure. So we created an Azure Web App, pointed it at our source control and then it all broke. The structure of source we use for Ionic or AppBuilder doesn’t lend itself to becoming a website from the folder structure, as is the common use case for source control provider deployments. The solution, Gulp!

azure-app-service-with-office-365-and-yammer-sharepoint-saturday-florence-2015-session-8-638

Azure uses an open source project called Kudu as an engine for executing git/hg deployments, running tasks and even WebJobs. This allows your to take code from a source code repository have Azure pick it up and deliver it to the cloud and run additional operations.

Note that Kudu itself isn’t limited to Gulp, you can run pretty much anything the underlying Azure VM has access to. Creating the script is pretty simple. If you have the Azure CLI tools installed you can run the following command:

azure site deploymentscript

Note there are a number of default switches you can use for example –aspWebSite for your ASP/MVC/WebAPI sites, –node, –php, –python and finally –basic. This command will create 2 files, a .deployment file and a deploy.cmd file. For the Ionic Framework one we used –node as our switch. The .deployment file is pretty simple:

[config]

command = deploy.cmd

This just a configuration file for Azure to tell it what to run. There is a lot you can do with with the .deployment file. The other file created is the deploy.cmd file, below is the one used in Resgrid’s Ionic Framework app deployment. I cut the code above out for brevity, at the end of the Setup section, just above this section of code is the “IF NOT DEFINED KUDU_SYNC_CMD” check.

:: Code above omitted for brevity

IF NOT DEFINED GULP_CMD (
  :: Install gulp
  echo Installing Gulp
  call npm --registry "http://registry.npmjs.org/" install gulp -g --silent
  IF !ERRORLEVEL! NEQ 0 goto error

  :: Locally just running "gulp" would also work
  SET GULP_CMD="%appdata%\npm\gulp.cmd"

)

goto Deployment

:: Utility Functions
:: -----------------

:SelectNodeVersion

IF DEFINED KUDU_SELECT_NODE_VERSION_CMD (
  :: The following are done only on Windows Azure Websites environment
  call %KUDU_SELECT_NODE_VERSION_CMD% "%DEPLOYMENT_SOURCE%" "%DEPLOYMENT_TARGET%" "%DEPLOYMENT_TEMP%"
  IF !ERRORLEVEL! NEQ 0 goto error

  IF EXIST "%DEPLOYMENT_TEMP%\__nodeVersion.tmp" (
    SET /p NODE_EXE=<"%DEPLOYMENT_TEMP%\__nodeVersion.tmp"
    IF !ERRORLEVEL! NEQ 0 goto error
  )
  
  IF EXIST "%DEPLOYMENT_TEMP%\__npmVersion.tmp" (
    SET /p NPM_JS_PATH=<"%DEPLOYMENT_TEMP%\__npmVersion.tmp"
    IF !ERRORLEVEL! NEQ 0 goto error
  )

  IF NOT DEFINED NODE_EXE (
    SET NODE_EXE=node
  )

  SET NPM_CMD="!NODE_EXE!" "!NPM_JS_PATH!"
) ELSE (
  SET NPM_CMD=npm
  SET NODE_EXE=node
)

goto :EOF

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:: Deployment
:: ----------

:Deployment
echo Handling custom app deployment

::  Select node version
call :SelectNodeVersion

::  Install NPM Packages
IF EXIST "%DEPLOYMENT_SOURCE%\package.json" (
  pushd "%DEPLOYMENT_SOURCE%"
  echo Installing NPM Dependicies.
  call :ExecuteCmd !NPM_CMD! install
  IF !ERRORLEVEL! NEQ 0 goto error
  popd
)

:: Run Gulp to build website from mobile app
IF EXIST "%DEPLOYMENT_SOURCE%\gulpfile.js" (
  pushd "%DEPLOYMENT_SOURCE%"
  echo Running Gulp.
  call :ExecuteCmd !GULP_CMD! web:build
  IF !ERRORLEVEL! NEQ 0 goto error
  popd
)

:: KuduSync
echo Handling Basic Web Site deployment.
IF /I "%IN_PLACE_DEPLOYMENT%" NEQ "1" (
  call :ExecuteCmd "%KUDU_SYNC_CMD%" -v 50 -f "%DEPLOYMENT_SOURCE%\web" -t "%DEPLOYMENT_TARGET%" -n "%NEXT_MANIFEST_PATH%" -p "%PREVIOUS_MANIFEST_PATH%" -i ".git;.hg;.deployment;deploy.cmd"
  IF !ERRORLEVEL! NEQ 0 goto error
)

The Utility functions are important. They setup the environment variables for Node and NPM. Note that Azure typically runs a few versions older then the current node version. Additionally some NPM dependencies, like fibers, that require locally complication (and thus Visual Studio or some other compiler) installed won’t work on Azure.

The Deployment section is where the big stuff happens. We first call our SelectNodeVersion utility function to setup Node and NPM then run NPM to install our modules. Again be cautious of what node modules you add, keep it to the bare minimum.

The next step is we run our gulp command against our gulpfile.js and call our task to be run, in this case it’s “web:build”. There is no Azure specific items in our gulpfile, we just copy our web items into a folder “called web at the root of our solution” and for KuduSync (the command that handles copying to the wwwroot) we point it to “%DEPLOYMENT_SOURCE%\web”.

Azure is a great PaaS (Platform as a Service) for your Microsoft and non-Microsoft technologies. Personally I feel that their PaaS capabilities far exceed any other cloud provider out there and when solving problems like the one above, using zero MS Tech, I was easily able to accomplish my goals without ever touching a VM or worrying about configuration.

Resgrid is a SaaS product utilizing Microsoft Azure, providing logistics, management and communication tools to first responder organizations like volunteer fire departments, career fire departments, EMS, search and rescue, CERT, public safety, disaster relief organizations, etc. It was founded in late 2012 by myself and Jason Jarrett (staxmanade).

Ionic Framework as a Web Site

Oh iOS 9, I’m not going to miss you when iOS 10 drops. But with Apple’s pattern lately of breaking more and more Cordova/Hybrid compatibility in their new iOS releases, WkWebView in iOS8 and now Url’s with hash’s\window.location in iOS9. When Apple uses the slogan “Nothing’s changed, but everything” it should be “Nothing’s changed, but our degraded support for your Hybrid applications”.

Sorry I’m a little sore. It wouldn’t be so bad if their review times weren’t 7 days long (in the best cases lately) and asking for a expedited review was akin to asking your overly protective mother if you can stay out late after the movie……wait off track again sorry, gotta focus.

The above is the reason why Resgrid launched “Web Edition’s” of our mobile apps. The same app (more or less) as you get through the store but delivered via the browser, We are eagerly awaiting Ionic Lab’s Deploy to be released and available to be used on Store applications. Ionic if you need any testers were willing Smile.

Ionic doesn’t recommend using the framework for websites, it’s specifically designed for high performance hybrid mobile applications. But there if very little standing in the way for you to turn your Ionic application into a web application. But why would you want to do this?

  1. An Edge/Trial/Free Version of your app
  2. An online demo
  3. Supporting Desktop/Laptop users

For Resgrid we wanted a web edition that we can updated on the fly or use automated deployments.

Cordova, Plugins and Device Access

The first area you will run into issues is if your trying to access Cordova. In a web site you will not have access to the Cordova (as there is no ‘device’ for it to broker calls to). For Resgrid we had only a few instances where we needed an actual Cordova device, some of them where:

  1. Check if a device is an iPhone or Android
  2. Opening a file using the File Opener
  3. Getting the device UUID/UDID (via a plugin)

So here’s a simple Angular service we wrote to give us a check, isPhone(), before we do any device access or show features that require a device.

(function () {
    'use strict';

    angular.module('responder.utils').factory('deviceUtils', deviceUtils);

    deviceUtils.$inject = ['$q', '$timeout', '$ionicPlatform', '$cordovaDevice'];
    function deviceUtils($q, $timeout, $ionicPlatform, $cordovaDevice) {

        return {
            getDevice: function () {
                if ($cordovaDevice)
                    return $cordovaDevice.getPlatform();

                return "Web";
            },
            isPhone: function () {
                if (typeof (cordova) !== "undefined")
                    return true;

                return false;
            },
            isWinPhone: function() {
                if ($cordovaDevice)
                    if ($cordovaDevice.getPlatform() == 'WP8' || $cordovaDevice.getPlatform() == 'Win32NT' || $cordovaDevice.getPlatform() == 'WinCE')
                        return true;

                return false;
            }
        }
    }

}());
WebSQL\SQLite Plugin

Oh SQLite, your awesome, but not all at the same time. If your using SQLite as a backend storage system you can fall back to WebSQL without any API changes, but there’s a catch, WebSQL is deprecated and unsupported in Firefox and IE. Chances are it will be unsupported more and more as time goes on.

The solution? YDN-DB. YDN-DB is an abstraction over a number of different database implementations. In our implementation below we tell YDN-DB the order of priority for it to use as a backing database store in the options {mechanisms} array. We’ve told it to use SQLite first, if that’s not available/support use IndexedDB, then WebSQL, then NoSQL LocalStorage and finally memory.

(function () {
    'use strict';

    angular.module('responder.services').factory('localDbService', localDbService);

    localDbService.$inject = ['$q'];
    function localDbService($q) {
        var db;
        var valid = true;

        return {
            init: function () {
                var deferred = $q.defer();

                // Order of preferred storage mechanisms.
                var options = { mechanisms: ['sqlite', 'indexeddb', 'websql', 'localstorage', 'memory'] };

                try {
                    db = new ydn.db.Storage('ResgridResponder', dbSchema, options);

                    db.onReady(function (err) {
                        if (err) {
                            console.log(err);
                            deferred.reject(err);
                        } else {
                            deferred.resolve();

                            // Occurs when the database halts and catches fire!
                            db.addEventListener('fail', function (event) {
                                var err = event.getError();
                                console.log('connection failed with ' + err.name + ' by ' + err.message);
                                db = null; // no operation can be placed to the database instance
                                valid = false;
                            });

                            // Occurs when a database error (i.e. a query error) occurs
                            db.addEventListener('error', function (event) {
                                var e = event.getError();
                                // common errors are AbortError, ConstraintError and UnknownError (possibliy for Quota exceed error).
                                // log error for debugging
                                console.log('connection failed with ' + e.name);
                            });
                        }
                    });
                } catch (e) {
                    console.log("Unsupported browser, cannot use WebSQL");
                    valid = false;
                    deferred.reject('Unsupported');
                }

                return deferred.promise;
            }
        }
}());

With these changes, replacing SQLite and check to ensure we are on a phone before trying to use any Cordova or Cordova Plugin functionality, we were able to quickly use Gulp to build our site and deploy it to a Azure Web App.

Resgrid is a SaaS product utilizing Microsoft Azure, providing logistics, management and communication tools to first responder organizations like volunteer fire departments, career fire departments, EMS, search and rescue, CERT, public safety, disaster relief organizations, etc. It was founded in late 2012 by myself and Jason Jarrett (staxmanade).

Go to Top