ember.nvp 0.7.0 → 1.1.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.
- package/.github/workflows/ci.yml +6 -0
- package/.release-plan.json +7 -59
- package/CHANGELOG.md +46 -0
- package/package.json +1 -1
- package/packages/rolldown/README.md +68 -1
- package/packages/rolldown/index.ts +8 -4
- package/packages/rolldown/package.json +13 -4
- package/packages/rolldown/rolldown.config.js +5 -3
- package/packages/rolldown/src/app-reexports.test.ts +220 -0
- package/packages/rolldown/src/app-reexports.ts +152 -0
- package/packages/rolldown/src/config.ts +50 -0
- package/packages/rolldown/src/dts.test.ts +166 -0
- package/packages/rolldown/src/transform.test.ts +173 -0
- package/src/bases/minimal-extension/extension.test.ts +251 -0
- package/src/bases/minimal-extension/files/.env.development +8 -0
- package/src/bases/minimal-extension/files/README.md +36 -0
- package/src/bases/minimal-extension/files/app/app.ts +21 -0
- package/src/bases/minimal-extension/files/app/boot.ts +8 -0
- package/src/bases/minimal-extension/files/app/config.ts +22 -0
- package/src/bases/minimal-extension/files/app/router.ts +10 -0
- package/src/bases/minimal-extension/files/app/templates/application.gts +5 -0
- package/src/bases/minimal-extension/files/babel.config.js +49 -0
- package/src/bases/minimal-extension/files/index.html +17 -0
- package/src/bases/minimal-extension/files/package.json +58 -0
- package/src/bases/minimal-extension/files/public/manifest.json +9 -0
- package/src/bases/minimal-extension/files/tsconfig.json +13 -0
- package/src/bases/minimal-extension/files/vite.config.mjs +6 -0
- package/src/bases/minimal-extension/index.js +142 -0
- package/src/bases/minimal-library/files/tsdown.config.js +2 -1
- package/src/cli/generator.js +4 -0
- package/src/cli/questions/project-type.js +9 -2
- package/src/layers/renovate/index.js +4 -3
- package/src/layers/typescript/index.js +6 -0
- package/src/utils/types.ts +1 -1
- package/test/ember.nvp/base-library.test.ts +41 -30
- package/test/ember.nvp/layer-publish-checks.test.ts +7 -10
- package/test/ember.nvp/layer-qunit.test.ts +17 -30
- package/test/ember.nvp/layer-vitest.test.ts +4 -18
- package/test/ember.nvp/permutations/app-checks.test.ts +3 -0
- package/test/ember.nvp/permutations/extension-1.test.ts +3 -0
- package/test/ember.nvp/permutations/extension-2.test.ts +3 -0
- package/test/ember.nvp/permutations/extension-checks.test.ts +3 -0
- package/test/ember.nvp/permutations/library-checks.test.ts +3 -0
- package/test/ember.nvp/permutations/shared.ts +68 -19
- package/test/test-helpers.ts +25 -5
- package/vitest.config.js +1 -1
- package/packages/rolldown/src/define-config.ts +0 -32
package/.github/workflows/ci.yml
CHANGED
|
@@ -45,6 +45,12 @@ jobs:
|
|
|
45
45
|
args: test/ember.nvp/permutations/library-1.test.ts
|
|
46
46
|
- name: library permutations 2/2
|
|
47
47
|
args: test/ember.nvp/permutations/library-2.test.ts
|
|
48
|
+
- name: extension permutations 1/2
|
|
49
|
+
args: test/ember.nvp/permutations/extension-1.test.ts
|
|
50
|
+
- name: extension permutations 2/2
|
|
51
|
+
args: test/ember.nvp/permutations/extension-2.test.ts
|
|
52
|
+
- name: check-layer permutations
|
|
53
|
+
args: test/ember.nvp/permutations/app-checks.test.ts test/ember.nvp/permutations/library-checks.test.ts test/ember.nvp/permutations/extension-checks.test.ts
|
|
48
54
|
- name: everything else
|
|
49
55
|
args: --exclude 'test/ember.nvp/permutations/**'
|
|
50
56
|
|
package/.release-plan.json
CHANGED
|
@@ -2,18 +2,14 @@
|
|
|
2
2
|
"solution": {
|
|
3
3
|
"ember.nvp": {
|
|
4
4
|
"impact": "minor",
|
|
5
|
-
"oldVersion": "0.
|
|
6
|
-
"newVersion": "
|
|
5
|
+
"oldVersion": "1.0.0",
|
|
6
|
+
"newVersion": "1.1.0",
|
|
7
7
|
"tagName": "latest",
|
|
8
8
|
"constraints": [
|
|
9
9
|
{
|
|
10
10
|
"impact": "minor",
|
|
11
11
|
"reason": "Appears in changelog section :rocket: Enhancement"
|
|
12
12
|
},
|
|
13
|
-
{
|
|
14
|
-
"impact": "patch",
|
|
15
|
-
"reason": "Appears in changelog section :bug: Bug Fix"
|
|
16
|
-
},
|
|
17
13
|
{
|
|
18
14
|
"impact": "patch",
|
|
19
15
|
"reason": "Appears in changelog section :memo: Documentation"
|
|
@@ -26,44 +22,18 @@
|
|
|
26
22
|
"pkgJSONPath": "./package.json"
|
|
27
23
|
},
|
|
28
24
|
"@nullvoxpopuli/ember-build-tooling-utils": {
|
|
29
|
-
"
|
|
30
|
-
"oldVersion": "1.0.0",
|
|
31
|
-
"newVersion": "1.1.0",
|
|
32
|
-
"tagName": "latest",
|
|
33
|
-
"constraints": [
|
|
34
|
-
{
|
|
35
|
-
"impact": "minor",
|
|
36
|
-
"reason": "Appears in changelog section :rocket: Enhancement"
|
|
37
|
-
},
|
|
38
|
-
{
|
|
39
|
-
"impact": "patch",
|
|
40
|
-
"reason": "Appears in changelog section :bug: Bug Fix"
|
|
41
|
-
},
|
|
42
|
-
{
|
|
43
|
-
"impact": "patch",
|
|
44
|
-
"reason": "Appears in changelog section :memo: Documentation"
|
|
45
|
-
}
|
|
46
|
-
],
|
|
47
|
-
"pkgJSONPath": "./packages/build-tooling-utils/package.json"
|
|
25
|
+
"oldVersion": "1.1.0"
|
|
48
26
|
},
|
|
49
27
|
"@nullvoxpopuli/ember-rolldown": {
|
|
50
28
|
"impact": "minor",
|
|
51
|
-
"oldVersion": "
|
|
52
|
-
"newVersion": "
|
|
29
|
+
"oldVersion": "2.0.0",
|
|
30
|
+
"newVersion": "2.1.0",
|
|
53
31
|
"tagName": "latest",
|
|
54
32
|
"constraints": [
|
|
55
|
-
{
|
|
56
|
-
"impact": "patch",
|
|
57
|
-
"reason": "Has dependency `workspace:*` on @nullvoxpopuli/ember-build-tooling-utils"
|
|
58
|
-
},
|
|
59
33
|
{
|
|
60
34
|
"impact": "minor",
|
|
61
35
|
"reason": "Appears in changelog section :rocket: Enhancement"
|
|
62
36
|
},
|
|
63
|
-
{
|
|
64
|
-
"impact": "patch",
|
|
65
|
-
"reason": "Appears in changelog section :bug: Bug Fix"
|
|
66
|
-
},
|
|
67
37
|
{
|
|
68
38
|
"impact": "patch",
|
|
69
39
|
"reason": "Appears in changelog section :memo: Documentation"
|
|
@@ -76,30 +46,8 @@
|
|
|
76
46
|
"pkgJSONPath": "./packages/rolldown/package.json"
|
|
77
47
|
},
|
|
78
48
|
"@nullvoxpopuli/ember-vite": {
|
|
79
|
-
"
|
|
80
|
-
"oldVersion": "1.0.3",
|
|
81
|
-
"newVersion": "1.1.0",
|
|
82
|
-
"tagName": "latest",
|
|
83
|
-
"constraints": [
|
|
84
|
-
{
|
|
85
|
-
"impact": "minor",
|
|
86
|
-
"reason": "Appears in changelog section :rocket: Enhancement"
|
|
87
|
-
},
|
|
88
|
-
{
|
|
89
|
-
"impact": "patch",
|
|
90
|
-
"reason": "Has dependency `workspace:*` on @nullvoxpopuli/ember-build-tooling-utils"
|
|
91
|
-
},
|
|
92
|
-
{
|
|
93
|
-
"impact": "patch",
|
|
94
|
-
"reason": "Appears in changelog section :bug: Bug Fix"
|
|
95
|
-
},
|
|
96
|
-
{
|
|
97
|
-
"impact": "patch",
|
|
98
|
-
"reason": "Appears in changelog section :house: Internal"
|
|
99
|
-
}
|
|
100
|
-
],
|
|
101
|
-
"pkgJSONPath": "./packages/vite/package.json"
|
|
49
|
+
"oldVersion": "1.1.0"
|
|
102
50
|
}
|
|
103
51
|
},
|
|
104
|
-
"description": "## Release (2026-07-
|
|
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"
|
|
105
53
|
}
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,51 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## Release (2026-07-22)
|
|
4
|
+
|
|
5
|
+
* ember.nvp 1.1.0 (minor)
|
|
6
|
+
* @nullvoxpopuli/ember-rolldown 2.1.0 (minor)
|
|
7
|
+
|
|
8
|
+
#### :rocket: Enhancement
|
|
9
|
+
* `@nullvoxpopuli/ember-rolldown`
|
|
10
|
+
* [#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))
|
|
11
|
+
* [#95](https://github.com/NullVoxPopuli/ember.nvp/pull/95) enable declaration maps in the rolldown plugin ([@NullVoxPopuli](https://github.com/NullVoxPopuli))
|
|
12
|
+
* `ember.nvp`
|
|
13
|
+
* [#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))
|
|
14
|
+
|
|
15
|
+
#### :memo: Documentation
|
|
16
|
+
* `@nullvoxpopuli/ember-rolldown`, `ember.nvp`
|
|
17
|
+
* [#96](https://github.com/NullVoxPopuli/ember.nvp/pull/96) rolldown: document + test co-located CSS support ([@NullVoxPopuli](https://github.com/NullVoxPopuli))
|
|
18
|
+
|
|
19
|
+
#### :house: Internal
|
|
20
|
+
* `@nullvoxpopuli/ember-rolldown`, `ember.nvp`
|
|
21
|
+
* [#93](https://github.com/NullVoxPopuli/ember.nvp/pull/93) More tests ([@NullVoxPopuli](https://github.com/NullVoxPopuli))
|
|
22
|
+
* `ember.nvp`
|
|
23
|
+
* [#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))
|
|
24
|
+
* [#90](https://github.com/NullVoxPopuli/ember.nvp/pull/90) Remove pinYukuParser test helper ([@Copilot](https://github.com/apps/copilot-swe-agent))
|
|
25
|
+
* [#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))
|
|
26
|
+
* [#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))
|
|
27
|
+
|
|
28
|
+
#### Committers: 3
|
|
29
|
+
- @NullVoxPopuli's reduced-access machine account for AI usage ([@NullVoxPopuli-ai-agent](https://github.com/NullVoxPopuli-ai-agent))
|
|
30
|
+
- Copilot [Bot] ([@copilot-swe-agent](https://github.com/apps/copilot-swe-agent))
|
|
31
|
+
- [@NullVoxPopuli](https://github.com/NullVoxPopuli)
|
|
32
|
+
|
|
33
|
+
## Release (2026-07-18)
|
|
34
|
+
|
|
35
|
+
* ember.nvp 1.0.0 (major)
|
|
36
|
+
* @nullvoxpopuli/ember-rolldown 2.0.0 (major)
|
|
37
|
+
|
|
38
|
+
#### :boom: Breaking Change
|
|
39
|
+
* `@nullvoxpopuli/ember-rolldown`, `ember.nvp`
|
|
40
|
+
* [#86](https://github.com/NullVoxPopuli/ember.nvp/pull/86) Remove defineConfig ([@NullVoxPopuli](https://github.com/NullVoxPopuli))
|
|
41
|
+
|
|
42
|
+
#### :rocket: Enhancement
|
|
43
|
+
* `@nullvoxpopuli/ember-rolldown`, `ember.nvp`
|
|
44
|
+
* [#84](https://github.com/NullVoxPopuli/ember.nvp/pull/84) Create config plugin for rolldown ([@NullVoxPopuli](https://github.com/NullVoxPopuli))
|
|
45
|
+
|
|
46
|
+
#### Committers: 1
|
|
47
|
+
- [@NullVoxPopuli](https://github.com/NullVoxPopuli)
|
|
48
|
+
|
|
3
49
|
## Release (2026-07-17)
|
|
4
50
|
|
|
5
51
|
* ember.nvp 0.7.0 (minor)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ember.nvp",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "1.1.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",
|
|
@@ -20,10 +20,15 @@ modern TypeScript when type-checking: 6+ with `lib` covering `es2025` (e.g.
|
|
|
20
20
|
|
|
21
21
|
## Usage
|
|
22
22
|
|
|
23
|
+
Import `defineConfig` from the bundler you're using — `tsdown` or `rolldown` —
|
|
24
|
+
so it carries that tool's own config types; `@nullvoxpopuli/ember-rolldown`
|
|
25
|
+
provides `ember()` (the defaults travel with the plugin, not `defineConfig`).
|
|
26
|
+
|
|
23
27
|
In your `tsdown.config.js` (recommended — emits declarations):
|
|
24
28
|
|
|
25
29
|
```js
|
|
26
|
-
import { defineConfig
|
|
30
|
+
import { defineConfig } from "tsdown";
|
|
31
|
+
import { ember } from "@nullvoxpopuli/ember-rolldown";
|
|
27
32
|
|
|
28
33
|
export default defineConfig({
|
|
29
34
|
entry: ["./src/index.ts"],
|
|
@@ -77,6 +82,27 @@ import type { TOC } from "@ember/component/template-only";
|
|
|
77
82
|
export const Badge: TOC<BadgeSignature> = <template>...</template>;
|
|
78
83
|
```
|
|
79
84
|
|
|
85
|
+
## CSS
|
|
86
|
+
|
|
87
|
+
Components that import co-located CSS (`import './popup.css'`) need
|
|
88
|
+
[`@tsdown/css`](https://www.npmjs.com/package/@tsdown/css) installed in your
|
|
89
|
+
library — tsdown auto-detects it and bundles every imported stylesheet into a
|
|
90
|
+
single CSS file in `dist/`. Install the version matching your `tsdown`
|
|
91
|
+
version (they're released in lockstep):
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
npm add --save-dev @tsdown/css
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Without it, tsdown's css-guard fails the build on the first CSS import — and
|
|
98
|
+
because the importing component module never loads, any declaration that
|
|
99
|
+
references that component dangles, surfacing as misleading
|
|
100
|
+
`UNLOADABLE_DEPENDENCY` errors on `<component>.d.ts` files.
|
|
101
|
+
|
|
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.
|
|
105
|
+
|
|
80
106
|
## What `ember()` does
|
|
81
107
|
|
|
82
108
|
`ember()` returns an array of rolldown plugins:
|
|
@@ -109,6 +135,47 @@ ember({
|
|
|
109
135
|
|
|
110
136
|
Each option is documented on `BabelOptions`.
|
|
111
137
|
|
|
138
|
+
## App re-exports
|
|
139
|
+
|
|
140
|
+
For libraries whose modules must appear in the consuming app's namespace
|
|
141
|
+
(classic resolution: `{{a-component}}`, services and helpers looked up by
|
|
142
|
+
name), `appReexports()` does the same job as `@embroider/addon-dev`'s
|
|
143
|
+
`appReexports` rollup plugin. It's a separate import because most libraries
|
|
144
|
+
don't need it:
|
|
145
|
+
|
|
146
|
+
```js
|
|
147
|
+
import { defineConfig } from "tsdown";
|
|
148
|
+
import { ember } from "@nullvoxpopuli/ember-rolldown";
|
|
149
|
+
import { appReexports } from "@nullvoxpopuli/ember-rolldown/app-reexports";
|
|
150
|
+
|
|
151
|
+
export default defineConfig({
|
|
152
|
+
entry: ["./src/index.ts", "./src/services/session.ts"],
|
|
153
|
+
plugins: [ember(), appReexports()],
|
|
154
|
+
});
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
With no arguments, top-level services (`services/*`) are re-exported — under
|
|
158
|
+
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:
|
|
161
|
+
|
|
162
|
+
```js
|
|
163
|
+
appReexports(); // services/*
|
|
164
|
+
appReexports("components/**"); // one include glob
|
|
165
|
+
appReexports({ include: ["services/*", "helpers/*"], exclude: [...] });
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
For every built file matching `include` (minus `exclude` and `.d.ts` files),
|
|
169
|
+
it writes a module under `dist/_app_/` re-exporting from the library's own
|
|
170
|
+
name, and records the set in `package.json` under `ember-addon.app-js`.
|
|
171
|
+
`mapFilename` renames a re-export; `exports` picks which bindings it forwards
|
|
172
|
+
(default `["default"]`).
|
|
173
|
+
|
|
174
|
+
Unlike the embroider plugin, nothing is written unless its content actually
|
|
175
|
+
differs from what is on disk — `_app_/` modules are compared byte-for-byte
|
|
176
|
+
and `package.json` is only rewritten when the `app-js` map itself changed —
|
|
177
|
+
so rebuilds don't re-trigger file watchers.
|
|
178
|
+
|
|
112
179
|
## Credit
|
|
113
180
|
|
|
114
181
|
The `emberExternals` and `emberTransform` plugins are derived from
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import type { Plugin } from "rolldown";
|
|
2
2
|
|
|
3
3
|
import { emberBabel, type BabelOptions } from "./src/babel.ts";
|
|
4
|
+
import { emberConfig } from "./src/config.ts";
|
|
4
5
|
import { emberExternals } from "./src/externals.ts";
|
|
5
6
|
import { emberIsolatedDeclarations } from "./src/isolated-declarations.ts";
|
|
6
7
|
import { emberTransform } from "./src/transform.ts";
|
|
7
8
|
|
|
8
|
-
export { defineConfig } from "./src/define-config.ts";
|
|
9
|
-
|
|
10
9
|
interface Config {
|
|
11
10
|
/**
|
|
12
11
|
* Options for the babel step; see `BabelOptions`.
|
|
@@ -21,6 +20,9 @@ interface Config {
|
|
|
21
20
|
* It bundles everything needed to compile `.gts`/`.gjs` and template-tag
|
|
22
21
|
* (`<template>`) source into publishable output:
|
|
23
22
|
*
|
|
23
|
+
* - `emberConfig()` — applies sensible tsdown defaults for a library build
|
|
24
|
+
* (sourcemaps, `clean`, `dts`, `.js`/`.d.ts` extensions, quiet logging);
|
|
25
|
+
* anything you set explicitly still wins.
|
|
24
26
|
* - `emberIsolatedDeclarations()` — errors when a tsconfig.json is present
|
|
25
27
|
* without `isolatedDeclarations: true` (required: it is the only
|
|
26
28
|
* declaration pipeline that can see compiled template-tag modules).
|
|
@@ -34,20 +36,22 @@ interface Config {
|
|
|
34
36
|
* native transform. The library's own `babel.config.js` is used when it
|
|
35
37
|
* exists; no config file is required.
|
|
36
38
|
*
|
|
37
|
-
* Usage in `tsdown.config.js`
|
|
39
|
+
* Usage in `tsdown.config.js` (import `defineConfig` from `tsdown` — or from
|
|
40
|
+
* `rolldown` for a `rolldown.config.js` — so it carries the correct types):
|
|
38
41
|
*
|
|
39
42
|
* ```js
|
|
43
|
+
* import { defineConfig } from "tsdown";
|
|
40
44
|
* import { ember } from "@nullvoxpopuli/ember-rolldown";
|
|
41
45
|
*
|
|
42
46
|
* export default defineConfig({
|
|
43
47
|
* entry: ["./src/index.ts"],
|
|
44
|
-
* dts: true,
|
|
45
48
|
* plugins: [ember()],
|
|
46
49
|
* });
|
|
47
50
|
* ```
|
|
48
51
|
*/
|
|
49
52
|
export function ember(config: Config = {}): Plugin[] {
|
|
50
53
|
return [
|
|
54
|
+
emberConfig(),
|
|
51
55
|
emberIsolatedDeclarations(),
|
|
52
56
|
emberExternals(),
|
|
53
57
|
emberTransform(),
|
|
@@ -1,11 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nullvoxpopuli/ember-rolldown",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "Meta plugin for building ember v2 libraries/addons with rolldown & tsdown.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": "./index.ts",
|
|
9
|
+
"./app-reexports": "./src/app-reexports.ts"
|
|
10
|
+
},
|
|
7
11
|
"publishConfig": {
|
|
8
|
-
"main": "dist/index.js"
|
|
12
|
+
"main": "dist/index.js",
|
|
13
|
+
"exports": {
|
|
14
|
+
".": "./dist/index.js",
|
|
15
|
+
"./app-reexports": "./dist/app-reexports.js"
|
|
16
|
+
}
|
|
9
17
|
},
|
|
10
18
|
"keywords": [
|
|
11
19
|
"rolldown",
|
|
@@ -52,8 +60,9 @@
|
|
|
52
60
|
}
|
|
53
61
|
},
|
|
54
62
|
"devDependencies": {
|
|
55
|
-
"
|
|
56
|
-
"
|
|
63
|
+
"@tsdown/css": "^0.22.13",
|
|
64
|
+
"rolldown": "^1.2.0",
|
|
65
|
+
"tsdown": "^0.22.9",
|
|
57
66
|
"typescript": "^6.0.3"
|
|
58
67
|
}
|
|
59
68
|
}
|
|
@@ -8,11 +8,13 @@ const deps = [
|
|
|
8
8
|
];
|
|
9
9
|
|
|
10
10
|
export default defineConfig({
|
|
11
|
-
input:
|
|
11
|
+
input: {
|
|
12
|
+
index: "index.ts",
|
|
13
|
+
"app-reexports": "src/app-reexports.ts",
|
|
14
|
+
},
|
|
12
15
|
output: {
|
|
13
16
|
format: "esm",
|
|
14
|
-
|
|
15
|
-
codeSplitting: false,
|
|
17
|
+
dir: "dist",
|
|
16
18
|
},
|
|
17
19
|
external(id) {
|
|
18
20
|
if (id.startsWith("node:")) return true;
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
import { mkdir, mkdtemp, readFile, rm, stat, utimes, writeFile } from "node:fs/promises";
|
|
2
|
+
import { tmpdir } from "node:os";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
|
|
5
|
+
import { rolldown, type Plugin } from "rolldown";
|
|
6
|
+
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
7
|
+
|
|
8
|
+
import { appReexports, type AppReexportsOptions } from "./app-reexports.ts";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* The plugin reads and writes package.json relative to the current working
|
|
12
|
+
* directory (matching the other plugins in this package), so each test runs
|
|
13
|
+
* inside its own temp project.
|
|
14
|
+
*/
|
|
15
|
+
describe("appReexports", () => {
|
|
16
|
+
let projectDir: string;
|
|
17
|
+
const originalCwd = process.cwd();
|
|
18
|
+
|
|
19
|
+
beforeEach(async () => {
|
|
20
|
+
projectDir = await mkdtemp(join(tmpdir(), "app-reexports-"));
|
|
21
|
+
|
|
22
|
+
await writeFile(
|
|
23
|
+
join(projectDir, "package.json"),
|
|
24
|
+
JSON.stringify(
|
|
25
|
+
{
|
|
26
|
+
name: "my-lib",
|
|
27
|
+
version: "1.0.0",
|
|
28
|
+
"ember-addon": { version: 2, type: "addon" },
|
|
29
|
+
},
|
|
30
|
+
null,
|
|
31
|
+
2,
|
|
32
|
+
) + "\n",
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
await mkdir(join(projectDir, "src/components"), { recursive: true });
|
|
36
|
+
await mkdir(join(projectDir, "src/utils"), { recursive: true });
|
|
37
|
+
await writeFile(
|
|
38
|
+
join(projectDir, "src/components/foo.js"),
|
|
39
|
+
"export default function foo() {}\n",
|
|
40
|
+
);
|
|
41
|
+
await writeFile(
|
|
42
|
+
join(projectDir, "src/utils/math.js"),
|
|
43
|
+
"export function add(a, b) { return a + b; }\n",
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
process.chdir(projectDir);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
afterEach(async () => {
|
|
50
|
+
process.chdir(originalCwd);
|
|
51
|
+
await rm(projectDir, { recursive: true, force: true });
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
async function build(options?: string | AppReexportsOptions) {
|
|
55
|
+
const bundle = await rolldown({
|
|
56
|
+
input: {
|
|
57
|
+
"components/foo": "./src/components/foo.js",
|
|
58
|
+
"utils/math": "./src/utils/math.js",
|
|
59
|
+
},
|
|
60
|
+
plugins: [appReexports(options)],
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
await bundle.write({ dir: "dist" });
|
|
64
|
+
await bundle.close();
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
async function readJson(path: string) {
|
|
68
|
+
return JSON.parse(await readFile(path, "utf8"));
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
it("writes _app_ re-exports and records them in package.json", async () => {
|
|
72
|
+
await build({ include: ["components/**"] });
|
|
73
|
+
|
|
74
|
+
expect(await readFile("dist/_app_/components/foo.js", "utf8")).toMatchInlineSnapshot(`
|
|
75
|
+
"export { default } from "my-lib/components/foo";
|
|
76
|
+
"
|
|
77
|
+
`);
|
|
78
|
+
|
|
79
|
+
const manifest = await readJson("package.json");
|
|
80
|
+
|
|
81
|
+
expect(manifest["ember-addon"]).toMatchInlineSnapshot(`
|
|
82
|
+
{
|
|
83
|
+
"app-js": {
|
|
84
|
+
"./components/foo.js": "./dist/_app_/components/foo.js",
|
|
85
|
+
},
|
|
86
|
+
"type": "addon",
|
|
87
|
+
"version": 2,
|
|
88
|
+
}
|
|
89
|
+
`);
|
|
90
|
+
|
|
91
|
+
// utils/math.js didn't match include
|
|
92
|
+
await expect(stat("dist/_app_/utils/math.js")).rejects.toThrow();
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it("accepts a string argument as the include glob", async () => {
|
|
96
|
+
await build("components/**");
|
|
97
|
+
|
|
98
|
+
const manifest = await readJson("package.json");
|
|
99
|
+
|
|
100
|
+
expect(Object.keys(manifest["ember-addon"]["app-js"])).toEqual(["./components/foo.js"]);
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
it("defaults to top-level services", async () => {
|
|
104
|
+
await mkdir(join(projectDir, "src/services/nested"), { recursive: true });
|
|
105
|
+
await writeFile(join(projectDir, "src/services/session.js"), "export default class {}\n");
|
|
106
|
+
await writeFile(join(projectDir, "src/services/nested/deep.js"), "export default class {}\n");
|
|
107
|
+
|
|
108
|
+
const bundle = await rolldown({
|
|
109
|
+
input: {
|
|
110
|
+
"components/foo": "./src/components/foo.js",
|
|
111
|
+
"services/session": "./src/services/session.js",
|
|
112
|
+
"services/nested/deep": "./src/services/nested/deep.js",
|
|
113
|
+
},
|
|
114
|
+
plugins: [appReexports()],
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
await bundle.write({ dir: "dist" });
|
|
118
|
+
await bundle.close();
|
|
119
|
+
|
|
120
|
+
const manifest = await readJson("package.json");
|
|
121
|
+
|
|
122
|
+
// services/* is not deep: nested services (and everything else) stay out
|
|
123
|
+
expect(manifest["ember-addon"]["app-js"]).toEqual({
|
|
124
|
+
"./services/session.js": "./dist/_app_/services/session.js",
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
it("respects exclude", async () => {
|
|
129
|
+
await build({ include: ["**/*.js"], exclude: ["utils/**"] });
|
|
130
|
+
|
|
131
|
+
const manifest = await readJson("package.json");
|
|
132
|
+
|
|
133
|
+
expect(Object.keys(manifest["ember-addon"]["app-js"])).toEqual(["./components/foo.js"]);
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
it("supports mapFilename and custom exports", async () => {
|
|
137
|
+
await build({
|
|
138
|
+
include: ["utils/**"],
|
|
139
|
+
mapFilename: (name) => name.replace("math", "arithmetic"),
|
|
140
|
+
exports: () => ["add"],
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
expect(await readFile("dist/_app_/utils/arithmetic.js", "utf8")).toMatchInlineSnapshot(`
|
|
144
|
+
"export { add } from "my-lib/utils/math";
|
|
145
|
+
"
|
|
146
|
+
`);
|
|
147
|
+
|
|
148
|
+
const manifest = await readJson("package.json");
|
|
149
|
+
|
|
150
|
+
expect(manifest["ember-addon"]["app-js"]).toMatchInlineSnapshot(`
|
|
151
|
+
{
|
|
152
|
+
"./utils/arithmetic.js": "./dist/_app_/utils/arithmetic.js",
|
|
153
|
+
}
|
|
154
|
+
`);
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
it("never re-exports .d.ts files", async () => {
|
|
158
|
+
const emitDeclaration: Plugin = {
|
|
159
|
+
name: "test:emit-declaration",
|
|
160
|
+
generateBundle() {
|
|
161
|
+
this.emitFile({
|
|
162
|
+
type: "asset",
|
|
163
|
+
fileName: "components/foo.d.ts",
|
|
164
|
+
source: "declare const foo: () => void;\nexport default foo;\n",
|
|
165
|
+
});
|
|
166
|
+
},
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
const bundle = await rolldown({
|
|
170
|
+
input: { "components/foo": "./src/components/foo.js" },
|
|
171
|
+
plugins: [emitDeclaration, appReexports({ include: ["**/*"] })],
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
await bundle.write({ dir: "dist" });
|
|
175
|
+
await bundle.close();
|
|
176
|
+
|
|
177
|
+
const manifest = await readJson("package.json");
|
|
178
|
+
|
|
179
|
+
expect(Object.keys(manifest["ember-addon"]["app-js"])).toEqual(["./components/foo.js"]);
|
|
180
|
+
await expect(stat("dist/_app_/components/foo.d.ts")).rejects.toThrow();
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
it("does not touch files whose content would be unchanged", async () => {
|
|
184
|
+
await build({ include: ["components/**"] });
|
|
185
|
+
|
|
186
|
+
const epoch = new Date(0);
|
|
187
|
+
|
|
188
|
+
await utimes("package.json", epoch, epoch);
|
|
189
|
+
await utimes("dist/_app_/components/foo.js", epoch, epoch);
|
|
190
|
+
|
|
191
|
+
await build({ include: ["components/**"] });
|
|
192
|
+
|
|
193
|
+
expect((await stat("package.json")).mtimeMs).toBe(0);
|
|
194
|
+
expect((await stat("dist/_app_/components/foo.js")).mtimeMs).toBe(0);
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
it("leaves an equivalent package.json alone, regardless of formatting", async () => {
|
|
198
|
+
await build({ include: ["components/**"] });
|
|
199
|
+
|
|
200
|
+
// Same app-js map, different formatting: the plugin must not reformat.
|
|
201
|
+
const reformatted =
|
|
202
|
+
JSON.stringify(await readJson("package.json"), null, 4).replace(/\n/g, "\r\n") + "\r\n";
|
|
203
|
+
|
|
204
|
+
await writeFile("package.json", reformatted);
|
|
205
|
+
await build({ include: ["components/**"] });
|
|
206
|
+
|
|
207
|
+
expect(await readFile("package.json", "utf8")).toBe(reformatted);
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
it("rewrites package.json when the app-js map changes", async () => {
|
|
211
|
+
await build({ include: ["components/**"] });
|
|
212
|
+
await build({ include: ["utils/**"] });
|
|
213
|
+
|
|
214
|
+
const manifest = await readJson("package.json");
|
|
215
|
+
|
|
216
|
+
expect(manifest["ember-addon"]["app-js"]).toEqual({
|
|
217
|
+
"./utils/math.js": "./dist/_app_/utils/math.js",
|
|
218
|
+
});
|
|
219
|
+
});
|
|
220
|
+
});
|