简体   繁体   中英

Angular is unable to resolve module path of a custom NPM package

I'm developing an Angular 13 custom library using NPM V8.19.3, and it makes use of Dynamsoft WebTwain library to manage a scanner. It should be later consumed by an Angular application in the same workspace. I started a new workspace because it is simply a "proof of concept", if it works will be made the same job on the real one.

Below I will summarize the context and the steps I followed.

  • create an empty workspace
  • add to it two projects, one of type library ( poc-scan-package ) and one of type application ( poc-scan-showcase )
  • add to the application its own package.json (so that the dependencies won't fall in the common one)
  • add the Dynamsoft WebTwain library as bundled dependency of my custom package (following this link as starting guide, but adapted to be used in a package instead of into an application) and
  • add to the common package.json a script to build the package and copy the required assets to the built package as declared in the starting guide
  • create a global link to my " dist/<package name> " folder using npm link and use that link in the application project
  • add to angular.json " projects/<application name>/architect/build/options/assets " the path where I copied the WebTwain assets
  • last step has been to change the html of the application to refer the package component, and the package component itself.

After these steps these are the relevant files/sections:

Workspace content

angular.json
{
    ...
    "projects": {
        ...
        "poc-scan-showcase": {
            "projectType": "application",
            "root": "projects/poc-scan-showcase",
            ...
            "architect": {
                "build": {
                    "options": {
                        ...
                        "assets": [
                            ...,
                            {
                                "glob": "**/*",
                                "input": "projects/poc-scan-showcase/node_modules/poc-scan-package/assets/dwt-resources/dist/",
                                "output": "assets/dwt-resources"
                            }
                        ]
                    }
                }
            }
        }
    }
}
package.json - build command:
"scripts": {
    "build:lib": "npm run build -- --project poc-scan-package && mkdir -p ./dist/poc-scan-package/assets/dwt-resources && cp ./projects/poc-scan-package/node_modules/dwt/dist ./dist/poc-scan-package/assets/dwt-resources -r"
}

Library content

package.json
{
    "name": "poc-scan-package",
    "version": "0.0.1",
    "peerDependencies": {
        "@angular/common": "^13.3.0",
        "@angular/core": "^13.3.0"
    },
    "dependencies": {
        "dwt": "^18.1.0",
        "tslib": "^2.3.0"
    },
    "bundledDependencies": [
        "dwt"
    ]
}
ng-package.json
{
    "$schema": "../../node_modules/ng-packagr/ng-package.schema.json",
    "dest": "../../dist/poc-scan-package",
    "lib": {
        "entryFile": "src/public-api.ts"
    },
    "allowedNonPeerDependencies": ["dwt"]
}
poc-scan-package.component.ts
import { Component, OnInit } from "@angular/core";
import Dynamsoft from "dwt";
import { WebTwain }  from "dwt/dist/types/WebTwain";
@Component({
    selector: "lib-poc-scan-package",
    template: `
        <button (click)="acquireImage()">Acquire Images</button>
        <div id="dwtcontrolContainer"></div>
    `
})
export class PocScanPackageComponent implements OnInit {
    DWObject: WebTwain | any = null;
    ngOnInit(): void {
        .
        .
        .
        Dynamsoft.DWT.RegisterEvent("OnWebTwainReady", () => {
            this.Dynamsoft_OnReady();
        });
        Dynamsoft.DWT.ProductKey = "YOUR-PRODUCT-KEY";
        Dynamsoft.DWT.ResourcesPath = "assets/dwt-resources"; // <--expected path for setup delivery
        Dynamsoft.DWT.Load();
    }
    .
    .
    .
}

Application content

app.component.ts
@Component({
selector: "poc-root",
    template: ` <lib-poc-scan-package></lib-poc-scan-package> `,
    styles: [],
})
export class AppComponent {
    title = "poc-scan-showcase";
}

So both the Dynamsoft object and the WebTwain interface seems to be not found during runtime. This is part of the output of the application build:

./dist/poc-scan-package/fesm2015/poc-scan-package.mjs:3:0-28 - Error: Module not found: Error: Can't resolve 'dwt' in '`/home/<username>/repos/test/poc/EmbedScanIntoPackage/dist/poc-scan-package/fesm2015`'

Error: dist/poc-scan-package/lib/poc-scan-package.component.d.ts:2:26 - error TS2307: Cannot find module 'dwt/dist/types/WebTwain' or its corresponding type declarations.

`import { WebTwain } from "dwt/dist/types/WebTwain";`
                           ~~~~~~~~~~~~~~~~~~~~~~~~~

I think to understand that the compiler is right because the built library has the expected directory remapped to " assets/dwt-resources/dist/types ", but I'm not sure why it has to look there.

I'm thinking to unlink the " dist " directory and make NPM point to the source library project, but every example I've ever seen make it point to it.

Here the link to the repo with the work I did up to now.

Let me know if I'm missing some useful information.

You can refer to my ngx-web-document-scanner project, which is a custom Angular module built with Dynamic Web TWAIN.

The projects/ngx-web-document-scanner/package.json file is very simple. You just add dwt as the peer dependency:

"peerDependencies": {
    "@angular/common": "^14.1.0",
    "@angular/core": "^14.1.0",
    "dwt": "^17.3.1"
  },

When creating an Angular project with the custom Angular module, add the asset output directory of Dynamic Web TWAIN resources in the angular.json file:

"assets": [
    "src/favicon.ico",
    "src/assets",
    {
      "glob": "**/*",
      "input": "./node_modules/dwt/dist",
      "output": "assets/dynamic-web-twain"
    }
],

In the meantime, you need to specify the resource path in TypeScript code:

import { Injectable, Optional } from '@angular/core';
import Dynamsoft from 'dwt';

export class DocumentScannerServiceConfig {
  licenseKey = '';
  resourcePath = '';
}

@Injectable({
  providedIn: 'root'
})

export class NgxDocumentScannerService {

  constructor(@Optional() config?: DocumentScannerServiceConfig) { 
    if (config) { 
      Dynamsoft.DWT.ProductKey = config.licenseKey;
      Dynamsoft.DWT.ResourcesPath = config.resourcePath;
    }
  }
}

Try https://www.npmjs.com/package/ngx-web-document-scanner

npm i ngx-web-document-scanner

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