Skip to content
/ esmdemo Public

Example CiviCRM extension that loads ECMAScript Modules (ESM)

License

Notifications You must be signed in to change notification settings

totten/esmdemo

Repository files navigation

esmdemo

This is a CiviCRM extension with some simple examples of loading ECMAScript Modules (ESMs).

To view the demos, install the extension and navigate to civicrm/esmdemo.

Part 1. Basic ESM Support

Basic ESM support allows you to load an ESM file. This resembles the traditional loading of Javascript files. Compare:

-Civi::resources()->addScriptFile('com.example.foo', 'my-script.js');
+Civi::resources()->addModuleFile('com.example.foo', 'my-script.js');

By switching from addScriptFile() to addModuleFile(), you gain the ability to import dependencies.

There are important limitations. With basic ESM support, the import must specify a physical path. This limits you to scenarios where the physical path is easy to identify, such as:

  • Importing dependencies from the same folder.
    import { myOtherStuff } from './my-other-module.js'
  • Importing dependencies from a specific CDN.
    import { myOtherStuff } from 'https://unpkg.com/foo/my-other-module.js'

We have a few examples of these techniques.

  • Hello World: Relative Path (civicrm/esmdemo/hello-relpath)
  • Hello World: VueJS CDN (civicrm/esmdemo/hello-vuejs-cdn)
    • The page-controller loads the first file and some static HTML.
      Civi::resources()->addModuleFile(E::LONG_NAME, 'js/hello-vuejs-cdn.js');
      CRM_Core_Region::instance('page-body')->addMarkup('<div id="app"><h2>{{ message }}</h2></div>');
    • hello-vuejs-cdn.js imports additional files from CDN.
      import { createApp } from 'https://unpkg.com/vue@3/dist/vue.esm-browser.js'
  • Hello World: ReactJS CDN (civicrm/esmdemo/hello-reactjs-cdn)
    • The page-controller loads the first file and some static HTML.
      Civi::resources()->addModuleFile(E::LONG_NAME, 'js/hello-reactjs-cdn.js');
      CRM_Core_Region::instance('page-body')->addMarkup('<div id="root"></div>');
    • hello-reactjs-cdn.js imports additional files from CDN.
      const React = await import('https://unpkg.com/@esm-bundle/react@17.0.2-fix.1/esm/react.production.min.js');
      const ReactDOM = await import ('https://unpkg.com/@esm-bundle/react-dom@17.0.2-fix.0/esm/react-dom.resolved.production.min.js');

Part 2. Import Map Support

If you want to share modules between different parts of the system (e.g. between civicrm/js/* and my-extension/js/*), then the basic support is not sufficient. You also need to support logical paths based on an import map.

Here is an example:

  • Hello World: Import Map Hook (civicrm/esmdemo/hello-import-map-hook)
    • The module declares that geolib/ maps to the physical path for {MY_EXTENSION}/packages/geometry-library-1.2.3/.
      function esmdemo_civicrm_esmImportMap(array &$importMap, array $context): void {
        $importMap['imports']['geolib/'] = E::url('packages/geometry-library-1.2.3/');
      }
    • The page-controller loads the first file:
      Civi::resources()->addModuleFile(E::LONG_NAME, 'js/hello-import-map-hook.js');
    • hello-import-map-hook.js imports a file from geolib/ and uses it:
      import Square from 'geolib/Square.js';
      var myShape = new Square(2.5);
    • Square.js imports more files:
      import Rectangle from './Rectangle.js';
      export default class Square extends Rectangle { ... }

About

Example CiviCRM extension that loads ECMAScript Modules (ESM)

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published