When building an angular 2 app for production we use
ng build --prod --w --aot
But our mock services also get bundled and minified probably because we have
import {XMockService} from "./xxx-mock.service";
and that prevents the tree shaking from dropping the unused service. Here is our simplified app.module.ts which conditionally lazy-loads the mock service when environment.mock=true
I would imagine this is a common scenario but I can't find any answers for it.
app.module.ts:
import {BrowserModule} from "@angular/platform-browser";
import {NgModule} from "@angular/core";
import {FormsModule} from "@angular/forms";
import {HttpModule} from "@angular/http";
import {AppComponent} from "./app.component";
import {environment} from "../environments/environment";
import {XService} from "./xxx.service";
import {XMockService} from "./xxx-mock.service";
let importedModules: Array<any> = [
XService
];
if (environment.mock) {
importedModules.push(
{provide: XService, useClass: XMockService}
);
} else {
importedModules.push(
XService
);
}
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
FormsModule,
HttpModule
],
providers: importedModules,
bootstrap: [AppComponent]
})
export class AppModule {}
So according to one of the main contributors the solution for your problem would be something like:
// main.ts
import './polyfills.ts';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { enableProdMode } from '@angular/core';
import { environment, AppModule } from './environments/environment';
if (environment.production) {
enableProdMode();
}
platformBrowserDynamic().bootstrapModule(AppModule);
// environments/environment.ts
export { DevModule as AppModule } from '../app/dev.module';
export const environment = {
production: false
};
// environments/environment.prod.ts
export { ProdModule as AppModule } from '../app/prod.module';
export const environment = {
production: true
};
So it's very similar to my previous answer the difference is that you will be using different environment files, instead of different main files.
It was recently opened an issue on Angular-cli, requesting a feature that would allow you to that. How? By switching your webpack entry point. Right now Angular-cli will always use the same entry point src/main.ts
, the idea behind this feature is that you can specify a different entry point, so you would have something like src/main.dev.ts
:
import './polyfills.ts';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { enableProdMode } from '@angular/core';
import { environment } from './environments/environment';
import { AppDevModule } from './app/app.dev.module';
if (environment.production) {
enableProdMode();
}
platformBrowserDynamic().bootstrapModule(AppDevModule);
And then you would import your mocks on AppDevModule
:
import {BrowserModule} from "@angular/platform-browser";
import {NgModule} from "@angular/core";
import {FormsModule} from "@angular/forms";
import {HttpModule} from "@angular/http";
import {AppComponent} from "./app.component";
import {environment} from "../environments/environment";
import {XMockService} from "./xxx-mock.service";
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
FormsModule,
HttpModule
],
providers: [XMockService],
bootstrap: [AppComponent]
})
export class AppDevModule {}
The only downside of doing things this way, is that you would have to keep your AppModule
and AppDevModule
synced.
Which you could solve by creating a third file, something like AppImportsModule
:
import {BrowserModule} from "@angular/platform-browser";
import {FormsModule} from "@angular/forms";
import {HttpModule} from "@angular/http";
import {AppComponent} from "./app.component";
import {environment} from "../environments/environment";
export {AppComponent} //we also export this for simplicity
export const declarations = [
AppComponent
];
export const imports = [
BrowserModule,
FormsModule,
HttpModule
];
And then on your AppModule.ts
or AppDevModule.ts
you would only need to import your providers:
import {NgModule} from "@angular/core";
import {declarations, imports, AppComponent} from "./app.imports.module";
import {XMockService} from "./xxx-mock.service";
@NgModule({
declarations, // with es6 this is the same as "declarations: declarations"
imports, //same as above
providers: [XMockService],
bootstrap: [AppComponent]
})
export class AppDevModule {}
So until that feature isn't implemented, I have no better solution to solve your problem.
The chosen answer no longer works. For Angular CLI 6, as recommended, we'll have to treat dev & prod as separate projects sharing the same codebase.
Solution summary
Details
Make a copy of AppModule and name it DevModule. (DevModule for dev & AppModule for prod). DevModule will be the one with the mock services.
Have separate main.ts files for each. Say prod-main.ts for prod & dev-main.ts for dev. The only difference being that the prod-main loads AppModule while dev-main loads DevModule.
Duplicate the tsconfig.app.json file into tsconfig.prod.json & tsconfig.dev.json. In the exclude section of tsconfig.prod.json, type in "dev-main.ts", "app/dev-module.ts", "**/mock-*.ts". Type in the other dev modules too (the ones that load the mocks).
Repeat for dev. For tsconfig.dev.json, exclude prod-main.ts, app/app-module.ts. Make relevant changes to tsconfig.spec.json files too, if necessary (with similar excludes).
Update angular.json files to reflect the new tsconfig files.
// angular.json. Only the relevant parts are given below.
// Essentially, separate tsconfig files for 2 projects - dev & prod
{
"newProjectRoot": "projects",
"projects": {
"my-prod-proj": {
"architect": {
"build": {
"options": {
"main": "src/main-prod.ts",
"tsConfig": "src/tsconfig.app.json",
},
},
"test": {
"options": {
"tsConfig": "src/tsconfig.prod.spec.json",
}
},
"lint": {
"options": {
"tsConfig": [
"src/tsconfig.prod.json",
"src/tsconfig.prod.spec.json"
],
}
}
}
},
"my-dev-proj": {
"architect": {
"build": {
"options": {
"main": "src/dev-main.ts",
"tsConfig": "src/tsconfig.dev.json",
}
},
"test": {
"options": {
"tsConfig": "src/tsconfig.dev.spec.json",
}
},
"lint": {
"options": {
"tsConfig": [
"src/tsconfig.dev.json",
"src/tsconfig.dev.spec.json"
],
}
}
}
},
},
"defaultProject": "my-prod-proj",
}
Run the projects by name
ng serve my-dev-proj // dev with mocks
ng serve // prod (set as default in angular.json)
same goes for the build command
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With