简体   繁体   中英

Angular library module is loaded without being imported

I'm trying to use a local library (created by the Angular CLI) for sharing components between projects. I've structured the library so that it holds multiple modules, each having their own components, services and shared logic.

I have a wrapping module in the consuming projects for each module inside the library. These local modules are being lazy-loaded which AFAIK is the only way to enable lazy-loading for the library modules. I can lazy-load these local modules without problems, everything works fine, the library components load and render correctly, no errors whatsoever.

The problem is that once a Module from the library is being loaded, it does not only load that specific module, but also the other modules from the library, even though I'm not importing them in my consuming project.

How can I set this up so that only this specific Module is loaded? It seems like no tree shaking is being performed.

This is what the folder structure looks like:

├── projects
│   ├── project1
│   ├── project2
│   └── lib
│       ├── src
│       │   ├── lib
│       │   │   ├── widgets  (module1)
│       │   │   ├── blobs    (module2)
│       │   │   └── lib.module.ts
│       │   └── public-api.ts

Each of the modules inside this library has their own public-api.ts file, containing the exports for this module. For my WidgetsModule this would be:

export { WidgetsModule } from './widgets.module';

export { Importance } from './enums/importance.enum';
export { BlockItem } from './interfaces/block-item.interface';
export { WidgetConfig } from './interfaces/widget-config.interface';
export { Link } from './interfaces/link.interface';

The main public-api.ts file of the library combines all these exports:

export * from './lib/widgets/public-api';
export * from './lib/blobs/public-api';

BlobsModule is a testing module which holds an insanely large JSON blob in a component to increase the page size - just for debugging purposes.

In my consuming project, I import the WidgetsModule like this:

// widgets-wrapper.module.ts - This local module file is being lazy loaded
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { WidgetsModule } from 'lib'; // This is the library, I import *only* the WidgetsModule

import { WidgetsWrapperRoutingModule } from './widgets-routing.module';

@NgModule({
  declarations: [...],
  imports: [CommonModule, WidgetsWrapperRoutingModule, WidgetsModule], // I import it
  exports: [...]
})
export class WidgetsWrapperModule {}

I have 0 references to my BlobsModule throughout the project. WidgetsModule has 0 references or dependencies to my BlobsModule . And yet, when I browse to the page where the WidgetsWrapperModule is being lazy loaded, I can see in the Chrome networking tab that the BlobsModule , including the huge JSON blob, is being downloaded as well. I can see this ending badly when I have 30+ modules in this library. I do not want to load them all when I only require 1 tiny module.

Perhaps the built-in library support from Angular isn't able to do this? Do I have to switch to eg ng-packagr for this to work the way I want it to?

UPDATE:

Running "ng serve project1" (which uses the library) produces the following chunk: widgets-widgets-module.js . This chunk holds the code for both WidgetsModule and BlobsModule which I really don't think should be happening?

Running "ng serve project1 --prod" removes the BlobsModule from the chunk which is what I'd expect, so this is good.

However, when also creating a new route in the project which will lazy load BlobsModule , the following chunks get generated (both in dev and prod): widgets-widgets-module.js , blobs-blobs-modules.js and default~blobs-blobs-module~widgets-widgets-module.js .

widgets-widgets-module.js and blobs-blobs-module.js both only hold a fraction of their Modules code. default~blobs-blob-module~widgets-widget-module.js holds the biggest part, including the huge JSON blob. This huge chunk is being loaded as soon as either lazy-loading modules start loading, resulting in most of the code ( as well as the huge JSON blob which is part of BlobsModule ) being loaded when either module is being loaded, resulting in the same problem.

In a production build, this long-named chunk is being renamed to 5.xxxxxxx.js , so I do not think this is the common chunk as that filename should start with a 0. I'm also not using or referencing the BlobModule anywhere else outside of its' route, so there should be no reason to move it to a common chunk.

I've changed the library to use ng-packagr as the build tool. Now everything works as expected: all the lazy-loading works, only the required Modules are being loaded and no weird combinations for the code chunks are taking place.

The changes are actually minimal: every Module inside the library now has its own package.json file containing:

// projects/lib/src/lib/widgets/package.json
{
  "name": "lib/widgets",
  "version": "0.0.1",
  "private": true,
  "ngPackage": {
    "$schema": "../../node_modules/ng-packagr/ng-package.schema.json",
    "lib": {
      "entryFile": "public-api.ts"
    },
    "dest": "../../../../../dist/lib/widgets"
  }
}

And a change in the main package.json which I use for building the library:

// old
{
  ...
  "scripts": {
    "build": "ng build",
    ...
}

// new
{
  ...
  "scripts": {
    "build": "ng-packagr -p ./projects/lib/src/lib/widgets/package.json",
    ...
}

(the above build command has to be run for every module inside the library folder, I've created a separate script to do that for me)

And lastly, the imports inside my consuming projects have been updated as well:

// widgets-wrapper.module.ts

// old
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { WidgetsModule } from 'lib'; // <-- This

...

// new
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { WidgetsModule } from 'lib/widgets'; // <-- To this

...

Everything works flawlessly. I'm still confused why the default setup using the Angular CLI doesn't work though. I'm probably just overlooking something so I'll leave this question open for now - I'd like to return to the Angular method without using ng-packagr directly.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM