Related
So I have an Angular application that I can build and run in production environment, but cannot run in dev mode.
Tried to use this command:
npm exec ng serve -c dev --port 4200 --proxy-config proxy.conf.json
and adding -c dev shows this error in the console
An unhandled exception occurred: Configuration 'dev' is not set in the workspace.
I have a environment folder with environment.prod.ts file and enviromnent.ts file
That contains :
//environment.ts
export const environment ={production: true};
//environment.prod.ts
export const environment = {development: true};
For the instance, there's a look of my angular.json file :
"$schema": "./node_modules/#angular/cli/lib/config/schema.json",
"version": 1,
"cli": {
"packageManager": "pnpm",
"analytics": "f9472df0-6689-4f76-b320-65b56b37836a"
},
"newProjectRoot": "projects",
"projects": {
"hellooara-web-ui": {
"projectType": "application",
"schematics": {
"#schematics/angular:component": {
"inlineStyle": true,
"style": "css"
}
},
"root": "",
"sourceRoot": "src",
"prefix": "app",
"architect": {
"build": {
"builder": "#angular-devkit/build-angular:browser",
"options": {
"outputPath": "target/classes/static",
"index": "src/index.html",
"main": "src/main.ts",
"polyfills": "src/polyfills.ts",
"preserveSymlinks": true,
"tsConfig": "tsconfig.app.json",
"aot": true,
"assets": [
{
"glob": "*",
"input": "node_modules/mch-common/assets/images",
"output": "assets/mch-common/images"
},
{
"glob": "*.json",
"input": "node_modules/mch-common/assets/i18n",
"output": "assets/mch-common/i18n"
},
"src/assets"
],
"styles": [
"src/styles.scss"
],
"vendorChunk": true,
"extractLicenses": false,
"buildOptimizer": false,
"sourceMap": true,
"optimization": false,
"namedChunks": true
},
"configurations": {
"production": {
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.dev.ts"
}
],
"optimization": true,
"outputHashing": "all",
"sourceMap": false,
"namedChunks": false,
"extractLicenses": true,
"vendorChunk": false,
"buildOptimizer": true,
"budgets": [
{
"type": "initial",
"maximumWarning": "2mb",
"maximumError": "5mb"
},
{
"type": "anyComponentStyle",
"maximumWarning": "6kb",
"maximumError": "100kb"
}
]
}
},
"defaultConfiguration": "development"
},
"serve": {
"builder": "#angular-devkit/build-angular:dev-server",
"options": {
"browserTarget": "hellooara-web-ui:build"
},
"configurations": {
"production": {
"browserTarget": "hellooara-web-ui:build:production"
}
}
},
"extract-i18n": {
"builder": "#angular-devkit/build-angular:extract-i18n",
"options": {
"browserTarget": "hellooara-web-ui:build"
}
},
"test": {
"builder": "#angular-devkit/build-angular:karma",
"options": {
"main": "src/test.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "tsconfig.spec.json",
"karmaConfig": "karma.conf.js",
"assets": [
"src/assets"
],
"styles": [
"src/styles.scss"
],
"scripts": []
}
},
"lint": {
"builder": "#angular-eslint/builder:lint",
"options": {
"lintFilePatterns": [
"src/**/*.ts",
"src/**/*.html"
]
}
},
"e2e": {
"builder": "#angular-devkit/build-angular:protractor",
"options": {
"protractorConfig": "e2e/protractor.conf.js",
"devServerTarget": "hellooara-web-ui:serve"
},
"configurations": {
"production": {
"devServerTarget": "hellooara-web-ui:serve:production"
}
}
}
}
}
}
}
I already tried to add an environment.dev file in environment folder, add environment into angular.json file.
Your error is correct.
Examine the following part of your angular.json:
"serve": {
"builder": "#angular-devkit/build-angular:dev-server",
"options": {
"browserTarget": "hellooara-web-ui:build"
},
"configurations": {
"production": {
"browserTarget": "hellooara-web-ui:build:production"
}
}
},
When you run ng serve -c dev what the angular cli does is use the "#angular-devkit/build-angular:dev-server" script and it looks for the configuration "dev" to override the default options (in "serve" > "options"). But you don't have a "dev" configuration, only a "production" one.
You can therefore run
ng serve (this is development by default)
ng serve -c production
Advanced: once you get comfortable you can add new configurations as you like (testing/staging/etc) with custom options. The available options are usually defined in a schema co-located where the "#angular-devkit/build-angular:dev-server" script is in node_modules.
Update per comment
The common form for environments is to do the following, referring in your application to environment.ts. You then set fileReplacements to replace environment.ts with environment.prod.ts. See https://angular.io/guide/build#configure-target-specific-file-replacements
//environment.ts
export const environment = { production: false };
//environment.prod.ts
export const environment = { production: true };
There is something called "serve" property in angular.json
"serve": {
"builder": "#angular-devkit/build-angular:dev-server",
"configurations": {
"devServer": {
"browserTarget": "myApp:build:devServer"
},
}
once did that try running
ng serve -c devServer
UPDATE 1:
"serve": {
"builder": "#angular-devkit/build-angular:dev-server",
"options": {
"browserTarget": "hellooara-web-ui:build"
},
"configurations": {
"production": {
"browserTarget": "hellooara-web-ui:build:production"
},
"development": {
"browserTarget": "hellooara-web-ui:build:development"
}
}
},
ng add #nguniversal/express-engine --clientProject cookbook
When I run this command to make my application angular universal. I get errors telling me the schema is not valid
Error Message from Console
gettingstarted#gettingstarted:~/WebstormProjects/cookbook$ ng add #nguniversal/express-engine --clientProject cookbook
ℹ Using package manager: npm
✔ Found compatible package version: #nguniversal/express-engine#14.2.0.
✔ Package information loaded.
The package #nguniversal/express-engine#14.2.0 will be installed and executed.
Would you like to proceed? Yes
✔ Packages successfully installed.
Schematic input does not validate against the Schema: {"clientProject":"cookbook","project":"cookbook"}
Errors:
Data path "" must NOT have additional properties(clientProject).
gettingstarted#gettingstarted:~/WebstormProjects/cookbook$
Angular.json
{
"$schema": "./node_modules/#angular/cli/lib/config/schema.json",
"cli": {
"analytics": false
},
"version": 1,
"newProjectRoot": "projects",
"projects": {
"cookbook": {
"projectType": "application",
"schematics": {
"#schematics/angular:application": {
"strict": true
}
},
"root": "",
"sourceRoot": "src",
"prefix": "app",
"architect": {
"build": {
"builder": "#angular-devkit/build-angular:browser",
"options": {
"outputPath": "dist/cookbook",
"index": "src/index.html",
"main": "src/main.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "tsconfig.app.json",
"assets": [
"src/favicon.ico",
"src/assets"
],
"styles": [
"./node_modules/bootstrap/dist/css/bootstrap.min.css",
"src/styles.css"
],
"scripts": [
"./node_modules/bootstrap/dist/js/bootstrap.min.js",
"./node_modules/jquery/dist/jquery.js",
"./node_modules/#popperjs/core/dist/umd/popper.min.js"
]
},
"configurations": {
"production": {
"budgets": [
{
"type": "initial",
"maximumWarning": "500kb",
"maximumError": "1mb"
},
{
"type": "anyComponentStyle",
"maximumWarning": "2kb",
"maximumError": "4kb"
}
],
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.prod.ts"
}
],
"outputHashing": "all"
},
"development": {
"buildOptimizer": false,
"optimization": false,
"vendorChunk": true,
"extractLicenses": false,
"sourceMap": true,
"namedChunks": true
}
},
"defaultConfiguration": "production"
},
"serve": {
"builder": "#angular-devkit/build-angular:dev-server",
"configurations": {
"production": {
"browserTarget": "cookbook:build:production"
},
"development": {
"browserTarget": "cookbook:build:development"
}
},
"defaultConfiguration": "development"
},
"extract-i18n": {
"builder": "#angular-devkit/build-angular:extract-i18n",
"options": {
"browserTarget": "cookbook:build"
}
},
"test": {
"builder": "#angular-devkit/build-angular:karma",
"options": {
"main": "src/test.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "tsconfig.spec.json",
"karmaConfig": "karma.conf.js",
"assets": [
"src/favicon.ico",
"src/assets"
],
"styles": [
"src/styles.css"
],
"scripts": []
}
}
}
}
}
}
I am testing a new aproach in my front end App build with Angular, and i want to hide the API url from the browser Network. form example : to call login on api.url.dz/login i want to call front.url.dz/login on the front then redirecte this to api.url.dz/login .
here is my proxy.config.json file :
{
"http://localhost:4200":{
"target":"http://localhost:9999/",
"secure":false,
"changeOrigin": true,
"logLevel":"debug",
"pathRewrite": {"^/authenticate": "authenticate",
"^/authenticate-refresh": "authenticate-refresh",
"^/refresh-token": "refresh-token",
"^/auth-logout": "auth-logout"
}
}
}
this works on localhost because i start project with this command :
ng serve --proxy-config proxy.config.json
but in production server when executing :
ng build
it doesn't work
this is the config in prod server :
{
"https://front.domaine.dz":{
"target":"https://back.domaine.dz:9999",
"secure":false,
"changeOrigin": true,
"logLevel":"debug",
"pathRewrite": {"^/authenticate": "authenticate",
"^/authenticate-refresh": "authenticate-refresh",
"^/refresh-token": "refresh-token",
"^/auth-logout": "auth-logout"
}
}
}
i want to know if there is an alternative to execute with proxy option in ng build command ?
angular.json :
{
"$schema": "./node_modules/#angular/cli/lib/config/schema.json",
"version": 1,
"newProjectRoot": "projects",
"projects": {
"argon-dashboard-angular": {
"root": "",
"sourceRoot": "src",
"projectType": "application",
"prefix": "app",
"schematics": {
"#schematics/angular:component": {
"styleext": "scss"
}
},
"architect": {
"build": {
"builder": "#angular-devkit/build-angular:browser",
"options": {
"outputPath": "dist",
"index": "src/index.html",
"main": "src/main.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "src/tsconfig.app.json",
"assets": [
"src/favicon.ico",
"src/assets"
],
"styles": [
"./node_modules/#angular/material/prebuilt-themes/indigo-pink.css",
"src/styles.scss",
"src/assets/scss/argon.scss"
],
"scripts": [
"node_modules/chart.js/dist/Chart.min.js",
"node_modules/clipboard/dist/clipboard.min.js"
]
},
"configurations": {
"production": {
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.prod.ts"
}
],
"optimization": true,
"outputHashing": "all",
"sourceMap": false,
"extractCss": true,
"namedChunks": false,
"aot": true,
"extractLicenses": true,
"vendorChunk": false,
"buildOptimizer": true
}
}
},
"serve": {
"builder": "#angular-devkit/build-angular:dev-server",
"options": {
"browserTarget": "argon-dashboard-angular:build"
},
"configurations": {
"production": {
"browserTarget": "argon-dashboard-angular:build:production"
}
}
},
"extract-i18n": {
"builder": "#angular-devkit/build-angular:extract-i18n",
"options": {
"browserTarget": "argon-dashboard-angular:build"
}
},
"test": {
"builder": "#angular-devkit/build-angular:karma",
"options": {
"main": "src/test.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "src/tsconfig.spec.json",
"karmaConfig": "src/karma.conf.js",
"styles": [
"./node_modules/#angular/material/prebuilt-themes/indigo-pink.css",
"src/styles.css"
],
"scripts": [],
"assets": [
"src/favicon.ico",
"src/assets"
]
}
},
"lint": {
"builder": "#angular-devkit/build-angular:tslint",
"options": {
"tsConfig": [
"src/tsconfig.app.json",
"src/tsconfig.spec.json"
],
"exclude": [
"**/node_modules/**"
]
}
}
}
},
"argon-dashboard-angular-e2e": {
"root": "e2e/",
"projectType": "application",
"architect": {
"e2e": {
"builder": "#angular-devkit/build-angular:protractor",
"options": {
"protractorConfig": "e2e/protractor.conf.js",
"devServerTarget": "argon-dashboard-angular:serve"
},
"configurations": {
"production": {
"devServerTarget": "argon-dashboard-angular:serve:production"
}
}
},
"lint": {
"builder": "#angular-devkit/build-angular:tslint",
"options": {
"tsConfig": "e2e/tsconfig.e2e.json",
"exclude": [
"**/node_modules/**"
]
}
}
}
}
},
"defaultProject": "argon-dashboard-angular",
"schematics": {
"#schematics/angular:component": {
"styleext": "scss"
}
},
"cli": {
"analytics": false
}
}
Angular proxy is not meant to be used in production.
You can circumvent this by running ng serve with your proxy configuration in production but that's bad practice.
You have to configure your web server (apache/nginx/other) to proxy requests according to your proxy.config.json (as in, use the relevant directives to get the same behavior as your proxy.config.json).
For instance, you can use ProxyPass and ProxyPassReverse with Apache.
I am building an Angular app and, when I tried to locally render it in the server side using Angular SSR (https://angular.io/guide/universal). It successfully compiles and runs the server side generated file, that's the message I get:
Node Express server listening on http://localhost:4000
However, when I try to access the specified addresss provided by the CLI, I get this error:
Error: Failed to lookup view "index" in views directory "projects/project-name/frontend/dist/server/dist/project-name/browser"
at Function.render (Documents/projects/project-name/frontend/dist/server/main.js:139878:17)
I noticed one thing: it's nesting the project folder.
I tried to follow along with some tutorials but I can't manage to find a solution. I have tried changing my angular.json file several times but no luck.
I know you guys don't like quesitons inside another questions but this might be related:
I have set up a multilingual app that also generates a nested path: example: dist/es/es instead of dist/es I really tried searching everywhere for a solution but couldn't find any that could solve my issue so I hope someone with more experience can enlighten me.
In my understanding, when I run npm run dev:ssr it should work, but it doesn't So I am hoping and praying someone can help me.
Heres my angular.json file
{
"$schema": "./node_modules/#angular/cli/lib/config/schema.json",
"version": 1,
"newProjectRoot": "projects",
"projects": {
"porject-name": {
"projectType": "application",
"schematics": {
"#schematics/angular:application": {
"strict": true
}
},
"root": "",
"sourceRoot": "src",
"prefix": "app",
"i18n": {
"sourceLocale": "en-US",
"locales": {
"pt": "src/locale/messages.pt.xlf",
"baseHref": ""
}
},
"architect": {
"build": {
"builder": "#angular-devkit/build-angular:browser",
"options": {
"outputPath": "dist",
"index": "src/index.html",
"main": "src/main.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "tsconfig.app.json",
"assets": [
"src/favicon.ico",
"src/assets"
],
"styles": [
"src/styles.css"
],
"scripts": []
},
"configurations": {
"production": {
"budgets": [
{
"type": "initial",
"maximumWarning": "500kb",
"maximumError": "1mb"
},
{
"type": "anyComponentStyle",
"maximumWarning": "2kb",
"maximumError": "4kb"
}
],
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.prod.ts"
}
],
"baseHref": "./",
"outputHashing": "all"
},
"pt": {
"aot": true,
"localize": ["pt"],
"outputPath": "dist/lang",
"baseHref": "../",
"i18nMissingTranslation": "error",
},
"development": {
"buildOptimizer": false,
"optimization": false,
"vendorChunk": true,
"extractLicenses": false,
"sourceMap": true,
"namedChunks": true
}
},
"defaultConfiguration": "production"
},
"serve": {
"builder": "#angular-devkit/build-angular:dev-server",
"configurations": {
"production": {
"browserTarget": "project-name:build:production"
},
"pt": {
"browserTarget":"project-name:build:pt"
},
"development": {
"browserTarget": "project-name:build:development"
},
},
"defaultConfiguration": "development"
},
"extract-i18n": {
"builder": "#angular-devkit/build-angular:extract-i18n",
"options": {
"browserTarget": "project-name:build"
}
},
"test": {
"builder": "#angular-devkit/build-angular:karma",
"options": {
"main": "src/test.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "tsconfig.spec.json",
"karmaConfig": "karma.conf.js",
"assets": [
"src/favicon.ico",
"src/assets"
],
"styles": [
"src/styles.css"
],
"scripts": []
}
},
"server": {
"builder": "#angular-devkit/build-angular:server",
"options": {
"outputPath": "dist/server",
"main": "server.ts",
"tsConfig": "tsconfig.server.json"
},
"configurations": {
"production": {
"outputHashing": "media",
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.prod.ts"
}
]
},
"pt": {
"i18nMissingTranslation": "error"
},
"development": {
"optimization": false,
"sourceMap": true,
"extractLicenses": false
}
},
"defaultConfiguration": "production"
},
"serve-ssr": {
"builder": "#nguniversal/builders:ssr-dev-server",
"configurations": {
"development": {
"browserTarget": "project-name:build:development",
"serverTarget": "project-name:server:development"
},
"production": {
"browserTarget": "project-name:build:production",
"serverTarget": "project-name:server:production"
}
},
"defaultConfiguration": "development"
},
"prerender": {
"builder": "#nguniversal/builders:prerender",
"options": {
"routes": [
"/"
]
},
"configurations": {
"production": {
"browserTarget": "project-name:build:production",
"serverTarget": "project-name:server:production"
},
"development": {
"browserTarget": "project-name:build:development",
"serverTarget": "project-name:server:development"
}
},
"defaultConfiguration": "production"
}
}
}
},
"defaultProject": "project-name"
}
`
I have tried different configurations but nothing works.
In server.ts file, change your dist folder path, while generating build
from
const distFolder = join(process.cwd(), 'dist/project-name/browser'); // for local run
to
const distFolder = join(process.cwd(), '../browser'); // for build
I followed a tutorial for integrating Universal in our Angular 9 app.
Now we have server.ts configured.
In every tutorial I see this:
// Example Express Rest API endpoints
// app.get('/api/**', (req, res) => { });
and then:
server.get(
'*.*',
express.static(distFolder, {
maxAge: '1y',
})
);
If we leave it like that I suppose every request is cached, also what goes to /api. Is this right?
Our app has lots of "product pages" where stock and price could change frequently. So we need to have always fresh stock and price. For this reason I wouldn't cache data from server that is returned from our API calls that are in "/api/" path (or https://api.my-app.com" if absolute path is needed). Leaving everything like written above should cache everything, if I'm not wrong. I made a test changing a price directly in the database and I expected to see the old one, but it's not like that, I see always the fresh one.
So my doubt is that cache mechanism dosn't work. And also when I navigate through components I continue to see every api calls (not cached)
Can anybody explain me better this mechanism please?
Another question about this is: If cache works, how to clear it in node? Node caches in memory everything. I supposed cache would be cleared when we stop node. Is this right?
This is my package json:
"scripts": {
"ng": "node --max_old_space_size=8192 node_modules/#angular/cli/bin/ng",
"start": "npm run ng -- serve",
"serve:server": "node ./dist-server/main.js",
"serve:server:debug": "node --inspect ./dist-server/main.js",
"start:server": "npm run build:server && node ./dist-server/main.js",
"start:server:debug": "npm run build:server && node ./dist-server/main.js --inspect",
"build": "npm run ng -- build",
"build:server": "ng run my-app:server:production",
"ssr:watch": "ng run my-app:serve-ssr:production",
"demo:ssr:watch": "ng run universal-demo:serve-ssr:dev",
"build-all": "npm-run-all build-production build:server-app:prod",
"start:express-server": "ts-node -P ./src/tsconfig.server.json ./server.ts",
"prerender": "ts-node -P ./server.tsconfig.json ./prerender.ts",
"prerender:debug": "ts-node -P ./server.tsconfig.json --inspect ./prerender.ts",
"test": "npm run ng -- test",
"lint": "npm run ng -- lint",
"e2e": "npm run ng -- e2e",
"analyze": "webpack-bundle-analyzer dist/stats.json",
"compodoc": "npx compodoc -p src/tsconfig.app.json",
"build:stats": "ng build --stats-json --prod",
"build-preprod": "ng build --configuration preprod --index=/src/index/preprod/index.html",
"build-production": "ng build --configuration production --index=/src/index/production/index.html",
"build-staging": "ng build --configuration staging --index=/src/index/staging/index.html"
}
This is my angular.json:
{
"$schema": "./node_modules/#angular/cli/lib/config/schema.json",
"version": 1,
"newProjectRoot": "projects",
"projects": {
"my-app": {
"root": "",
"sourceRoot": "src",
"projectType": "application",
"prefix": "app",
"schematics": {
"#schematics/angular:component": {
"style": "scss"
}
},
"architect": {
"build": {
"builder": "#angular-devkit/build-angular:browser",
"options": {
"aot": true,
"outputPath": "dist",
"index": "src/index.html",
"main": "src/main.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "src/tsconfig.app.json",
"stylePreprocessorOptions": {
"includePaths": ["src/assets/sass"]
},
"assets": [
"src/assets",
"src/favicon.ico",
"src/manifest.json",
"src/firebase-messaging-sw.js",
"src/main-sw.js",
"src/assets/js/intersection-observer.js"
],
"styles": [
"src/styles/styles.scss",
"src/styles/my-app.scss",
"node_modules/font-awesome/css/font-awesome.css"
],
"scripts": [],
"es5BrowserSupport": true
},
"configurations": {
"staging": {
"budgets": [
{
"type": "anyComponentStyle",
"maximumWarning": "6kb"
}
],
"optimization": true,
"outputHashing": "all",
"sourceMap": false,
"extractCss": true,
"namedChunks": false,
"aot": true,
"extractLicenses": true,
"vendorChunk": false,
"buildOptimizer": true,
"ngswConfigPath": "src/app/config/ngsw-config.json",
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.staging.ts"
}
],
"serviceWorker": true
},
"preprod": {
"budgets": [
{
"type": "anyComponentStyle",
"maximumWarning": "6kb"
}
],
"optimization": true,
"outputHashing": "all",
"sourceMap": false,
"extractCss": true,
"namedChunks": false,
"aot": true,
"extractLicenses": true,
"vendorChunk": false,
"buildOptimizer": true,
"ngswConfigPath": "src/app/config/ngsw-config.json",
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.preprod.ts"
}
],
"serviceWorker": true
},
"production": {
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.prod.ts"
}
],
"optimization": true,
"outputHashing": "all",
"sourceMap": true,
"extractCss": true,
"namedChunks": true,
"aot": true,
"extractLicenses": true,
"vendorChunk": false,
"buildOptimizer": true,
"ngswConfigPath": "src/app/config/ngsw-config.json",
"budgets": [
{
"type": "initial",
"maximumWarning": "2mb",
"maximumError": "5mb"
},
{
"type": "anyComponentStyle",
"maximumWarning": "6kb"
}
],
"serviceWorker": true
}
}
},
"serve": {
"builder": "#angular-devkit/build-angular:dev-server",
"options": {
"browserTarget": "my-app:build"
},
"configurations": {
"production": {
"browserTarget": "my-app:build:production"
}
}
},
"extract-i18n": {
"builder": "#angular-devkit/build-angular:extract-i18n",
"options": {
"browserTarget": "my-app:build"
}
},
"test": {
"builder": "#angular-devkit/build-angular:karma",
"options": {
"main": "src/test.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "src/tsconfig.spec.json",
"karmaConfig": "src/karma.conf.js",
"styles": ["src/styles.scss"],
"scripts": [],
"assets": ["src/favicon.ico", "src/assets"]
}
},
"lint": {
"builder": "#angular-devkit/build-angular:tslint",
"options": {
"tsConfig": ["src/tsconfig.app.json", "src/tsconfig.spec.json"],
"exclude": ["**/node_modules/**"]
}
},
"server": {
"builder": "#angular-devkit/build-angular:server",
"options": {
"outputPath": "dist-server",
"main": "server.ts",
"tsConfig": "src/tsconfig.server.json",
"stylePreprocessorOptions": {
"includePaths": ["src/assets/sass"]
}
},
"configurations": {
"dev": {
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.prod.ts"
}
],
"optimization": true
},
"production": {
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.prod.ts"
}
],
"optimization": true
}
}
},
"serve-ssr": {
"builder": "#nguniversal/builders:ssr-dev-server",
"options": {
"browserTarget": "my-app:build",
"serverTarget": "my-app:server"
},
"configurations": {
"production": {
"browserTarget": "my-app:build:production",
"serverTarget": "my-app:server:production"
}
}
},
"prerender": {
"builder": "#nguniversal/builders:prerender",
"options": {
"browserTarget": "my-app:build:production",
"serverTarget": "my-app:server:production",
"routes": ["/"]
},
"configurations": {
"production": {}
}
}
}
},
"my-app-e2e": {
"root": "e2e/",
"projectType": "application",
"prefix": "",
"architect": {
"e2e": {
"builder": "#angular-devkit/build-angular:protractor",
"options": {
"protractorConfig": "e2e/protractor.conf.js",
"devServerTarget": "my-app:serve"
},
"configurations": {
"production": {
"devServerTarget": "my-app:serve:production"
}
}
},
"lint": {
"builder": "#angular-devkit/build-angular:tslint",
"options": {
"tsConfig": "e2e/tsconfig.e2e.json",
"exclude": ["**/node_modules/**"]
}
}
}
}
},
"defaultProject": "my-app"
}
Thanks
The following code applies to static files which are located in the dist/browser directory after building the project. These are mostly JavaScript, CSS and image files. The maxAge will set the Cache-Control header which indicates the maximum amount of time the file will be considered fresh. Again, this only applies to serving the files in dist/browser which will never change.
server.get(
'*.*',
express.static(distFolder, {
maxAge: '1y',
})
);
The following code is included just as an example of how additional endpoints can be added to the Express server: https://expressjs.com/en/guide/routing.html. It does not have anything to do with caching.
// Example Express Rest API endpoints
// app.get('/api/**', (req, res) => { });
The following code is what renders the HTML response using the Angular app. There is no caching provided for this in the default implementation because it would differ depending on how frequently content changes in your app.
server.get('*', (req, res) => {
res.render(
indexHtml,
{
req,
providers: [{ provide: APP_BASE_HREF, useValue: req.baseUrl }]
});
});
Here's some pseudocode of how caching could be implemented. The cache variable could be an in-memory cache like Redis or some other implementation.
server.get('*',
// Middleware to check if cached response exists
(req, res, next) => {
const cachedHtml = cache.get(req.url);
if (cachedHtml) {
// Cache exists. Send it.
res.send(cachedHtml);
} else {
// Cache does not exist. Render a response using the Angular app
next();
}
},
// Angular SSR rendering
(req, res) => {
res.render(
indexHtml,
{
req,
providers: [{ provide: APP_BASE_HREF, useValue: req.baseUrl }]
},
(err: Error, html: string) => {
// Cache the rendered `html` for this request url to use for subsequent requests
cache.set(req.url, html);
res.send(html);
}
);
}
);