diff --git a/.vscode/launch.json b/.vscode/launch.json index d3b1c133e..3356019dd 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -56,6 +56,18 @@ }, "outputCapture": "std" }, + { + "type": "node", + "request": "launch", + "name": "Build fastboot-app", + "program": "/Users/edward/hacking/sample/node_modules/.bin/ember", + "cwd": "${workspaceFolder}/test-packages/fastboot-app", + "args": ["build"], + "env": { + "JOBS": "1" + }, + "outputCapture": "std" + }, { "type": "node", "request": "launch", diff --git a/packages/compat/src/detect-babel-plugins.ts b/packages/compat/src/detect-babel-plugins.ts new file mode 100644 index 000000000..de78c4647 --- /dev/null +++ b/packages/compat/src/detect-babel-plugins.ts @@ -0,0 +1,37 @@ +import { PluginItem } from '@babel/core'; + +export function isEmberAutoImportDynamic(item: PluginItem): boolean { + let pluginPath: string; + if (typeof item === 'string') { + pluginPath = item; + } else if (Array.isArray(item) && item.length > 0 && typeof item[0] === 'string') { + pluginPath = item[0]; + } else { + return false; + } + return /(^|\/)ember-auto-import\//.test(pluginPath); +} + +export function isCompactReexports(item: PluginItem): boolean { + let pluginPath: string; + if (typeof item === 'string') { + pluginPath = item; + } else if (Array.isArray(item) && item.length > 0 && typeof item[0] === 'string') { + pluginPath = item[0]; + } else { + return false; + } + return /(^|\/)babel-plugin-compact-reexports\//.test(pluginPath); +} + +export function isColocationPlugin(item: PluginItem): boolean { + let pluginPath: string; + if (typeof item === 'string') { + pluginPath = item; + } else if (Array.isArray(item) && item.length > 0 && typeof item[0] === 'string') { + pluginPath = item[0]; + } else { + return false; + } + return /(^|\/)ember-cli-htmlbars\/lib\/colocated-babel-plugin/.test(pluginPath); +} diff --git a/packages/compat/src/detect-ember-auto-import.ts b/packages/compat/src/detect-ember-auto-import.ts deleted file mode 100644 index 9fe4ce35f..000000000 --- a/packages/compat/src/detect-ember-auto-import.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { PluginItem } from '@babel/core'; - -export function isEmberAutoImportDynamic(item: PluginItem): boolean { - let pluginPath: string; - if (typeof item === 'string') { - pluginPath = item; - } else if (Array.isArray(item) && item.length > 0 && typeof item[0] === 'string') { - pluginPath = item[0]; - } else { - return false; - } - return /(^|\/)ember-auto-import\//.test(pluginPath); -} diff --git a/packages/compat/src/v1-addon.ts b/packages/compat/src/v1-addon.ts index cc16c0fcd..327dfe281 100644 --- a/packages/compat/src/v1-addon.ts +++ b/packages/compat/src/v1-addon.ts @@ -22,8 +22,7 @@ import V1App from './v1-app'; import modulesCompat from './modules-compat'; import writeFile from 'broccoli-file-creator'; import SynthesizeTemplateOnlyComponents from './synthesize-template-only-components'; -import { isEmberAutoImportDynamic } from './detect-ember-auto-import'; -import { isCompactReexports } from './detect-compact-reexports'; +import { isEmberAutoImportDynamic, isCompactReexports, isColocationPlugin } from './detect-babel-plugins'; import { ResolvedDep } from '@embroider/core/src/resolver'; const stockTreeNames = Object.freeze([ @@ -179,12 +178,18 @@ export default class V1Addon { }, }); - if (this.needsCustomBabel()) { - // there is customized babel behavior needed, so we will leave - // ember-cli-babel in place, but modify its config so it doesn't do the - // things we don't want to do in stage1. - this.updateBabelConfig(); - } else { + // first, look into the babel config and related packages to decide whether + // we need to run babel at all in this stage. + let needsCustomBabel = this.needsCustomBabel(); + + // regardless of the answer, we modify the babel config, because even if + // we're unregistering ember-cli-babel, some addons manually invoke + // ember-cli-babel in their custom hooks, and in that case we want to be + // sure we've taken out the babel plugins that really shouldn't run at this + // stage. + this.updateBabelConfig(); + + if (!needsCustomBabel) { // no custom babel behavior, so we don't run the ember-cli-babel // preprocessor at all. We still need to register a no-op preprocessor to // prevent ember-cli from emitting a deprecation warning. @@ -247,8 +252,7 @@ export default class V1Addon { return true; } - let babelConfig = this.options.babel as TransformOptions | undefined; - if (babelConfig && babelConfig.plugins && babelConfig.plugins.length > 0) { + if ((this.options.babel?.plugins?.filter(babelPluginAllowedInStage1)?.length ?? 0) > 0) { // this addon has custom babel plugins, so we need to run them here in // stage1 return true; @@ -1016,6 +1020,13 @@ function babelPluginAllowedInStage1(plugin: PluginItem) { return false; } + if (isColocationPlugin(plugin)) { + // template co-location is a first-class feature we support directly, so + // whether or not the app brought a plugin for it we're going to do it our + // way. + return false; + } + return true; } diff --git a/packages/compat/src/v1-app.ts b/packages/compat/src/v1-app.ts index ff2fa4a52..74005622d 100644 --- a/packages/compat/src/v1-app.ts +++ b/packages/compat/src/v1-app.ts @@ -18,7 +18,7 @@ import resolvePackagePath from 'resolve-package-path'; import Concat from 'broccoli-concat'; import mapKeys from 'lodash/mapKeys'; import SynthesizeTemplateOnlyComponents from './synthesize-template-only-components'; -import { isEmberAutoImportDynamic } from './detect-ember-auto-import'; +import { isEmberAutoImportDynamic } from './detect-babel-plugins'; // This controls and types the interface between our new world and the classic // v1 app instance. diff --git a/test-packages/fastboot-addon/index.js b/test-packages/fastboot-addon/index.js index 5d4fffb6c..61d363113 100644 --- a/test-packages/fastboot-addon/index.js +++ b/test-packages/fastboot-addon/index.js @@ -6,4 +6,7 @@ module.exports = { manifest.vendorFiles.push('fastboot-addon/sample.js'); return manifest; }, + included(...args) { + this._super.included.call(this, ...args); + }, };