diff --git a/packages/compat/src/htmlbars-unwrapper.ts b/packages/compat/src/htmlbars-unwrapper.ts
new file mode 100644
index 000000000..842ca307b
--- /dev/null
+++ b/packages/compat/src/htmlbars-unwrapper.ts
@@ -0,0 +1,4 @@
+export function unwrapPlugin(params: { requireFile: string; buildUsing: string; params: any }) {
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
+ return require(params.requireFile)[params.buildUsing](params.params).plugin;
+}
diff --git a/packages/compat/src/v1-app.ts b/packages/compat/src/v1-app.ts
index 2b815c96f..4f9d4476d 100644
--- a/packages/compat/src/v1-app.ts
+++ b/packages/compat/src/v1-app.ts
@@ -558,6 +558,23 @@ export default class V1App {
// even if the app was using @embroider/macros, we drop it from the config
// here in favor of our globally-configured one.
options.plugins.ast = options.plugins.ast.filter((p: any) => !isEmbroiderMacrosPlugin(p));
+
+ // The parallelization protocol in ember-cli-htmlbars doesn't actually
+ // apply to the AST plugins, it applies to wrappers that
+ // ember-cli-htmlbars keeps around the plugins. Those wrappers aren't
+ // availble to us when we look at the template compiler configuration, so
+ // we need to find them directly out of the registry here. And we need to
+ // provide our own unwrapper shim to pull the real plugin out of the
+ // wrapper after deserializing.
+ for (let wrapper of this.app.registry.load('htmlbars-ast-plugin')) {
+ if (wrapper.parallelBabel && wrapper.plugin && !wrapper.plugin.parallelBabel) {
+ wrapper.plugin.parallelBabel = {
+ requireFile: join(__dirname, 'htmlbars-unwrapper.js'),
+ buildUsing: 'unwrapPlugin',
+ params: wrapper.parallelBabel,
+ };
+ }
+ }
}
return options.plugins;
}