Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

First page is loaded twice in universal app #7477

Closed
sravikiran opened this issue Aug 23, 2017 · 49 comments
Closed

First page is loaded twice in universal app #7477

sravikiran opened this issue Aug 23, 2017 · 49 comments

Comments

@sravikiran
Copy link

sravikiran commented Aug 23, 2017

Bug Report or Feature Request (mark with an x)

bug report

Versions.

λ ng --version
@angular/cli: 1.3.0
node: 6.11.0
os: win32 x64
@angular/animations: 4.3.4
@angular/common: 4.3.4
@angular/compiler: 4.3.4
@angular/core: 4.3.4
@angular/forms: 4.3.4
@angular/http: 4.3.4
@angular/platform-browser: 4.3.4
@angular/platform-browser-dynamic: 4.3.4
@angular/router: 4.3.4
@angular/cli: 1.3.0
@angular/compiler-cli: 4.3.4
@angular/language-service: 4.3.4
@angular/platform-server: 4.3.4

λ node --version
v6.11.0

λ npm --version
v3.9.3

Running on Windows 10

Repro steps.

I built a sample repo using angular-cli and followed the steps in the Universal Rendering story to enable server side rendering. The application loads well on running, but I see the client rendering also happening after the page is served from the server. So the page gets rendered from the server and then the content disappears for a second as the client rendering happens.

To reproduce this, you can clone this repository, install the packages and run the following commands:

  • ng build && ng build -prod -app 1 --output-hashing none
  • node server.js

I am using the dist/index.html file instead of src/index.html, as on using the file from the src causes full page reload when I switch between the routes.

The log given by the failure.

No log, as there are no errors from npm and angular-cli

Desired functionality.

Client rendering shouldn't happen after the page is loaded from the server

@grizzm0
Copy link
Contributor

grizzm0 commented Aug 23, 2017

The server renders the page without any state and outputs static HTML to view in the browser while the angular application is being bootstrapped. A re-render when the application has been bootstrapped is required to use state saved in the browser such as logged in user information.

@sravikiran
Copy link
Author

@grizzm0 So you are saying it is a required operation. Then is there a way in which we can prevent the flicker and to make the user's experience better?

@grizzm0
Copy link
Contributor

grizzm0 commented Aug 23, 2017

Yes, it's required. The initial page contains static HTML which needs to be replaced with your angular application once bootstrapped.

I haven't tried out universal myself yet so I don't know how bad the flicker is. Anyhow, this isn't really an issue with AngularCLI but with @angular/universal. Try searching at https://github.com/angular/angular/issues to see if anyone else has reported similar issues.

@matmeylan
Copy link

I'm also experiencing a pretty bad flicker when angular bootstraps in the browser. @sravikiran Have you found an answer somewhere else ?

@sravikiran
Copy link
Author

This issue is solved in Angular 5 release. Angular 5 has State Transfer API, that allows to send the data retrieved on server to the browser. You can read about it in the following links: https://blog.angular.io/version-5-0-0-of-angular-now-available-37e414935ced and www.dotnetcurry.com/angularjs/1388/server-side-rendering-angular-nodejs

@jfahrenkrug
Copy link

@sravikiran Thanks for that great tutorial!

For all those looking at this issue to figure out how to fix the flickering issue, I believe this is the relevant part of the article:

To make the transfer state work, the Angular application must be bootstrapped after the DOM is loaded. This is because, the data transferred from the server is stored in an HTML element and this element should be accessible to Angular to get the data. Open the file main.ts and move the application bootstrap logic inside the DOMContentLoaded event as shown below:

document.addEventListener('DOMContentLoaded', () => {  
  platformBrowserDynamic().bootstrapModule(AppModule)    
  .catch(err => console.log(err));
});

@hesampour
Copy link

hesampour commented Dec 28, 2017

I have the same problem. I used asp.net core at first and then upgrade my application to angular 5 and know using angular universal. but the problem still exist. and I think google dose not render my page correctly. because when I checked my page with google console it didn't show my page correctly.

I also changed all my http to new httpClient but the problem still exist

@gimox
Copy link

gimox commented Jan 15, 2018

same problem here with angular 5.2

1 similar comment
@HuddleHouse
Copy link

same problem here with angular 5.2

@patrykp57
Copy link

That code given above by @jfahrenkrug is sometimes bugging. For example I had a problem with home page, I couldn't see view-source.

Anyway, did you get any solution for that blinking ?

@EdwinChua
Copy link

EdwinChua commented Feb 19, 2018

@sravikiran Thanks for the great tutorial!
I want to suggest an update to it:

In pokemon.service.ts :

 listPokemons() {
    let pokemons = this.state.get(POKEMONS_KEY, null as any);  //4
    if (pokemons) {
      this.state.remove(POKEMONS_KEY); // maybe add this?
      return Promise.resolve(pokemons);
    }
    return this.http.get(`${this.baseUrl}/pokedex/1/`).toPromise().then((res: any) => {
        let pokemons: Pokemon[] = [];
        let reducedPokemonEntries = res.pokemon_entries.splice(0, 50);

        reducedPokemonEntries.forEach((entry) => {
            let pokemon = new Pokemon();
            pokemon.name = entry.pokemon_species.name;
            pokemon.id = entry.entry_number;
            pokemon.imageurl = `https://rawgit.com/PokeAPI/sprites/master/sprites/pokemon/${pokemon.id}.png`;

            pokemons.push(pokemon);
    });
    if (isPlatformServer(this.platformId)) { // add this check so that state is only set when called from server
        this.state.set(POKEMONS_KEY, pokemons as any);
    }
    return pokemons;
  });
}

this.state.remove would allow the state to be cleared once it is checked. In my use case, the component loads a different article based on user interaction, and I only want to block the state once, and only when the the page is rendered on the server.

Not sure if it is a good idea to do what I did. Appreciate if anyone can point out improvements / possible mistakes in my suggestion. :)

@patrykp57 the guide works well. The page blinking/flickering has stopped for me. I implemented the guide on my own site with slight modifications as seen above.

@nishadmenezes
Copy link

nishadmenezes commented Feb 21, 2018

@gimox and @HuddleHouse did you manage to solve this issue for Angular 5.2? I am facing the same problem. Please, give me the solution if you have one.

@tedishero
Copy link

same here

@denzLLL
Copy link

denzLLL commented Feb 26, 2018

same problem here with angular 5.2

@thovo
Copy link

thovo commented Mar 7, 2018

I have similar problem with this issue in Angular 5.2.4. I have tried to add [RouterModule.forRoot(routes, { initialNavigation: 'enabled' })] but it didn't work either. Do anyone have any complete solution for this case?

@nishadmenezes
Copy link

I managed to solve the double request problem (the main reason as to why the page flickers or blinks) similar to @EdwinChua 's solution, but with a HttpInterceptor between service and the backend API.

This module should help - TransferHttpCacheModule

It has a HttpInteceptor that basically does something like @EdwinChua's solution.

I modified it a bit check for urlWithParams instead of url as I send requests sometimes with different parameters and I don't need those requests to be cached. I also, modified it to un-cache a request after the second request that was triggered gets blocked.

This basically solved the flicker on Angular 5.2

@gimox
Copy link

gimox commented Mar 8, 2018

@nishadmenezes problem is still here!.
I try first TransferHttpCacheModule it resolve some double call but not the first double call.
I add the extra code for state followin the Angular universal github guide but double cal on first page is here!

 /**
   * Get all data from http and clean it
   * transferstate is a patch, remove when universal is more stable.
   *
   *
   * @returns {Observable<DataModel>}
   */
  getData(key: string, params = null): Observable<any> {

    const PAGEID_KEY = makeStateKey<string>(key);

    // we have a trasferState data
    if (this.transferState.hasKey(PAGEID_KEY)) {

      const res = this.transferState.get(PAGEID_KEY, null);
      this.transferState.remove(PAGEID_KEY);

      return Observable.of(res);
    }

    // need to get data from http
    return this.http.get(`${environment.apiUrl}/frontend/${key}`, {params: params})
      .do(pages => {

        if (this.isServer) {
          this.transferState.set(PAGEID_KEY, pages);
        }

        return pages;
      });
  }

it' like the browser render a not processed html page first and after a 0.500 ms get the real page from server.

The only think i can do now is to add a preloading full screen page that hide after all data received in browser.
It's not a good solution!!

@hesampour
Copy link

sometimes its because of your routing. check for your routing that may be you redirect the first page to another component or module.

@masoudline
Copy link

I have same issue

@adheegm
Copy link

adheegm commented Apr 18, 2018

read this post--> angular/universal-starter#436

@patrykp57
Copy link

@adheegm I've tried that solution but still it's not working.
I made an topic on Angular repo. My problem seems to be similar. I think it only exist when you are trying to combine Service Worker and Universal together. I'm using TransferState + initialNavigation and it doesn't work also.

You can check described issue here angular/angular#23427

@hesampour
Copy link

finally I found the solution that worked.
look at the following post:
https://medium.com/@evertonrobertoauler/angular-5-universal-with-transfer-state-using-angular-cli-19fe1e1d352c

@nghenglim
Copy link

nghenglim commented Jul 1, 2018

using angular 6.0.4, even with the state transfer, the flickering will be still there:

  1. page loaded with css and with styling
  2. quick 0.1 - 0.4 sec of whiteness (even obvious with image reloading)
  3. page back with css and styling

@hinalshah91
Copy link

@nghenglim Have you implemented Angular 6 + Angular Universal + transfer state? I have some issues including transfer state to my code. Can you please help?

@hesampour
Copy link

hesampour commented Jul 4, 2018

The following link is a complete tutorial. I implement that and thank god it is OK now. I did it for angular 6+
https://medium.com/@evertonrobertoauler/angular-5-universal-with-transfer-state-using-angular-cli-19fe1e1d352c

@nghenglim
Copy link

nghenglim commented Jul 4, 2018

@hinalshah91

yes my new blog is using angular universal and transfer state. The result is better than not using it, but flickering will be still there.

flickering-universal. make service worker update on reload and use slow 3g network and disable cache. You can see the flickering.

@hinalshah91
Copy link

@nghenglim That looks great! Can you provide the steps to implement the same?

@nghenglim
Copy link

@hinalshah91 Still enhancing the app, and it currently has a bad first meaningful paint time which is near 3000ms in my browser. Thinking it could be due to the flickering from angular which makes the time to first paint actually a bit later

@pawelfurman
Copy link

pawelfurman commented Jul 4, 2018

I spend two days to find solution and still have no idea. I also couldn't find any working example (try all linked above). For me SSR is completely unuseful in this situation, I can't deploy "flickering" app on my server.
For now in my app (and each other which I tested) server returns html, and Browser app replace whole html (based on app-root tag) after load. Which, as I understand is not expected behaviour. I use APP_INITIAlIZER to prepare data before BrowserApp appears so it easy to spot 'replacing moment'.

Could you provide any, even super simple example of app, which I run on local server and which will work without html replacing? For now Im not even sure that my problem is possible to resolve. But it looks exactly the same as in @nghenglim blog example.

I work on complex app but for a sake of resolve that problem I create simple app: https://bitbucket.org/7furik7/angular-universal-test/src/master/

@nghenglim
Copy link

@pawelfurman seems like it mainly serve for SEO purpose. However it will be awesome if the flickering can be solved.

For simplicity I also created a gif to explain the flickering with the implementation of transfer state.

flickering-universal

@nghenglim
Copy link

Seems like I found that my flickering is due to lazy-module. Seems like it is fixed by using

@NgModule({
  imports: [ RouterModule.forRoot(routes, { initialNavigation: 'enabled' }) ],
  exports: [ RouterModule ]
})
export class AppRoutingModule {}

which is mentioned in angular/angular#15716

@hesampour
Copy link

hesampour commented Jul 5, 2018

you can see my implementation with angular universal 6 and state worker.
http://www.biomaze.ir

@hesampour
Copy link

when working with angular this problem sometimes happens. especially when you ram is full. I had more problem with ram. my ram would become full and sometimes my cpu usage. but this problem is exist in development not in production. when I have this problem I usually close all other applications.

@Muthu25
Copy link

Muthu25 commented Jul 21, 2018

I am having this same issue. What is the solution for this? I dont want my DOM to render again in client since it rendered at server side. Flickering is happening. We have to check condition like “not equals Browser” for our code?

@hesampour
Copy link

hesampour commented Jul 22, 2018

the solution is using state worker. you can check the following link:
https://medium.com/@evertonrobertoauler/angular-5-universal-with-transfer-state-using-angular-cli-19fe1e1d352c

@hinalshah91
Copy link

@hesampour, the above medium.com link also works with angular 6?

@hesampour
Copy link

yes. you can see my implementation in https://biomaze.org

@hinalshah91
Copy link

hinalshah91 commented Jul 24, 2018

I am using angular 6 + universal. First page is reloading twice. Can anybody help resolve this issue?Following is my angular.json file:

{
  "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
  "version": 1,
  "newProjectRoot": "projects",
  "projects": {
    "mobilesite-ecommerce": {
      "root": "",
      "sourceRoot": "src",
      "projectType": "application",
      "architect": {
        "build": {
          "builder": "@angular-devkit/build-angular:browser",
          "options": {
            "outputPath": "dist/browser",
            "index": "src/index.html",
            "main": "src/main.ts",
            "tsConfig": "src/tsconfig.app.json",
            "polyfills": "src/polyfills.ts",
            "assets": [
              {
                "glob": "**/*",
                "input": "src/assets",
                "output": "/assets"
              },
              {
                "glob": "favicon.ico",
                "input": "src",
                "output": "/"
              }
            ],
            "styles": [
              "node_modules/bootstrap/dist/css/bootstrap.min.css",
              "src/assets/fonts.css",              
              "src/styles.scss"
            ],
            "scripts": [
              "src/assets/js/commonScript.js"
            ]
          },
          "configurations": {
            "alpha": {
              "fileReplacements": [
                {
                  "replace": "src/environments/environment.ts",
                  "with": "src/environments/environment.alpha.ts"
                }
              ]
            },
            "production": {
              "optimization": true,
              "outputHashing": "all",
              "sourceMap": false,
              "extractCss": true,
              "namedChunks": false,
              "aot": true,
              "extractLicenses": true,
              "vendorChunk": false,
              "buildOptimizer": true,
              "fileReplacements": [
                {
                  "replace": "src/environments/environment.ts",
                  "with": "src/environments/environment.prod.ts"
                }
              ]
            },
            "development": {
              "fileReplacements": [
                {
                  "replace": "src/environments/environment.ts",
                  "with": "src/environments/environment.development.ts"
                }
              ]
            },
            "local": {
              "fileReplacements": [
                {
                  "replace": "src/environments/environment.ts",
                  "with": "src/environments/environment.local.ts"
                }
              ]
            }
          }
        },
        "serve": {
          "builder": "@angular-devkit/build-angular:dev-server",
          "options": {
            "browserTarget": "mobilesite-ecommerce:build"
          },
          "configurations": {
            "local": {
              "browserTarget": "mobilesite-ecommerce:build:local"
            },
            "alpha": {
              "browserTarget": "mobilesite-ecommerce:build:alpha"
            },
            "production": {
              "browserTarget": "mobilesite-ecommerce:build:production"
            },
            "development": {
              "browserTarget": "mobilesite-ecommerce:build:development"
            }
          }
        },
        "extract-i18n": {
          "builder": "@angular-devkit/build-angular:extract-i18n",
          "options": {
            "browserTarget": "mobilesite-ecommerce:build"
          }
        },
        "test": {
          "builder": "@angular-devkit/build-angular:karma",
          "options": {
            "main": "src/test.ts",
            "karmaConfig": "./karma.conf.js",
            "polyfills": "src/polyfills.ts",
            "tsConfig": "src/tsconfig.spec.json",
            "scripts": [
              "src/assets/js/commonScript.js"
            ],
            "styles": [
              "node_modules/bootstrap/dist/css/bootstrap.min.css",
              "src/assets/fonts.css",              
              "src/styles.scss"
            ],
            "assets": [
              {
                "glob": "**/*",
                "input": "src/assets",
                "output": "/assets"
              },
              {
                "glob": "favicon.ico",
                "input": "src",
                "output": "/"
              }
            ]
          }
        },
        "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": "src/main.server.ts",
            "tsConfig": "src/tsconfig.server.json"
          },
          "configurations": {
            "production": {
              "fileReplacements": [
                {
                  "replace": "src/environments/environment.ts",
                  "with": "src/environments/environment.prod.ts"
                }
              ]
            },
            "local": {
              "fileReplacements": [
                {
                  "replace": "src/environments/environment.ts",
                  "with": "src/environments/environment.local.ts"
                }
              ]
            },
            "alpha": {
              "fileReplacements": [
                {
                  "replace": "src/environments/environment.ts",
                  "with": "src/environments/environment.alpha.ts"
                }
              ]
            },
            "development": {
              "fileReplacements": [
                {
                  "replace": "src/environments/environment.ts",
                  "with": "src/environments/environment.development.ts"
                }
              ]
            }
          }
        }
      }
    },
    "mobilesite-ecommerce-e2e": {
      "root": "",
      "sourceRoot": "e2e",
      "projectType": "application",
      "architect": {
        "e2e": {
          "builder": "@angular-devkit/build-angular:protractor",
          "options": {
            "protractorConfig": "./protractor.conf.js",
            "devServerTarget": "mobilesite-ecommerce:serve"
          }
        },
        "lint": {
          "builder": "@angular-devkit/build-angular:tslint",
          "options": {
            "tsConfig": [
              "src/tsconfig.app.json",
              "src/tsconfig.spec.json",
              "e2e/tsconfig.e2e.json"
            ],
            "exclude": ["**/node_modules/**"]
          }
        },
        "server": {
          "builder": "@angular-devkit/build-angular:server",
          "options": {
            "outputPath": "dist/server",
            "main": "src/main.server.ts",
            "tsConfig": "src/tsconfig.server.json"
          },
          "configurations": {
            "production": {
              "fileReplacements": [
                {
                  "replace": "src/environments/environment.ts",
                  "with": "src/environments/environment.prod.ts"
                }
              ]
            },
            "local": {
              "fileReplacements": [
                {
                  "replace": "src/environments/environment.ts",
                  "with": "src/environments/environment.local.ts"
                }
              ]
            },
            "alpha": {
              "fileReplacements": [
                {
                  "replace": "src/environments/environment.ts",
                  "with": "src/environments/environment.alpha.ts"
                }
              ]
            },
            "development": {
              "fileReplacements": [
                {
                  "replace": "src/environments/environment.ts",
                  "with": "src/environments/environment.development.ts"
                }
              ]
            }
          }
        }
      }
    }
  },
  "defaultProject": "mobilesite-ecommerce",
  "cli": {},
  "schematics": {
    "@schematics/angular:class": {
      "spec": false
    },
    "@schematics/angular:component": {
      "spec": false,
      "inlineStyle": true,
      "inlineTemplate": true,
      "prefix": "app",
      "styleext": "scss"
    },
    "@schematics/angular:directive": {
      "spec": false,
      "prefix": "app"
    },
    "@schematics/angular:guard": {
      "spec": false
    },
    "@schematics/angular:module": {
      "spec": false
    },
    "@schematics/angular:pipe": {
      "spec": false
    },
    "@schematics/angular:service": {
      "spec": false
    }
  }
}

My package.json file:

{
  "name": "mobilesite-ecommerce",
  "version": "0.0.0",
  "license": "MIT",
  "scripts": {
    "ng": "ng",
    "start": "ng serve -c local",
    "build": "ng build",
    "test": "ng test",
    "lint": "ng lint",
    "e2e": "ng e2e",
    "build:ssr": "npm run build:client-and-server-bundles && npm run webpack:server",
    "serve:ssr": "node dist/server",
    "build:client-and-server-bundles": "ng build --prod && ng run mobilesite-ecommerce:server:production",
    "webpack:server": "webpack --config webpack.server.config.js --progress --colors",
    "build:prerender": "npm run build:client-and-server-bundles && npm run webpack:server && npm run generate:prerender",
    "generate:prerender": "cd dist && node prerender",
    "serve:prerender": "cd dist/browser && http-server",
    "build:local:ssr": "npm run build:local:client-and-server-bundles && npm run webpack:local:server",
    "serve:local:ssr": "node dist/server",
    "build:local:client-and-server-bundles": "ng build -c local && ng run mobilesite-ecommerce:server:local",
    "webpack:local:server": "webpack --config webpack.server.config.js --progress --colors",
    "build:development:ssr": "npm run build:development:client-and-server-bundles && npm run webpack:development:server",
    "serve:development:ssr": "node dist/server",
    "build:development:client-and-server-bundles": "ng build -c development && ng run mobilesite-ecommerce:server:development",
    "webpack:development:server": "webpack --config webpack.server.config.js --progress --colors",
    "build:alpha:ssr": "npm run build:alpha:client-and-server-bundles && npm run webpack:alpha:server",
    "serve:alpha:ssr": "node dist/server",
    "build:alpha:client-and-server-bundles": "ng build -c alpha && ng run mobilesite-ecommerce:server:alpha",
    "webpack:alpha:server": "webpack --config webpack.server.config.js --progress --colors"
  },
  "private": true,
  "dependencies": {
    "@angular/animations": "^6.0.6",
    "@angular/common": "6.0.6",
    "@angular/compiler": "6.0.6",
    "@angular/core": "6.0.6",
    "@angular/forms": "6.0.6",
    "@angular/http": "6.0.6",
    "@angular/platform-browser": "6.0.6",
    "@angular/platform-browser-dynamic": "6.0.6",
    "@angular/platform-server": "^6.0.6",
    "@angular/router": "6.0.6",
    "@angular/service-worker": "6.0.6",
    "@fortawesome/fontawesome-svg-core": "^1.2.0-11",
    "@fortawesome/free-brands-svg-icons": "^5.1.0-11",
    "@fortawesome/free-solid-svg-icons": "^5.1.0-11",
    "@ng-bootstrap/ng-bootstrap": "^2.1.1",
    "@ng-select/ng-select": "^2.3.0",
    "@nguniversal/common": "^6.0.0",
    "@nguniversal/express-engine": "^6.0.0",
    "@nguniversal/module-map-ngfactory-loader": "^6.0.0",
    "@ngx-share/core": "^6.0.1",
    "angular-6-social-login": "^1.1.1",
    "bootstrap": "^4.1.1",
    "core-js": "^2.4.1",
    "font-awesome": "^4.7.0",
    "localstorage-polyfill": "^1.0.1",
    "mock-browser": "^0.92.14",
    "moment": "^2.22.1",
    "ngx-swiper-wrapper": "^6.3.0",
    "node-sass": "^4.7.2",
    "rxjs": "^6.2.1",
    "sourcebuster": "^1.1.0",
    "ts-loader": "^4.4.1",
    "webpack-cli": "^3.0.8",
    "zone.js": "^0.8.26"
  },
  "devDependencies": {
    "@angular-devkit/build-angular": "~0.6.8",
    "@angular/cli": "^6.0.8",
    "@angular/compiler-cli": "6.0.6",
    "@angular/language-service": "6.0.6",
    "@types/jasmine": "~2.5.53",
    "@types/jasminewd2": "~2.0.2",
    "@types/node": "~6.0.60",
    "@types/youtube": "0.0.31",
    "codelyzer": "^4.0.1",
    "express": "^4.16.3",
    "http-server": "^0.11.1",
    "jasmine-core": "~2.6.2",
    "jasmine-spec-reporter": "~4.1.0",
    "karma": "~1.7.0",
    "karma-chrome-launcher": "~2.1.1",
    "karma-cli": "~1.0.1",
    "karma-coverage-istanbul-reporter": "^1.2.1",
    "karma-jasmine": "~1.1.0",
    "karma-jasmine-html-reporter": "^0.2.2",
    "protractor": "~5.1.2",
    "ts-node": "~3.2.0",
    "tslint": "~5.7.0",
    "typescript": "2.7.2"
  }
}

My webpack.server.config.js

const path = require("path");
const webpack = require("webpack");

// Work around for https://github.com/angular/angular-cli/issues/7200
module.exports = {
  mode: 'none',
  entry: {
    // This is our Express server for Dynamic universal
    server: './server.ts'
  },
  target: 'node',
  resolve: { extensions: ['.ts', '.js'] },
  // Make sure we include all node_modules etc
  externals: [/node_modules/],
  optimization: {
    minimize: false
  },
  output: {
    // Puts the output at the root of the dist folder
    path: path.join(__dirname, 'dist'),
    filename: '[name].js'
  },
  module: {
    rules: [
      { test: /\.ts$/, loader: 'ts-loader' },
      {
        // Mark files inside `@angular/core` as using SystemJS style dynamic imports.
        // Removing this will cause deprecation warnings to appear.
        test: /(\\|\/)@angular(\\|\/)core(\\|\/).+\.js$/,
        parser: { system: true },
      },
    ]
  },
  plugins: [
    new webpack.ContextReplacementPlugin(
      // fixes WARNING Critical dependency: the request of a dependency is an expression
      /(.+)?angular(\\|\/)core(.+)?/,
      path.join(__dirname, 'src'), // location of your src
      {} // a map of your routes
    ),
    new webpack.ContextReplacementPlugin(
      // fixes WARNING Critical dependency: the request of a dependency is an expression
      /(.+)?express(\\|\/)(.+)?/,
      path.join(__dirname, 'src'),
      {}
    )
  ]
}

@hesampour
Copy link

hesampour commented Jul 24, 2018

you are using http request in your page. HTTP request fetching data happens twice, one time on the server and one time on the browser. so for this one not happen you should use angular madule transfer state. so at first import ServerModule, ServerTransferStateModule in your AppServerModule . and import BrowserTransferStateModule in your app madule. then every where in your code that you have used http request you should make a state key as the following:

`
import { Component, OnInit } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { TransferState, makeStateKey } from '@angular/platform-browser';

const DOGS_KEY = makeStateKey('dogs');

@component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit {

title = 'app';

dogs: any;

constructor(
private http: HttpClient,
private state: TransferState
) { }

ngOnInit() {
this.dogs = this.state.get(DOGS_KEY, null as any);

if (!this.dogs) {
  this.http
    .get('https://dog.ceo/api/breeds/list/all')
    .subscribe(data => {
      this.dogs = data;
      this.state.set(DOGS_KEY, data as any);
    });
}

}
}
`

@hinalshah91
Copy link

@hesampour Have you also used prerender?

@hesampour
Copy link

yes

@hinalshah91
Copy link

The transfer state works now. However, we have one api which returns different response for different slug parameter we pass. So, if I use transfer state for that Api call with one slug parameter on one page and transfer state for same api call with different slug parameter on another page, it returns the previous response. Any solution for this?

@Hiranlive
Copy link

I have been searching for a proper solution for this issue. Seems like Transfer-State is the solution. But in my case I have used Lazy Loading on Angular too. So the issue persists. I managed to fix it by using,

@NgModule({
  imports: [RouterModule.forRoot(routes, { initialNavigation: 'enabled' }) ],
  exports: [RouterModule]
})

Try this with your project. It will resolve your flickering or reloading twice issue.

@sirajtahra
Copy link

using initialNavigation: 'enabled' removes the flickering, but in case you have a resolver in one of the lazy loaded routes, the resolver runs even before app.component.ts does, causing some weird behaviour. if i removed initialNavigation: 'enabled', app.component.ts runs first thing, and the state is loaded in my app correctly and initially, the behaviour isnt the same for initialNavigation: 'enabled'

@vggarg96
Copy link

@sirajtahra using {initialNavigation: 'enabled'} will only solve the problem partially. If u see the page getting load in frames you will see flickering still happening but will not be visible to user as it happen for a very short time. I am using angular universal and currently facing the same issue

@AndreasKz
Copy link

AndreasKz commented Aug 2, 2019

Hey guys,
just wanted to provide my solution too.
What i did to make it work is use the {initialNavigation: 'enabled'} but also implemented an interceptor creating and handling states transfer for requests caching.
Using both of these solutions fixed all flickering on my side.
Quick note: when using a transfer state interceptor, if your UI has duplicate calls to the api which you may need to have those calls in (even though i would not recommend), for instance, two sub components need to get same data from server, then dont delete the key from the state within your interceptor, otherwise, when browser boots it won't find the data that it needs and it will request data to server and re-render DOM.

// this.transferState.remove(key); // commented out

@joeabala
Copy link

joeabala commented Aug 18, 2019

In my case the issue was i had similar routes i.e for HomeComponent i was using '' and for ItemComponent i was using ':id/:category' so i had to change my ItemComponent to use 'item/:id/:category' as below:

RouterModule.forRoot([ {path: '', component: HomeComponent}, {path: 'item/:id/:category', component: ItemComponent} ])

@angular-automatic-lock-bot
Copy link

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.

@angular-automatic-lock-bot angular-automatic-lock-bot bot locked and limited conversation to collaborators Sep 18, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests