Showing posts with label NodeJS. Show all posts
Showing posts with label NodeJS. Show all posts

Thursday, 16 December 2021

React Router and NodeJS


Hosting your React app is usually as simple as copying over the files to a "public" or "static" directory.
 
You could simply paste the files onto an IIS or Apache Server and this article could still help you if you are using sub directories. However, I have written this to tackle the situation where a pre-existing web application will host, in this scenario the host application is written in NodeJS. 

Generally, all you need to worry about is serving the "index.html" file that comes in the production build bundle at the right time, something like: 
router.get('/myroute', async (req, res) => {
return res.sendFile(path.join(__dirname + '/public/client/index.html'));
}

// later on make the public directory accessible
app.use('/public', express.static(__dirname + '/public'));

However, in this case I want to use React Router to navigate to sub pages. e.g. myroute/ home, myroute/user etc...

The way to do it is to use a wildcard off of your main route so that your React app will load on every child route of "myroute":
// this is required to support any client side routing written in react.
router.get('/myroute/*', (req, res) => { 
    res.sendFile(path.join(__dirname + '/public/client/index.html'));
});
On the React application side the "basename" property of the Router wrapper component (in React Router 5+) needs to be set. In my case I set "base" when in production mode to "/myroute". This will mean React router will look for "/myroute/new" to render the Start component rather than just "/new".
const base = process.env.NODE_ENV === "production" ? "/myroute" : "/";

<Router basename={base}>
   <Switch>
     <Route exact path='/new'>
       <Start />
     </Route>
   </Switch>
</Router>
It is also worth mentioning that it is considered best practice to add a href meta tag to you index.html page.

References
react-router | https://reactrouter.com/web
medium | https://dev-listener.medium.com/react-routes-nodejs-routes-2875f148065b

Wednesday, 9 September 2020

Azure Functions with TypeScript

Things to know about using TypeScript with Azure functions:

  1. Make sure that you have node installed using the latest LTS version (Long Term Support). If you need the latest version for other projects try using nvm-windows to manage multiple versions of Node. Install the latest version of nvm using the zip file in assets of the latest release. nvm list and then nvm use. Also nvm install v 64/32bit is pretty nifty.
  2. To run Azure functions manually (particularly useful for timers etc.. anything that is not an Http Trigger). http://localhost:<port>/admin/functions/<FunctionName>. Also for CRON timings see this cheatsheet.
  3. Azure Functions in TypeScript still use CommonJS modules, so while you can use imports and exports in your code the transpiled JS will be using Node style modules. Bear this in mind if you are expecting to be able to use any of your own libraries that compile to anything other than CommonJS. Check your TSConfig.
So is TypeScript support any good? So far it seems good, the only problems are with my own libraries. I have also noticed that you cannot use fat-arrows for Azure Index functions (for those not so familiar - the entry point called by Azure infrastructure).

Saturday, 19 November 2016

Isomorphic or Universal Javascript

Why I have decided to learn about this?
I first truly took note of the term "Isomorphic JavaScript" when a recruiter sent me through a job which I thought looked extremely interesting. At the time I was not looking for a job, but it reminded me about the long standing problem with decent SEO and Single Page Applications (SPAs). I had heard a lot about React and Angular 2 providing some way to solve the problem, so I was curious.

Notably, the company in question were listing some other design patterns and technologies which were new to me and were also of interest: 12 factor app, Mesos and Marathon, CircleCI.

Godammit man, what does Isomorphic mean!
Isomorphic means "corresponding or similar in form". So essentially we are describing some sort of server side rendering to support the client side application.

Or as the AngularJS Universal Repository puts it: "A JavaScript Application that runs in more environments than just the browser".

The advantages?
  • The application does not need to rely on JavaScript being turned on in the browser for it to function
  • The application does not need to have a loading gif to explain to the user that patience is required
  • THE BIG ONE - The application can be more easily crawled by search engines because the page is also available from a static URL.
Some disadvantages and limitations
  • "Uncanny valley" - this is a term used to describe the time between the application appearing to be functioning and available and the time before it is actually responding to the users demands. This can be confusing for the user.
  • Loss of separation between back-end and front-end application code. However, I would say, in this API/ Micro-service architecture world, that this actually makes quite a bit of sense. The User Interface will still be separated from Business Logic, we are just blurring the line between server-side "Get" request responses and view rendering.
  • This is still just a bootstrapping technique and some SEO issues do still remain.
For a more thorough discussion on why Isomorphic JavaScript is "not the answer" take a look at this discussion on ycombinator (at your own risk of course!).

Wednesday, 5 November 2014

Asynchronous JavaScript programming in Node

I want to be able to read an atom feed!! This is NodeJS, so of course there is this great library for doing just that (feed-read), the feed function is asynchronous. I also want to use a Node abstraction in the form using Express modules.
Ok, no problem, I thought. I tried putting the feed directly in my server.js file. There was a simple problem - I don't have the blog data because feed-read has made an asynchronous call to gather the feed information leaving me with nothing.
Once I understood the problem I started searching for solutions. What generally comes up are yet more helpful libraries to help you 'deal with' the async 'problem'.
I am sure there are more complicated problems which may merit a complex library but I happen to know that this is something that JavaScript is great at. JQuery introduced the idea of a promise in version 1.5 and this is basically the same problem, with a similar solution. So the answer?

In my case chain callbacks. Yes, if you are using a function from an abstracted module, pass in a function which will then pass a function etc... When the function at the bottom of the chain passes us some data back we will be ready!! Use an API call to do this perhaps so we can give our users a spinner while they are waiting.
     var blogReader = { 
      GetMostRecentBlog : function(callback) {  
        feed('http://bloglocation.com/feeds', function(articles) {  
         var mostRecentBlogPost = articles[0];  
         var blog = {  
            Title: mostRecentBlogPost.title,  
            Content: mostRecentBlogPost.content  
         };  
         callback(blog);  
       }); 
    };  
    module.exports = blogReader;
    
    You then can use it like :
     blogReader.GetMostRecentBlog(function(blog) {  
       //use Blog object here for display  
     });  
    
I found this exact pattern in Mixu's Node book chapter 7 - http://book.mixu.net/node/ch7.html. He also talks about two other useful patterns to deal with asynchronous calls which may be useful on larger scale projects - Parallel and Limited Parallel patterns.

 As always, the code for my solution can be found on github.

Sunday, 14 September 2014

NodeJS progress and the mighty Bootstrap

Since writing my last post I have spent some more time with NodeJS.
Things I have done:

  • I created an API using Express using this article to create some bears - http://scotch.io/tutorials/javascript/build-a-restful-api-using-node-and-express-4) 
  • I added a favicon using this - https://github.com/expressjs/serve-favicon
  • I pondered Jade as my view engine and then quickly decided that Handlebars would be much easier as I was already very familiar - https://github.com/ericf/express-handlebars
As you can see progress is good. 

Unfortunately, next came the bit I always dread, trying to set out an effective design for the website. I struggle as a designer. At university I got familiar Photoshop and Illustrator, and while I really liked doing it at the time, sadly I have not kept up with the evolution of the software since. Luckily I can just prototype and see where it...

...Mild panic began to build.... oh god what about phones and tablets! As if deciding on a design isn't hard enough, I have to think responsive! Anyway - thank god for the kind people/companies of open source. Luckily we have Zurb Foundation and Bootstrap. Zurb Foundation is fantastic, but as I am already familiar with Zurb I thought I would use Bootstrap.

I am not going to bore you with all the details but provide you with my gotcha's list:

  • By default Node does not permit the public directory to be accessed. I wanted to do this so I could access the bootstrap files which were stored in public/libs. If you would like to store your bower packages in a custom directory rather than the default like me, create a .bowerrc file in your route directory with no file name, if unsure check this. Then add the following: 
    {
          "directory": "public/libs"
    }
  • To access the public directory for styles and scripts:
    app.use(express.static(__dirname + '/public'));
  • To use in your views:
    <script src="libs/bootstrap/dist/js/bootstrap.min.js"></script>
  • Use navbar-static-top rather than navbar-fixed-top. This is a new class as of Bootstrap 3.0, it addresses the problem wherein the navbar sits over the content of the page.

Sunday, 6 July 2014

Getting started with NodeJS and pushing it to the cloud using Git and Azure

Yes I know, getting started with NodeJS has been covered many times by far brighter people. However, there are not too many posts written by stubborn PC users (yeah that's right, turn in your grave Steve) and don't make me put another grumpy cat here! I also want to write this as a lead in for a more exciting post later on! If you are new to NodeJS like I am and you are excited at the thought of writing your next API in JavaScript then this is the place for you!

Pre-requisites:
  • NodeJS (this includes the npm package manager as well)
  • A Github account and therefore Git DVCS (Distribruted Version Control System)

To begin with lets make a new directory for the project. I am using  C:\code\nodestart

Create a file called package.json :
{ 
   "name": "nodestart" , 
   "version": "0.0.1" , 
   "dependencies": 
        { 
            "express": "latest" 
        } 
}

Then change directory to the location of your project in Command Prompt, and run npm install  
to install the express module.
cd C:\code\nodestart
npm install


So at this point we have everything we need to add further packages in the future. Lets add a new server.js file in our directory as well.


console.log("Hello World");

To run this, go back to the command line and type:

node server.js

You are treated with a "server running at http://127.0.0.1:1337/" message, paste this into your browser and voilĂ ! Basic node achieved! Hazzah!

Now what if, for some strange reason, we wanted to publish our fine work? I mean everyone needs a useless site. No, well lets do it anyway!

First we need to use some slightly more sophisticated code:
var http = require('http')
   var port = process.env.PORT || 1337;
   http.createServer(function(req,res){
   res.writeHead(200, {'Content-Type':'text/plain'});
   res.end("hello world");
}).listen(port);

Now we need to initialise git to make our nodestart project a working git repository. Go to Git Bash (downloaded from git hub) or the command line, cd to the project directory and type:


git init

Notice that this will add a .git folder to the root of your project. We must also add a new file in the root called .gitignore. Add the following lines:


npm-debug.log
node_modules

This is so that you do not add all the node library files to the solution. Now it is safe to type:


git add .
git commit -m 'Initial commit'

It would be nice to setup ourselves properly in terms of our credentials and user names - (https://help.github.com/articles/set-up-git). Nobody likes annonymous commits... there is no-one to blame! 

Also rather than keep typing in your credentials you may want to setup an SSH key. This is very much optional and takes a little time but it makes pushing to source control far less tedious. If you do decide to do this remember to change the clone URL to the SSH one in github! 

Now all we need to do is set the origin and push to our github repository.


git remote set-url origin git@github.com/username/nodestart
git push -u origin master

I am going to use Windows Azure to host this application. You can sign up to get an account with a free trial. Afterwards you can keep the server in free mode and keep auto scale off to guarantee that it will not cost you any money.

Azure has the ability to "integrate source control". This can be done from the UI as shown below or you can use the Azure command line tools through Windows PowerShell.



It's really neat and means that you can push directly to Azure without using a web based repository host like Github or Bitbucket. For more information on this method check out Scott Hanselmans post on the subject. 

Now back in the Azure console I am going to choose integrate source code as before but this time choose "github" rather than "local git repository".

Select your repository and treat master as your CI branch and there you go! Success!



Additional: Windows Azure can cope with npm but what about bower? I found a solution for this problem here: http://gregtrowbridge.com/deploying-a-bower-dependent-node-app-on-windows-azure/

The only problem was that it relies on a deploy.sh file being produced when running "azure site deploymentscript --node". Instead my solution produced a batch file with Kudu code. To cut a long painful story short I was able to resolve this with the following code:
:: 4. Install bower packages
if EXIST "%DEPLOYMENT_TARGET%\bower.json" (
  pushd "%DEPLOYMENT_TARGET%"
  call :ExecuteCmd !NPM_CMD! install -g bower
  pushd "%DEPLOYMENT_TARGET%\public\libs"
  call :ExecuteCmd bower install
  IF !ERRORLEVEL! NEQ 0 goto error
  popd
)

Sources and references: http://www.nodebeginner.org/#javascript-and-you, http://kunkle.org/nodejs-explained-pres/#/example-http-server, http://howtonode.org/, http://nodejs.org/api/http.html#http_http