/resolution-map-builder

Primary LanguageJavaScriptMIT LicenseMIT

resolution-map-builder Build Status

Utilities and a Broccoli plugin for building a resolution map compatible with @glimmerjs/resolver and the expectations of Ember's module unification RFC.

This package is a low-level utility and most people should not need to use it directly. A new Glimmer app will be configured to generate the resolution map automatically via the @glimmer/application-pipeline package.

The Resolution Map

Glimmer uses a resolver to locate your app's modules. For example, if you use the component <my-component> in a template, the resolver is what tells Glimmer that that component lives in your app's src/ui/components/my-component/component.ts file.

To make this process fast, Glimmer generates a resolution map when you build your application. This resolution map allows the resolver to quickly locate the requested object.

Specifiers

Internally, Glimmer uses specifiers to identify objects in the system. A specifier is a specially-formatted string that encodes the type and path of an object.

For example, the specifier for the text-editor component's template in an app might be:

"template:/my-app/components/text-editor"

In addition to the type of object (component, template, route, etc.), a specifier's path includes information about the root name (an app or an addon), collection, and namespace.

Generated Source

This package can generate the source code for a JavaScript module that imports the files in your app and includes them in a resolution map object. For example:

import { default as __ui_components_my_app_component__ } from '../ui/components/my-app/component';
import { default as __ui_components_my_app_page_banner_component__ } from '../ui/components/my-app/page-banner/component';
import { default as __ui_components_my_app_page_banner_template__ } from '../ui/components/my-app/page-banner/template';
import { default as __ui_components_my_app_page_banner_titleize__ } from '../ui/components/my-app/page-banner/titleize';
import { default as __ui_components_my_app_template__ } from '../ui/components/my-app/template';
export default {'component:/my-app/components/my-app': __ui_components_my_app_component__,'component:/my-app/components/my-app/page-banner': __ui_components_my_app_page_banner_component__,'template:/my-app/components/my-app/page-banner': __ui_components_my_app_page_banner_template__,'component:/my-app/components/my-app/page-banner/titleize': __ui_components_my_app_page_banner_titleize__,'template:/my-app/components/my-app': __ui_components_my_app_template__};

Usage

Broccoli Plugin

If using as a Broccoli plugin, instantiate the plugin with two input trees:

  1. The src directory
  2. The config directory
const ResolutionMapBuilder = require('@glimmer/resolution-map-builder');
return new ResolutionMapBuilder(srcTree, configTree, {
  srcDir: 'src',
  defaultModulePrefix: this.name,
  defaultModuleConfiguration
});

The Broccoli plugin will read the module prefix and module configuration from the configTree. If none are found, you can still provide fallback configurations with the defaultModulePrefix and defaultModuleConfiguration options.

Utilities

If you want to generate your own resolution map without using Broccoli, this package includes several helper functions you can use.

buildResolutionMapSource()

Returns a string of generated JavaScript that imports each module and has a default export of an object with specifiers as keys and each module's default export as its value.

const { buildResolutionMapSource } = require('@glimmer/resolution-map-builder');
let moduleConfig = {
  types: {
    application: { definitiveCollection: 'main' },
    component: { definitiveCollection: 'components' },
    helper: { definitiveCollection: 'components' },
    renderer: { definitiveCollection: 'main' },
    template: { definitiveCollection: 'components' }
  },
  collections: {
    main: {
      types: ['application', 'renderer']
    },
    components: {
      group: 'ui',
      types: ['component', 'template', 'helper'],
      defaultType: 'component',
      privateCollections: ['utils']
    },
    styles: {
      group: 'ui',
      unresolvable: true
    },
    utils: {
      unresolvable: true
    }
  }
};

let contents = buildResolutionMapSource({
  projectDir: 'path/to/app',
  srcDir: 'src',
  modulePrefix: 'my-app',
  moduleConfig
});
// returns
// `import { default as __ui_components_my_app_component_ts__ } from '../ui/components/my-app/component.ts';
// export default { 'component:/my-app/components/my-app': __ui_components_my_app_component_ts__ };`

fs.writeFileSync('config/module-map.js', contents, { encoding: 'utf8' });

buildResolutionMapTypeDefinitions()

Returns a string of TypeScript source code that provides type information for the resolution map generated by buildResolutionMapSource(). This source can be included in a .d.ts file with the same name as the resolution map to avoid TypeScript errors at compilation time.

const { buildResolutionMapTypeDefinitions } = require('@glimmer/resolution-map-builder');

let types = buildResolutionMapTypeDefinitions();
fs.writeFileSync('config/module-map.d.ts', types, { encoding: 'utf8' });

buildResolutionMap()

Similar to buildResolutionMapSource() (and takes the same arguments), but allows you to generate the JavaScript output yourself. Instead of returning JavaScript source, buildResolutionMap() returns an object with module specifiers as the keys and the path to the module (relative to projectDir) as the value.

const { buildResolutionMap } = require('@glimmer/resolution-map-builder');

let map = buildResolutionMap({
  projectDir: 'path/to/app',
  srcDir: 'src',
  modulePrefix: 'my-app',
  moduleConfig
});

// returns {
//   'component:/my-app/components/my-app': 'src/ui/components/my-app/component'
// }

Acknowledgements

Thanks to Monegraph and Cerebris for funding the initial development of this library.

License

MIT License.