39

I am creating an angular library (version 6) which is based on angular material for which I need to include the hammer js library.

I know that in angular 6 we can add the external js library in the angular.json under the project's configuration. But this does not work in case of above library. I tried to add the external library in the following way.

"my-library": {
  "root": "projects/my-library",
  "sourceRoot": "projects/my-library/src",
  "projectType": "library",
  "architect": {
    "build": {
      "builder": "@angular-devkit/build-ng-packagr:build",
      "options": {
        "tsConfig": "projects/my-library/tsconfig.lib.json",
        "project": "projects/my-library/ng-package.json",
        "scripts": [
          "../node_modules/hammerjs/hammer.min.js"
        ]
      }
    }
}

But I am getting this error.

Schema validation failed with the following errors: Data path "" should NOT have additional properties(scripts).

Please suggest what is the correct way to add external js file in the angular library.

ford04
  • 66,267
  • 20
  • 199
  • 171
nikhil
  • 823
  • 1
  • 7
  • 19
  • 1
    You either have a typo somewhere in your actual code, or this is a bug, and you should file a bug report with the angular cli. There is nothing wrong with the code you just posted – Poul Kruijt Jun 29 '18 at 08:41
  • This could be useful: https://github.com/angular/angular-cli/wiki/stories-third-party-lib – R. Richards Jun 29 '18 at 11:05
  • @nikhil have you found a solution for this? I am in a similar situation and import * or require do not work. – Andrew Anderson Jul 25 '18 at 20:11
  • Hi @Nikhil, have you got any luck on this , how to include scripts in angular library. – Sethuraman Jul 02 '19 at 09:45

9 Answers9

2

So here are two possible problems we need to address

1) How to add the reference of external JS in the main angular project(demo project)

2) How to add the reference of external JS in NPM package.

The solution for the 1'st scenario is :

Provide the reference of your external JS in your angular.json file of main angular project in a script tag and provide the path of your package from your libraries node_modules folder like this.

"scripts": [ "./projects/my-cool-library/node_modules/my-exteranl-library/dist/x.js"]

The solution for the 2'nd scenario is :

Approach 1

So now you have created the NPM package from your library and you are going to use it in different project. obviously your 3rd party package dependency will get auto downloaded once you download your package you just have to provide the reference of that JS in script tag of angular.json file of new project.

"scripts": [ "./node_modules/my-exteranl-library/dist/x.js"]

Approach 2

Don't specify your third party dependency while creating your NPM package remove the entry from package.json file of your cool-library

"dependencies": { "my-exteranl-library": "^1.1.0" <-- Remove this } and add the js directly in newly created application via CDN in index.html file using script tag

<script src="https://demo-cdn.com/ajax/libs/my-exteranl-library/dist/x.js"></script>

There is 3rd way very you can download the JS by writing the code in your library will share here shortly.

Kedar9444
  • 1,745
  • 1
  • 11
  • 15
1

you can add your external library in the tsconfig.lib.json file.

Open that file and add your desires library under types node that you can find in compilerOptios. I give you and example. In my case I referenced the library from my project node module. You can do the same with your hammer.js library. Good luck

using types to configure external js file

El Ronnoco
  • 11,753
  • 5
  • 38
  • 65
Jorge Vega
  • 29
  • 4
1

Regarding the OP's specific example trying to add hammer.js. Just npm install hammerjs then edit your main.ts file and add import 'hammerjs' then it will be available globally.

Also see this article.

Post Impatica
  • 14,999
  • 9
  • 67
  • 78
0

You should try below command if you have used angular version 1.x before. And it works for me.

ng update @angular/cli --migrate-only --from=1.7.4
Emon
  • 1,401
  • 14
  • 24
0

first add the libbrary in index.html or in

"scripts": [
"node_modules/hammerjs/hammer.min.js"
]

npm install d3 --save

npm install @types/d3 --save-dev

If the library doesn't have typings available at @types/, you can still use it by manually adding typings for it:

  1. First, create a typings.d.ts file in your src/ folder. This file will be automatically included as global type definition.
  2. Then, in src/typings.d.ts, add the following code:

    declare module 'typeless-package';
    
  3. Finally, in the component or file that uses the library, add the following code:

    import * as typelessPackage from 'typeless-package';
    
    typelessPackage.method();
    

please follow the link

Hasta Dhana
  • 4,699
  • 7
  • 17
  • 26
Paul Cheriyan
  • 33
  • 1
  • 2
  • 8
0

You can't, that's the behavior of ng-packagr, you'll get that error every time you try to add assets to a Library. check this discussion for possible solution : https://github.com/angular/angular-cli/issues/11071

Hasta Dhana
  • 4,699
  • 7
  • 17
  • 26
Romaric
  • 21
  • 1
  • 1
0

There two possible ways to solve this problem:

1) In your library specify @angular/material and hammerjs as peer dependencies so that all the applications that will use your library are required to provide the library themselves (this means that each app will have it's own angular.json with the scripts property containing the hammerjs js file)

2) Use ng-cli-packagr-tasks custom build steps to copy a hammen.min.js file from node_modules to the dist of a library and use relative import in your code.

Let me explain step #2 more detailed:

you want to use some kind of relative import like require('../dependencies/hammer.min.js') but this will result an error because after the library is build, the ../dependencies/hammer.min.js will lead to uncertain place. To make sure that each time not only your .ts files will be magically transpiled to .js files but also the static .js files will be copied to a certain directory of a dist output of a library, you use ng-cli-packagr-tasks. After the build phase the ng-cli-packagr-tasks will copy the files using glob so that after you install the library in your application, the static .js files will be bundled as well. This means that the import import('../dependencies/hammer.min.js).then() will always lead to the file you've provided by yourself.

Yevhenii Dovhaniuk
  • 1,073
  • 5
  • 11
0

To load js file externally from assets

create service file add file to the assets and write path in array.

import { Injectable } from "@angular/core";


    declare var document: any;
    @Injectable({
        providedIn:'root'
    })
    export class ScriptService {
      private scripts: any = {};

      constructor() {
        ScriptConstant.forEach((script: any) => {
          this.scripts[script.name] = {
            loaded: false,
            src: script.src
          };
        });
      }

      load(...scripts: string[]) {
        var promises: any[] = [];
        scripts.forEach(script => promises.push(this.loadScript(script)));
        return Promise.all(promises);
      }
      loadAll() {
        var promises: any[] = [];
        ScriptConstant.forEach(script => {
          // promises.push(delay(1000));
          promises.push(this.loadScript(script.name));
        });
        return Promise.all(promises);
      }

      loadScript(name: string) {
        return new Promise((resolve, reject) => {
          //resolve if already loaded
          if (this.scripts[name].loaded) {
            resolve({ script: name, loaded: true, status: "Already Loaded" });
          } else {
            //load script
            let script = document.createElement("script");
            script.type = "text/javascript";
            script.src = this.scripts[name].src;
            if (script.readyState) {
              //IE
              script.onreadystatechange = () => {
                if (
                  script.readyState === "loaded" ||
                  script.readyState === "complete"
                ) {
                  script.onreadystatechange = null;
                  this.scripts[name].loaded = true;
                  resolve({ script: name, loaded: true, status: "Loaded" });
                }
              };
            } else {
              //Others
              script.onload = () => {
                this.scripts[name].loaded = true;
                resolve({ script: name, loaded: true, status: "Loaded" });
              };
            }
            script.onerror = (error: any) =>
              resolve({ script: name, loaded: false, status: "Loaded" });
            document.getElementsByTagName("body")[0].appendChild(script);
          }
        });
      }
    }

    interface Scripts {
        name: string;
        src: string;
      }
      export const ScriptConstant: Scripts[] = [
        { name: "multislider", src: "assets/js/multislider.js" },

      ];

Inject this ScriptService wherever you need it and load js libs like this

this.script.load('multislider').then(data => {
    console.log('script loaded ', data);
}).catch(error => console.log(error));
rajhim
  • 259
  • 2
  • 14
-3

remove ../ before path of node_modules

"scripts": [
    "node_modules/hammerjs/hammer.min.js"
]
Krishna Rathore
  • 9,389
  • 5
  • 24
  • 48
  • 5
    Does not work with this approach. Still getting the same error. It is not the path issue. It is basically the script property is not allowed in case of library configuration. It works fine for test application but not for library. – nikhil Jun 29 '18 at 09:09
  • This answer may not solve the entire issue, but Krishna is right, I don't have the `../` prefix in my `angular.json` scripts section, and my app builds perfectly fine. – Arnaud P Oct 21 '19 at 08:59
  • @ArnaudP is your app a library type? – Joseph Khella Oct 28 '19 at 12:52
  • @JosephKhella I am referrering to a library project yes, bootstrapped with angular-cli. So to be precise, the `projects/` directory contains both a `lib/` directory, and an `app/` one. Only `lib/` is meant to be released as a package, and `app/` is only used locally to test (eg. Cypress) the integration of `lib` in a bigger app. Hope it answers your question. – Arnaud P Oct 28 '19 at 15:32
  • @ArnaudP it does thank u :) did you have to include hammer in your project (not library) package.json as well? – Joseph Khella Oct 28 '19 at 15:41
  • I believe it depends on how you want your dependencies to be resolved. Me, I decided to declare `peerDependencies` only in the lib `package.json`, which means that anyone wanting to use this lib will have to install the dependencies themselves (so, in that project, the dependencies have to be declared in the app `package.json`) Alternately, I believe you can declare `dependencies` directly in your lib `package.json`, and in that case, they will be resolved transitively. No need to add them to the app `package.json`. – Arnaud P Oct 28 '19 at 16:17