Make v2 addons work in non-Embroider apps by providing compatibility shim that transforms v2 addon structure into v1-compatible format.
npx @tessl/cli install tessl/npm-embroider--addon-shim@1.10.0@embroider/addon-shim provides a compatibility shim that enables Ember.js v2 addons to work in classic (non-Embroider) applications. The shim transforms v2 addon structure into v1-compatible format, handling module resolution, asset bundling, and build pipeline integration without requiring users to migrate to Embroider.
npm install @embroider/addon-shimconst { addonV1Shim } = require("@embroider/addon-shim");For TypeScript (type imports only):
import type { ShimOptions, AddonInstance } from "@embroider/addon-shim";
const { addonV1Shim } = require("@embroider/addon-shim");// Create an addon-main.js file in your v2 addon
const { addonV1Shim } = require('@embroider/addon-shim');
module.exports = addonV1Shim(__dirname);With configuration options:
const { addonV1Shim } = require('@embroider/addon-shim');
module.exports = addonV1Shim(__dirname, {
disabled(options) {
// Conditionally disable shim functionality
let welcomeConfig = options['ember-welcome-page'] || {};
return process.env.EMBER_ENV === 'production' && !welcomeConfig.enabled;
},
autoImportCompat: {
customizeMeta(meta) {
// Customize ember-auto-import metadata
return meta;
}
}
});The addon shim operates as a bridge between v2 and v1 addon architectures:
included, treeForApp, treeForPublic, etc.)app-js and public-assets configurations to v1 Broccoli treesember-auto-import for proper module resolutionCreates a v1-compatible addon instance from a v2 addon directory and optional configuration.
/**
* Creates a v1-compatible addon instance from a v2 addon
* @param directory - The directory path of the v2 addon
* @param options - Optional configuration for the shim
* @returns A v1 addon instance object with lifecycle hooks
*/
function addonV1Shim(directory: string, options?: ShimOptions): AddonInstance;
interface AddonInstance {
/** The name of the addon from package.json */
name: string;
/** Package information from package.json */
pkg: PackageInfo;
/** Parent addon instance or project */
parent: AddonInstance | Project;
/** Project instance (root project) */
project: Project;
/** App instance (if directly under app) */
app?: AppInstance;
/** Broccoli tree generator function */
treeGenerator: (dir: string) => BroccoliTree;
/** V1 addon lifecycle hook for initialization and registration */
included(this: AddonInstance, ...args: unknown[]): void;
/** V1 addon hook for providing app-js files to the consuming application */
treeForApp(this: AddonInstance): BroccoliTree | undefined;
/** V1 addon hook for addon files (always returns undefined for shim) */
treeForAddon(): undefined;
/** V1 addon hook for public assets to be served by the application */
treeForPublic(this: AddonInstance): BroccoliTree | undefined;
/** V1 addon hook for cache key generation for Broccoli trees */
cacheKeyForTree(this: AddonInstance, treeType: string): string;
/** V1 addon hook to determine if addon is under development */
isDevelopingAddon(this: AddonInstance): boolean;
/** Legacy method for v2 addon registration (backward compatibility) */
registerV2Addon(this: AddonInstance, name: string, root: string): void;
/** Find the host app instance */
_findHost(): AppInstance;
/** Super method for calling parent implementation */
_super: { included: { apply: (context: any, args: unknown[]) => void } };
}Optional configuration interface for customizing shim behavior.
interface ShimOptions {
/**
* Function to conditionally disable shim functionality
* @param options - Parent options from consuming app or addon
* @returns true to disable shim features, false to enable
*/
disabled?: (options: any) => boolean;
/** Configuration for ember-auto-import integration */
autoImportCompat?: {
/**
* Customize the ember-addon metadata used by ember-auto-import
* @param meta - Original addon metadata from package.json
* @returns Modified addon metadata
*/
customizeMeta?: (meta: AddonMeta) => AddonMeta;
};
}
interface AddonMeta {
/** Version of the ember-addon format (must be 2) */
version: 2;
/** Type of addon */
type: "addon";
/** Main entry point for the addon */
main?: string;
/** Order index for controlling addon loading order */
"order-index"?: number;
/** Whether this addon is a lazy engine */
"lazy-engine"?: boolean;
/** Indicates this addon was auto-upgraded from v1 format */
"auto-upgraded"?: true;
/** App-js mapping for JavaScript files to be included in the app */
"app-js"?: Record<string, string>;
/** FastBoot-specific JavaScript files */
"fastboot-js"?: Record<string, string>;
/** Modules that should be implicitly imported */
"implicit-modules"?: string[];
/** Scripts that should be implicitly included */
"implicit-scripts"?: string[];
/** Styles that should be implicitly included */
"implicit-styles"?: string[];
/** Test modules that should be implicitly imported */
"implicit-test-modules"?: string[];
/** Test scripts that should be implicitly included */
"implicit-test-scripts"?: string[];
/** Test styles that should be implicitly included */
"implicit-test-styles"?: string[];
/** Public assets mapping for static files */
"public-assets"?: Record<string, string>;
/** Package name remapping for dependencies */
"renamed-packages"?: Record<string, string>;
/** Module name remapping for imports */
"renamed-modules"?: Record<string, string>;
}/** Broccoli tree type representing a file tree structure */
type BroccoliTree = any;
/** Validation result for ember-auto-import presence and version */
type AutoImportInfo =
| { present: false }
| { present: true; version: string; satisfiesV2: false }
| { present: true; version: string; satisfiesV2: true; instance: EAI2Instance };
interface EAI2Instance {
/** Root directory of the ember-auto-import addon */
root: string;
/** Register a v2 addon with ember-auto-import */
registerV2Addon(name: string, root: string): void;
/** Get the current ember-auto-import leader (v2.10.0+) */
leader?(): {
registerV2Addon(name: string, root: string, options?: ShimOptions['autoImportCompat']): void;
};
}
/** Additional types */
interface Project {
/** Root directory of the project */
root: string;
/** Project addons */
addons: AddonInstance[];
}
interface AppInstance {
/** App project */
project: Project;
}
interface PackageInfo {
/** Package name */
name: string;
/** Package version */
version: string;
/** Package dependencies */
dependencies?: Record<string, string>;
/** Package devDependencies */
devDependencies?: Record<string, string>;
/** Ember addon metadata */
"ember-addon"?: AddonMeta | { version?: 1; main?: string; };
}The shim performs validation and throws errors for common misconfigurations:
package.json doesn't contain valid ember-addon.version: 2ember-auto-import dependencyember-auto-import version is < 2.0.0Example error messages:
"did not find valid v2 addon metadata in <package-name>"
"<parent-name> needs to depend on ember-auto-import in order to use <addon-name>"
"<parent-name> has ember-auto-import <version> which is not new enough to use <addon-name>. It needs to upgrade to >=2.0"