1

I have experience developing angular apps, but I am new to the mean stack, I am trying out the mean stack and have an express server running and a angular site running. My express if for my REST api primarily, but would like to have an entry point to point back to the my client in a case of an unknown url to the server: server.js:

    // Setup View Engines
app.set('views', path.join(__dirname, 'public'));
app.engine('html', require('ejs').renderFile);
app.set('view engine', 'html');

// Serve files from your "public" directory
app.use('/public', express.static(path.join(__dirname + 'public')));

// Serve files from your "bower_components" directory
app.use('/bower_components', express.static(path.join(__dirname + '/bower_components')));

// GET index.html route
app.get('/', function(req, res) {
    return res.render('index');
});

my angular resides in Public folder and here is my index.html file:

    <!DOCTYPE html>
<html ng-app="havuraApp">
    <head lang="en">
        <meta charset="UTF-8">
        <title></title>
    </head>
    <body>
        <div>
            main
            <ui-view></ui-view>
        </div>

    </body>

    <script src="../bower_components/angular/angular.js"></script>
    <script src="../bower_components/angular-ui-router/release/angular-ui-router.js"></script>
    <script src="../bower_components/angular-ui-bootstrap/index.js"></script>
    <script src="../bower_components/angular-resource/angular-resource.js"></script>
    <script src="app.js"></script>


    <!--services-->
    <script src="Services/svcModule.js"></script>
    <script src="Services/userSvc.js"></script>
    <!--dashboard-->
    <script src="Views/dashboard/dashboard.module.js"></script>
    <script src="Views/dashboard/config.route.js"></script>
    <script src="Views/dashboard/dashboard.js"></script>
</html>

If i hit the angular site index.html, my loads my correct default route page, but when I hit it using the express route, it loads the html only and not the ui-view part of it.

Any help will be appreciated.

peteb
  • 18,552
  • 9
  • 50
  • 62
Pacman
  • 2,183
  • 6
  • 39
  • 70
  • What is the "express route"? – Brent Washburne Mar 17 '16 at 16:43
  • It's in the above code: module.exports = function(app) { app.route('*') .get(function (req, res) { var path = require('path'); res.sendFile(path.resolve(__dirname + '/../Public/index.html')); }); } – Pacman Mar 17 '16 at 16:50

3 Answers3

0

I think the problem lies in your html. You're pointing to the node_modules directory which you have not declared to be public. I would suggest you just copy the dist files from there using a taskrunner to your public directory instead of opening node_modules to the public.

ruedamanuel
  • 1,930
  • 1
  • 22
  • 23
  • This works if I browse directly to the HTML, the issue is when express navigates to this HTML, I dont see how the node_module being public is the issue, please elaborate. – Pacman Mar 17 '16 at 17:45
  • What I understood from your question is that you're getting the html but the angular app isn't loading, so when you open the index.html from your local file path (i.e. /User/Username ...) your paths are referencing your local files, so it will be able to find your scripts. However, if you're loading your html via http://localhost:8080/index.html (assuming you're running express in 8080 and that's the node path you're referring to), your relative paths in the html are now rooted with localhost:8080/ so your node app needs to know that node_modules is public or your scripts won't come through – ruedamanuel Mar 17 '16 at 18:21
0

The express route app.route('*') is sending all requests to __dirname + '/../Public/index.html'. You need to get more fine-grained with the requests: http://expressjs.com/en/guide/routing.html

Brent Washburne
  • 12,904
  • 4
  • 60
  • 82
0

I would say, its not the best practice to expose your node_modules directory to your front end. If you want to use npm packages in your client side code you should look into Browserify or Webpack.

You need to setup static files for Express via express.static(); Also you need to clean up your route. Right now every request to the Express server will be served to index.html. It would be better though to define a single resource for this route instead. Alternatively, you could define all your other routes prior to app.route('*') since Express will look for your route Top-down based on declaration.

server.js

var express = require('express');
var app = express();

// define static locations to serve
app.use(express.static(path.join(__dirname + 'public')));
app.use(express.static(path.join(__dirname + 'node_modules')));

// single route for index.html
app.get('/', function(req, res) {
   return res.sendFile('../Public/index.html');
});

app.listen(process.env.PORT || 3000);

module.exports = app;

Now you can access your static directories and their contents without needing to specify the parent directory in your html.

index.html

<!-- load our dependencies from our static locations -->
<script src="/angular/angular.js"></script>
<script src="/angular-ui-router/release/angular-ui-router.js"></script>
<script src="/angular-ui-bootstrap/dist/ui-bootstrap.js"></script>
<script src="/angular-resource/angular-resource.js"></script>


Using Bower instead of NPM for client packages

I would change these dependencies from being npm packages to bower packages. Bower is a package manager specifically for client-side packages.

// Install bower as a global package
npm install -g bower

// same process type as npm init
// creates a bower.json, very similar to package.json
// and ./bower_components, same concept as node_modules
// in our project directory
bower init 

// save our dependencies to bower.json & ./bower_components
bower install --save angular
bower install --save angular-ui-router
bower install --save angular-boostrap
bower install --save angular-resource

Then you can just serve your Bower dependencies straight from the bower_components directory.

app.use(express.static(path.join(__dirname +'bower_components')));

Your index.html will still look the same as the one above in this answer.


Using View Engines

You're currently returning your view by using res.sendFile(), while this works it doesn't leverage a feature existing in Express, View Engines. Express has support for Template Engines such as Jade, Handlebars & EJS. This enables use of res.render() which, uses the set engine to render the view requested.

To use a Template Engine, you'll need to install one of them from npm, I prefer ejs although, Jade and Handlebars are the more popular choices.

npm install --save ejs

server.js

// Tell Express to look for Views to render in the `./views` directory
app.set('views', path.join(__dirname + 'views'));

// Set EJS as the View Engine
app.use('view engine', 'ejs');

app.use('/', function(req, res) { 
  res.render('index');
});
peteb
  • 18,552
  • 9
  • 50
  • 62
  • I switched to bower, and I have the app.get('/', function(req, res) { return res.sendFile('../Public/index.html'); }); defined, I put a breakpoint in it and it stops there, but I still dont see my angular displayed, I only see the main html which is in public/index.html – Pacman Mar 17 '16 at 22:18
  • @Pacman see my edit on using View Engines to replace `res.sendFile()` – peteb Mar 17 '16 at 23:14
  • Not following, so what is happening to my Public folder with all of my html and angular code ? – Pacman Mar 17 '16 at 23:26
  • Your Angular code will continue to be served from your `public` directory and work as you originally set it up. The only difference is that Express will look for `index.html` in `./views`. Check out [this repo](https://github.com/pbaio/node-angular-example). Its setup to use Node, Bower and Angular and will show you the setup I'm talking about in this quesiton. See [this answer](http://stackoverflow.com/questions/35856152/how-do-you-install-angular-on-windows-7/35856360#35856360) for a walkthrough of this repo if you need more info. – peteb Mar 17 '16 at 23:34
  • I think there is a miscommunication here, this is what my server.js looks like: app.set('views', path.join(__dirname, 'views')); app.engine('html', require('ejs').renderFile); app.set('view engine', 'html'); // Serve files from your "public" directory app.use('/public', express.static(path.join(__dirname + 'public'))); // Serve files from your "bower_components" directory app.use('/bower_components', express.static(path.join(__dirname + '/bower_components'))); // GET index.html route app.get('/', function(req, res) { return res.render('../Public/index'); }); still no angular – Pacman Mar 17 '16 at 23:41
  • You don't need `../Public/index`, you just need `index` when doing render, your `index.html` will load the dependencies specified in the ` – peteb Mar 17 '16 at 23:44
  • but this index now is in a different location (Views) and not my Public folder where all the angular stuff is in, I changed it to use: pp.set('views', path.join(__dirname, 'public')); app.engine('html', require('ejs').renderFile); app.set('view engine', 'html'); but angular still not working – Pacman Mar 17 '16 at 23:51
  • Please update the question with your files as they look since being modified. It doesn't matter that they're located in different folders. You've already done all the declarations for serving up the static content. As long as Angular and your Angular app are in `bower_components` and `public` respectively and you're properly including them in your ` – peteb Mar 17 '16 at 23:52
  • I updated the question with the latest code, I am served the index.html from Public, but I do not see the angular. – Pacman Mar 17 '16 at 23:56
  • You don't need the `..` before your `/bower_components`. Also make sure that your `Services` and `Views` directories are within `public` and also, you should add a `/` before them such as `/Services` and `/Views`. Your `app.js` needs to be in your `public` folder root based on your current ` – peteb Mar 17 '16 at 23:57
  • my bower_component is one level up from Public, so I do need the ../ Services and Views are inside Publi, my app.js is inside public as well – Pacman Mar 18 '16 at 00:01
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/106664/discussion-between-peteb-and-pacman). – peteb Mar 18 '16 at 00:02
  • it seems that when requesting app.js, the path it is looking in is: http://localhost:8080/app.js, it doesnt add the "Public" to the path so I get 404 error even if I add the Public to the public script path, I still get 404 error – Pacman Mar 18 '16 at 14:37