ember.nvp 1.7.0 → 1.7.1
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/.release-plan.json +45 -13
- package/CHANGELOG.md +18 -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 +1 -1
- 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 +1 -1
- 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 +1 -1
- 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
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
# `@nullvoxpopuli/ember-rolldown`
|
|
2
2
|
|
|
3
3
|
A batteries-included meta-plugin for building Ember v2 libraries (addons) with
|
|
4
|
-
[rolldown](https://rolldown.rs/)
|
|
5
|
-
built on top of rolldown and also emits `.d.ts` files.
|
|
4
|
+
[rolldown](https://rolldown.rs/), or with [tsdown](https://tsdown.dev/), which
|
|
5
|
+
is built on top of rolldown and also emits `.d.ts` files.
|
|
6
6
|
|
|
7
|
-
It compiles `.gts
|
|
8
|
-
publishable output
|
|
7
|
+
It compiles `.gts` / `.gjs` and template-tag (`<template>`) source into
|
|
8
|
+
publishable output. A single `ember()` call replaces the usual stack of
|
|
9
9
|
`@embroider/*` externals handling, content-tag preprocessing, and babel wiring.
|
|
10
10
|
|
|
11
11
|
## Install
|
|
@@ -14,17 +14,18 @@ publishable output, so a single `ember()` call replaces the usual stack of
|
|
|
14
14
|
npm add --save-dev @nullvoxpopuli/ember-rolldown
|
|
15
15
|
```
|
|
16
16
|
|
|
17
|
-
Requires node 24
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
Requires node 24+.
|
|
18
|
+
|
|
19
|
+
These packages ship TypeScript source, so type-checking needs a modern
|
|
20
|
+
TypeScript: 6+ with `lib` covering `es2025` (e.g. `esnext`).
|
|
20
21
|
|
|
21
22
|
## Usage
|
|
22
23
|
|
|
23
|
-
Import `defineConfig` from the bundler you
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
Import `defineConfig` from the bundler you use, `tsdown` or `rolldown`, so it
|
|
25
|
+
carries that tool's own config types. `@nullvoxpopuli/ember-rolldown` provides
|
|
26
|
+
`ember()`. The defaults travel with the plugin, not with `defineConfig`.
|
|
26
27
|
|
|
27
|
-
In your `tsdown.config.js` (recommended
|
|
28
|
+
In your `tsdown.config.js` (recommended, because it emits declarations):
|
|
28
29
|
|
|
29
30
|
```js
|
|
30
31
|
import { defineConfig } from "tsdown";
|
|
@@ -36,10 +37,10 @@ export default defineConfig({
|
|
|
36
37
|
});
|
|
37
38
|
```
|
|
38
39
|
|
|
39
|
-
This builds your entry to `dist/*.js` and `dist/*.d.ts` with sourcemaps
|
|
40
|
-
|
|
41
|
-
consuming app. You choose the `entry` and `plugins
|
|
42
|
-
|
|
40
|
+
This builds your entry to `dist/*.js` and `dist/*.d.ts` with sourcemaps. It
|
|
41
|
+
cleans `dist/` between builds and leaves the ember virtual packages to the
|
|
42
|
+
consuming app. You choose the `entry` and `plugins`. Any tsdown option you pass
|
|
43
|
+
wins.
|
|
43
44
|
|
|
44
45
|
Or in a plain `rolldown.config.js`:
|
|
45
46
|
|
|
@@ -53,16 +54,16 @@ export default defineConfig({
|
|
|
53
54
|
});
|
|
54
55
|
```
|
|
55
56
|
|
|
56
|
-
A babel config is optional. Without one, `ember()` compiles templates
|
|
57
|
-
|
|
57
|
+
A babel config is optional. Without one, `ember()` compiles templates (to
|
|
58
|
+
`precompileTemplate`), decorators (via
|
|
58
59
|
[decorator-transforms](https://github.com/ef4/decorator-transforms)), and
|
|
59
|
-
TypeScript
|
|
60
|
-
preferred over a `babel.config
|
|
60
|
+
TypeScript. With one, your config runs instead. A `babel.publish.config.*` is
|
|
61
|
+
preferred over a `babel.config.*`. See
|
|
61
62
|
[Publish vs. development babel config](#publish-vs-development-babel-config).
|
|
62
63
|
|
|
63
64
|
### Entrypoints
|
|
64
65
|
|
|
65
|
-
Entries may be any extension
|
|
66
|
+
Entries may be any extension: `.ts`, `.js`, `.gts`, `.gjs`.
|
|
66
67
|
|
|
67
68
|
```js
|
|
68
69
|
export default defineConfig({
|
|
@@ -72,19 +73,20 @@ export default defineConfig({
|
|
|
72
73
|
```
|
|
73
74
|
|
|
74
75
|
Whatever the source extension, the emitted `.js` and `.d.ts` paths mirror the
|
|
75
|
-
entry paths
|
|
76
|
-
`dist/
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
public API
|
|
80
|
-
own
|
|
76
|
+
entry paths. The example emits `dist/index.js` + `dist/index.d.ts` and
|
|
77
|
+
`dist/components/menu.js` + `dist/components/menu.d.ts`.
|
|
78
|
+
|
|
79
|
+
Type imports resolve against those emitted paths. So your entries, together
|
|
80
|
+
with your `exports` map, _are_ your public API. A module that isn't an entry has
|
|
81
|
+
no stable `dist/` path of its own. It is only reachable through the entrypoints
|
|
82
|
+
that re-export it.
|
|
81
83
|
|
|
82
84
|
### Declarations
|
|
83
85
|
|
|
84
|
-
Declarations are emitted with isolated declarations
|
|
85
|
-
pipeline that can see `<template>` (`.gts
|
|
86
|
-
inside the bundler's module graph. The tsconfig your build uses must
|
|
87
|
-
|
|
86
|
+
Declarations are emitted with isolated declarations. That is the only
|
|
87
|
+
declaration pipeline that can see `<template>` (`.gts` / `.gjs`) modules, which
|
|
88
|
+
exist only inside the bundler's module graph. The tsconfig your build uses must
|
|
89
|
+
enable it. `ember()` errors otherwise.
|
|
88
90
|
|
|
89
91
|
```jsonc
|
|
90
92
|
{
|
|
@@ -106,14 +108,16 @@ export const Badge: TOC<BadgeSignature> = <template>...</template>;
|
|
|
106
108
|
#### Keeping the constraint off dev-only code
|
|
107
109
|
|
|
108
110
|
`isolatedDeclarations` is a constraint on how _published_ code is written, so it
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
111
|
+
must cover only the code you emit declarations for.
|
|
112
|
+
|
|
113
|
+
If your package also holds dev-only code (a demo app, in-package tests), putting
|
|
114
|
+
the flag on the single `tsconfig.json` that covers everything would force
|
|
115
|
+
explicit annotations on demo components and test helpers that never get a
|
|
116
|
+
`.d.ts`.
|
|
113
117
|
|
|
114
118
|
The tsconfig `ember()` checks is the one
|
|
115
|
-
[tsdown's `tsconfig` option](https://tsdown.dev/options/tsconfig) points at
|
|
116
|
-
point the build at a publish-only config and leave `tsconfig.json` alone for
|
|
119
|
+
[tsdown's `tsconfig` option](https://tsdown.dev/options/tsconfig) points at. So
|
|
120
|
+
point the build at a publish-only config, and leave `tsconfig.json` alone for
|
|
117
121
|
editors and `tsc --noEmit`:
|
|
118
122
|
|
|
119
123
|
```js
|
|
@@ -127,21 +131,21 @@ export default defineConfig({
|
|
|
127
131
|
```
|
|
128
132
|
|
|
129
133
|
Any path works, so the publish config can live wherever you keep build
|
|
130
|
-
configuration
|
|
131
|
-
too: `tsconfig: "./config"` picks up `config/tsconfig.json`.
|
|
134
|
+
configuration: `tsconfig: "./config/tsconfig.publish.json"`. A directory works
|
|
135
|
+
too: `tsconfig: "./config"` picks up `config/tsconfig.json`.
|
|
132
136
|
|
|
133
|
-
`tsconfig: false` is rejected while declarations are on
|
|
137
|
+
`tsconfig: false` is rejected while declarations are on. With no tsconfig there
|
|
134
138
|
is no `isolatedDeclarations`, and the fallback pipeline can't see compiled
|
|
135
139
|
`.gts`, so it would fail later with "Source file not found". Set `dts: false`
|
|
136
140
|
alongside it if the library ships no types.
|
|
137
141
|
|
|
138
|
-
A tsconfig's relative paths resolve against the file itself
|
|
142
|
+
A tsconfig's relative paths resolve against the file itself. So a config kept in
|
|
139
143
|
`config/` wants `"include": ["../src/**/*"]` and `"rootDir": "../src"`. The build
|
|
140
|
-
won't tell you if you get that wrong
|
|
141
|
-
`entry`, not from the tsconfig's `include`
|
|
142
|
-
editor will, if you ever point them at that config.
|
|
144
|
+
won't tell you if you get that wrong, because tsdown drives declaration emit
|
|
145
|
+
from `entry`, not from the tsconfig's `include`. `tsc` / `ember-tsc` and your
|
|
146
|
+
editor will tell you, if you ever point them at that config.
|
|
143
147
|
|
|
144
|
-
The tradeoff: isolated-declaration errors in `src` then surface when you build
|
|
148
|
+
The tradeoff: isolated-declaration errors in `src` then surface when you build,
|
|
145
149
|
rather than in your editor, since the editor uses `tsconfig.json`. Run the build
|
|
146
150
|
(or `tsc --noEmit -p tsconfig.publish.json`) in CI so nothing lands unchecked.
|
|
147
151
|
|
|
@@ -149,24 +153,24 @@ rather than in your editor, since the editor uses `tsconfig.json`. Run the build
|
|
|
149
153
|
|
|
150
154
|
Components that import co-located CSS (`import './popup.css'`) need
|
|
151
155
|
[`@tsdown/css`](https://www.npmjs.com/package/@tsdown/css) installed in your
|
|
152
|
-
library
|
|
153
|
-
single CSS file in `dist/`. Install the version matching your `tsdown`
|
|
154
|
-
|
|
156
|
+
library. tsdown auto-detects it and bundles every imported stylesheet into a
|
|
157
|
+
single CSS file in `dist/`. Install the version matching your `tsdown` version.
|
|
158
|
+
They are released in lockstep.
|
|
155
159
|
|
|
156
160
|
```bash
|
|
157
161
|
npm add --save-dev @tsdown/css
|
|
158
162
|
```
|
|
159
163
|
|
|
160
|
-
Without it, tsdown's css-guard fails the build on the first CSS import
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
+
Without it, tsdown's css-guard fails the build on the first CSS import. Because
|
|
165
|
+
the importing component module never loads, any declaration that references
|
|
166
|
+
that component dangles. That surfaces as misleading `UNLOADABLE_DEPENDENCY`
|
|
167
|
+
errors on `<component>.d.ts` files.
|
|
164
168
|
|
|
165
169
|
### ember-scoped-css
|
|
166
170
|
|
|
167
171
|
[ember-scoped-css](https://github.com/auditboard/ember-scoped-css) works with
|
|
168
|
-
this pipeline
|
|
169
|
-
`babel.templateTransforms` option
|
|
172
|
+
this pipeline. Its template transform rides along via `ember()`'s
|
|
173
|
+
`babel.templateTransforms` option. Its unplugin (`ember-scoped-css/rollup`)
|
|
170
174
|
resolves the scoped CSS requests the transform injects:
|
|
171
175
|
|
|
172
176
|
```js
|
|
@@ -191,33 +195,32 @@ export default defineConfig({
|
|
|
191
195
|
```
|
|
192
196
|
|
|
193
197
|
This scopes co-located `.css` files, inline `<style scoped>` blocks, and the
|
|
194
|
-
`scopedClass` pseudo-helper
|
|
195
|
-
handles
|
|
198
|
+
`scopedClass` pseudo-helper. That last one is what the `babel.plugins` entry
|
|
199
|
+
handles. Leave it off if you don't use `scopedClass` in module code.
|
|
196
200
|
|
|
197
|
-
`css.inject` matters for libraries
|
|
198
|
-
statement in `dist/index.js`, so consuming apps pull the styles in through
|
|
199
|
-
|
|
200
|
-
it.
|
|
201
|
+
`css.inject` matters for libraries. It keeps the `import "./style.css"`
|
|
202
|
+
statement in `dist/index.js`, so consuming apps pull the styles in through the
|
|
203
|
+
module graph. Without it, the bundled CSS is emitted but nothing loads it.
|
|
201
204
|
|
|
202
205
|
## What `ember()` does
|
|
203
206
|
|
|
204
207
|
`ember()` returns an array of rolldown plugins:
|
|
205
208
|
|
|
206
|
-
- **`emberIsolatedDeclarations()`**
|
|
209
|
+
- **`emberIsolatedDeclarations()`** errors when the tsconfig the build uses
|
|
207
210
|
(tsdown's `tsconfig` option, defaulting to `tsconfig.json`) is present without
|
|
208
211
|
`isolatedDeclarations: true`.
|
|
209
|
-
- **`emberExternals()`**
|
|
210
|
-
|
|
212
|
+
- **`emberExternals()`** keeps your `dependencies`, `peerDependencies`, and the
|
|
213
|
+
ember virtual packages (e.g. `@ember/component`, `@glimmer/tracking`, the
|
|
211
214
|
template compiler) external, so the consuming app resolves them.
|
|
212
|
-
- **`emberBundle()`**
|
|
213
|
-
|
|
214
|
-
- **`emberTransform()`**
|
|
215
|
+
- **`emberBundle()`** replaces `emberExternals()` in bundle mode. It makes the
|
|
216
|
+
ember virtual packages resolvable, so they can be bundled.
|
|
217
|
+
- **`emberTransform()`** preprocesses `<template>` via
|
|
215
218
|
[content-tag](https://github.com/embroider-build/content-tag) and maps
|
|
216
|
-
`.gts
|
|
217
|
-
`.gts` specifiers in emitted `.d.ts` files.
|
|
218
|
-
- **`emberBabel()`**
|
|
219
|
-
|
|
220
|
-
|
|
219
|
+
`.gts` / `.gjs` to `.ts` / `.js` so rolldown understands them. It also
|
|
220
|
+
rewrites `.gts` specifiers in emitted `.d.ts` files.
|
|
221
|
+
- **`emberBabel()`** runs babel with `babelHelpers: "bundled"`, but only on the
|
|
222
|
+
files that need it (template-tag, decorators, template imports). Everything
|
|
223
|
+
else stays on rolldown's fast native (oxc) transform. It uses your
|
|
221
224
|
`babel.publish.config.*` (root or `config/`) in preference to your
|
|
222
225
|
`babel.config.*`.
|
|
223
226
|
|
|
@@ -236,11 +239,12 @@ ember({
|
|
|
236
239
|
});
|
|
237
240
|
```
|
|
238
241
|
|
|
239
|
-
Each option is documented on `BabelOptions`.
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
242
|
+
Each option is documented on `BabelOptions`.
|
|
243
|
+
|
|
244
|
+
`templateTransforms` feeds template AST transforms to the default
|
|
245
|
+
template-compilation step. It can't be combined with a babel config file. A
|
|
246
|
+
config lists `babel-plugin-ember-template-compilation` itself, so its
|
|
247
|
+
transforms belong there.
|
|
244
248
|
|
|
245
249
|
### Bundle mode
|
|
246
250
|
|
|
@@ -276,12 +280,13 @@ Do not combine bundle mode with tsdown's `unbundle` option.
|
|
|
276
280
|
|
|
277
281
|
### Publish vs. development babel config
|
|
278
282
|
|
|
279
|
-
A library's plain `babel.config.*` is usually its _development_ config
|
|
283
|
+
A library's plain `babel.config.*` is usually its _development_ config. It
|
|
280
284
|
compiles `@embroider/macros` away, targets the wire format, and wires up
|
|
281
|
-
whatever the in-package demo app or test suite needs.
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
+
whatever the in-package demo app or test suite needs.
|
|
286
|
+
|
|
287
|
+
None of that belongs in a published artifact. Macros must survive for the
|
|
288
|
+
consuming app to evaluate. The wire format is private between one template
|
|
289
|
+
compiler and one glimmer runtime of the same version.
|
|
285
290
|
|
|
286
291
|
Babel's own resolution can't tell those apart, so `ember()` looks for a config
|
|
287
292
|
named for publishing first. With no explicit `configFile`, detection is:
|
|
@@ -289,8 +294,8 @@ named for publishing first. With no explicit `configFile`, detection is:
|
|
|
289
294
|
1. `babel.publish.config.{mjs,cjs,js,mts,cts,ts,json}` in the package root
|
|
290
295
|
2. the same names in `config/`
|
|
291
296
|
3. otherwise babel's own resolution (`babel.config.*`, honoring `rootMode`)
|
|
292
|
-
4. otherwise no config file
|
|
293
|
-
handled by the built-in defaults
|
|
297
|
+
4. otherwise no config file. Templates, decorators and TypeScript are still
|
|
298
|
+
handled by the built-in defaults.
|
|
294
299
|
|
|
295
300
|
So a library that keeps both configs needs no `babel` option at all:
|
|
296
301
|
|
|
@@ -307,18 +312,18 @@ my-addon/
|
|
|
307
312
|
babel.config.mjs
|
|
308
313
|
config/
|
|
309
314
|
babel.publish.config.mjs # what ember() uses
|
|
310
|
-
tsconfig.publish.json # see
|
|
315
|
+
tsconfig.publish.json # see above
|
|
311
316
|
```
|
|
312
317
|
|
|
313
|
-
Set `configFile` explicitly to override that
|
|
314
|
-
files entirely
|
|
315
|
-
restate the built-in defaults
|
|
318
|
+
Set `configFile` explicitly to override that. `configFile: false` ignores
|
|
319
|
+
config files entirely. That is what you want when your publish config would
|
|
320
|
+
only restate the built-in defaults.
|
|
316
321
|
|
|
317
322
|
## App re-exports
|
|
318
323
|
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
name
|
|
324
|
+
Some libraries need their modules to appear in the consuming app's namespace
|
|
325
|
+
for classic resolution: `{{a-component}}`, services and helpers looked up by
|
|
326
|
+
name. For those, `appReexports()` does the same job as `@embroider/addon-dev`'s
|
|
322
327
|
`appReexports` rollup plugin. It's a separate import because most libraries
|
|
323
328
|
don't need it:
|
|
324
329
|
|
|
@@ -333,10 +338,12 @@ export default defineConfig({
|
|
|
333
338
|
});
|
|
334
339
|
```
|
|
335
340
|
|
|
336
|
-
With no arguments, top-level services (`services/*`) are re-exported
|
|
341
|
+
With no arguments, top-level services (`services/*`) are re-exported. Under
|
|
337
342
|
strict mode, components and helpers are imported, but services are still
|
|
338
|
-
injected by name.
|
|
339
|
-
|
|
343
|
+
injected by name.
|
|
344
|
+
|
|
345
|
+
A string or array of strings is the include glob(s), optionally followed by the
|
|
346
|
+
remaining options. An object gives full control:
|
|
340
347
|
|
|
341
348
|
```js
|
|
342
349
|
appReexports(); // services/*
|
|
@@ -346,16 +353,14 @@ appReexports("components/**", { exclude: ["components/-private/**"] });
|
|
|
346
353
|
appReexports({ include: ["services/*", "helpers/*"], exclude: [...] });
|
|
347
354
|
```
|
|
348
355
|
|
|
349
|
-
For every built file matching `include` (minus `exclude` and `.d.ts` files),
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
`mapFilename` renames a re-export
|
|
356
|
+
For every built file matching `include` (minus `exclude` and `.d.ts` files), it
|
|
357
|
+
writes a module under `dist/_app_/` re-exporting from the library's own name,
|
|
358
|
+
and records the set in `package.json` under `ember-addon.app-js`.
|
|
359
|
+
`mapFilename` renames a re-export. `exports` picks which bindings it forwards
|
|
353
360
|
(default `["default"]`).
|
|
354
361
|
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
and `package.json` is only rewritten when the `app-js` map itself changed —
|
|
358
|
-
so rebuilds don't re-trigger file watchers.
|
|
362
|
+
Nothing is written unless its content differs from what is on disk, so rebuilds
|
|
363
|
+
don't re-trigger file watchers.
|
|
359
364
|
|
|
360
365
|
## Credit
|
|
361
366
|
|
|
@@ -27,39 +27,52 @@ interface Config {
|
|
|
27
27
|
*/
|
|
28
28
|
bundle?: boolean;
|
|
29
29
|
/**
|
|
30
|
-
* Options for the babel step
|
|
30
|
+
* Options for the babel step.
|
|
31
|
+
* See `BabelOptions`.
|
|
31
32
|
*/
|
|
32
33
|
babel?: BabelOptions;
|
|
33
34
|
}
|
|
34
35
|
|
|
35
36
|
/**
|
|
36
|
-
* A batteries-included plugin for building Ember v2 libraries (addons)
|
|
37
|
-
* rolldown
|
|
37
|
+
* A batteries-included plugin for building Ember v2 libraries (addons)
|
|
38
|
+
* with rolldown, or with tsdown (which is built on rolldown).
|
|
38
39
|
*
|
|
39
|
-
* It bundles everything needed to compile `.gts
|
|
40
|
-
* (`<template>`) source into publishable output:
|
|
40
|
+
* It bundles everything needed to compile `.gts` / `.gjs` and
|
|
41
|
+
* template-tag (`<template>`) source into publishable output:
|
|
41
42
|
*
|
|
42
|
-
* - `emberConfig()`
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
43
|
+
* - `emberConfig()`
|
|
44
|
+
* applies sensible tsdown defaults for a library build
|
|
45
|
+
* (sourcemaps, `clean`, `dts`, `.js` / `.d.ts` extensions, quiet logging).
|
|
46
|
+
* Anything you set explicitly still wins.
|
|
47
|
+
*
|
|
48
|
+
* - `emberIsolatedDeclarations()`
|
|
49
|
+
* errors when a tsconfig.json is present without `isolatedDeclarations: true`.
|
|
50
|
+
* That is the only declaration pipeline that can see compiled template-tag modules.
|
|
51
|
+
*
|
|
52
|
+
* - `emberExternals()`
|
|
53
|
+
* keeps your dependencies, peerDependencies, and the ember virtual packages external,
|
|
54
|
+
* so consuming apps resolve them.
|
|
55
|
+
*
|
|
56
|
+
* - `emberBundle()`
|
|
57
|
+
* bundle mode only, in place of `emberExternals()`.
|
|
58
|
+
* Aliases the ember virtual packages into ember-source,
|
|
52
59
|
* whose export conditions pick the build to bundle.
|
|
53
|
-
* - `emberTransform()` — preprocesses `<template>` via content-tag and maps
|
|
54
|
-
* `.gts`/`.gjs` to `.ts`/`.js` so rolldown can understand them.
|
|
55
|
-
* - `emberBabel()` — runs babel (template compilation, decorators, type
|
|
56
|
-
* stripping) with `babelHelpers: "bundled"`, but only on the files that
|
|
57
|
-
* actually need it (via `maybeBabel`); everything else stays on the fast
|
|
58
|
-
* native transform. The library's own `babel.config.js` is used when it
|
|
59
|
-
* exists; no config file is required.
|
|
60
60
|
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
61
|
+
* - `emberTransform()`
|
|
62
|
+
* preprocesses `<template>` via content-tag,
|
|
63
|
+
* and maps `.gts` / `.gjs` to `.ts` / `.js` so rolldown can understand them.
|
|
64
|
+
*
|
|
65
|
+
* - `emberBabel()`
|
|
66
|
+
* runs babel (template compilation, decorators, type stripping)
|
|
67
|
+
* with `babelHelpers: "bundled"`.
|
|
68
|
+
* Only the files that need it go through babel (via `maybeBabel`).
|
|
69
|
+
* Everything else stays on the fast native transform.
|
|
70
|
+
* The library's own `babel.config.js` is used when it exists.
|
|
71
|
+
* No config file is required.
|
|
72
|
+
*
|
|
73
|
+
* Usage in `tsdown.config.js`.
|
|
74
|
+
* Import `defineConfig` from `tsdown` (or from `rolldown` for a `rolldown.config.js`)
|
|
75
|
+
* so it carries the correct types:
|
|
63
76
|
*
|
|
64
77
|
* ```js
|
|
65
78
|
* import { defineConfig } from "tsdown";
|
|
@@ -8,9 +8,10 @@ import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
|
8
8
|
import { appReexports, type AppReexportsOptions } from "./app-reexports.ts";
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
|
-
* The plugin reads and writes package.json relative to the current working
|
|
12
|
-
*
|
|
13
|
-
*
|
|
11
|
+
* The plugin reads and writes package.json relative to the current working directory
|
|
12
|
+
* (matching the other plugins in this package).
|
|
13
|
+
*
|
|
14
|
+
* So each test runs inside its own temp project.
|
|
14
15
|
*/
|
|
15
16
|
describe("appReexports", () => {
|
|
16
17
|
let projectDir: string;
|
|
@@ -5,13 +5,14 @@ import type { RolldownPluginLike } from "./plugin-like.ts";
|
|
|
5
5
|
|
|
6
6
|
export interface AppReexportsOptions {
|
|
7
7
|
/**
|
|
8
|
-
* Globs
|
|
9
|
-
*
|
|
8
|
+
* Globs selecting which modules get an app re-export.
|
|
9
|
+
* Matched against each built filename, relative to the output directory.
|
|
10
10
|
*
|
|
11
|
-
* Defaults to `["services/*"]
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
11
|
+
* Defaults to `["services/*"]`: top-level services only.
|
|
12
|
+
*
|
|
13
|
+
* Under strict mode, components and helpers are imported.
|
|
14
|
+
* Services are still injected by name,
|
|
15
|
+
* so they are the one thing an app must always be able to resolve.
|
|
15
16
|
*
|
|
16
17
|
* `.d.ts` files never match.
|
|
17
18
|
*/
|
|
@@ -23,33 +24,39 @@ export interface AppReexportsOptions {
|
|
|
23
24
|
exclude?: string[];
|
|
24
25
|
|
|
25
26
|
/**
|
|
26
|
-
* Rename a re-export
|
|
27
|
-
*
|
|
27
|
+
* Rename a re-export.
|
|
28
|
+
*
|
|
29
|
+
* Receives the built filename, returns the filename the app sees.
|
|
30
|
+
* Defaults to the built filename unchanged.
|
|
28
31
|
*/
|
|
29
32
|
mapFilename?: (filename: string) => string;
|
|
30
33
|
|
|
31
34
|
/**
|
|
32
|
-
* Which bindings a file's re-export module forwards:
|
|
33
|
-
* (default `["default"]`)
|
|
35
|
+
* Which bindings a file's re-export module forwards:
|
|
36
|
+
* - an array of names (default `["default"]`)
|
|
37
|
+
* - or a raw export clause string such as `"*"`
|
|
34
38
|
*/
|
|
35
39
|
exports?: (filename: string) => string[] | string | undefined;
|
|
36
40
|
}
|
|
37
41
|
|
|
38
42
|
/**
|
|
39
|
-
* Merges built modules into the consuming app's namespace,
|
|
40
|
-
*
|
|
41
|
-
*
|
|
43
|
+
* Merges built modules into the consuming app's namespace,
|
|
44
|
+
* so classic resolution finds them
|
|
45
|
+
* (`{{a-component}}`, service / helper lookup by name).
|
|
46
|
+
*
|
|
47
|
+
* The same job as `@embroider/addon-dev`'s `appReexports` rollup plugin.
|
|
42
48
|
*
|
|
43
|
-
* For every built file matching `include` (minus `exclude` and `.d.ts`)
|
|
44
|
-
* writes a tiny module under `<outDir>/_app_
|
|
45
|
-
* library's own name
|
|
46
|
-
* `ember-addon.app-js
|
|
49
|
+
* For every built file matching `include` (minus `exclude` and `.d.ts`):
|
|
50
|
+
* - writes a tiny module under `<outDir>/_app_/`,
|
|
51
|
+
* re-exporting from the library's own name
|
|
52
|
+
* - records the full set in `package.json` under `ember-addon.app-js`
|
|
47
53
|
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
54
|
+
* Nothing is written unless its content differs from what is on disk:
|
|
55
|
+
* - the `_app_/` modules are compared byte-for-byte
|
|
56
|
+
* - `package.json` is only rewritten when the `app-js` map itself changed
|
|
57
|
+
* (an equivalent map in different formatting is left alone)
|
|
58
|
+
*
|
|
59
|
+
* This keeps rebuilds from re-triggering file watchers.
|
|
53
60
|
*
|
|
54
61
|
* This is a separate import, because most libraries don't need it:
|
|
55
62
|
*
|
|
@@ -64,9 +71,12 @@ export interface AppReexportsOptions {
|
|
|
64
71
|
* });
|
|
65
72
|
* ```
|
|
66
73
|
*
|
|
67
|
-
* With no arguments, top-level services (`services/*`) are re-exported.
|
|
68
|
-
*
|
|
69
|
-
*
|
|
74
|
+
* With no arguments, top-level services (`services/*`) are re-exported.
|
|
75
|
+
*
|
|
76
|
+
* The first argument can be:
|
|
77
|
+
* - a string or array of strings: the include glob(s),
|
|
78
|
+
* optionally followed by the remaining options
|
|
79
|
+
* - an object: full control
|
|
70
80
|
*
|
|
71
81
|
* ```js
|
|
72
82
|
* appReexports(); // services/*
|
|
@@ -97,7 +107,7 @@ export function appReexports(
|
|
|
97
107
|
const appJs: Record<string, string> = {};
|
|
98
108
|
|
|
99
109
|
// Sorted so the app-js map (and therefore package.json) is stable
|
|
100
|
-
// across builds regardless of chunk emission order.
|
|
110
|
+
// across builds, regardless of chunk emission order.
|
|
101
111
|
for (const builtFilename of Object.keys(bundle).sort()) {
|
|
102
112
|
if (!isIncluded(builtFilename, include, resolved.exclude)) continue;
|
|
103
113
|
|
|
@@ -143,7 +153,7 @@ function writeFileIfChanged(path: string, content: string) {
|
|
|
143
153
|
try {
|
|
144
154
|
existing = readFileSync(path, { encoding: "utf8" });
|
|
145
155
|
} catch {
|
|
146
|
-
// Doesn't exist yet (or isn't readable)
|
|
156
|
+
// Doesn't exist yet (or isn't readable): write it.
|
|
147
157
|
}
|
|
148
158
|
|
|
149
159
|
if (existing === content) return;
|
|
@@ -15,8 +15,9 @@ afterEach(() => {
|
|
|
15
15
|
});
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
|
-
* A babel config whose only plugin rewrites the string `"MARKER"` to `name
|
|
19
|
-
*
|
|
18
|
+
* A babel config whose only plugin rewrites the string `"MARKER"` to `name`.
|
|
19
|
+
*
|
|
20
|
+
* So the emitted code says which config file babel loaded.
|
|
20
21
|
*/
|
|
21
22
|
function markerConfig(name: string): string {
|
|
22
23
|
return [
|
|
@@ -37,9 +38,13 @@ function markerConfig(name: string): string {
|
|
|
37
38
|
}
|
|
38
39
|
|
|
39
40
|
/**
|
|
40
|
-
* Builds a `.gts` entry
|
|
41
|
-
*
|
|
42
|
-
*
|
|
41
|
+
* Builds a `.gts` entry in a temp dir that becomes the cwd,
|
|
42
|
+
* the way config detection sees it under the tsdown CLI.
|
|
43
|
+
*
|
|
44
|
+
* A `.gts` entry so babel runs at all:
|
|
45
|
+
* `maybeBabel` skips files that need no transform.
|
|
46
|
+
*
|
|
47
|
+
* Returns the emitted code.
|
|
43
48
|
*/
|
|
44
49
|
async function bundleWithBabel(
|
|
45
50
|
files: Record<string, string>,
|