Sunday, 24 January 2021

Angular library bundle local dependency

I have two libraries: core and client.

Core is meant to be private and client is the one to be published. I want to include core inside client bundle (client uses core functions), so the final user does not need to manage core dependency.

¿How can I do this? Any help would be appreciated.

packages

packages
├── client
│   ├── ng-package.json
│   ├── node_modules
│   │   └── @lib
│   │       └── core -> ../../../core
│   ├── package-lock.json
│   ├── package.json
│   └── src
│       ├── lib
│       │   ├── client.ts
│       └── public-api.ts
└── core
    ├── ng-package.json
    ├── package-lock.json
    ├── package.json
    └── src
        ├── lib
        │   ├── core.ts
        └── public-api.ts

As you see, there is a symbolic in from packages/client/node_modules/@lib-core pointing to core. This makes that when I run the app in local environment it finds the reference to core. The problem is that after generating the build, there is no link.

core/package.json

{
  "dependencies": { "tslib": "^1.10.0" },
  "main": "src/public-api.ts",
  "name": "@lib/core",
  "scripts": {
    "build": "ng build core",
    "test": "ng test core"
  },
  "version": "0.0.1"
}

core/ng-package.json

{
  "$schema": "../../node_modules/ng-packagr/ng-package.schema.json",
  "dest": "../../dist/core",
  "lib": {
    "entryFile": "src/public-api.ts"
  }
}

client/package.json

{
  "bundledDependencies": ["@lib/core"],
  "dependencies": {
    "@lib/core": "^0.0.1",
    "tslib": "^1.10.0"
  },
  "main": "src/public-api.ts",
  "name": "@lib/client",
  "scripts": {
    "build": "ng build client",
    "test": "ng test client"
  },
  "version": "0.0.1"
}

client/ng-package.json

{
  "$schema": "../../node_modules/ng-packagr/ng-package.schema.json",
  "dest": "../../dist/client",
  "lib": {
    "entryFile": "src/public-api.ts",
    "umdModuleIds": {
      "@lib/core": "@lib/core"
    }
  },
  "whitelistedNonPeerDependencies": ["@lib/core"]
}

As you can see, I use npm bundledDependencies in client/package.json, as mentioned here. This works when running npm pack inside package/client, but I want to build with Angular first (so it generates javascript code and apply performance techniques). My intention is to pack after generating the build.

dist

After generating the bundle, I tried running npm install inside dist/client to see if the dependency could be installed and packed from there.

It throws the error 404 Not Found '@lib/core@^0.0.1' is not in the npm registry.

This is the tree of dist/client after build:

client
├── README.md
├── bundles
│   ├── lib-client.umd.js
│   ├── lib-client.umd.js.map
│   ├── lib-client.umd.min.js
│   └── lib-client.umd.min.js.map
├── esm2015
│   └── ...
├── esm5
│   └── ...
├── fesm2015
│   └── ...
├── fesm5
│   └── ...
├── lib
│   └── client.d.ts
├── lib-client.d.ts
├── package.json
└── public-api.d.ts

The dist/client/package.json has the same dependencies defined inside packages

  "bundledDependencies": [
    "@lib/core"
  ],
  "dependencies": {
    "@lib/core": "^0.0.1",
    "tslib": "^1.10.0"
  },

This are the imports in the bundles/lib-client.umd.js file:

(function (global, factory) {
    typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('tslib'), require('@lib/core')) :
    typeof define === 'function' && define.amd ? define('@lib/client', ['exports', 'tslib', '@lib/core'], factory) :
    (global = global || self, factory((global['lib'] = global['lib'] || {}, global['lib']['client'] = {}), global.tslib, global['@lib/core']));
}(this, (function (exports, tslib, core) { 'use strict';

It looks that, instead of copying core code its referencing it as an external dependency.

Recap

The objective of this question is to generate a single bundle with the library to the user.


I also have another question on how to test this in ci: Lerna package import in CI



from Angular library bundle local dependency

No comments:

Post a Comment