ember.nvp 1.7.0 → 1.8.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 +22 -0
- package/.release-plan.json +35 -7
- package/CHANGELOG.md +32 -0
- package/README.md +41 -28
- package/RELEASE.md +16 -14
- package/package.json +1 -1
- package/packages/build-tooling-utils/README.md +7 -12
- package/packages/build-tooling-utils/package.json +2 -2
- package/packages/build-tooling-utils/src/extensions.ts +4 -3
- package/packages/build-tooling-utils/src/maybe-babel.ts +18 -15
- package/packages/rolldown/README.md +105 -100
- package/packages/rolldown/index.ts +37 -24
- package/packages/rolldown/package.json +4 -4
- package/packages/rolldown/src/app-reexports.test.ts +4 -3
- package/packages/rolldown/src/app-reexports.ts +37 -27
- package/packages/rolldown/src/babel.test.ts +10 -5
- package/packages/rolldown/src/babel.ts +88 -69
- package/packages/rolldown/src/config.ts +21 -17
- package/packages/rolldown/src/dts.test.ts +42 -26
- package/packages/rolldown/src/externals.test.ts +16 -11
- package/packages/rolldown/src/externals.ts +18 -12
- package/packages/rolldown/src/isolated-declarations.ts +56 -43
- package/packages/rolldown/src/plugin-like.ts +18 -15
- package/packages/rolldown/src/published-types.test.ts +18 -13
- package/packages/rolldown/src/transform.test.ts +26 -17
- package/packages/rolldown/src/transform.ts +68 -48
- package/packages/vite/README.md +10 -11
- package/packages/vite/package.json +2 -2
- package/packages/vite/src/ember.ts +44 -36
- package/packages/vite/src/test-html.ts +13 -11
- package/src/bases/README.md +6 -3
- package/src/bases/minimal-app/app.test.ts +7 -4
- package/src/bases/minimal-app/files/app/app.ts +2 -3
- package/src/bases/minimal-app/files/app/router.ts +3 -3
- package/src/bases/minimal-app/index.js +10 -6
- package/src/bases/minimal-custom-element/files/README.md +16 -12
- package/src/bases/minimal-extension/files/README.md +13 -5
- package/src/bases/minimal-extension/files/app/app.ts +2 -3
- package/src/bases/minimal-extension/files/app/config.ts +5 -3
- package/src/bases/minimal-extension/index.js +16 -11
- package/src/bases/minimal-library/files/README.md +8 -7
- package/src/bases/minimal-library/index.js +21 -15
- package/src/cli/index.js +23 -18
- package/src/cli/questions/write.js +12 -10
- package/src/layers/are-the-types-wrong/index.js +4 -4
- package/src/layers/github-actions/index.js +7 -4
- package/src/layers/inspector-support/index.js +2 -2
- package/src/layers/qunit/index.js +18 -14
- package/src/layers/readme/index.js +2 -4
- package/src/layers/renovate/index.js +2 -1
- package/src/layers/typescript/index.js +12 -12
- package/src/layers/vitest/index.js +7 -3
- package/src/utils/babel.js +3 -2
- package/src/utils/buffer.js +2 -2
- package/src/utils/cli.js +4 -4
- package/src/utils/fs.js +23 -14
- package/src/utils/inspector-support.js +22 -19
- package/src/utils/npm.js +15 -12
- package/src/utils/project-type.js +19 -0
- package/src/utils/project.js +4 -13
- package/src/utils/remove-types.js +2 -4
- package/src/utils/rewrite-imports.js +43 -31
- package/src/utils/stage.js +44 -33
- package/src/utils/tsdown-config.js +6 -5
- package/src/utils/types.ts +9 -8
- package/test/ember.nvp/base-library.test.ts +6 -4
- package/test/ember.nvp/generator-replace-or-update.test.ts +6 -4
- package/test/ember.nvp/inspector-support.test.ts +4 -3
- package/test/ember.nvp/layer-inspector-support.test.ts +2 -3
- package/test/ember.nvp/layer-publish-checks.test.ts +2 -3
- package/test/ember.nvp/layer-qunit.test.ts +2 -2
- package/test/ember.nvp/layer-readme.test.ts +2 -2
- package/test/ember.nvp/layer-vitest.test.ts +16 -9
- package/test/ember.nvp/layers-load.test.ts +26 -0
- package/test/ember.nvp/library-src-fixtures.ts +7 -3
- package/test/ember.nvp/permutations/shared.ts +19 -12
- package/test/ember.nvp/publish-configs.test.ts +44 -31
- package/test/ember.nvp/rewrite-imports.test.ts +4 -3
- package/test/ember.nvp/scoped-css-library.test.ts +6 -4
- package/test/test-helpers/permutate.test.ts +3 -3
- package/test/test-helpers.ts +10 -6
|
@@ -28,14 +28,15 @@ export interface BabelOptions {
|
|
|
28
28
|
/**
|
|
29
29
|
* The babel config file to use.
|
|
30
30
|
*
|
|
31
|
-
* - `undefined`: auto-detect.
|
|
32
|
-
*
|
|
33
|
-
*
|
|
31
|
+
* - `undefined`: auto-detect.
|
|
32
|
+
* A `babel.publish.config.*` (in the package root or `config/`) wins,
|
|
33
|
+
* because this is a publish build.
|
|
34
|
+
* Otherwise babel's own config resolution applies (see `detectConfigFile`).
|
|
34
35
|
* - a string: use that config file.
|
|
35
36
|
* - `false`: ignore config files entirely.
|
|
36
37
|
*
|
|
37
|
-
* Without a config file, templates, decorators, and TypeScript are still
|
|
38
|
-
*
|
|
38
|
+
* Without a config file, templates, decorators, and TypeScript are still handled
|
|
39
|
+
* (see `defaultPlugins`).
|
|
39
40
|
*/
|
|
40
41
|
configFile?: string | false;
|
|
41
42
|
/**
|
|
@@ -43,17 +44,20 @@ export interface BabelOptions {
|
|
|
43
44
|
*/
|
|
44
45
|
plugins?: PluginItem[];
|
|
45
46
|
/**
|
|
46
|
-
* Template AST transforms
|
|
47
|
-
*
|
|
47
|
+
* Template AST transforms passed to the default
|
|
48
|
+
* `babel-plugin-ember-template-compilation` entry.
|
|
49
|
+
* e.g. ember-scoped-css's `scopedCSS.template()`
|
|
48
50
|
*
|
|
49
|
-
* Only valid without a babel config file
|
|
50
|
-
* `babel-plugin-ember-template-compilation` yourself,
|
|
51
|
-
* belong there.
|
|
51
|
+
* Only valid without a babel config file.
|
|
52
|
+
* With your own config, you list `babel-plugin-ember-template-compilation` yourself,
|
|
53
|
+
* so its `transforms` belong there.
|
|
52
54
|
*/
|
|
53
55
|
templateTransforms?: Transform[];
|
|
54
56
|
/**
|
|
55
|
-
* Opt additional files into babel (see maybeBabel's `filter`).
|
|
56
|
-
*
|
|
57
|
+
* Opt additional files into babel (see maybeBabel's `filter`).
|
|
58
|
+
*
|
|
59
|
+
* Use this to cover addons that ship code needing babel
|
|
60
|
+
* (e.g. `ember-concurrency`).
|
|
57
61
|
*/
|
|
58
62
|
filter?: {
|
|
59
63
|
include: {
|
|
@@ -63,27 +67,34 @@ export interface BabelOptions {
|
|
|
63
67
|
};
|
|
64
68
|
}
|
|
65
69
|
|
|
66
|
-
/**
|
|
70
|
+
/**
|
|
71
|
+
* Tried in order, so an ESM config wins over a JSON one of the same name.
|
|
72
|
+
*/
|
|
67
73
|
const PUBLISH_CONFIG_EXTENSIONS = ["mjs", "cjs", "js", "mts", "cts", "ts", "json"];
|
|
68
74
|
|
|
69
75
|
/**
|
|
70
|
-
* Tried in order:
|
|
71
|
-
*
|
|
76
|
+
* Tried in order:
|
|
77
|
+
* - next to package.json first
|
|
78
|
+
* - then `config/`, for libraries that keep their build configuration
|
|
79
|
+
* out of the package root
|
|
72
80
|
*/
|
|
73
81
|
const PUBLISH_CONFIG_DIRECTORIES = [".", "config"];
|
|
74
82
|
|
|
75
83
|
/**
|
|
76
|
-
* A `babel.publish.config.*` (in the package root or `config/`), if there is
|
|
77
|
-
*
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
* compiles `@embroider/macros` away
|
|
81
|
-
*
|
|
82
|
-
*
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
*
|
|
84
|
+
* A `babel.publish.config.*` (in the package root or `config/`), if there is one.
|
|
85
|
+
*
|
|
86
|
+
* A library's plain `babel.config.*` is its *development* config.
|
|
87
|
+
* It typically:
|
|
88
|
+
* - compiles `@embroider/macros` away
|
|
89
|
+
* - targets the wire format
|
|
90
|
+
* - wires up whatever the in-package demo app or test suite needs
|
|
91
|
+
*
|
|
92
|
+
* None of that belongs in a published artifact:
|
|
93
|
+
* - macros must stay, for the consuming app to evaluate
|
|
94
|
+
* - the wire format is private between one template compiler and one glimmer runtime
|
|
95
|
+
*
|
|
96
|
+
* Babel's own resolution can't tell the two apart (it finds whatever `babel.config.*` exists),
|
|
97
|
+
* so a publish build has to prefer the config named for publishing.
|
|
87
98
|
*/
|
|
88
99
|
function detectPublishConfigFile(): string | undefined {
|
|
89
100
|
for (const directory of PUBLISH_CONFIG_DIRECTORIES) {
|
|
@@ -98,14 +109,16 @@ function detectPublishConfigFile(): string | undefined {
|
|
|
98
109
|
}
|
|
99
110
|
|
|
100
111
|
/**
|
|
101
|
-
* The config this publish build
|
|
102
|
-
*
|
|
103
|
-
*
|
|
104
|
-
*
|
|
105
|
-
*
|
|
106
|
-
*
|
|
107
|
-
*
|
|
108
|
-
*
|
|
112
|
+
* The config this publish build must use:
|
|
113
|
+
* - a `babel.publish.config.*`, when the library has one
|
|
114
|
+
* - else the project's root babel config, resolved the way babel itself does
|
|
115
|
+
* (`babel.config.{js,cjs,mjs,cts,json}`, honoring `rootMode` semantics)
|
|
116
|
+
*
|
|
117
|
+
* For a library whose only config *is* its publish config,
|
|
118
|
+
* that is the same file either way.
|
|
119
|
+
*
|
|
120
|
+
* The sync API evaluates the config file.
|
|
121
|
+
* On node 24+ that works for native ESM configs too (require(esm)).
|
|
109
122
|
*/
|
|
110
123
|
function detectConfigFile(): string | undefined {
|
|
111
124
|
const publishConfig = detectPublishConfigFile();
|
|
@@ -121,20 +134,21 @@ function detectConfigFile(): string | undefined {
|
|
|
121
134
|
* Everything a library without its own babel config needs:
|
|
122
135
|
*
|
|
123
136
|
* - TypeScript stripping
|
|
137
|
+
*
|
|
124
138
|
* - template compilation to `precompileTemplate` (`targetFormat: "hbs"`).
|
|
125
|
-
* Published libraries must NOT ship wire format
|
|
126
|
-
* private between the template compiler and the glimmer runtime
|
|
127
|
-
* same version, so baking it in ties the published artifact
|
|
128
|
-
* consuming app's exact ember-source.
|
|
129
|
-
* compilation.
|
|
139
|
+
* Published libraries must NOT ship wire format.
|
|
140
|
+
* The wire format is private between the template compiler and the glimmer runtime
|
|
141
|
+
* of the same version, so baking it in ties the published artifact
|
|
142
|
+
* to the consuming app's exact ember-source.
|
|
143
|
+
* The consuming app performs final compilation.
|
|
130
144
|
*
|
|
131
145
|
* A bundle-mode build ships that exact ember-source,
|
|
132
146
|
* so it compiles to the wire format with ember-source's own compiler,
|
|
133
147
|
* and needs no compiler at runtime.
|
|
134
148
|
*
|
|
135
|
-
* - decorator-transforms, with its runtime left as a bare specifier
|
|
136
|
-
* consuming app resolves it
|
|
137
|
-
* a real dependency)
|
|
149
|
+
* - decorator-transforms, with its runtime left as a bare specifier
|
|
150
|
+
* so the consuming app resolves it.
|
|
151
|
+
* (the library keeps `decorator-transforms` as a real dependency)
|
|
138
152
|
*
|
|
139
153
|
* A bundle-mode build resolves it itself.
|
|
140
154
|
*/
|
|
@@ -155,8 +169,8 @@ function defaultPlugins(templateTransforms?: Transform[], bundle = false): Plugi
|
|
|
155
169
|
[
|
|
156
170
|
decoratorTransforms,
|
|
157
171
|
{
|
|
158
|
-
// Emit `import ... from "decorator-transforms/runtime-esm"` as a bare
|
|
159
|
-
//
|
|
172
|
+
// Emit `import ... from "decorator-transforms/runtime-esm"` as a bare specifier,
|
|
173
|
+
// so it stays external and the consuming app resolves it.
|
|
160
174
|
runtime: { import: "decorator-transforms/runtime-esm" },
|
|
161
175
|
},
|
|
162
176
|
],
|
|
@@ -164,29 +178,34 @@ function defaultPlugins(templateTransforms?: Transform[], bundle = false): Plugi
|
|
|
164
178
|
}
|
|
165
179
|
|
|
166
180
|
/**
|
|
167
|
-
* We still need babel (not just oxc/rolldown's native transforms) for two
|
|
168
|
-
*
|
|
169
|
-
*
|
|
170
|
-
*
|
|
171
|
-
*
|
|
172
|
-
*
|
|
173
|
-
*
|
|
174
|
-
*
|
|
175
|
-
*
|
|
176
|
-
*
|
|
177
|
-
*
|
|
178
|
-
*
|
|
179
|
-
*
|
|
180
|
-
*
|
|
181
|
-
*
|
|
182
|
-
*
|
|
183
|
-
*
|
|
184
|
-
*
|
|
185
|
-
*
|
|
186
|
-
*
|
|
187
|
-
*
|
|
188
|
-
*
|
|
189
|
-
*
|
|
181
|
+
* We still need babel (not just oxc / rolldown's native transforms) for two reasons:
|
|
182
|
+
*
|
|
183
|
+
* - template compilation.
|
|
184
|
+
* `babel-plugin-ember-template-compilation` turns the content-tag output
|
|
185
|
+
* into `precompileTemplate` calls.
|
|
186
|
+
* oxc has no equivalent.
|
|
187
|
+
*
|
|
188
|
+
* - decorators.
|
|
189
|
+
* Ember uses the legacy / stage-1 decorator signature together with `decorator-transforms`,
|
|
190
|
+
* which rewrites decorated class fields (`@tracked x`) into getter / setters backed by a runtime.
|
|
191
|
+
* oxc's native "legacy decorators" emit tsc-style `__decorate` output,
|
|
192
|
+
* which does not match those semantics.
|
|
193
|
+
*
|
|
194
|
+
* But we don't want to send *every* file through babel
|
|
195
|
+
* and give back the speed rolldown / oxc buys us.
|
|
196
|
+
*
|
|
197
|
+
* So we run babel via `maybeBabel`, which filters down to only the files that need it
|
|
198
|
+
* (template-tag, decorators, template imports).
|
|
199
|
+
* Everything else stays on the native transform.
|
|
200
|
+
*
|
|
201
|
+
* The library's own babel config is used when it exists.
|
|
202
|
+
* Its `babel.publish.config.*` (root or `config/`) wins over its `babel.config.*`,
|
|
203
|
+
* since this is a publish build.
|
|
204
|
+
*
|
|
205
|
+
* Without one, `defaultPlugins` covers templates, decorators, and TypeScript,
|
|
206
|
+
* so no config file is required.
|
|
207
|
+
*
|
|
208
|
+
* Libraries default to `babelHelpers: "bundled"`, so the emitted output is self-contained.
|
|
190
209
|
*/
|
|
191
210
|
export function emberBabel(options: BabelOptions = {}): Plugin {
|
|
192
211
|
const configFile = options.configFile === undefined ? detectConfigFile() : options.configFile;
|
|
@@ -214,8 +233,8 @@ export function emberBabel(options: BabelOptions = {}): Plugin {
|
|
|
214
233
|
|
|
215
234
|
return maybeBabel({
|
|
216
235
|
...shared,
|
|
217
|
-
// No config file (or the caller opted out)
|
|
218
|
-
// for one
|
|
236
|
+
// No config file (or the caller opted out).
|
|
237
|
+
// Don't let babel go looking for one: we provide the whole plugin list inline.
|
|
219
238
|
configFile: false,
|
|
220
239
|
babelrc: false,
|
|
221
240
|
plugins: defaultPlugins(options.templateTransforms, options.bundle).concat(
|
|
@@ -1,29 +1,33 @@
|
|
|
1
1
|
import type { TsdownPlugin, UserConfig } from "tsdown";
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* Sensible defaults for an Ember v2 library
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* Sensible defaults for an Ember v2 library.
|
|
5
|
+
*
|
|
6
|
+
* Applied through plugin hooks, so they travel with `ember()`.
|
|
7
|
+
* You get them whether you use this package's `defineConfig`, tsdown's,
|
|
8
|
+
* or a plain `tsdown.config.js` / `rolldown.config.js`.
|
|
7
9
|
*
|
|
8
10
|
* Every value is applied with `??=`, so anything you set explicitly wins.
|
|
9
11
|
*
|
|
10
|
-
* Under tsdown, the full set applies via the `tsdownConfig` hook
|
|
11
|
-
* Vite's `config` hook):
|
|
12
|
+
* Under tsdown, the full set applies via the `tsdownConfig` hook
|
|
13
|
+
* (analogous to Vite's `config` hook):
|
|
12
14
|
*
|
|
13
|
-
* - `sourcemap` — emit sourcemaps alongside the output
|
|
14
|
-
* - `clean` — wipe `dist/` between builds
|
|
15
|
-
* - `dts` — emit `.d.ts` declarations (via isolated declarations)
|
|
16
|
-
* - `outExtensions` — `.js
|
|
17
|
-
*
|
|
18
|
-
* - `report` — off
|
|
19
|
-
*
|
|
20
|
-
*
|
|
15
|
+
* - `sourcemap` — emit sourcemaps alongside the output
|
|
16
|
+
* - `clean` — wipe `dist/` between builds
|
|
17
|
+
* - `dts` — emit `.d.ts` declarations (via isolated declarations)
|
|
18
|
+
* - `outExtensions` — `.js` / `.d.ts` rather than tsdown's default `.mjs` / `.d.mts`
|
|
19
|
+
* (exports maps conventionally point at `.js` / `.d.ts`)
|
|
20
|
+
* - `report` — off.
|
|
21
|
+
* The size report is noise for a library build.
|
|
22
|
+
* - `deps.neverBundle` — leave node builtins and the ember virtual packages
|
|
23
|
+
* to the consuming app (`emberExternals()` handles the rest)
|
|
21
24
|
*
|
|
22
|
-
* A plain rolldown build has no notion of `clean
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
+
* A plain rolldown build has no notion of `clean` / `dts` / `outExtensions` / `report`.
|
|
26
|
+
* Those are tsdown-level concepts.
|
|
27
|
+
* So only the options with rolldown equivalents are applied there,
|
|
28
|
+
* via rolldown's own `outputOptions` hook:
|
|
25
29
|
*
|
|
26
|
-
* - `output.sourcemap` — on
|
|
30
|
+
* - `output.sourcemap` — on
|
|
27
31
|
*
|
|
28
32
|
* Externals are handled by `emberExternals()` (a `resolveId` hook) in both cases.
|
|
29
33
|
*
|
|
@@ -7,9 +7,13 @@ import { afterEach, describe, expect, it } from "vitest";
|
|
|
7
7
|
import { ember } from "../index.ts";
|
|
8
8
|
|
|
9
9
|
interface Dist {
|
|
10
|
-
/**
|
|
10
|
+
/**
|
|
11
|
+
* Sorted dist-relative paths of every emitted file.
|
|
12
|
+
*/
|
|
11
13
|
files: string[];
|
|
12
|
-
/**
|
|
14
|
+
/**
|
|
15
|
+
* dist-relative path -> content, for every emitted .d.ts and .css file.
|
|
16
|
+
*/
|
|
13
17
|
contents: Record<string, string>;
|
|
14
18
|
}
|
|
15
19
|
|
|
@@ -22,12 +26,16 @@ afterEach(() => {
|
|
|
22
26
|
|
|
23
27
|
/**
|
|
24
28
|
* Drives `ember()` through a real tsdown build (the dts pipeline included).
|
|
25
|
-
* `files` is a map of relative path -> source, written into a temp dir that
|
|
26
|
-
* becomes the cwd for the build (the externals and isolated-declarations
|
|
27
|
-
* plugins read package.json / tsconfig.json from cwd, like the tsdown CLI).
|
|
28
29
|
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
30
|
+
* `files` is a map of relative path -> source.
|
|
31
|
+
* It is written into a temp dir that becomes the cwd for the build.
|
|
32
|
+
* (the externals and isolated-declarations plugins read package.json / tsconfig.json
|
|
33
|
+
* from cwd, like the tsdown CLI)
|
|
34
|
+
*
|
|
35
|
+
* Returns:
|
|
36
|
+
* - the emitted file list
|
|
37
|
+
* - the full contents of every declaration and css file
|
|
38
|
+
* (js output is covered by transform.test.ts)
|
|
31
39
|
*/
|
|
32
40
|
async function buildFixture(files: Record<string, string>, entry: string[]): Promise<Dist> {
|
|
33
41
|
const dir = await mkdtemp(path.join(tmpdir(), "ember-rolldown-dts-"));
|
|
@@ -81,7 +89,9 @@ async function buildFixture(files: Record<string, string>, entry: string[]): Pro
|
|
|
81
89
|
return dist;
|
|
82
90
|
}
|
|
83
91
|
|
|
84
|
-
/**
|
|
92
|
+
/**
|
|
93
|
+
* One printable document of every captured file, for a single snapshot.
|
|
94
|
+
*/
|
|
85
95
|
function printed(dist: Dist): string {
|
|
86
96
|
return Object.entries(dist.contents)
|
|
87
97
|
.sort(([a], [b]) => a.localeCompare(b))
|
|
@@ -91,10 +101,12 @@ function printed(dist: Dist): string {
|
|
|
91
101
|
|
|
92
102
|
describe("declarations (full ember() via tsdown)", () => {
|
|
93
103
|
it("emits .d.ts for an entry that type-imports from a non-entry .gts", async () => {
|
|
94
|
-
// Mirrors a design-system shape:
|
|
95
|
-
// the
|
|
96
|
-
//
|
|
97
|
-
//
|
|
104
|
+
// Mirrors a design-system shape:
|
|
105
|
+
// - the component is in the runtime graph via the index entry
|
|
106
|
+
// - a second entry (a service) only *type*-imports from it
|
|
107
|
+
//
|
|
108
|
+
// The service's declaration then references the component's (virtual) .d.ts,
|
|
109
|
+
// which only exists in the bundler's module graph.
|
|
98
110
|
const dist = await buildFixture(
|
|
99
111
|
{
|
|
100
112
|
"src/index.ts": `export { default as Popup } from './popup.gts';`,
|
|
@@ -174,11 +186,12 @@ describe("declarations (full ember() via tsdown)", () => {
|
|
|
174
186
|
});
|
|
175
187
|
|
|
176
188
|
it("emits .d.ts when a .gts module is only ever type-imported", async () => {
|
|
177
|
-
// Nothing value-imports popup.gts, so its virtual module never enters the
|
|
178
|
-
//
|
|
179
|
-
//
|
|
180
|
-
// their (virtual) source loads,
|
|
181
|
-
//
|
|
189
|
+
// Nothing value-imports popup.gts, so its virtual module never enters the runtime graph.
|
|
190
|
+
// The only route to its declaration is the dts resolver loading it on demand.
|
|
191
|
+
//
|
|
192
|
+
// The declaration pipeline registers modules as their (virtual) source loads,
|
|
193
|
+
// so the import must resolve to the source id.
|
|
194
|
+
// A pre-rewritten `.d.ts` id skips that registration and dangles.
|
|
182
195
|
const dist = await buildFixture(
|
|
183
196
|
{
|
|
184
197
|
"src/service.ts": [
|
|
@@ -233,10 +246,10 @@ describe("declarations (full ember() via tsdown)", () => {
|
|
|
233
246
|
});
|
|
234
247
|
|
|
235
248
|
it("emits .d.ts for a .gts that type-imports another (otherwise unimported) .gts", async () => {
|
|
236
|
-
// A nested component type-imports a sibling from the parent directory
|
|
237
|
-
//
|
|
238
|
-
//
|
|
239
|
-
// runtime graph).
|
|
249
|
+
// A nested component type-imports a sibling from the parent directory.
|
|
250
|
+
//
|
|
251
|
+
// Its declaration then carries a relative source specifier for a module
|
|
252
|
+
// that exists only in the bundler's graph (never on disk, never in the runtime graph).
|
|
240
253
|
const dist = await buildFixture(
|
|
241
254
|
{
|
|
242
255
|
"src/index.ts": `export { default as OptionList } from './components/select/option-list.gts';`,
|
|
@@ -288,11 +301,14 @@ describe("declarations (full ember() via tsdown)", () => {
|
|
|
288
301
|
});
|
|
289
302
|
|
|
290
303
|
it("bundles co-located CSS (via @tsdown/css) without breaking declarations", async () => {
|
|
291
|
-
// Ember components routinely import a co-located .css file.
|
|
292
|
-
//
|
|
293
|
-
//
|
|
294
|
-
//
|
|
295
|
-
//
|
|
304
|
+
// Ember components routinely import a co-located .css file.
|
|
305
|
+
//
|
|
306
|
+
// Without CSS handling, the build dies on tsdown's css-guard.
|
|
307
|
+
// And because the failing component module never loads,
|
|
308
|
+
// every declaration that references it dangles
|
|
309
|
+
// (surfacing as misleading UNLOADABLE_DEPENDENCY errors on <component>.d.ts).
|
|
310
|
+
//
|
|
311
|
+
// @tsdown/css makes both work.
|
|
296
312
|
const dist = await buildFixture(
|
|
297
313
|
{
|
|
298
314
|
"src/index.ts": `export { default as Popup } from './popup.gts';`,
|
|
@@ -14,8 +14,9 @@ afterEach(() => {
|
|
|
14
14
|
});
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
|
-
* An ember-source stub whose `ember-addon.renamed-modules` provides
|
|
18
|
-
*
|
|
17
|
+
* An ember-source stub whose `ember-addon.renamed-modules` provides `@glimmer/runtime`.
|
|
18
|
+
*
|
|
19
|
+
* File-path keys, like the real manifest.
|
|
19
20
|
*/
|
|
20
21
|
const EMBER_SOURCE_STUB = {
|
|
21
22
|
name: "ember-source",
|
|
@@ -29,9 +30,11 @@ const EMBER_SOURCE_STUB = {
|
|
|
29
30
|
};
|
|
30
31
|
|
|
31
32
|
/**
|
|
32
|
-
* Writes a fixture package
|
|
33
|
-
*
|
|
34
|
-
*
|
|
33
|
+
* Writes a fixture package and cds into it:
|
|
34
|
+
* - a manifest
|
|
35
|
+
* - an optional stub ember-source in its node_modules
|
|
36
|
+
*
|
|
37
|
+
* The plugin reads both from the library's own context, like the tsdown CLI.
|
|
35
38
|
*/
|
|
36
39
|
async function fixture(manifest: object, { emberSource = true } = {}): Promise<string> {
|
|
37
40
|
const dir = await mkdtemp(path.join(tmpdir(), "ember-rolldown-externals-"));
|
|
@@ -50,7 +53,9 @@ async function fixture(manifest: object, { emberSource = true } = {}): Promise<s
|
|
|
50
53
|
return dir;
|
|
51
54
|
}
|
|
52
55
|
|
|
53
|
-
/**
|
|
56
|
+
/**
|
|
57
|
+
* Runs the plugin's own hooks directly against the current fixture.
|
|
58
|
+
*/
|
|
54
59
|
function resolveWith(source: string): unknown {
|
|
55
60
|
const plugin = emberExternals();
|
|
56
61
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-explicit-any
|
|
@@ -68,17 +73,17 @@ describe("emberExternals", () => {
|
|
|
68
73
|
});
|
|
69
74
|
|
|
70
75
|
it("externalizes the modules ember-source provides via renamed-modules", async () => {
|
|
71
|
-
// Private API like @glimmer/runtime exists only inside the app's
|
|
72
|
-
//
|
|
73
|
-
// emberVirtualPackages doesn't list it.
|
|
76
|
+
// Private API like @glimmer/runtime exists only inside the app's ember-source
|
|
77
|
+
// (its ember-addon.renamed-modules).
|
|
78
|
+
// @embroider/core's emberVirtualPackages doesn't list it.
|
|
74
79
|
await fixture({});
|
|
75
80
|
expect(resolveWith("@glimmer/runtime")).toBe(false);
|
|
76
81
|
expect(resolveWith("@ember/-internals/glimmer")).toBe(false);
|
|
77
82
|
});
|
|
78
83
|
|
|
79
84
|
it("does not blanket-externalize @glimmer packages ember-source doesn't provide", async () => {
|
|
80
|
-
// e.g. @glimmer/component is a real package a library may want bundled
|
|
81
|
-
//
|
|
85
|
+
// e.g. @glimmer/component is a real package a library may want bundled.
|
|
86
|
+
// Only declared deps / virtual packages / renamed-modules are external.
|
|
82
87
|
await fixture({});
|
|
83
88
|
expect(resolveWith("@glimmer/not-provided")).toBeUndefined();
|
|
84
89
|
});
|
|
@@ -18,8 +18,8 @@ function readJsonSync(path: string) {
|
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
/**
|
|
21
|
-
* Everything the library declares as a `dependency` or `peerDependency`
|
|
22
|
-
* resolvable by the consuming app, so we never bundle it.
|
|
21
|
+
* Everything the library declares as a `dependency` or `peerDependency`
|
|
22
|
+
* is resolvable by the consuming app, so we never bundle it.
|
|
23
23
|
*/
|
|
24
24
|
function resolvableDependencies(): Set<string> {
|
|
25
25
|
const deps = new Set<string>();
|
|
@@ -79,10 +79,13 @@ function emberSourceProvidedModules(): Set<string> {
|
|
|
79
79
|
}
|
|
80
80
|
|
|
81
81
|
/**
|
|
82
|
-
* Keeps
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
*
|
|
82
|
+
* Keeps external:
|
|
83
|
+
* - the library's declared dependencies
|
|
84
|
+
* - the ember virtual packages
|
|
85
|
+
* (things like `@ember/component`, `@glimmer/tracking`, the template compiler, …)
|
|
86
|
+
*
|
|
87
|
+
* So the app that consumes the library resolves them,
|
|
88
|
+
* instead of the library bundling copies of them.
|
|
86
89
|
*/
|
|
87
90
|
export function emberExternals(): Plugin {
|
|
88
91
|
let deps: Set<string>;
|
|
@@ -100,8 +103,8 @@ export function emberExternals(): Plugin {
|
|
|
100
103
|
resolveId: {
|
|
101
104
|
order: "pre",
|
|
102
105
|
handler(source) {
|
|
103
|
-
// Anything with a protocol (`node:`, virtual modules, …)
|
|
104
|
-
// to externalize.
|
|
106
|
+
// Anything with a protocol (`node:`, virtual modules, …)
|
|
107
|
+
// is not ours to externalize.
|
|
105
108
|
if (source.includes(":")) {
|
|
106
109
|
return null;
|
|
107
110
|
}
|
|
@@ -124,10 +127,13 @@ export function emberExternals(): Plugin {
|
|
|
124
127
|
}
|
|
125
128
|
|
|
126
129
|
// Modules ember-source provides by renaming them into itself
|
|
127
|
-
// (`ember-addon.renamed-modules`)
|
|
128
|
-
//
|
|
129
|
-
//
|
|
130
|
-
//
|
|
130
|
+
// (`ember-addon.renamed-modules`).
|
|
131
|
+
//
|
|
132
|
+
// Private API like `@glimmer/runtime`,
|
|
133
|
+
// which only exists inside the app's ember-source.
|
|
134
|
+
//
|
|
135
|
+
// Matched on the full specifier:
|
|
136
|
+
// the renamed modules are module paths, not packages.
|
|
131
137
|
if (renamedModules.has(source)) {
|
|
132
138
|
return false;
|
|
133
139
|
}
|