ember.nvp 1.1.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,21 +2,13 @@
2
2
  "solution": {
3
3
  "ember.nvp": {
4
4
  "impact": "minor",
5
- "oldVersion": "1.0.0",
6
- "newVersion": "1.1.0",
5
+ "oldVersion": "1.2.0",
6
+ "newVersion": "1.3.0",
7
7
  "tagName": "latest",
8
8
  "constraints": [
9
9
  {
10
10
  "impact": "minor",
11
11
  "reason": "Appears in changelog section :rocket: Enhancement"
12
- },
13
- {
14
- "impact": "patch",
15
- "reason": "Appears in changelog section :memo: Documentation"
16
- },
17
- {
18
- "impact": "patch",
19
- "reason": "Appears in changelog section :house: Internal"
20
12
  }
21
13
  ],
22
14
  "pkgJSONPath": "./package.json"
@@ -26,21 +18,13 @@
26
18
  },
27
19
  "@nullvoxpopuli/ember-rolldown": {
28
20
  "impact": "minor",
29
- "oldVersion": "2.0.0",
30
- "newVersion": "2.1.0",
21
+ "oldVersion": "2.4.0",
22
+ "newVersion": "2.5.0",
31
23
  "tagName": "latest",
32
24
  "constraints": [
33
25
  {
34
26
  "impact": "minor",
35
27
  "reason": "Appears in changelog section :rocket: Enhancement"
36
- },
37
- {
38
- "impact": "patch",
39
- "reason": "Appears in changelog section :memo: Documentation"
40
- },
41
- {
42
- "impact": "patch",
43
- "reason": "Appears in changelog section :house: Internal"
44
28
  }
45
29
  ],
46
30
  "pkgJSONPath": "./packages/rolldown/package.json"
@@ -49,5 +33,5 @@
49
33
  "oldVersion": "1.1.0"
50
34
  }
51
35
  },
52
- "description": "## Release (2026-07-22)\n\n* ember.nvp 1.1.0 (minor)\n* @nullvoxpopuli/ember-rolldown 2.1.0 (minor)\n\n#### :rocket: Enhancement\n* `@nullvoxpopuli/ember-rolldown`\n * [#97](https://github.com/NullVoxPopuli/ember.nvp/pull/97) Add appReexports plugin as a separate ember-rolldown entrypoint ([@NullVoxPopuli-ai-agent](https://github.com/NullVoxPopuli-ai-agent))\n * [#95](https://github.com/NullVoxPopuli/ember.nvp/pull/95) enable declaration maps in the rolldown plugin ([@NullVoxPopuli](https://github.com/NullVoxPopuli))\n* `ember.nvp`\n * [#91](https://github.com/NullVoxPopuli/ember.nvp/pull/91) Add a browser extension project type (minimal-extension base) ([@NullVoxPopuli-ai-agent](https://github.com/NullVoxPopuli-ai-agent))\n\n#### :memo: Documentation\n* `@nullvoxpopuli/ember-rolldown`, `ember.nvp`\n * [#96](https://github.com/NullVoxPopuli/ember.nvp/pull/96) rolldown: document + test co-located CSS support ([@NullVoxPopuli](https://github.com/NullVoxPopuli))\n\n#### :house: Internal\n* `@nullvoxpopuli/ember-rolldown`, `ember.nvp`\n * [#93](https://github.com/NullVoxPopuli/ember.nvp/pull/93) More tests ([@NullVoxPopuli](https://github.com/NullVoxPopuli))\n* `ember.nvp`\n * [#92](https://github.com/NullVoxPopuli/ember.nvp/pull/92) Move check layers into their own permutation matrix ([@NullVoxPopuli-ai-agent](https://github.com/NullVoxPopuli-ai-agent))\n * [#90](https://github.com/NullVoxPopuli/ember.nvp/pull/90) Remove pinYukuParser test helper ([@Copilot](https://github.com/apps/copilot-swe-agent))\n * [#89](https://github.com/NullVoxPopuli/ember.nvp/pull/89) refactor(test): extract shared listFiles/read helpers to #test-helpers ([@Copilot](https://github.com/apps/copilot-swe-agent))\n * [#87](https://github.com/NullVoxPopuli/ember.nvp/pull/87) Convert Greeting declaration check to inline snapshot assertion ([@Copilot](https://github.com/apps/copilot-swe-agent))\n\n#### Committers: 3\n- @NullVoxPopuli's reduced-access machine account for AI usage ([@NullVoxPopuli-ai-agent](https://github.com/NullVoxPopuli-ai-agent))\n- Copilot [Bot] ([@copilot-swe-agent](https://github.com/apps/copilot-swe-agent))\n- [@NullVoxPopuli](https://github.com/NullVoxPopuli)\n"
36
+ "description": "## Release (2026-08-03)\n\n* ember.nvp 1.3.0 (minor)\n* @nullvoxpopuli/ember-rolldown 2.5.0 (minor)\n\n#### :rocket: Enhancement\n* `ember.nvp`\n * [#106](https://github.com/NullVoxPopuli/ember.nvp/pull/106) README layer ([@tcjr](https://github.com/tcjr))\n* `@nullvoxpopuli/ember-rolldown`\n * [#107](https://github.com/NullVoxPopuli/ember.nvp/pull/107) rolldown: check the tsconfig the build uses, not always tsconfig.json ([@NullVoxPopuli](https://github.com/NullVoxPopuli))\n\n#### Committers: 2\n- Tom Carter ([@tcjr](https://github.com/tcjr))\n- [@NullVoxPopuli](https://github.com/NullVoxPopuli)\n"
53
37
  }
package/CHANGELOG.md CHANGED
@@ -1,5 +1,64 @@
1
1
  # Changelog
2
2
 
3
+ ## Release (2026-08-03)
4
+
5
+ * ember.nvp 1.3.0 (minor)
6
+ * @nullvoxpopuli/ember-rolldown 2.5.0 (minor)
7
+
8
+ #### :rocket: Enhancement
9
+ * `ember.nvp`
10
+ * [#106](https://github.com/NullVoxPopuli/ember.nvp/pull/106) README layer ([@tcjr](https://github.com/tcjr))
11
+ * `@nullvoxpopuli/ember-rolldown`
12
+ * [#107](https://github.com/NullVoxPopuli/ember.nvp/pull/107) rolldown: check the tsconfig the build uses, not always tsconfig.json ([@NullVoxPopuli](https://github.com/NullVoxPopuli))
13
+
14
+ #### Committers: 2
15
+ - Tom Carter ([@tcjr](https://github.com/tcjr))
16
+ - [@NullVoxPopuli](https://github.com/NullVoxPopuli)
17
+
18
+ ## Release (2026-07-24)
19
+
20
+ * @nullvoxpopuli/ember-rolldown 2.4.0 (minor)
21
+
22
+ #### :rocket: Enhancement
23
+ * `@nullvoxpopuli/ember-rolldown`
24
+ * [#104](https://github.com/NullVoxPopuli/ember.nvp/pull/104) rolldown: support .gts/.gjs build entries ([@NullVoxPopuli](https://github.com/NullVoxPopuli))
25
+
26
+ #### Committers: 1
27
+ - [@NullVoxPopuli](https://github.com/NullVoxPopuli)
28
+
29
+ ## Release (2026-07-22)
30
+
31
+ * @nullvoxpopuli/ember-rolldown 2.3.0 (minor)
32
+
33
+ #### :rocket: Enhancement
34
+ * `@nullvoxpopuli/ember-rolldown`
35
+ * [#101](https://github.com/NullVoxPopuli/ember.nvp/pull/101) appReexports: accept string[] include and options as second argument ([@NullVoxPopuli-ai-agent](https://github.com/NullVoxPopuli-ai-agent))
36
+
37
+ #### :bug: Bug Fix
38
+ * `@nullvoxpopuli/ember-rolldown`
39
+ * [#103](https://github.com/NullVoxPopuli/ember.nvp/pull/103) rolldown: externalize the modules ember-source provides (renamed-modules) ([@NullVoxPopuli](https://github.com/NullVoxPopuli))
40
+
41
+ #### Committers: 2
42
+ - @NullVoxPopuli's reduced-access machine account for AI usage ([@NullVoxPopuli-ai-agent](https://github.com/NullVoxPopuli-ai-agent))
43
+ - [@NullVoxPopuli](https://github.com/NullVoxPopuli)
44
+
45
+ ## Release (2026-07-22)
46
+
47
+ * ember.nvp 1.2.0 (minor)
48
+ * @nullvoxpopuli/ember-rolldown 2.2.0 (minor)
49
+
50
+ #### :rocket: Enhancement
51
+ * `@nullvoxpopuli/ember-rolldown`, `ember.nvp`
52
+ * [#98](https://github.com/NullVoxPopuli/ember.nvp/pull/98) Integration-test ember-scoped-css; add babel.templateTransforms ([@NullVoxPopuli-ai-agent](https://github.com/NullVoxPopuli-ai-agent))
53
+
54
+ #### :bug: Bug Fix
55
+ * `@nullvoxpopuli/ember-rolldown`
56
+ * [#99](https://github.com/NullVoxPopuli/ember.nvp/pull/99) rolldown: fix virtual .gts declaration resolution + specifier-rewrite sourcemaps ([@NullVoxPopuli](https://github.com/NullVoxPopuli))
57
+
58
+ #### Committers: 2
59
+ - @NullVoxPopuli's reduced-access machine account for AI usage ([@NullVoxPopuli-ai-agent](https://github.com/NullVoxPopuli-ai-agent))
60
+ - [@NullVoxPopuli](https://github.com/NullVoxPopuli)
61
+
3
62
  ## Release (2026-07-22)
4
63
 
5
64
  * ember.nvp 1.1.0 (minor)
package/README.md CHANGED
@@ -198,6 +198,11 @@ export default {
198
198
 
199
199
  await packageJson.addScripts({ "my-script": 'echo "Hello"' }, project.directory);
200
200
  },
201
+
202
+ // Optionally add something to the README.md file
203
+ readme() {
204
+ return "### My Feature\n\nHere's what my feature brings to the table.";
205
+ },
201
206
  };
202
207
  ```
203
208
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ember.nvp",
3
- "version": "1.1.0",
3
+ "version": "1.3.0",
4
4
  "description": "ember project generator, alternative to the official blueprints, but more modern -- hopefully one day to upstream back in to ember-cli / official blueprints",
5
5
  "repository": {
6
6
  "type": "git",
@@ -58,11 +58,30 @@ A `babel.config.js` is optional. Without one, `ember()` compiles templates
58
58
  [decorator-transforms](https://github.com/ef4/decorator-transforms)), and
59
59
  TypeScript; with one, your config runs instead.
60
60
 
61
+ ### Entrypoints
62
+
63
+ Entries may be any extension — `.ts`, `.js`, `.gts`, `.gjs`:
64
+
65
+ ```js
66
+ export default defineConfig({
67
+ entry: ["./src/index.ts", "./src/components/menu.gts"],
68
+ plugins: [ember()],
69
+ });
70
+ ```
71
+
72
+ Whatever the source extension, the emitted `.js` and `.d.ts` paths mirror the
73
+ entry paths (that's how tsdown's dts support works): the example emits
74
+ `dist/index.js` + `dist/index.d.ts` and `dist/components/menu.js` +
75
+ `dist/components/menu.d.ts`. Type imports resolve against those emitted
76
+ paths, so your entries — together with your `exports` map — _are_ your
77
+ public API: a module that isn't an entry has no stable `dist/` path of its
78
+ own and is only reachable through the entrypoints that re-export it.
79
+
61
80
  ### Declarations
62
81
 
63
82
  Declarations are emitted with isolated declarations — the only declaration
64
83
  pipeline that can see `<template>` (`.gts`/`.gjs`) modules, which exist only
65
- inside the bundler's module graph. Your `tsconfig.json` must enable it
84
+ inside the bundler's module graph. The tsconfig your build uses must enable it
66
85
  (`ember()` errors otherwise):
67
86
 
68
87
  ```jsonc
@@ -82,6 +101,33 @@ import type { TOC } from "@ember/component/template-only";
82
101
  export const Badge: TOC<BadgeSignature> = <template>...</template>;
83
102
  ```
84
103
 
104
+ #### Keeping the constraint off dev-only code
105
+
106
+ `isolatedDeclarations` is a constraint on how _published_ code is written, so it
107
+ should cover only the code you emit declarations for. If your package also holds
108
+ dev-only code — a demo app, in-package tests — putting the flag on the single
109
+ `tsconfig.json` that covers everything would force explicit annotations on demo
110
+ components and test helpers that never get a `.d.ts` emitted for them.
111
+
112
+ The tsconfig `ember()` checks is the one
113
+ [tsdown's `tsconfig` option](https://tsdown.dev/options/tsconfig) points at, so
114
+ point the build at a publish-only config and leave `tsconfig.json` alone for
115
+ editors and `tsc --noEmit`:
116
+
117
+ ```js
118
+ // tsdown.config.js
119
+ export default defineConfig({
120
+ entry: ["./src/index.ts"],
121
+ // include: ["src/**/*"], isolatedDeclarations: true
122
+ tsconfig: "./tsconfig.publish.json",
123
+ plugins: [ember()],
124
+ });
125
+ ```
126
+
127
+ The tradeoff: isolated-declaration errors in `src` then surface when you build
128
+ rather than in your editor, since the editor uses `tsconfig.json`. Run the build
129
+ (or `tsc --noEmit -p tsconfig.publish.json`) in CI so nothing lands unchecked.
130
+
85
131
  ## CSS
86
132
 
87
133
  Components that import co-located CSS (`import './popup.css'`) need
@@ -99,16 +145,50 @@ because the importing component module never loads, any declaration that
99
145
  references that component dangles, surfacing as misleading
100
146
  `UNLOADABLE_DEPENDENCY` errors on `<component>.d.ts` files.
101
147
 
102
- Scoping/transforming the CSS itself (e.g.
103
- [ember-scoped-css](https://github.com/soxhub/ember-scoped-css)) is separate
104
- from bundling and runs via its own plugins.
148
+ ### ember-scoped-css
149
+
150
+ [ember-scoped-css](https://github.com/auditboard/ember-scoped-css) works with
151
+ this pipeline: its template transform rides along via `ember()`'s
152
+ `babel.templateTransforms` option, and its unplugin (`ember-scoped-css/rollup`)
153
+ resolves the scoped CSS requests the transform injects:
154
+
155
+ ```js
156
+ import { defineConfig } from "tsdown";
157
+ import { ember } from "@nullvoxpopuli/ember-rolldown";
158
+ import { scopedCSS } from "ember-scoped-css/rollup";
159
+ import { scopedCSS as scopedCssBabel } from "ember-scoped-css/babel";
160
+
161
+ export default defineConfig({
162
+ entry: ["./src/index.ts"],
163
+ css: { inject: true },
164
+ plugins: [
165
+ ember({
166
+ babel: {
167
+ plugins: [scopedCssBabel()],
168
+ templateTransforms: [scopedCssBabel.template({})],
169
+ },
170
+ }),
171
+ scopedCSS(),
172
+ ],
173
+ });
174
+ ```
175
+
176
+ This scopes co-located `.css` files, inline `<style scoped>` blocks, and the
177
+ `scopedClass` pseudo-helper (that last one is what the `babel.plugins` entry
178
+ handles — leave it off if you don't use `scopedClass` in module code).
179
+
180
+ `css.inject` matters for libraries: it keeps the `import "./style.css"`
181
+ statement in `dist/index.js`, so consuming apps pull the styles in through
182
+ the module graph — without it the bundled CSS is emitted but nothing loads
183
+ it.
105
184
 
106
185
  ## What `ember()` does
107
186
 
108
187
  `ember()` returns an array of rolldown plugins:
109
188
 
110
- - **`emberIsolatedDeclarations()`** — errors when a `tsconfig.json` is present
111
- without `isolatedDeclarations: true`.
189
+ - **`emberIsolatedDeclarations()`** — errors when the tsconfig the build uses
190
+ (tsdown's `tsconfig` option, defaulting to `tsconfig.json`) is present without
191
+ `isolatedDeclarations: true`.
112
192
  - **`emberExternals()`** — keeps your `dependencies`, `peerDependencies`, and
113
193
  the ember virtual packages (e.g. `@ember/component`, `@glimmer/tracking`, the
114
194
  template compiler) external, so the consuming app resolves them.
@@ -128,12 +208,17 @@ ember({
128
208
  configFile: "./babel.config.js",
129
209
  babelHelpers: "bundled",
130
210
  plugins: [],
211
+ templateTransforms: [],
131
212
  filter: { include: { imports: ["ember-concurrency"], code: [] } },
132
213
  },
133
214
  });
134
215
  ```
135
216
 
136
- Each option is documented on `BabelOptions`.
217
+ Each option is documented on `BabelOptions`. `templateTransforms` feeds
218
+ template AST transforms to the default template-compilation step; it can't be
219
+ combined with a babel config file — a config lists
220
+ `babel-plugin-ember-template-compilation` itself, so its transforms belong
221
+ there.
137
222
 
138
223
  ## App re-exports
139
224
 
@@ -156,12 +241,14 @@ export default defineConfig({
156
241
 
157
242
  With no arguments, top-level services (`services/*`) are re-exported — under
158
243
  strict mode, components and helpers are imported, but services are still
159
- injected by name. A string argument is an include glob, and an object gives
160
- full control:
244
+ injected by name. A string or array of strings is the include glob(s),
245
+ optionally followed by the remaining options; an object gives full control:
161
246
 
162
247
  ```js
163
248
  appReexports(); // services/*
164
249
  appReexports("components/**"); // one include glob
250
+ appReexports(["services/*", "helpers/*"]);
251
+ appReexports("components/**", { exclude: ["components/-private/**"] });
165
252
  appReexports({ include: ["services/*", "helpers/*"], exclude: [...] });
166
253
  ```
167
254
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nullvoxpopuli/ember-rolldown",
3
- "version": "2.1.0",
3
+ "version": "2.5.0",
4
4
  "description": "Meta plugin for building ember v2 libraries/addons with rolldown & tsdown.",
5
5
  "type": "module",
6
6
  "main": "index.ts",
@@ -51,13 +51,16 @@ describe("appReexports", () => {
51
51
  await rm(projectDir, { recursive: true, force: true });
52
52
  });
53
53
 
54
- async function build(options?: string | AppReexportsOptions) {
54
+ async function build(
55
+ include?: string | string[] | AppReexportsOptions,
56
+ options?: Omit<AppReexportsOptions, "include">,
57
+ ) {
55
58
  const bundle = await rolldown({
56
59
  input: {
57
60
  "components/foo": "./src/components/foo.js",
58
61
  "utils/math": "./src/utils/math.js",
59
62
  },
60
- plugins: [appReexports(options)],
63
+ plugins: [appReexports(include, options)],
61
64
  });
62
65
 
63
66
  await bundle.write({ dir: "dist" });
@@ -100,6 +103,36 @@ describe("appReexports", () => {
100
103
  expect(Object.keys(manifest["ember-addon"]["app-js"])).toEqual(["./components/foo.js"]);
101
104
  });
102
105
 
106
+ it("accepts an array of include globs", async () => {
107
+ await build(["components/**", "utils/**"]);
108
+
109
+ const manifest = await readJson("package.json");
110
+
111
+ expect(Object.keys(manifest["ember-addon"]["app-js"])).toEqual([
112
+ "./components/foo.js",
113
+ "./utils/math.js",
114
+ ]);
115
+ });
116
+
117
+ it("accepts options as the second argument alongside a string or array include", async () => {
118
+ await build("**/*.js", { exclude: ["utils/**"] });
119
+
120
+ let manifest = await readJson("package.json");
121
+
122
+ expect(Object.keys(manifest["ember-addon"]["app-js"])).toEqual(["./components/foo.js"]);
123
+
124
+ await build(["components/**", "utils/**"], {
125
+ mapFilename: (name) => name.replace("math", "arithmetic"),
126
+ });
127
+
128
+ manifest = await readJson("package.json");
129
+
130
+ expect(manifest["ember-addon"]["app-js"]).toEqual({
131
+ "./components/foo.js": "./dist/_app_/components/foo.js",
132
+ "./utils/arithmetic.js": "./dist/_app_/utils/arithmetic.js",
133
+ });
134
+ });
135
+
103
136
  it("defaults to top-level services", async () => {
104
137
  await mkdir(join(projectDir, "src/services/nested"), { recursive: true });
105
138
  await writeFile(join(projectDir, "src/services/session.js"), "export default class {}\n");
@@ -65,16 +65,27 @@ export interface AppReexportsOptions {
65
65
  * ```
66
66
  *
67
67
  * With no arguments, top-level services (`services/*`) are re-exported. A
68
- * string argument is an include glob; an object gives full control:
68
+ * string or array of strings is the include glob(s), optionally followed by
69
+ * the remaining options; an object gives full control:
69
70
  *
70
71
  * ```js
71
72
  * appReexports(); // services/*
72
73
  * appReexports("components/**"); // one include glob
74
+ * appReexports(["services/*", "helpers/*"]);
75
+ * appReexports("components/**", { exclude: ["components/-private/**"] });
73
76
  * appReexports({ include: ["services/*", "helpers/*"], exclude: [...] });
74
77
  * ```
75
78
  */
76
- export function appReexports(options: string | AppReexportsOptions = {}): Plugin {
77
- const resolved = typeof options === "string" ? { include: [options] } : options;
79
+ export function appReexports(
80
+ includeOrOptions: string | string[] | AppReexportsOptions = {},
81
+ options: Omit<AppReexportsOptions, "include"> = {},
82
+ ): Plugin {
83
+ const resolved =
84
+ typeof includeOrOptions === "string"
85
+ ? { ...options, include: [includeOrOptions] }
86
+ : Array.isArray(includeOrOptions)
87
+ ? { ...options, include: includeOrOptions }
88
+ : includeOrOptions;
78
89
  const include = resolved.include ?? ["services/*"];
79
90
 
80
91
  return {
@@ -0,0 +1,17 @@
1
+ import { describe, expect, it } from "vitest";
2
+
3
+ import { emberBabel } from "./babel.ts";
4
+
5
+ describe("emberBabel", () => {
6
+ it("rejects templateTransforms combined with a config file", () => {
7
+ expect(() =>
8
+ emberBabel({ configFile: "./babel.config.js", templateTransforms: ["some-transform"] }),
9
+ ).toThrow(/pass the transforms/);
10
+ });
11
+
12
+ it("allows templateTransforms when config files are opted out", () => {
13
+ expect(() =>
14
+ emberBabel({ configFile: false, templateTransforms: ["some-transform"] }),
15
+ ).not.toThrow();
16
+ });
17
+ });
@@ -4,6 +4,7 @@ import templateCompilation from "babel-plugin-ember-template-compilation";
4
4
  import decoratorTransforms from "decorator-transforms";
5
5
  import { loadPartialConfigSync } from "@babel/core";
6
6
  import type { PluginItem } from "@babel/core";
7
+ import type { Transform } from "babel-plugin-ember-template-compilation";
7
8
  import type { Plugin } from "rolldown";
8
9
 
9
10
  export interface BabelOptions {
@@ -24,6 +25,15 @@ export interface BabelOptions {
24
25
  * Extra babel plugins to run, appended after the config's plugins.
25
26
  */
26
27
  plugins?: PluginItem[];
28
+ /**
29
+ * Template AST transforms (e.g. ember-scoped-css's `scopedCSS.template()`)
30
+ * passed to the default `babel-plugin-ember-template-compilation` entry.
31
+ *
32
+ * Only valid without a babel config file: with your own config, you list
33
+ * `babel-plugin-ember-template-compilation` yourself, so its `transforms`
34
+ * belong there.
35
+ */
36
+ templateTransforms?: Transform[];
27
37
  /**
28
38
  * Opt additional files into babel (see maybeBabel's `filter`). Use this to
29
39
  * cover addons that ship code needing babel (e.g. `ember-concurrency`).
@@ -63,7 +73,7 @@ function detectConfigFile(): string | undefined {
63
73
  * consuming app resolves it (the library keeps `decorator-transforms` as
64
74
  * a real dependency).
65
75
  */
66
- function defaultPlugins(): PluginItem[] {
76
+ function defaultPlugins(templateTransforms?: Transform[]): PluginItem[] {
67
77
  return [
68
78
  [
69
79
  transformTypeScript,
@@ -73,7 +83,7 @@ function defaultPlugins(): PluginItem[] {
73
83
  allowDeclareFields: true,
74
84
  },
75
85
  ],
76
- [templateCompilation, { targetFormat: "hbs" }],
86
+ [templateCompilation, { targetFormat: "hbs", transforms: templateTransforms ?? [] }],
77
87
  [
78
88
  decoratorTransforms,
79
89
  {
@@ -118,6 +128,14 @@ export function emberBabel(options: BabelOptions = {}): Plugin {
118
128
  };
119
129
 
120
130
  if (configFile) {
131
+ if (options.templateTransforms?.length) {
132
+ throw new Error(
133
+ `\`babel.templateTransforms\` cannot be combined with a babel config file (found ${configFile}). ` +
134
+ `Your config lists babel-plugin-ember-template-compilation itself, so pass the transforms ` +
135
+ `to its \`transforms\` option there instead.`,
136
+ );
137
+ }
138
+
121
139
  return maybeBabel({
122
140
  ...shared,
123
141
  configFile,
@@ -131,6 +149,6 @@ export function emberBabel(options: BabelOptions = {}): Plugin {
131
149
  // for one -- we provide the whole plugin list inline.
132
150
  configFile: false,
133
151
  babelrc: false,
134
- plugins: defaultPlugins().concat(options.plugins ?? []),
152
+ plugins: defaultPlugins(options.templateTransforms).concat(options.plugins ?? []),
135
153
  }) as unknown as Plugin;
136
154
  }