Skip to content

SSR builder and externals dependencies (Angular 9) #16348

Closed

Description

@kamilmysliwiec

Bug Report

In relation to the conversation with @manfredsteyer.

What is the expected behavior?

In some specific scenarios, I would like to bundle dependencies and minify the code of my Angular application, but at the same time leave my server-side code untouched (no dependencies bundled, no minification/obfuscation). This is important because:

  • sometimes you may not want to bundle all server dependencies (especially when you're building a full-stack app). For instance, you won’t be able to bundle pg (if you use postgres) as well as internal deps of mongoose (or bcrypt) because they use a native node.js binaries (C++ code)
  • sometimes you may not want to obfuscate class names, properties names, function names etc because there are important for libraries such as Typeorm (to automatically create columns with proper names in a database) or e.g. NestJS. Having full control over what can be optimized for server-side is quite important here

What is the current behavior?

When I try to set bundleDependencies to none under server configuration in angular.json, the application will stop working:

image

Both serve:ssr and serve:ssr:dev won't work.

Also, I'm not entirely sure how I can determine the behavior of webpack for the server part now. Previously, we had webpack.server.config in which we could simply use plugins like nodeExternals or set optimization to false (to avoid code minification). This is worth adding to the docs (how to accomplish this now with a new setup).

What modules are related to this issue?

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

Minimal reproduction with instructions:

No reproduction needed - new Angular app with ng add @nguniversal/express-engine@next (or any other engine)

What is the use-case or motivation for changing an existing behavior?

Mainly full-stack applications, compatibility with other Node.js platforms

Environment:

@nguniversal versions

  • aspnetcore-engine:
  • common:
  • express-engine: 9.0.0-next.7
  • hapi-engine:
  • module-map-ngfactory-loader:
Angular CLI: 9.0.0-rc.4
Node: 12.13.0
OS: darwin x64

Angular: 9.0.0-rc.4

Is there anything else we should know?

Activity

  1. self-assigned this
    on Dec 3, 2019
  2. alan-agius4 commented on Dec 4, 2019

    @alan-agius4
    Collaborator

    Hi, this is expected unless 'node_modules' are transformed using the standalone Angular compatibility compiler (NGCC).

    See: angular/universal#1327 (comment) for more context and how to address this.

  3. kamilmysliwiec commented on Dec 4, 2019

    @kamilmysliwiec
    Author
    • Disable server dependency bundling which can be done via the angular.json configuration. Under your server target options add "bundleDependencies": "none"
    • Run NGCC binary prior to building. This can be done by adding a postinstall script in your package.json - "postinstall": "ngcc"

    Following the above steps fixed the issue, thanks!

    Nonetheless, I still can't find a way to apply a custom webpack configuration to both build:ssr (for prod) and serve:ssr:dev scripts. I want to leverage builders to avoid using three different scripts (as in Angular <= 8), have a live reload built-in and at the same time, have an ability to adjust ts-loader configuration (e.g. apply plugins) and externals dynamically from js file. Is it possible?

  4. kamilmysliwiec commented on Dec 4, 2019

    @kamilmysliwiec
    Author

    Also, since adding postinstall script, manually removing & reinstalling all packages and setting bundleDependencies to none isn't straightforward, I'd suggest adding an option to the ng add UNIVERSAL_ENGINE[?] schematic that would perform all these tasks automatically (e.g. --no-bundle-server?).

    This is, in fact, very important for everyone who wants to not only serve SSR Angular app but also create, for instance, a basic REST API that connects to a database. With current setup (without manually performing all changes listed above), the following stack: express/nestjs/koa + Angular SSR + postgres/mongoose won't work properly.

  5. alan-agius4 commented on Dec 4, 2019

    @alan-agius4
    Collaborator

    Nonetheless, I still can't find a way to apply a custom webpack configuration to both build:ssr (for prod) and serve:ssr:dev scripts. I want to leverage builders to avoid using three different scripts (as in Angular <= 8), have a live reload built-in and at the same time, have an ability to adjust ts-loader configuration (e.g. apply plugins) and externals dynamically from js file. Is it possible?

    To achive this you'd need to replace the @angular-devkit/build-angular:server builder with a 3rd party builder that allows such behaviour.

    This is, in fact, very important for everyone who wants to not only serve SSR Angular app but also create, for instance, a basic REST API that connects to a database. With current setup (without manually performing all changes listed above), the following stack: express/nestjs/koa + Angular SSR + postgres/mongoose won't work properly.

    Can you elaborate please to why this doesn't work properly? Is this because @nestjs/ng-universal requires a bundle as an external file?

  6. kamilmysliwiec commented on Dec 4, 2019

    @kamilmysliwiec
    Author

    Can you elaborate please to why this doesn't work properly? Is this because @nestjs/ng-universal requires a bundle as an external file?

    It's not about @nestjs/ng-universal. Even with a default configuration and the @angular-devkit/build-angular:server builder, NestJS itself will work fine.

    The problem starts when you would like to create a real-world full-stack app with Angular SSR, regardless of whether you're going to use either express or NestJS or anything else.

    Once you try to "bundle" your app which consists of Angular, Express and MongoDB, you will see the following error:

    Error: Cannot find module './drivers/node-mongodb-native/connection'
    at webpackEmptyContext

    Why? Because mongoose depends on mongodb which depends on kerberos (C++) and node-gyp.

    Similarly, if you try to build an application which consists of Angular, Express, and Postgres (with, let's say, TypeORM as ORM), you will see this error:

    ERROR in ./node_modules/pg/lib/native/client.js
    Module not found: Error: Can't resolve 'pg-native'

    Why? Because pg depends on pg-native which depends on node-libpq (low level C++ native bindings to PostgreSQL).

    Lots of popular Node.js packages that are "required" to build a typical REST/GraphQL API depend on native bindings. With the current (default) configuration, this builder will be useless for most people who want to do more than perform server-side rendering.

  7. alan-agius4 commented on Dec 4, 2019

    @alan-agius4
    Collaborator

    I see what you mean now, maybe we should also users to specify externals in an easier manner. I'll move this to the CLI repo since that is where the server builder resides.

    We'll have a chat around this in our next team meeting and we'll decide if we should support this out-of-box or rely on 3rd party builders to allow specifying externals.

  8. removed
    needs: discussionOn the agenda for team meeting to determine next steps
    on Dec 5, 2019
  9. added a commit that references this issue on Dec 6, 2019
    6f4fef5
  10. angular-automatic-lock-bot commented on Jan 6, 2020

    @angular-automatic-lock-bot

    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.

  11. locked and limited conversation to collaborators on Jan 6, 2020
  12. added a commit that references this issue on May 29, 2026
    fb57eed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions