Answers.Body: <h2>An approach: composer-downloads-plugin</h2>
  
  <p><code>civicrm-core</code> now uses the <a href="https://github.com/civicrm/composer-downloads-plugin" rel="nofollow noreferrer">https://github.com/civicrm/composer-downloads-plugin</a> for Javascript and CSS libraries. You can use the same technique in an extension. For example, suppose you have an extension <code>civinfinite</code> with a <code>composer.json</code> file which declares:</p>
  
  
  
  <pre><code>{
    "name": "example/civinfinite",
    "require": {
      "civicrm/composer-downloads-plugin": "~2.1"
    },
    "extra": {
      "downloads": {
        "ngInfiniteScroll": {
          "url": "https://github.com/sroze/ngInfiniteScroll/archive/1.3.4.zip",
          "path": "extern/ngInfiniteScroll",
          "ignore": ["test"]
        }
      }
    }
  }
  </code></pre>
  
  <p>The <code>zip</code> file will be downloaded and extracted into your extension's folder (under <code>extern/ngInfiniteScroll</code>).</p>
  
  <p>For example, suppose that you install <code>civinfinite</code> on a Civi-D7 site under:</p>
  
  <pre><code>sites/default/civicrm/ext/civinfinite
  </code></pre>
  
  <p>If you run <code>composer install</code>, then the assets will be at:</p>
  
  <pre><code>sites/default/civicrm/ext/civinfinite/extern/ngInfiniteScroll
  </code></pre>
  
  <p>At runtime, you can determine the URL as:</p>
  
  
  
  <pre><code>Civi::resources()-&gt;getUrl('civinfinite', 'extern/ngInfiniteScroll/src/infinite-scroll.js');
  </code></pre>
  
  <p>Similarly, if you're registering an Angular module for use in Civi (<code>hook_civirm_angularModules</code> or <code>*.ang.php</code>), then the registration can reference that path:</p>
  
  
  
  <pre><code>[
    'ext' =&gt; 'civinfinite',
    'basePages' =&gt; [],
    'js' =&gt; ['extern/ngInfiniteScroll/src/infinite-scroll.js'],
  ];
  
  </code></pre>
  
  <h2>Critical analysis</h2>
  
  <p>There are many different techniques for managing JS/CSS assets in PHP projects -- D7 modules have <code>libraries</code>; Backdrop and WordPress modules tend to embed assets within modules; <code>composer</code> has various add-ons like <code>installer-paths</code>, <code>asset-packagist</code>, <code>composer-npm-bridge</code>, <code>composer-asset-plugin</code>, etc. Each of these has strengths and weaknesses.</p>
  
  <p>I would submit that the relative strength of this technique is that it is easy for both developers and site-builders to reason about the behavior. (<em>Tangentially, it's also faster than other composer-based techniques because it has no affect on the size of the dependency graph. But the main purpose is to make it easier to reason.</em>)</p>
  
  <p>For example: Consider that there are different ways in which people may deploy an extension:</p>
  
  <ul>
  <li>One may download an extension as a <code>*.zip</code> file with all assets bundled in. (This is what happens when using the in-app extension UI or <code>cv dl</code> or <code>Extension</code> API.) One may not be running <code>composer</code> at all.</li>
  <li>One may clone the extension's git repo and run <code>composer install</code>.</li>
  <li>One may have a <code>composer.json</code> in a site-root (and some open-ended mix of dependencies, plugins, configuration options), and then you add the extension as a dependency. </li>
  </ul>
  
  <p>As a developer, it's hard to predict which mix of techniques are being used by downstream site-builders. In the <code>composer-downloads-plugin</code> approach, you can rely on the JS/CSS assets <em>always</em> being in the same place (<em>relative to your code</em>).</p>
  
  <p>As a site-builder, this approach does not require you to add (or change/update) any "repositories" or "plugins" or configuration-options in a composer root-project. You don't even need to have a composer root-project. (<em>You probably should for other reasons... but the extension and its assets aren't going to force you into it.</em>) If a developer changes some small detail of the assets in their package, then it's not your concern.</p>
  
  <p>This approach complies with a simple, pre-existing contract:</p>
  
  <ul>
  <li>The developer decides what code goes inside their extension.</li>
  <li>The site-builder decides which extensions to get - and where to put them.</li>
  </ul>
  
  <p>A developer is free to use <code>composer-downloads-plugin</code> without requiring any changes to that basic contract.</p>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2020-02-01T00:31:35.377Z
Answers.Text: Maybe one part that's not clear: The way I read this, and looking also at something like https://github.com/veda-consulting/uk.co.vedaconsulting.mosaico: For the in-app extensions screen to work, YOU, the extension developer, need to run `composer install` and your info.xml file needs to point to a tarball that includes the resulting files, and those downloaded files don't get committed to your extension repo tree. The above just makes it easier to make it work whether you run composer or the end user.
Answers.UserDisplayName: Demerit
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2020-02-01T02:37:57.137Z
Answers.Text: Yeah, for the in-app distribution, someone needs to run `composer install` on per-extension basis. It's preferable to have some kind of job (Jenkins/Gitlab CI/Github Action/etc) for making those zip files, but committing `vendor` gets it done too. ... Something a bit tangential to the JS/CSS, but to make the PHP side more forgiving/adaptable, I'm pretty tempted to do https://gist.github.com/totten/cdcf5542911052322003db7a8ba16b0a
Answers.UserDisplayName: Tim Otten
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2020-01-31T23:38:22.773Z
Answers.LastActivityDate: 2020-02-01T00:08:10.593Z
Answers.LastEditDate: 2020-02-01T00:08:10.593Z
Answers.UserDisplayName: Tim Otten
Body: <p>I'm creating an extension and using AngularJS within it. I've found a 3rd party AngularJS library that I'd like to use in my extension (in this case <a href="https://github.com/sroze/ngInfiniteScroll" rel="nofollow noreferrer">ngInfiniteScroll</a>). What is the proper way to make my extension depend on this external library (and to ensure that the library is installed when the extension is installed)?  </p>
  
  <p>I'm pretty new to AngularJS development and CiviCRM development, so I still don't have a clear understanding of the difference between npm, webpack, bower, yarn, grunt, gulp, and browserify. Mostly I need to be pointed in the right direction.</p>
  
Tags: <developer><angular>
Title: How to manage AngularJS dependencies within an extension
ThreadText: # How to manage AngularJS dependencies within an extension
  
  (Asked by: username_0 on 2017-07-08)
  
  I'm creating an extension and using AngularJS within it. I've found a 3rd party AngularJS library that I'd like to use in my extension (in this case [ngInfiniteScroll](https://github.com/sroze/ngInfiniteScroll)). What is the proper way to make my extension depend on this external library (and to ensure that the library is installed when the extension is installed)?
  
  I'm pretty new to AngularJS development and CiviCRM development, so I still don't have a clear understanding of the difference between npm, webpack, bower, yarn, grunt, gulp, and browserify. Mostly I need to be pointed in the right direction.
  
  **Tags:** developer, angular
  
  
  ---
  
  ## 1 answers
  
  ### Answer by username_1 on 2020-01-31. Score: 1
  
  An approach: composer-downloads-plugin
  civicrm-core now uses the https://github.com/civicrm/composer-downloads-plugin for Javascript and CSS libraries. You can use the same technique in an extension. For example, suppose you have an extension civinfinite with a composer.json file which declares:
  {
    "name": "example/civinfinite",
    "require": {
      "civicrm/composer-downloads-plugin": "~2.1"
    },
    "extra": {
      "downloads": {
        "ngInfiniteScroll": {
          "url": "https://github.com/sroze/ngInfiniteScroll/archive/1.3.4.zip",
          "path": "extern/ngInfiniteScroll",
          "ignore": ["test"]
        }
      }
    }
  }
  
  The zip file will be downloaded and extracted into your extension's folder (under extern/ngInfiniteScroll).
  For example, suppose that you install civinfinite on a Civi-D7 site under:
  sites/default/civicrm/ext/civinfinite
  
  If you run composer install, then the assets will be at:
  sites/default/civicrm/ext/civinfinite/extern/ngInfiniteScroll
  
  At runtime, you can determine the URL as:
  Civi::resources()->getUrl('civinfinite', 'extern/ngInfiniteScroll/src/infinite-scroll.js');
  
  Similarly, if you're registering an Angular module for use in Civi (hook_civirm_angularModules or *.ang.php), then the registration can reference that path:
  [
    'ext' => 'civinfinite',
    'basePages' => [],
    'js' => ['extern/ngInfiniteScroll/src/infinite-scroll.js'],
  ];
  
  
  Critical analysis
  There are many different techniques for managing JS/CSS assets in PHP projects -- D7 modules have libraries; Backdrop and WordPress modules tend to embed assets within modules; composer has various add-ons like installer-paths, asset-packagist, composer-npm-bridge, composer-asset-plugin, etc. Each of these has strengths and weaknesses.
  I would submit that the relative strength of this technique is that it is easy for both developers and site-builders to reason about the behavior. (Tangentially, it's also faster than other composer-based techniques because it has no affect on the size of the dependency graph. But the main purpose is to make it easier to reason.)
  For example: Consider that there are different ways in which people may deploy an extension:
  
  One may download an extension as a *.zip file with all assets bundled in. (This is what happens when using the in-app extension UI or cv dl or Extension API.) One may not be running composer at all.
  One may clone the extension's git repo and run composer install.
  One may have a composer.json in a site-root (and some open-ended mix of dependencies, plugins, configuration options), and then you add the extension as a dependency. 
  
  As a developer, it's hard to predict which mix of techniques are being used by downstream site-builders. In the composer-downloads-plugin approach, you can rely on the JS/CSS assets always being in the same place (relative to your code).
  As a site-builder, this approach does not require you to add (or change/update) any "repositories" or "plugins" or configuration-options in a composer root-project. You don't even need to have a composer root-project. (You probably should for other reasons... but the extension and its assets aren't going to force you into it.) If a developer changes some small detail of the assets in their package, then it's not your concern.
  This approach complies with a simple, pre-existing contract:
  
  The developer decides what code goes inside their extension.
  The site-builder decides which extensions to get - and where to put them.
  
  A developer is free to use composer-downloads-plugin without requiring any changes to that basic contract.
  
  > **Comments:**
  > **username_2**: Maybe one part that's not clear: The way I read this, and looking also at something like https://github.com/veda-consulting/uk.co.vedaconsulting.mosaico: For the in-app extensions screen to work, YOU, the extension developer, need to run `composer install` and your info.xml file needs to point to a tarball that includes the resulting files, and those downloaded files don't get committed to your extension repo tree. The above just makes it easier to make it work whether you run composer or the end user.  
  > **username_1**: Yeah, for the in-app distribution, someone needs to run `composer install` on per-extension basis. It's preferable to have some kind of job (Jenkins/Gitlab CI/Github Action/etc) for making those zip files, but committing `vendor` gets it done too. ... Something a bit tangential to the JS/CSS, but to make the PHP side more forgiving/adaptable, I'm pretty tempted to do https://gist.github.com/totten/cdcf5542911052322003db7a8ba16b0a  
  
  ---
  
  