Angular-cli: ng build --prod breaks routes error "cannot match any routes"

Created on 20 Jun 2017  路  23Comments  路  Source: angular/angular-cli

Bug Report or Feature Request (mark with an x)

- [ ] bug report -> please search issues before submitting
- [ ] feature request

Versions.


@angular/cli: 1.0.0
node: 6.9.2
os: win32 x64
@angular/common: 4.2.2
@angular/compiler: 4.2.2
@angular/core: 4.2.2
@angular/forms: 4.2.2
@angular/http: 4.2.2
@angular/platform-browser: 4.2.2
@angular/platform-browser-dynamic: 4.2.2
@angular/router: 4.2.2
@angular/cli: 1.0.0
@angular/compiler-cli: 4.2.2

Repro steps.

Simple steps to reproduce this bug.
Before bundling the app it works all fine, but once its bundled up it somehow can't find any routes on IE but works on chrome just fine.

ng build --prod --base-href ./ this seems to work on chrome, but not IE if the base is just / it doesn't work at all. Then just redirects me to the IIS root folder. _Tried --base-href='/Demo/AppFiles/_ didn't work as well.

I copied the dist folder and stick it to my IIS server.

Router.ts

const routes: Routes = [
    {
        path: '',
        component: CatalogsComponent,
        pathMatch: 'full'
    }
];

export const appRoutingProviders: any[] = [];

// - Updated Export
export const routing = RouterModule.forRoot(routes);

The log given by the failure.

ERRORError: Uncaught (in promise): Error: Cannot match any routes. URL 
Segment: 'SalesNew
Error: Cannot match any routes. URL Segment: 'SalesNew'
   at Anonymous function 

Also when I refresh the page it goes to 404 error.

Directory tree

/root
  /Appfolder(SalesNew
    /AppFiles (index.html, etc)
investigation

Most helpful comment

My issue was that I was trying to create my routes array dynamically based on components. Angular 4 uses UglifyJS in production to rename components and types. The result was incorrect routes. Creating a static array of routes fixed the issue for me.

const appRoutes: Routes = [
  {
    path: '',
    component: HomeComponent
  },
  {
     path: 'login',
     component: LoginComponent
  }
];

All 23 comments

Hmm strange, I have to use {provide: LocationStrategy, useClass: HashLocationStrategy} for it to work without any error :/ this gives www.site.com/app/#/. Can someone point out what's wrong here, hash solves it but I don't really want to have hash in the URL.

I can reproduce the issue as well. In case required for anyone:

Repro steps.

  1. Clone repository: https://github.com/kichnan/ng-app
  2. Run following commands:

    1. npm install

    2. npm run build

  3. Host application anywhere in your local as http://localhost/ng-app-sample/. Does NOT WORK.
  4. Run npm start, and open application http://localhost:4205/. Does WORK.

Fixed with IIS web.config and with --base-href='/AppFolder'/

<configuration>
    <system.webServer>
        <rewrite>
        <rules>
            <rule name="AngularJS Routes" stopProcessing="true">
            <match url=".*" />
            <conditions logicalGrouping="MatchAll">
                <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
                <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
            </conditions>
            <action type="Rewrite" url="/AppFolder/" />
            </rule>
        </rules>
        </rewrite>
    </system.webServer>
</configuration>

@estradamarkie Hi... can you check out my repo and try making that application work? I have my base-href properly set. The dev mode has always built and ran fine when hosted in IIS.

If I compile the app in dev mode, ng build --env=dev --base-href /ng-app-sample/, and host those files, the routing works fine. Hence, I figure that this has got something to do with the "prod" mode. Also, I had someone test the dist file on a different web-server than IIS. It didn't work there either. (I'll check with that person again.)

The IIS web.config does a 404 redirection instead of url.rewrite actually. Here it is:
<?xml version="1.0" encoding="UTF-8"?> <configuration> <system.webServer> <httpErrors existingResponse="Replace" errorMode="Custom"> <remove statusCode="404" subStatusCode="-1" /> <error statusCode="404" prefixLanguageFilePath="" path="/ng-app-sample/index.html" responseMode="ExecuteURL" /> </httpErrors> </system.webServer> <system.web> <sessionState mode="Off" /> <httpRuntime requestValidationMode="2.0" requestPathInvalidCharacters="&lt;,&gt;,%,&amp;,\,?,*" /> <pages validateRequest="false" /> </system.web> </configuration>

Try to use the web.config I have in my post above and just change the rewrite path to where you host your app. I bundled my app using prod env when I posted my fix, so its just configuring your server to redirect to your app index.html. You don't necessarily need to specify index.html in the web config just the the directory.

Nope. Doesn't work. :( The sample application I have is a dead-simple one (ref: screenshot below). The default URL http://localhost/ng-app-sample/ works with or without the url-rewrite rules. That is because it is the main/primary page to be loaded.

I also completely realize that this bug is not possible! The Angular team cannot miss something so basic. So, there is definitely something I'm doing wrong. Any help would be appreciated. Meanwhile, I'll keep trying from my end as well. Thanks.

image

Quick update: I'm attaching main.bundle.js files.
Bundle that works: main.c70bc6dc97933f4525f1.bundle.txt
Bundle that does NOT work: main.d2818fc0b709592f3eeb.bundle.txt

NOTE:
OH! I totally missed one detail:
The source file app-routes.ts has TWO variables: orgRoutes and routes. If I use the first-created variable orgRoutes, then my application works fine. If I use the second variable routes which is created _using_ orgRoutes, then the app fails. The bundle doesn't contain routes variable AT ALL.

Hope this helps!

QUESTION: If you are able to reproduce this issue, should I create a "New Issue" for this one, or is it better to reopen this issue?

My issue was that I was trying to create my routes array dynamically based on components. Angular 4 uses UglifyJS in production to rename components and types. The result was incorrect routes. Creating a static array of routes fixed the issue for me.

const appRoutes: Routes = [
  {
    path: '',
    component: HomeComponent
  },
  {
     path: 'login',
     component: LoginComponent
  }
];

Can someone help me on this? I created the routes as static array, my main.bundle.js has the variable routes (the name of static array) and I am able to see the image in assets using url to that assets/image path. Where as, I am getting the errors - uncaught: cannot match any routes and 404() on the image.

screen shot 2017-11-09 at 5 37 46 pm

@estradamarkie @kichnan @jkuczek15 Can you help resolve the problem above? TIA

Without seeing the code it's difficult to tell what's happening. Ensure that you have a valid route and component associated with the route. Then display the image via the component. Also ensure that you can display the image in a standard html before throwing it into a component.

Hi mates,

I use first please excuse my English, it's not my native language..

My problems seems to be similar to this topic.

I use the Github repo to deploy my app.
I have no problem with localhost when I try to get my REST API, but I've the Promise error when I push with angular-cli-ghpages.

I resolve with a CNAME from my DNS.

Here's the app link :
[(http://mean.negi.fr/)]

The Github Repo:
[https://github.com/BlackNeo/gedprocedures]

Here's my code :

server.js

const express = require('express');
const bodyParser = require('body-parser');
const path = require('path');

const api = require('./server/routes/api');

const port = 3000;

const app = express();

app.use(express.static(path.join(__dirname, 'dist')));

app.use(bodyParser.urlencoded({extended: true}));
app.use(bodyParser.json());

app.use('/api', api);

app.use('*', function allowCrossDomain(res, req, next) {
    res.header('Access-Control-Allow-Origin', 'example.com');
    res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
    res.header('Access-Control-Allow-Headers', 'Content-Type');
    next();
});

app.get('*', (req, res) => {
    res.sendFile(path.join(__dirname, 'dist/index.html'));
});

app.listen(port, function() {
    console.log("Server running on localhost :" + port);
});

server/routes/api.js

const express = require('express');
const bodyParser = require('body-parser');
const path = require('path');

const api = require('./server/routes/api');

const port = 3000;

const app = express();

app.use(express.static(path.join(__dirname, 'dist')));

app.use(bodyParser.urlencoded({extended: true}));
app.use(bodyParser.json());

app.use('/api', api);

app.use('*', function allowCrossDomain(res, req, next) {
    res.header('Access-Control-Allow-Origin', 'example.com');
    res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
    res.header('Access-Control-Allow-Headers', 'Content-Type');
    next();
});

app.get('*', (req, res) => {
    res.sendFile(path.join(__dirname, 'dist/index.html'));
});

app.listen(port, function() {
    console.log("Server running on port :" + port);
});

server/models/user.js

`const mongoose = require('mongoose');

const Schema = mongoose.Schema;

const usersSchema = new Schema ({
    username: String,
    password: String
});

module.exports = mongoose.model('users', usersSchema, 'users');

src/app/user.service.ts

const mongoose = require('mongoose');

const Schema = mongoose.Schema;

const usersSchema = new Schema ({
    username: String,
    password: String
});

module.exports = mongoose.model('users', usersSchema, 'users');

src/app/app-routing.module.ts

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { HomeComponent } from './home/home.component';
import { LoginComponent } from './login/login.component';
import { PanelComponent } from './panel/panel.component';

const routes: Routes = [
  {path: '', pathMatch: 'full', component: HomeComponent},
  {path: 'panel', component: PanelComponent},
  {path: 'login', component: LoginComponent}
];

@NgModule({
  imports: [RouterModule.forRoot(routes, { useHash: true})],
  exports: [RouterModule],
  providers: []
})
export class AppRoutingModule { }`

src/app/app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppRoutingModule } from './app-routing.module';

import { AppComponent } from './app.component';
import { HomeComponent } from './home/home.component';
import { LoginComponent } from './login/login.component';
import { PanelComponent } from './panel/panel.component';
import { GedComponent } from './ged/ged.component';
import { FormsModule } from '@angular/forms';
import { ListComponent } from './list/list.component';
import { HttpModule } from '@angular/http';

@NgModule({
  declarations: [
    AppComponent,
    HomeComponent,
    LoginComponent,
    PanelComponent,
    GedComponent,
    ListComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    FormsModule,
    HttpModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

src/app/panel/panel.component.html

import { Component, OnInit } from '@angular/core';
import { User } from '../user';
import { UserService } from '../user.service';

@Component({
  selector: 'app-panel',
  templateUrl: './panel.component.html',
  styleUrls: ['./panel.component.css'],
  providers : [UserService]
})
export class PanelComponent implements OnInit {

  users: Array<User>;

  selectedUser: User;

  isLogin: boolean;

  constructor(private _userService: UserService) { }

  ngOnInit() {
    this.isLogin = true;
    this._userService.getUsers()
      .subscribe(resUserData => this.users = resUserData);
  }

  onSelectUser(user: any) {
    this.selectedUser = user;
    this.isLogin = false;
    console.log(this.selectedUser);
  }
}

npm run deploy :
ng build --prod && angular-cli-ghpages --branch gh-pages

If someone can tell me what I'm doing wrong ?
Thanks

For prod use this command

ng build --prod --base-href ./test--deploy-url ./

and I faced the same issue apply, all possible solution but finally, this solve my problem

`

export class AppRoutingModule {

constructor(private router: Router) {

    this.router.errorHandler = (error: any) => {

        this.router.navigate(['404']); // or redirect to default route

    }

  }

}

`
Hope this will help you.

@estradamarkie Could you reopen this issue, seems a lot people are still having problems (me included)

@larssn
Hi,
It's open again, from what I can see from my IIS fixed that my redirect is always pointing to my angular-cli project folder.

when rebuilding for prod --base-href='/AppFolder'/
IIS: see my IIS fixed above see match url and rewrite line.

Edit: but I would really open a new ticket instead if this issue still exists in the new version of ng-cli.

Thanks

Thanks for reopening.

We're using Cordova, so its a different environment than IIS.

In our case it seems that relative paths break in production mode:

Works in dev, breaks in prod:
this.router.navigate(['./', { outlets: { popup: ['product-modal'] } }], { relativeTo: this.actRoute, queryParamsHandling: 'preserve' });

Switching to absolute routing fixes it, but not a real solution:
this.router.navigate(['sales', { outlets: { popup: ['product-modal'] } }], { queryParamsHandling: 'preserve' });

for me, it is because I have a for loop to "dynamiclly" construct the routing object. it works with ng serve, but not work with ng build.
After removing for-loop, it went back to work.

Are you still able to reproduce the issue? If it's still reproducible, would you share a minimal demo?

Closing the issue due to inactivity. If the problem still exists in the latest version of the CLI, please open a new issue following the template and providing a minimal demo where we can reproduce it. Thanks! :-)

Closing the issue due to inactivity. If the problem still exists in the latest version of the CLI, please open a new issue following the template and providing a minimal demo where we can reproduce it. Thanks! :-)

Thank you for replying! And it sounds it's been resolved in the new released CLI? But anyway, I will give it a try in Angular CLI 7 when I get a chance! Absolutely appreciate it.

@mgechev sir i have the same problem in prod , but only the first time you open the app and after refresh the page every thing works fine
kindly advice

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

_This action has been performed automatically by a bot._

Was this page helpful?
0 / 5 - 0 ratings