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

[Discussion] .Net Core: Alternative approaches #1221

Closed
naveedahmed1 opened this issue Aug 30, 2019 · 6 comments
Closed

[Discussion] .Net Core: Alternative approaches #1221

naveedahmed1 opened this issue Aug 30, 2019 · 6 comments
Labels
need: investigation Requires some digging to determine if action is needed

Comments

@naveedahmed1
Copy link

What modules are related to this issue?

- [x ] aspnetcore-engine
- [ ] common
- [ x] express-engine
- [ ] hapi-engine
- [ x] module-map-ngfactory-loader

. Do we really need @nguniversal/aspnetcore-engine for SSR with .Net Core if we can do SSR without it?

Here's my main.server file:

import 'zone.js/dist/zone-node';
import 'reflect-metadata';
import { renderModule, renderModuleFactory } from '@angular/platform-server';
import { APP_BASE_HREF } from '@angular/common';
import { enableProdMode } from '@angular/core';
import { provideModuleMap } from '@nguniversal/module-map-ngfactory-loader';
import { createServerRenderer } from 'aspnet-prerendering';
export { AppServerModule } from './app/app.module.server';

import * as myGlobals from './app/globals';

enableProdMode();

export default createServerRenderer(params => {
  const { AppServerModule, AppServerModuleNgFactory, LAZY_MODULE_MAP } = (module as any).exports;
  const options = {
    document: params.data.originalHtml,
    url: params.url,
    extraProviders: [
      provideModuleMap(LAZY_MODULE_MAP),
      { provide: APP_BASE_HREF, useValue: params.baseUrl },
      { provide: 'BASE_URL', useValue: params.origin + params.baseUrl }
    ]
  };

  const renderPromise = AppServerModuleNgFactory
    ? /* AoT */ renderModuleFactory(AppServerModuleNgFactory, options)
    : /* dev */ renderModule(AppServerModule, options);

  return renderPromise.then((html) => {

    let statusCode: number = 200;
    if (myGlobals.response.statusCode == 404) {
      statusCode = 404;
      //reset status code to 200 for next request
      myGlobals.response.statusCode = 200;
    }

    return {
      html: statusCode == 404 ? '<!DOCTYPE html><html lang="en"><head><title>404 Page Not Found</title><META NAME="ROBOTS" CONTENT="NOINDEX, NOFOLLOW"></head><body>>Error! Page not found</body></html>' : html, StatusCode: statusCode
    }

  });
});

And below is the .Net Code in Startup.cs file:

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
app.UseSpa(spa =>
            {
                spa.Options.SourcePath = "ClientApp";

                spa.UseSpaPrerendering(options =>
                {
                    options.BootModulePath = $"{spa.Options.SourcePath}/dist-server/main.js";
                    options.BootModuleBuilder = env.IsDevelopment() ? new AngularCliBuilder(npmScript: "build:ssr") : null;
                    options.ExcludeUrls = new[] { "/sockjs-node" };
                });

                if (env.IsDevelopment())
                {
                    spa.UseAngularCliServer(npmScript: "start");
                }
            });

}

This setup works fine, and can return HTTP status code e.g. 404 in case of page not found errors.

Using this approach we can setup page title and meta tags directly from Angular app i.e. using Meta, Title services from Angular.

import { Meta, Title } from '@angular/platform-browser';

The only issue with this approach is that we can not enable optimization ("optimization": false,) for server builds as a result the server bundle is not treeshaken due to this issue:

angular/angular-cli#8616

I would like to know your feedback on this approach.

@MarkPieszak @paolomainardi @PatrickJS @Toxicable @vikerman

@naveedahmed1
Copy link
Author

I have found one solution to optimize bundle:

  1. Disable optimizations i.e. "optimization": false, in angular.json file.
  2. Enable bundle dependencies "bundleDependencies": "all", in angular.json file.
  3. Build your bundle (in my case npm run build:ssr). This will generate a large bundle., in my case the size of the bundle is 9.89Mb with IVY Enabled.
  4. Install terser plugin npm install terser -g
  5. Run terser to minify bundle terser dist-server/main.js -o dist-server/main.js -c -m --keep-fnames. The compressed build in my case is of 3.9mb i.e. ~60% reduction.

@CaerusKaru
Copy link
Member

I don't think there's ever been a firm, "you have to do it this way" for any of the @nguniversal packages. They exist to make life easier for people in certain situations. We're certainly not going to unpublish one of our packages just because there is one other way to do it.

@MarkPieszak feel free to chime in here. If you feel that this is the better way to go, we can certainly publish more than one package.

@CaerusKaru CaerusKaru changed the title .Net Core: We can do SSR without @nguniversal/aspnetcore-engine then why use this package? [Discussion] .Net Core: Alternative approaches Sep 16, 2019
@vikerman
Copy link
Contributor

Just one update - With 9.0(@next version) we also fixed all optimization issues with server bundles and is actually on by default for new projects. You should be able to use "optimization": true for existing projects.

@vikerman vikerman added the need: investigation Requires some digging to determine if action is needed label Sep 25, 2019
@naveedahmed1
Copy link
Author

@vikerman thanks for sharing, yes I can confirm this works perfectly with .net core project.

@alan-agius4
Copy link
Collaborator

It is still beneficial to use the an engine for additional functionality such as inlining of critical css.

That said, in future we might deprecate the aspnetcore-engine in favor of the common-engine. Although at the moment it is not clear how .NET 5 is going to support SSR due to the removal of the SpaServices and NodeServices. See: dotnet/aspnetcore#12890.

@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 Feb 13, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
need: investigation Requires some digging to determine if action is needed
Projects
None yet
Development

No branches or pull requests

4 participants