I've got my redirect working correctly, the only problem is now all my style sheets are being served as text/html because it's being piped through core.index It only gives me the error for style sheets too not JS. How do I resolve this?
Error:
Resource interpreted as Stylesheet but transferred with MIME type text/html:
application.js
angular.module(ApplicationConfiguration.applicationModuleName).config(['$locationProvider',
function($locationProvider) {
$locationProvider.html5Mode({
enabled: true,
requireBase: false
});
$locationProvider.hashPrefix('!');
}
])
express.js
app.use(express.static(path.resolve('./public')));
// Globbing routing files
config.getGlobbedFiles('./app/routes/**/*.js').forEach(function(routePath) {
require(path.resolve(routePath))(app);
});
var core = require('../app/controllers/core.server.controller.js');
app.get('/*', core.index);
core.server.controller.js
exports.index = function(req, res) {
res.render('index', {
user: req.user || null,
request: req
});
};
core.client.routes.js
// Setting up route
angular.module('core').config(['$stateProvider', '$urlRouterProvider',
function($stateProvider, $urlRouterProvider) {
// Redirect to home view when route not found
$urlRouterProvider.otherwise('/404');
$stateProvider
.state('admin', {
url: '/admin',
templateUrl: 'modules/core/views/home.client.admin.view.html',
});
}
]);
That would not be the correct way to serve static content - images, CSS and javascript files that run on the browser.
Take a look at this article
Basically, assuming that your directory structure is as follows:
-- public
|-- css
|-- img
`-- js
where public is the folder that contains all the sub folders for hosting stylesheets, images etc.
Then, in your nodejs code, where you have the var app = express() code, have the following code after it:
app.use(express.static('public'));
Thus, when the browser encounters a stylesheet declaration such as:
<link rel="stylesheet" href="css/style.css/>
it will make a request to /css/style.css and your express server will then correctly serve the stylesheet.
Have the code app.get("/*", core.index) at the end of all the above code to ensure that it is the last option that the server tries when attempting to match a request path to a request handler.
Related
I am trying to run AngularJS, using Angular Router, with a NodeJS server. I do not plan on serving the various views in Node, but instead I want to use the angular router. This first page is served correctly with no errors but when I try to click on another link, the browser displays the following
error code. Below is the relevant code from the server script, the routing script, and where the link in the HTML is.
HTML Link
<li>Add Workout</li>
Server.js
app.get('/', function(req, res) {
res.sendFile(path.join(__dirname + '/public/app/views/home.html'));
});
app.use(express.static('public'));
App.js
var app = angular.module("fitness2Uapp", ["ngRoute"]);
app.config(function($routeProvider) {
$routeProvider
.when("/", {
templateUrl : "./app/views/home.html"
})
.when("/browse", {
templateUrl : "./app/views/browse.html"
})
.when("/add", {
templateUrl : "./add.html"
})
.when("/workout", {
templateUrl : "./app/views/workout.html"
});
});
Try putting in a "catch all" route that just redirects back to the main page. This will in turn allow the angular routing mechanism to kick in. Right now the problem is that it's trying to find an endpoint path of '/add' on the node server, but nothing is found. This should be the very last route established on your server.
I personally use AngularJS and had to do this, and everything works great. Not sure if this will also perform the same way as Angular2+
// Catch all if all other routes fail to match.
app.get('*', (req, res) => {
res.sendFile(path.resolve(`${__dirname}/path/to/home.html`));
});
My AngularJS application won't route to /login when accessing /login directly. It will route to /login if I first access / then route from / to /login.
It is working on my local environment but not with Heroku servers. Are there some settings I have to configure on the Heroku server?
I am using angular-ui-router to route to different states throughout my application.
My app.js config snippet looks like this:
angular.module('app', [
angularUiRouter
])
.config(($stateProvider) => {
"ngInject";
$stateProvider
.state("home", {
url: "/",
template: "<home></home>"
})
.state("login", {
url: "/login",
template: "<login></login>"
});
})
Answering my own question.
Since the setup on this application is using MEAN stack, we have to also add routing from server side to client.
For all templates in AngularJS there has to be a routing from Express to AngularJS to index.html
for all templates and routings created in angular we need to get the request and send index.html in response
when we use angularjs stateProvider to route in Angularjs.., we have to also add routing to /dist/index.html from server side.
$locationProvider.html5Mode(true).hashPrefix('!'); has to be defined in app.js on AngularJS side
A snippet of my Server.js file:
var express = require('express');
var app = express();
app.use(express.static(__dirname + '/dist'));
app.get('/', function(req, res){
res.sendFile(__dirname + '/dist/index.html');
});
app.get('/login', function(req, res){
res.sendFile(__dirname + '/dist/index.html');
});
So I needed to change my URL so that google analytics could track it. Google analytics wouldn't accept it with the "/#/" (hash) in the link. That said, I used Angular's locationProvider and revised my app routing with:
(function() {
'use strict';
angular
.module('mbapp')
.config(routerConfig);
/** #ngInject */
function routerConfig($stateProvider, $urlRouterProvider, $locationProvider) {
$stateProvider
.state('home', {
url: '/',
templateUrl: 'app/main/main.html',
controller: 'MainController',
controllerAs: 'main'
});
$stateProvider
.state('steps', {
url: '/steps',
templateUrl: 'app/steps/steps.html',
controller: 'StepsController',
controllerAs: 'steps'
});
// use the HTML5 History API
$locationProvider.html5Mode(true);
$urlRouterProvider.otherwise('/');
}
})();
My URL is fine and changes it to http://website.com/steps rather than http://website.com/#/steps. However, now, if a user refreshes (f5) the link it then throw a 404 error and not sure why. Additionally, it seems that somehow this gets injected as the URL when the refresh is called "http://website/steps#/steps".
Any ideas on this?
Thanks much.
The problem is probably on the server side. You have to configure your server so it responds to every request with your html file. For example in express:
var app = require('express')();
app.configure(function(){
// static - all our js, css, images, etc go into the assets path
app.use('/assets', express.static('/assets'));
app.get('/api/users/:id', function(req, res){
// return data for user....
});
// This route deals enables HTML5Mode by forwarding missing files to the index.html
app.all('/*', function(req, res) {
res.sendfile('index.html');
});
});
When you reload the page, the request goes to the server side of your application, and it tries to resolve the url but it probably can't, because those routes only exists on the client side of your application.
Also it is a good idea to prefix every server side route with an /api route prefix, so you can easily distinguish between client side and server side routes.
I want to define a default route for single page application (angular core) using the express.js. The problem occurs when static file is requested and it does not exist in the routes. In this scenario the default page content is returned instead of the 404 status (Not Found). Sample code:
var path = require('path');
var express = require('express');
var app = express();
var router = express.Router();
router.use(express.static(path.join(__dirname, '/scripts')));
router.get('*', function(request, response) {
response.sendFile(path.join(__dirname, 'views/index.html'));
});
app.use(router);
app.listen(80);
Is exists a good solution to exclude the default route for static files and handle status 404 properly? Would a regular expression for the file urls instead of wildcard be a good approach?
You need to be able to tell if a request is being made for a script file. The problem is that you have a directory structure like this:
/root
/scripts
foo.js
bar.js
And you set up your static handler to allow for users to load scripts like this:
<script src="/foo.js"></script>
What you need to do is set up your folder structure like this:
/root
/static
/scripts
foo.js
bar.js
... then set up your static handler:
router.use(express.static(path.join(__dirname, '/static')));
... then update your script tags:
<script src="/scripts/foo.js"></script>
... and finally update your catch-all route to check if someone is trying to load a script:
router.get('*', function(request, response) {
if (request.originalUrl.indexOf("/scripts/") > -1) {
response.status(404);
response.send('Nah Nah Nah');
} else {
response.sendFile(path.join(__dirname, 'views/index.html'));
}
});
Update: It's a good idea to keep all your static assets in the static folder. You should group your assets by type: scripts, css, fonts, images, etc. Then you can update your catch-all handler to something like this which will 404 if the URL contains /scripts/, /css/, /img/, or /fonts/:
var REG_STATIC_ASSET = /\/(?:scripts|css|img|fonts)\//;
router.get('*', function(request, response) {
if (REG_STATIC_ASSET.test(request.originalUrl)) {
response.status(404);
response.send('Nah Nah Nah');
} else {
response.sendFile(path.join(__dirname, 'views/index.html'));
}
});
This is my router file:
it's nested inside a require.js block and configured to work with Jade templates
define([
'./app',
'angular.uirouter'
], function(app, angularUIRouter) {
"use strict";
// ROUTES
app.config(['$stateProvider', '$urlRouterProvider', '$locationProvider', function($stateProvider, $urlRouterProvider, $locationProvider) {
// loads url from the index
$urlRouterProvider.otherwise('/');
$locationProvider.html5Mode(true);
$stateProvider
.state('dashboard', {
url:'/dashboard',
views: {
'core' : {
templateUrl: '/articles/dashboard'
}
}
})
}]);
});
And this is my Express.js router file:
var express = require('express');
var router = express.Router();
/* GET home page. */
router.get('/', function(req, res) {
res.render('main', {
title: 'Express'
});
});
router.get('/dashboard', function(req, res) {
console.log("/dashboard requested");
});
router.get('/articles/:name', function (req, res) {
var name = req.params.name;
res.render('articles/' + name);
});
module.exports = router;
When I go to localhost:3000/dashboard, it's making a GET request to the server. How do I configure Angular UI Router to handle GET requests instead of the server?
Note: I can still go to localhost:3000/articles/dashboard and see the dashboard. Also,
a(ui-sref="dashboard")
loads the dashboard correctly.
Neither angular nor ui router can not handle server GET. Angular $locationProvider html5Mode solves only client-side setting - url does not contain # and location controls also path part in URL.
Html5 mode requires server side configuration. Every requests must return application entry point - usually index.html.
For example
router.get('/dashboard', function(req, res) {
res.sendfile('path-to/index.html');
});