Search code examples
angularjsnpmwebpackangular-directive

Is it possible to build a self-contained Angular plugin to be embedded in other angular sites?


I really like Angular.

Having said that, I want to create a plugin in Angular that can be hosted in other websites - no matter what framework they're using. These frameworks can be Angular and it might be something else.

Surely, the latter it easier. I just add my Angular code and violla. It just works. The former is what I'm having troubles with - websites that do use Angular.

A simple setup created locally failed due to:

WARNING: Tried to load angular more than once.

Any suggestions on how I can overcome this issue ?


Solution

  • It sounds almost like you want to create an angular module that you may register on NPM.

    In terms of the error you referenced, you may want to tweak your "loader" script. I have created a few public npm modules that use this format also with webpack to create the scripts. This is what my "loader" script looks like. It allows for script tag, commonJS, and AMD module loading.

    import mooAccordionDirective from './mooAccordion.js';
    import mooRepeatTranscludeModule from 'moo-utility-repeat-transclude';
    
    (function (root, factory) {
        if (typeof module !== 'undefined' && module.exports) {
            // CommonJS
            if (typeof angular === 'undefined') {
                var angular = require('angular');
                factory(angular);
                module.exports = 'mooAngularAccordion';
            } else {
                factory(angular);
                module.exports = 'mooAngularAccordion';
            }
        } else if (typeof define === 'function' && define.amd) {
            // AMD
            define(['angular'], factory);
        } else {
            // Global Variables
            factory(root.angular);
        }
    }(this, function (angular) {
      'use strict';
      // create your angular module and do stuff
      var moduleName = 'mooAngular.accordion';
      var mod = angular.module(moduleName, ['mooAngular.utilityRepeatTransclude']);
    
      mooAccordionDirective(mod);
    
      return moduleName; // the name of your module
    }));
    

    For more reference on how I built the entire project using Webpack+AngularJS+ES6 you can view my github page for the moo-angular-accordion project.

    For you to use this script it would look like:

    (function (root, factory) {
        if (typeof module !== 'undefined' && module.exports) {
            // CommonJS also this prevents your error you are getting.
            if (typeof angular === 'undefined') {
                var angular = require('angular');
                factory(angular);
                module.exports = 'myModuleExportString';
            } else {
                factory(angular);
                module.exports = 'myModuleExportString';
            }
        } else if (typeof define === 'function' && define.amd) {
            // AMD
            define(['angular'], factory);
        } else {
            // Global Variables
            factory(root.angular);
        }
    }(this, function (angular) {
      'use strict';
      // create your angular module and do stuff
      var moduleName = 'myModule';
      var mod = angular.module(moduleName, ['otherDepModulesIfNeeded']);
    
      mod.directive(/*... defined here ...*/);
    
      return moduleName; // the name of your module
    }));
    

    Breakdown:

    • You define a IIEF which is called with this and your module function (factory) provided as arguments.
    • The logic checks to see if angular already exists in the global namespace (and if CommonJS support is available.
    • If angular exists, use it (so that it isn't defined twice), and pass that angular to your module definition (factory)
    • If not CommonJS, check AMD
    • If not AMD, load to root as a global (usable as a Script tag)

    EDIT: You can also use Grunt, Gulp, or whatever build system you want to bundle your assets instead of Webpack, however the magical script above makes your module exportable in multiple formats (AMD, Script Tag, CommonJS, etc.).