ember.nvp 1.15.0 → 1.17.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,13 +2,17 @@
2
2
  "solution": {
3
3
  "ember.nvp": {
4
4
  "impact": "minor",
5
- "oldVersion": "1.14.0",
6
- "newVersion": "1.15.0",
5
+ "oldVersion": "1.16.0",
6
+ "newVersion": "1.17.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 :bug: Bug Fix"
12
16
  }
13
17
  ],
14
18
  "pkgJSONPath": "./package.json"
@@ -17,11 +21,21 @@
17
21
  "oldVersion": "1.2.0"
18
22
  },
19
23
  "@nullvoxpopuli/ember-rolldown": {
20
- "oldVersion": "2.10.0"
24
+ "impact": "minor",
25
+ "oldVersion": "2.11.0",
26
+ "newVersion": "2.12.0",
27
+ "tagName": "latest",
28
+ "constraints": [
29
+ {
30
+ "impact": "minor",
31
+ "reason": "Appears in changelog section :rocket: Enhancement"
32
+ }
33
+ ],
34
+ "pkgJSONPath": "./packages/rolldown/package.json"
21
35
  },
22
36
  "@nullvoxpopuli/ember-vite": {
23
- "oldVersion": "1.2.0"
37
+ "oldVersion": "1.3.0"
24
38
  }
25
39
  },
26
- "description": "## Release (2026-10-02)\n\n* ember.nvp 1.15.0 (minor)\n\n#### :rocket: Enhancement\n* `ember.nvp`\n * [#158](https://github.com/NullVoxPopuli/ember.nvp/pull/158) Migrate projects from the older blueprints ([@NullVoxPopuli-ai-agent](https://github.com/NullVoxPopuli-ai-agent))\n\n#### Committers: 1\n- @NullVoxPopuli's reduced-access machine account for AI usage ([@NullVoxPopuli-ai-agent](https://github.com/NullVoxPopuli-ai-agent))\n"
40
+ "description": "## Release (2026-10-16)\n\n* ember.nvp 1.17.0 (minor)\n* @nullvoxpopuli/ember-rolldown 2.12.0 (minor)\n\n#### :rocket: Enhancement\n* `@nullvoxpopuli/ember-rolldown`, `ember.nvp`\n * [#166](https://github.com/NullVoxPopuli/ember.nvp/pull/166) Require babel-plugin-ember-template-compilation 4.0.1 ([@NullVoxPopuli-ai-agent](https://github.com/NullVoxPopuli-ai-agent))\n\n#### :bug: Bug Fix\n* `ember.nvp`\n * [#164](https://github.com/NullVoxPopuli/ember.nvp/pull/164) Add vite/client types to the dev tsconfig of libraries with tests ([@NullVoxPopuli-ai-agent](https://github.com/NullVoxPopuli-ai-agent))\n\n#### Committers: 1\n- @NullVoxPopuli's reduced-access machine account for AI usage ([@NullVoxPopuli-ai-agent](https://github.com/NullVoxPopuli-ai-agent))\n"
27
41
  }
package/CHANGELOG.md CHANGED
@@ -1,5 +1,41 @@
1
1
  # Changelog
2
2
 
3
+ ## Release (2026-10-16)
4
+
5
+ * ember.nvp 1.17.0 (minor)
6
+ * @nullvoxpopuli/ember-rolldown 2.12.0 (minor)
7
+
8
+ #### :rocket: Enhancement
9
+ * `@nullvoxpopuli/ember-rolldown`, `ember.nvp`
10
+ * [#166](https://github.com/NullVoxPopuli/ember.nvp/pull/166) Require babel-plugin-ember-template-compilation 4.0.1 ([@NullVoxPopuli-ai-agent](https://github.com/NullVoxPopuli-ai-agent))
11
+
12
+ #### :bug: Bug Fix
13
+ * `ember.nvp`
14
+ * [#164](https://github.com/NullVoxPopuli/ember.nvp/pull/164) Add vite/client types to the dev tsconfig of libraries with tests ([@NullVoxPopuli-ai-agent](https://github.com/NullVoxPopuli-ai-agent))
15
+
16
+ #### Committers: 1
17
+ - @NullVoxPopuli's reduced-access machine account for AI usage ([@NullVoxPopuli-ai-agent](https://github.com/NullVoxPopuli-ai-agent))
18
+
19
+ ## Release (2026-10-12)
20
+
21
+ * ember.nvp 1.16.0 (minor)
22
+ * @nullvoxpopuli/ember-rolldown 2.11.0 (minor)
23
+ * @nullvoxpopuli/ember-vite 1.3.0 (minor)
24
+
25
+ #### :rocket: Enhancement
26
+ * `@nullvoxpopuli/ember-rolldown`, `@nullvoxpopuli/ember-vite`, `ember.nvp`
27
+ * [#163](https://github.com/NullVoxPopuli/ember.nvp/pull/163) Update the embroider dependencies, give the config hook its plugin context ([@NullVoxPopuli-ai-agent](https://github.com/NullVoxPopuli-ai-agent))
28
+
29
+ #### :bug: Bug Fix
30
+ * `@nullvoxpopuli/ember-vite`, `ember.nvp`
31
+ * [#162](https://github.com/NullVoxPopuli/ember.nvp/pull/162) Find the embroider config plugin by name ([@NullVoxPopuli-ai-agent](https://github.com/NullVoxPopuli-ai-agent))
32
+ * `@nullvoxpopuli/ember-rolldown`
33
+ * [#160](https://github.com/NullVoxPopuli/ember.nvp/pull/160) Fix macOS tests ([@tcjr](https://github.com/tcjr))
34
+
35
+ #### Committers: 2
36
+ - @NullVoxPopuli's reduced-access machine account for AI usage ([@NullVoxPopuli-ai-agent](https://github.com/NullVoxPopuli-ai-agent))
37
+ - Tom Carter ([@tcjr](https://github.com/tcjr))
38
+
3
39
  ## Release (2026-10-02)
4
40
 
5
41
  * ember.nvp 1.15.0 (minor)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ember.nvp",
3
- "version": "1.15.0",
3
+ "version": "1.17.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",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nullvoxpopuli/ember-rolldown",
3
- "version": "2.10.0",
3
+ "version": "2.12.0",
4
4
  "description": "Meta plugin for building ember v2 libraries/addons with rolldown & tsdown.",
5
5
  "type": "module",
6
6
  "main": "index.ts",
@@ -45,10 +45,10 @@
45
45
  "dependencies": {
46
46
  "@babel/core": "^7.28.10 || ^8.0.0",
47
47
  "@babel/plugin-transform-typescript": "^7.28.10 || ^8.0.0",
48
- "@embroider/core": "^4.4.2",
48
+ "@embroider/core": "^4.6.9",
49
49
  "@jridgewell/remapping": "^2.3.5",
50
50
  "@nullvoxpopuli/ember-build-tooling-utils": "workspace:*",
51
- "babel-plugin-ember-template-compilation": "^4.0.0",
51
+ "babel-plugin-ember-template-compilation": "^4.0.1",
52
52
  "content-tag": "^4.2.0",
53
53
  "decorator-transforms": "^2.4.0",
54
54
  "get-tsconfig": "^4.14.3",
@@ -1,6 +1,6 @@
1
1
  import { originalPositionFor, TraceMap } from "@jridgewell/trace-mapping";
2
2
  import { existsSync } from "node:fs";
3
- import { mkdtemp, mkdir, readFile, writeFile } from "node:fs/promises";
3
+ import { mkdtemp, mkdir, readFile, realpath, writeFile } from "node:fs/promises";
4
4
  import { tmpdir } from "node:os";
5
5
  import path from "node:path";
6
6
  import { rolldown } from "rolldown";
@@ -38,7 +38,7 @@ async function generate(
38
38
  files: Record<string, string>,
39
39
  { input = ["index.ts"], plugins = () => [], sourcemap = false }: BuildOptions = {},
40
40
  ): Promise<Build> {
41
- const dir = await mkdtemp(path.join(tmpdir(), "ember-rolldown-build-"));
41
+ const dir = await realpath(await mkdtemp(path.join(tmpdir(), "ember-rolldown-build-")));
42
42
 
43
43
  for (const [relative, source] of Object.entries(files)) {
44
44
  const full = path.join(dir, relative);
@@ -347,7 +347,7 @@ describe("emberTransform (full plugin via rolldown)", () => {
347
347
  });
348
348
 
349
349
  it("emits sourcemaps for the specifier rewrite (no SOURCEMAP_BROKEN warnings)", async () => {
350
- const dir = await mkdtemp(path.join(tmpdir(), "ember-rolldown-map-"));
350
+ const dir = await realpath(await mkdtemp(path.join(tmpdir(), "ember-rolldown-map-")));
351
351
 
352
352
  const files = {
353
353
  // index.ts contains a `.gts` specifier, so it goes through the rewrite.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nullvoxpopuli/ember-vite",
3
- "version": "1.2.0",
3
+ "version": "1.3.0",
4
4
  "description": "Meta plugin for ember projects focusing on speed.",
5
5
  "type": "module",
6
6
  "main": "index.ts",
@@ -26,9 +26,9 @@
26
26
  "packageManager": "pnpm@10.28.0",
27
27
  "dependencies": {
28
28
  "@babel/core": "^7.28.10 || ^8.0.0",
29
- "@embroider/core": "^4.4.2",
30
- "@embroider/macros": "^1.20.3",
31
- "@embroider/vite": "^1.5.0",
29
+ "@embroider/core": "^4.6.9",
30
+ "@embroider/macros": "^1.21.3",
31
+ "@embroider/vite": "^1.7.15",
32
32
  "@nullvoxpopuli/ember-build-tooling-utils": "workspace:*"
33
33
  },
34
34
  "engines": {
@@ -0,0 +1,38 @@
1
+ import { extensions } from "@embroider/vite";
2
+ import type { ConfigEnv, ConfigPluginContext } from "vite";
3
+ import { describe, expect, it } from "vitest";
4
+
5
+ import { ember } from "./ember.ts";
6
+
7
+ const ROLLDOWN = { meta: { rolldownVersion: "1.0.0" } } as ConfigPluginContext;
8
+
9
+ async function configure(env: ConfigEnv) {
10
+ const config: any = {};
11
+ const [plugin] = ember();
12
+
13
+ // @ts-expect-error the first entry is the config plugin
14
+ await plugin.config.call(ROLLDOWN, config, env);
15
+
16
+ return config;
17
+ }
18
+
19
+ describe("ember", () => {
20
+ /**
21
+ * These values come from the config hook of `@embroider/vite`.
22
+ * They are missing when that hook does not run.
23
+ */
24
+ it("applies the config from @embroider/vite", async () => {
25
+ const config = await configure({ command: "build", mode: "production" });
26
+
27
+ expect(config.resolve.extensions).toEqual(extensions);
28
+ expect(config.server.port).toBe(4200);
29
+ expect(config.optimizeDeps.exclude).toContain("@embroider/macros");
30
+ });
31
+
32
+ it("gives @embroider/vite the plugin context, so that it configures rolldown", async () => {
33
+ const config = await configure({ command: "build", mode: "production" });
34
+
35
+ expect(config.build.rolldownOptions.moduleTypes).toEqual({ ".ts": "js" });
36
+ expect(config.optimizeDeps.rolldownOptions.resolve.extensions).toEqual(extensions);
37
+ });
38
+ });
@@ -2,13 +2,43 @@ import { buildMacros } from "@embroider/macros/babel";
2
2
  import { ember as embroiderEmber, extensions, resolver, templateTag } from "@embroider/vite";
3
3
  import { existsSync } from "node:fs";
4
4
  import { join, resolve } from "node:path";
5
- import type { ConfigEnv, ResolvedConfig } from "vite";
5
+ import type { ConfigEnv, ConfigPluginContext, ResolvedConfig, UserConfig } from "vite";
6
6
 
7
7
  import { maybeBabel } from "@nullvoxpopuli/ember-build-tooling-utils";
8
8
 
9
9
  import { testHtml } from "./test-html.ts";
10
10
 
11
- const emberConfig = embroiderEmber()[3]!;
11
+ const EMBER_CONFIG = "vite-plugin-ember-config";
12
+
13
+ type ConfigHook = (
14
+ this: ConfigPluginContext,
15
+ config: UserConfig,
16
+ env: ConfigEnv,
17
+ ) => Promise<unknown> | unknown;
18
+
19
+ /**
20
+ * `@embroider/vite` does not export its config hook on its own.
21
+ *
22
+ * The position of the plugin in the list changes between releases,
23
+ * so the name is the only stable way to find it.
24
+ */
25
+ function findEmberConfig(): ConfigHook {
26
+ for (const plugin of embroiderEmber()) {
27
+ if (plugin.name !== EMBER_CONFIG) continue;
28
+
29
+ const hook = plugin.config;
30
+ const handler = typeof hook === "function" ? hook : hook?.handler;
31
+
32
+ if (handler) return handler as ConfigHook;
33
+ }
34
+
35
+ throw new Error(
36
+ `@embroider/vite has no "${EMBER_CONFIG}" plugin with a config hook. ` +
37
+ `This version of @embroider/vite is not supported by @nullvoxpopuli/ember-vite.`,
38
+ );
39
+ }
40
+
41
+ const emberConfig = findEmberConfig();
12
42
 
13
43
  const cwd = process.cwd();
14
44
  function absolutePath(relativePath: string) {
@@ -173,9 +203,12 @@ export function ember(nvpConfig: Config = {}) {
173
203
  {
174
204
  // no compat
175
205
  name: "ember:nullvoxpopuli",
176
- async config(viteConfig: any, env: ConfigEnv) {
177
- // @ts-expect-error it exists
178
- await emberConfig.config(viteConfig, env);
206
+ async config(this: ConfigPluginContext, viteConfig: any, env: ConfigEnv) {
207
+ /**
208
+ * The hook reads the rolldown version from the plugin context,
209
+ * and takes its esbuild path without it.
210
+ */
211
+ await emberConfig.call(this, viteConfig, env);
179
212
 
180
213
  viteConfig.experimental ||= {};
181
214
  viteConfig.build ||= {};
@@ -25,7 +25,7 @@
25
25
  "start": "vite"
26
26
  },
27
27
  "dependencies": {
28
- "@embroider/macros": "^1.20.3",
28
+ "@embroider/macros": "^1.21.3",
29
29
  "@embroider/router": "^3.0.6",
30
30
  "@glimmer/component": "^2.1.1",
31
31
  "decorator-transforms": "^2.3.2",
@@ -37,14 +37,14 @@
37
37
  "@babel/plugin-transform-typescript": "^7.29.7",
38
38
  "@babel/runtime": "^7.29.7",
39
39
  "@ember/app-tsconfig": "^2.0.0",
40
- "@embroider/core": "^4.4.2",
40
+ "@embroider/core": "^4.6.9",
41
41
  "@glint/ember-tsc": "^1.7.5",
42
42
  "@glint/template": "^1.7.7",
43
43
  "@glint/tsserver-plugin": "^2.5.5",
44
44
  "@nullvoxpopuli/ember-vite": "workspace:*",
45
45
  "@rollup/plugin-babel": "^7.1.0",
46
46
  "babel-plugin-debug-macros": "^2.0.0",
47
- "babel-plugin-ember-template-compilation": "^4.0.0",
47
+ "babel-plugin-ember-template-compilation": "^4.0.1",
48
48
  "typescript": "^6.0.3",
49
49
  "vite": "^8.0.14"
50
50
  },
@@ -26,7 +26,7 @@
26
26
  "start": "vite"
27
27
  },
28
28
  "dependencies": {
29
- "@embroider/macros": "^1.20.3",
29
+ "@embroider/macros": "^1.21.3",
30
30
  "@embroider/router": "^3.0.6",
31
31
  "@glimmer/component": "^2.1.1",
32
32
  "decorator-transforms": "^2.3.2",
@@ -38,14 +38,14 @@
38
38
  "@babel/plugin-transform-typescript": "^7.29.7",
39
39
  "@babel/runtime": "^7.29.7",
40
40
  "@ember/app-tsconfig": "^2.0.0",
41
- "@embroider/core": "^4.4.2",
41
+ "@embroider/core": "^4.6.9",
42
42
  "@glint/ember-tsc": "^1.7.5",
43
43
  "@glint/template": "^1.7.7",
44
44
  "@glint/tsserver-plugin": "^2.5.5",
45
45
  "@nullvoxpopuli/ember-vite": "workspace:*",
46
46
  "@rollup/plugin-babel": "^7.1.0",
47
47
  "babel-plugin-debug-macros": "^2.0.0",
48
- "babel-plugin-ember-template-compilation": "^4.0.0",
48
+ "babel-plugin-ember-template-compilation": "^4.0.1",
49
49
  "typescript": "^6.0.3",
50
50
  "vite": "^8.0.14"
51
51
  },
@@ -29,9 +29,9 @@ const tsDeps = {
29
29
  */
30
30
  const libraryDeps = {
31
31
  ...deps,
32
- "@embroider/macros": "^1.20.3",
32
+ "@embroider/macros": "^1.21.3",
33
33
  "@nullvoxpopuli/ember-vite": "workspace:*",
34
- "babel-plugin-ember-template-compilation": "^4.0.0",
34
+ "babel-plugin-ember-template-compilation": "^4.0.1",
35
35
  vite: "^8.0.14",
36
36
  };
37
37
  const libraryTsDeps = {
@@ -223,7 +223,9 @@ async function syncTestBabelConfig(project, ts) {
223
223
  * Tests live outside `src`, and editors, `lint:types`, and eslint read tsconfig.json.
224
224
  * So in a TypeScript library, this layer:
225
225
  * - widens tsconfig.json to `src` and `tests`, without the publish-only settings
226
- * - moves those settings to `config/tsconfig.publish.json`, which the build uses
226
+ * - adds the `vite/client` types to tsconfig.json, because the tests build with Vite
227
+ * - moves the publish-only settings to `config/tsconfig.publish.json`, which the build uses.
228
+ * That file keeps the library types, without `vite/client`, because `src` does not run through Vite.
227
229
  *
228
230
  * @param {import('#utils/project.js').Project} project
229
231
  */
@@ -233,18 +235,35 @@ async function usePublishTsconfig(project) {
233
235
 
234
236
  let config = await tsconfig.read(project.directory);
235
237
 
236
- if (!needsWidening(config)) return;
238
+ if (needsWidening(config)) {
239
+ await tsconfig.modify((json) => {
240
+ json.include ||= [];
237
241
 
238
- await tsconfig.modify((json) => {
239
- json.include ||= [];
242
+ if (!json.include.includes("tests")) {
243
+ json.include.push("tests");
244
+ }
240
245
 
241
- if (!json.include.includes("tests")) {
242
- json.include.push("tests");
243
- }
246
+ delete json.compilerOptions?.rootDir;
247
+ delete json.compilerOptions?.isolatedDeclarations;
248
+ }, project.directory);
249
+ }
244
250
 
245
- delete json.compilerOptions?.rootDir;
246
- delete json.compilerOptions?.isolatedDeclarations;
247
- }, project.directory);
251
+ if (!hasViteTypes(config)) {
252
+ await tsconfig.modify((json) => {
253
+ json.compilerOptions ||= {};
254
+ json.compilerOptions.types ||= [];
255
+ json.compilerOptions.types.push(VITE_TYPES);
256
+ }, project.directory);
257
+ }
258
+ }
259
+
260
+ const VITE_TYPES = "vite/client";
261
+
262
+ /**
263
+ * @param {Record<string, any>} config
264
+ */
265
+ function hasViteTypes(config) {
266
+ return Boolean(config.compilerOptions?.types?.includes(VITE_TYPES));
248
267
  }
249
268
 
250
269
  /**
@@ -3,6 +3,7 @@
3
3
  "include": ["../src"],
4
4
  "compilerOptions": {
5
5
  "rootDir": "../src",
6
- "isolatedDeclarations": true
6
+ "isolatedDeclarations": true,
7
+ "types": ["ember-source/types", "@glint/ember-tsc/types"]
7
8
  }
8
9
  }
@@ -23,7 +23,7 @@ const deps = {
23
23
  const libraryDeps = {
24
24
  "@babel/plugin-transform-typescript": "^7.28.10",
25
25
  "@nullvoxpopuli/ember-vite": "workspace:*",
26
- "babel-plugin-ember-template-compilation": "^4.0.0",
26
+ "babel-plugin-ember-template-compilation": "^4.0.1",
27
27
  vite: "^8.0.14",
28
28
  };
29
29
 
@@ -5,6 +5,7 @@ import { execa } from "execa";
5
5
  import { mkdir, rm, writeFile } from "node:fs/promises";
6
6
  import { dirname, join } from "node:path";
7
7
 
8
+ import { generateProject } from "ember.nvp";
8
9
  import type { Project } from "ember.nvp";
9
10
 
10
11
  async function installAndTest(project: Project) {
@@ -271,7 +272,8 @@ describe("layer: qunit", () => {
271
272
  "include": ["../src"],
272
273
  "compilerOptions": {
273
274
  "rootDir": "../src",
274
- "isolatedDeclarations": true
275
+ "isolatedDeclarations": true,
276
+ "types": ["ember-source/types", "@glint/ember-tsc/types"]
275
277
  }
276
278
  }
277
279
  "
@@ -282,7 +284,7 @@ describe("layer: qunit", () => {
282
284
  "include": ["src", "tests"],
283
285
  "compilerOptions": {
284
286
  "lib": ["esnext", "dom", "dom.iterable"],
285
- "types": ["ember-source/types", "@glint/ember-tsc/types"],
287
+ "types": ["ember-source/types", "@glint/ember-tsc/types", "vite/client"],
286
288
  },
287
289
  "contentMappers": [
288
290
  {
@@ -316,6 +318,31 @@ describe("layer: qunit", () => {
316
318
  });
317
319
  });
318
320
 
321
+ describe("library (TypeScript), updating a project from before vite/client", () => {
322
+ it("adds vite/client to tsconfig.json only", async () => {
323
+ const project = await generate({
324
+ type: "library",
325
+ name: "my-lib",
326
+ layers: ["qunit", "typescript"],
327
+ });
328
+ dirs.push(project.directory);
329
+
330
+ let tsconfig = await project.read("tsconfig.json");
331
+ expect(tsconfig).toContain(', "vite/client"');
332
+ await writeFile(
333
+ join(project.directory, "tsconfig.json"),
334
+ tsconfig!.replace(', "vite/client"', ""),
335
+ );
336
+
337
+ await generateProject(project, "update");
338
+
339
+ expect(await project.read("tsconfig.json")).toContain(
340
+ '"types": ["ember-source/types", "@glint/ember-tsc/types", "vite/client"]',
341
+ );
342
+ expect(await project.read("config/tsconfig.publish.json")).not.toContain("vite/client");
343
+ });
344
+ });
345
+
319
346
  describe("library (TypeScript) with eslint", () => {
320
347
  it("lints the tests", { timeout: 300_000 }, async () => {
321
348
  const project = await generate({
@@ -126,7 +126,7 @@ describe("publish configs", () => {
126
126
 
127
127
  manifest.devDependencies["@babel/core"] = "^7.28.10";
128
128
  manifest.devDependencies["@babel/plugin-transform-typescript"] = "^7.28.10";
129
- manifest.devDependencies["babel-plugin-ember-template-compilation"] = "^4.0.0";
129
+ manifest.devDependencies["babel-plugin-ember-template-compilation"] = "^4.0.1";
130
130
 
131
131
  await writeFile(
132
132
  join(project.directory, "package.json"),