or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

build-time-integration.mdcli-commands.mdfeature-system.mdindex.mdutilities.md
tile.json

build-time-integration.mddocs/

Build-time Integration

Build-time methods for addons to conditionally include functionality based on feature states. These methods are available during the Ember build process and allow addons to adapt their behavior based on optional feature configuration.

Capabilities

Feature State Checking

Check whether a specific optional feature is enabled, considering both explicit configuration and default values.

/**
 * Check if a feature is enabled (explicitly set or using default value)
 * @param name - Feature name to check
 * @returns true if feature is enabled, false otherwise
 */
isFeatureEnabled(name: string): boolean;

Usage Example:

// In an addon's index.js
included() {
  let optionalFeatures = this.addons.find(a => a.name === '@ember/optional-features');
  
  if (optionalFeatures.isFeatureEnabled('jquery-integration')) {
    // Include jQuery-specific functionality
    this.import('vendor/jquery-plugins.js');
  }
  
  if (optionalFeatures.isFeatureEnabled('template-only-glimmer-components')) {
    // Configure for Glimmer component semantics
    this.options.babel = {
      plugins: [
        // Add Glimmer-specific transformations
      ]
    };
  }
}

Behavior:

  • Returns true if feature is explicitly enabled in configuration
  • Returns false if feature is explicitly disabled in configuration
  • Returns the feature's default value if not explicitly configured
  • Handles unknown features by returning false

Explicit Configuration Detection

Check whether a feature has been explicitly set by the user, regardless of its enabled/disabled state.

/**
 * Check if a feature has been explicitly configured by the user
 * @param name - Feature name to check
 * @returns true if explicitly set, false if using default
 */
isFeatureExplicitlySet(name: string): boolean;

Usage Example:

// In an addon's index.js  
included() {
  let optionalFeatures = this.addons.find(a => a.name === '@ember/optional-features');
  
  if (optionalFeatures.isFeatureExplicitlySet('jquery-integration')) {
    // User has made an explicit choice about jQuery
    if (optionalFeatures.isFeatureEnabled('jquery-integration')) {
      console.log('User explicitly enabled jQuery integration');
    } else {
      console.log('User explicitly disabled jQuery integration');
    }
  } else {
    // Using default value - perhaps show a deprecation warning
    console.warn('jQuery integration will change defaults in future versions');
  }
}

Behavior:

  • Returns true if feature is present in config/optional-features.json
  • Returns true if feature is set via EMBER_OPTIONAL_FEATURES environment variable
  • Returns false if feature is using its default value
  • Useful for deprecation warnings and migration guidance

Configuration Generation

Generate the EmberENV configuration object based on enabled features.

/**
 * Generate EmberENV configuration for enabled features
 * @returns Configuration object with feature flags
 */
config(): { EmberENV: Record<string, any> };

Usage Example:

// In an addon's index.js
config(environment, appConfig) {
  let optionalFeatures = this.addons.find(a => a.name === '@ember/optional-features');
  let featureConfig = optionalFeatures.config();
  
  // Merge feature configuration into app config
  return {
    ...featureConfig,
    // Other configuration options
  };
}

Generated Configuration Format:

The configuration object contains EmberENV flags with feature names converted to uppercase constants:

// Example output for enabled features
{
  EmberENV: {
    _TEMPLATE_ONLY_GLIMMER_COMPONENTS: true,
    _JQUERY_INTEGRATION: false,
    _APPLICATION_TEMPLATE_WRAPPER: true
  }
}

Feature Name Transformation:

  • Convert to uppercase: template-only-glimmer-componentsTEMPLATE_ONLY_GLIMMER_COMPONENTS
  • Replace hyphens with underscores: -_
  • Add underscore prefix: TEMPLATE_ONLY_GLIMMER_COMPONENTS_TEMPLATE_ONLY_GLIMMER_COMPONENTS

Integration Patterns

Addon Discovery

Find the @ember/optional-features addon instance within your addon's included hook:

// Standard pattern for finding the addon
included() {
  let optionalFeatures = this.addons.find(a => a.name === '@ember/optional-features');
  
  if (!optionalFeatures) {
    // Handle case where @ember/optional-features is not installed
    console.warn('@ember/optional-features not found, using defaults');
    return;
  }
  
  // Use optionalFeatures methods...
}

Conditional Asset Inclusion

Include different assets based on feature states:

included() {
  let optionalFeatures = this.addons.find(a => a.name === '@ember/optional-features');
  
  // Conditionally import jQuery plugins
  if (optionalFeatures.isFeatureEnabled('jquery-integration')) {
    this.import('vendor/jquery-dependent-plugin.js');
  } else {
    this.import('vendor/vanilla-js-alternative.js');
  }
}

Build Configuration

Modify build configuration based on features:

included() {
  let optionalFeatures = this.addons.find(a => a.name === '@ember/optional-features');
  
  if (optionalFeatures.isFeatureEnabled('template-only-glimmer-components')) {
    // Configure Babel for Glimmer components
    this.options.babel = this.options.babel || {};
    this.options.babel.plugins = this.options.babel.plugins || [];
    this.options.babel.plugins.push('glimmer-component-transform');
  }
}

Error Handling

Build-time integration methods are designed to be safe and handle edge cases gracefully:

  • Missing addon: Methods return sensible defaults when @ember/optional-features is not installed
  • Invalid feature names: Unknown features return false for isFeatureEnabled()
  • Configuration errors: Malformed configuration files are handled with fallback to defaults

Performance Considerations

  • Feature state is cached during addon initialization for fast access
  • Configuration is loaded once and validated at startup
  • Method calls have minimal overhead during build process