Angular Cli Webpack, How to add or bundle external js files?

100,942

Solution 1

Last tested using angular-cli 11.x.x with Angular 11.x.x

This can be accomplished using scripts:[] in angular.json.

{
  "project": {
    "version": "1.0.0",
    "name": "my-project"
  },
  "apps": [
    {
      "root": "src",
      "outDir": "dist",
      "assets": ["assets"],
      "index": "index.html",
      "main": "main.ts",
      "polyfills": "polyfills.ts",
      "test": "test.ts",
      "tsconfig": "tsconfig.json",
      "prefix": "app",
      "mobile": false,
      "styles": [
        "styles.css"
      ],
      "scripts": [
        "../node_modules/jquery/dist/jquery.js"
      ],
      "environments": {
        "source": "environments/environment.ts",
        "dev": "environments/environment.ts",
        "prod": "environments/environment.prod.ts"
      }
    }
  ],
  "addons": [],
  "packages": [],
  "e2e": {
    "protractor": {
      "config": "./protractor.conf.js"
    }
  },
  "test": {
    "karma": {
      "config": "./karma.conf.js"
    }
  },
  "defaults": {
    "styleExt": "css",
    "prefixInterfaces": false
  }
}

Note: As the documentation suggests in the global library installation: if you change the value of your styles (or scripts!) property, then:

Restart ng serve if you're running it,

..to see the scripts executed in a **globalcontext via the scripts.bundle.js file.

Note: As discussed in the comments below. JS libs that support UMD modules via es6 imports such as jQuery can also be imported into your typescript files using the es6 import syntax. For example: import $ from 'jquery';.

Solution 2

There is a subtle difference to using scripts:[] then to adding something to the <head> with <script>. Scripts from scripts:[] get added to the scripts.bundle.js that gets always loaded in the body tag and will thus be loaded AFTER scripts in <head>. Thus if script loading order matters (i.e. you need to load a global polyfill), then your only option is to manually copy scripts to a folder (e.g. with a npm script) and add this folder as an asset to .angular-cli.json.

So if you really depend on something being loaded before angular itself (Option A), then you need to copy it manually to a folder that will be included in the angular build and then you can load it manually with a <script> in <head>.

Thus, for achieving option a you have to:

  • create a vendor folder in src/
  • add this folder as an asset to .angular-cli.json:
"assets": [
    "assets",
    "favicon.ico",
     "vendor"
  ]
  • copy your vendor script node_modules/some_package/somejs.js to vendor

  • load it manually in index.html: <head> <script src="vendor/some_package/somejs.js"> </head>

However most of the time you only need this approach for packages, that need to be available globally, before everything else (i.e. certain polyfills). Kris' answer holds true for Option B and you get the benefit of the webpack build (Minification, Hashes, ...).

However if your scripts need not be globally available and if they are module-ready you can import them in src/polyfills.ts or even better import them only when you need them in your specific components.

Making scripts globally available via scripts:[] or via manually loading them brings it own set of problems and should really only be used, when it is absolutely necessary.

Solution 3

You need to open file .angular-cli.json file and need to search for "scripts:" or if you want to add external css you need to find the word "styles": in the same file.

as an example shown below you will see how the bootstrap Js(bootstrap.min.js) and bootstrap CSS(bootstrap.min.css) includes in .angular-cli.json:

"styles": [
    "styles.css",
    "../node_modules/bootstrap/dist/css/bootstrap.min.css"
  ],
  "scripts": [
    "../node_modules/jquery/dist/jquery.min.js",
    "../node_modules/bootstrap/dist/js/bootstrap.min.js"
  ],

For sure if you have your own js file you can add your file path here in .angular-cli.json at the same place(in "scripts":[]).

Solution 4

You might want to have a look at this page: https://github.com/angular/angular-cli#global-library-installation

It show the basics of how to include .js and .css files

Some javascript libraries need to be added to the global scope, and loaded as if they were in a script tag. We can do this using the apps[0].scripts and apps[0].styles properties of angular-cli.json.

Share:
100,942
khollenbeck
Author by

khollenbeck

Various levels of experience with: JAVASCRIPT JavaScript Angular/Typescript Node jQuery Dabbled with React lodash mustache JS Tooling/Testing Angular Cli Grunt Cli Webpack NPM Karma Protractor HTML and CSS HTML Jade CSS SASS Java Java Ant/Maven Database MYSQL Mongo Source Control GIT SVN

Updated on July 10, 2022

Comments

  • khollenbeck
    khollenbeck almost 2 years

    I am not sure how to include JS files (vendors) after switching Angular Cli from SystemJs to Webpack.

    For example

    Option A

    I have some js files that were installed via npm. Adding script tags to the head tag like this does not work. Nor does it seem like the best way.

    <head>
       <script src="node_modules/some_package/somejs.js">
    </head>
    
    //With systemJs I could do this
    
    <head>
       <script src="vendor/some_package/somejs.js">
    </head>
    

    Option B

    Include these js files as part of the webpack bundle. This seems like the way it probably should be done. However I am not sure how to do this as all of the webpack code seems to be hidden behind the angular-cli-webpack node package. I was thinking maybe there is another webpack config that we might have access to. But I am not sure as I didn't see one when creating a new angular-cli-webpack project.

    More Info:

    The js files I am trying to include need to be included before the Angular project. For example jQuery and a third party js lib that isn't really setup for module loading or typescript.

    References https://github.com/angular/angular-cli/blob/master/WEBPACK_UPDATE.md https://github.com/angular/angular-cli/tree/webpack

  • khollenbeck
    khollenbeck over 7 years
    The angular cli webpack config is actually part of the angular cli node package. So unfortunately I can not modify that. For example in the CLI there are preset commands to build. ng build this is all handled by the cli. But I was thinking there is probably a way to add things as part of the build. But I haven't seen any clear example.
  • zilj
    zilj over 7 years
    Ah my apologies. I'd filtered angular 2 questions but this one slipped through. Best of luck.
  • Stuart Siegler
    Stuart Siegler over 7 years
    Link only answers are discouraged. Please quote the essential parts of the answer from the reference link(s), as the answer can become invalid if the linked page(s) change.
  • nthaxis
    nthaxis over 7 years
    How can I reference jquery in Typescript once I have added the script to angular-cli.json?
  • khollenbeck
    khollenbeck over 7 years
    @Ibanez0, You need to install the jQuery definition files. From @types. npmjs.com/~types Here is a related post. stackoverflow.com/questions/35660498/…
  • rmag
    rmag about 7 years
    BTW If the external file being added is a polyfill, then there is a dedicated mechanism for that nicely described in src/polyfills.ts (as of beta.31)
  • metamaker
    metamaker about 7 years
    @Ibanez0 Refer to stackoverflow.com/questions/42510334/…. There are several ways to do it.
  • Blair Connolly
    Blair Connolly about 7 years
    If you're using jQuery in your Angular project, then you're doing it wrong. I love jQuery, it took me far on my career, but if you're using Angular correctly, there is no more need for jQuery.
  • khollenbeck
    khollenbeck about 7 years
    @BlairConnolly, While I agree and we would love to get rid of jQuery. We are consuming a Jquery UI from another team within our company whom doesn't have time to rewrite the whole UI at the moment. So sometimes people just don't have a choice.
  • Aluan Haddad
    Aluan Haddad about 6 years
    This is the wrong way to load jQuery. jQuery is a UMD module. import $ from 'jquery'; and remove the global.
  • khollenbeck
    khollenbeck about 6 years
    @AluanHaddad, In my case I have some JS libraries that aren't UMD (and can't be imported) and I need jQuery to load before those scripts. Using the scripts array in the JSON file seems to work best in order to ensure everything loads in the right order.
  • Aluan Haddad
    Aluan Haddad about 6 years
    @KrisHollenbeck for one thing, it would be better to use Webpack or SystemJS or whatever you use to specify those dependencies as such tools are designed with these scenarios in mind (For example SystemJS can shim a global but only for those that need it as a global). More importantly, just because you needed to load jQuery as a global due to a transitive dependency doesn't mean that everyone does! This answer has 61 +1 votes and it's suggesting a practice where you get all of the complexities that modules introduce and none of their benefits.
  • Aluan Haddad
    Aluan Haddad about 6 years
    @KrisHollenbeck I'm not trying to be a jerk but seriously consider the complexity of the tools we have accreted in order to adopt ES Modules. From transpilers, to frameworks, to loaders, to package managers, to bundlers, to CLIs we use incredibly complex, interdependent and often incompatible tools to leverage modules. We should be loath to do so if we throw away all the benefits. This should be a last resort approach, but will become de facto for users who don't understand why the complexity is even there, just accepting it.
  • khollenbeck
    khollenbeck about 6 years
    @AluanHaddad, Angular CLI does use webpack to load these scripts via the scripts. So I am not sure what you mean by it would be better to use Webpack when it is being used. However I understand your concerns in regards to module loading. And I was just stating why it was posted that way vs the other. Originally the question was meant to be about jQuewry specifically but about thirdparty JS libraries within the Angular CLI framework. If you think it is beneficial to the community to better understand the options within this context. Then feel free to edit/update the answer.
  • Aluan Haddad
    Aluan Haddad about 6 years
    @KrisHollenbeck since I'm not an angular CLI user, I'm not going to edit this but I appreciate your attitude. Really I just think this needs commentary explaining that one should begin by making a best-effort to properly install dependencies, their type declarations, and attempt to import them and not jump at this as a solution to what are often easily resolved issues. This should be considered a workaround.
  • PaulCo
    PaulCo about 6 years
    There's something written about that here that suggest > Once you import a library via the scripts array, you should not import it via a import statement in your TypeScript code (e.g. import * as $ from 'jquery';)
  • Erik Philips
    Erik Philips over 4 years
    This is great because I can create a js config files per environment leave them there and load them at runtime instead of using environment.ts files and having to build angular for each environment (terrible...)
  • Steve Lam
    Steve Lam over 4 years
    Do you have any example to use polyfills or load in specific components?
  • Christian Ulbrich
    Christian Ulbrich over 4 years
    @SteveLam Please be more specific or ask a new question. Usually polyfills would not be loaded in a specific component, but globally unless you want you components to be self-contained but even then it is prefered to define the runtime environment that you expect and let the consumer of the component decide when and how to load a polyfill.
  • Steve Lam
    Steve Lam over 4 years
    Thank Chris, do you have any article about that?
  • luis alberto juarez
    luis alberto juarez over 3 years
    Hi im using angular 7, when i run mi app the script is loaded in the index page but i need use the script in other page, when i click in other page the script is unloaded, how can i load it on a specific page or for a whole application?
  • Christian Ulbrich
    Christian Ulbrich over 3 years
    @luisalbertojuarez Angular is a framework for single page applications, there is no other page. If you mean by "other page", a HTML file outside of your Angular application, simply load it there as well, via a direct script tag.