ember.nvp 1.6.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/.github/workflows/ci.yml +5 -1
- package/.release-plan.json +51 -9
- package/CHANGELOG.md +30 -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 +138 -98
- package/packages/rolldown/index.ts +66 -28
- 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 +117 -72
- package/packages/rolldown/src/bundle.test.ts +149 -0
- package/packages/rolldown/src/bundle.ts +71 -0
- package/packages/rolldown/src/config.ts +42 -18
- package/packages/rolldown/src/dts.test.ts +42 -26
- package/packages/rolldown/src/externals.test.ts +16 -11
- package/packages/rolldown/src/externals.ts +45 -28
- 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 +95 -0
- package/src/bases/minimal-custom-element/files/package.json +47 -0
- package/src/bases/minimal-custom-element/files/src/components/counter.gts +27 -0
- package/src/bases/minimal-custom-element/files/src/element.ts +45 -0
- package/src/bases/minimal-custom-element/files/src/index.ts +2 -0
- package/src/bases/minimal-custom-element/files/src/register.ts +5 -0
- package/src/bases/minimal-custom-element/files/tsconfig.json +10 -0
- package/src/bases/minimal-custom-element/files/tsdown.config.js +7 -0
- package/src/bases/minimal-custom-element/index.js +212 -0
- 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/args.js +1 -1
- package/src/cli/generator.js +4 -0
- package/src/cli/index.js +23 -18
- package/src/cli/questions/project-type.js +17 -2
- package/src/cli/questions/write.js +12 -10
- package/src/layers/are-the-types-wrong/index.js +6 -6
- package/src/layers/github-actions/index.js +7 -4
- package/src/layers/inspector-support/index.js +2 -2
- package/src/layers/publint/index.js +2 -2
- package/src/layers/qunit/index.js +21 -17
- package/src/layers/readme/index.js +55 -4
- package/src/layers/renovate/index.js +5 -5
- package/src/layers/typescript/index.js +20 -13
- package/src/layers/vitest/index.js +8 -4
- 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 +14 -2
- 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 +10 -9
- package/test/ember.nvp/base-custom-element.test.ts +440 -0
- 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 +63 -3
- 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/custom-element-1.test.ts +3 -0
- package/test/ember.nvp/permutations/custom-element-2.test.ts +3 -0
- package/test/ember.nvp/permutations/custom-element-checks.test.ts +3 -0
- package/test/ember.nvp/permutations/shared.ts +22 -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 +12 -7
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "minimal-custom-element",
|
|
3
|
+
"version": "0.0.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"description": "An Ember component, packaged as a custom element",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"author": "",
|
|
8
|
+
"type": "module",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"default": "./dist/index.js"
|
|
13
|
+
},
|
|
14
|
+
"./register": {
|
|
15
|
+
"types": "./dist/register.d.ts",
|
|
16
|
+
"default": "./dist/register.js"
|
|
17
|
+
},
|
|
18
|
+
"./*": {
|
|
19
|
+
"types": "./dist/*.d.ts",
|
|
20
|
+
"default": "./dist/*.js"
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
"files": [
|
|
24
|
+
"dist",
|
|
25
|
+
"src"
|
|
26
|
+
],
|
|
27
|
+
"scripts": {
|
|
28
|
+
"build": "tsdown",
|
|
29
|
+
"prepack": "tsdown",
|
|
30
|
+
"start": "tsdown --watch"
|
|
31
|
+
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"@ember/library-tsconfig": "^2.0.0",
|
|
34
|
+
"@glimmer/component": "^2.1.1",
|
|
35
|
+
"@nullvoxpopuli/ember-rolldown": "workspace:*",
|
|
36
|
+
"decorator-transforms": "^2.3.2",
|
|
37
|
+
"ember-source": "~7.2.0",
|
|
38
|
+
"tsdown": "^0.22.7",
|
|
39
|
+
"typescript": "^6.0.3"
|
|
40
|
+
},
|
|
41
|
+
"engines": {
|
|
42
|
+
"node": ">= 24"
|
|
43
|
+
},
|
|
44
|
+
"ember": {
|
|
45
|
+
"edition": "octane"
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import Component from "@glimmer/component";
|
|
2
|
+
import { tracked } from "@glimmer/tracking";
|
|
3
|
+
import { on } from "@ember/modifier";
|
|
4
|
+
|
|
5
|
+
export interface CounterSignature {
|
|
6
|
+
Element: HTMLDivElement;
|
|
7
|
+
Args: {
|
|
8
|
+
label: string;
|
|
9
|
+
step: number;
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export default class Counter extends Component<CounterSignature> {
|
|
14
|
+
@tracked count = 0;
|
|
15
|
+
|
|
16
|
+
increment = (): void => {
|
|
17
|
+
this.count += this.args.step;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
<template>
|
|
21
|
+
<div ...attributes>
|
|
22
|
+
<span class="label">{{@label}}</span>:
|
|
23
|
+
<output>{{this.count}}</output>
|
|
24
|
+
<button type="button" {{on "click" this.increment}}>+{{@step}}</button>
|
|
25
|
+
</div>
|
|
26
|
+
</template>
|
|
27
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { renderComponent } from "@ember/renderer";
|
|
2
|
+
import { trackedObject } from "@ember/reactive/collections";
|
|
3
|
+
|
|
4
|
+
import Counter from "./components/counter.gts";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Every element renders through one shared owner.
|
|
8
|
+
*
|
|
9
|
+
* ember keeps one renderer per owner,
|
|
10
|
+
* so this is one renderer for the whole library instead of one per element.
|
|
11
|
+
*/
|
|
12
|
+
const owner = {};
|
|
13
|
+
|
|
14
|
+
export class CounterElement extends HTMLElement {
|
|
15
|
+
static observedAttributes: string[] = ["label", "step"];
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* The rendered component reads its args from this object.
|
|
19
|
+
*
|
|
20
|
+
* A write to a property here re-renders the component.
|
|
21
|
+
*/
|
|
22
|
+
#args = trackedObject({ label: "Count", step: 1 });
|
|
23
|
+
|
|
24
|
+
#rendered: ReturnType<typeof renderComponent> | undefined;
|
|
25
|
+
|
|
26
|
+
connectedCallback(): void {
|
|
27
|
+
this.#rendered = renderComponent(Counter, { into: this, owner, args: this.#args });
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
disconnectedCallback(): void {
|
|
31
|
+
this.#rendered?.destroy();
|
|
32
|
+
this.#rendered = undefined;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
attributeChangedCallback(name: string, _previous: string | null, value: string | null): void {
|
|
36
|
+
switch (name) {
|
|
37
|
+
case "label":
|
|
38
|
+
this.#args.label = value ?? "Count";
|
|
39
|
+
break;
|
|
40
|
+
case "step":
|
|
41
|
+
this.#args.step = Number(value ?? 1);
|
|
42
|
+
break;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import { packageJson } from "ember-apply";
|
|
2
|
+
import { readFile, writeFile } from "node:fs/promises";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { getLatest } from "#utils/npm.js";
|
|
5
|
+
import { applyFolderTo } from "#utils/fs.js";
|
|
6
|
+
import { removeConfiguredPlugin } from "#utils/babel.js";
|
|
7
|
+
|
|
8
|
+
const TEMPLATE_TAG_NAME = "minimal-custom-element";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Minimal Custom Element Base
|
|
12
|
+
*
|
|
13
|
+
* The minimal-library toolchain, around one pattern:
|
|
14
|
+
* - a `<template>` component (`src/components/counter.gts`)
|
|
15
|
+
* - a custom element that renders it with `renderComponent`,
|
|
16
|
+
* and forwards its observed attributes as reactive args (`src/element.ts`)
|
|
17
|
+
* - `src/index.ts` exports the element class and the component
|
|
18
|
+
* - `src/register.ts` defines the tag, for consumers to import as a side effect
|
|
19
|
+
*
|
|
20
|
+
* Built in bundle mode: ember ships inside the package.
|
|
21
|
+
*
|
|
22
|
+
* Like minimal-library:
|
|
23
|
+
* - built with tsdown + @nullvoxpopuli/ember-rolldown
|
|
24
|
+
* - No babel.config.js
|
|
25
|
+
* - No testing framework
|
|
26
|
+
* - No linting or formatting
|
|
27
|
+
*
|
|
28
|
+
* Testing, linting, formatting, etc. are opt-in via layers.
|
|
29
|
+
*/
|
|
30
|
+
export default {
|
|
31
|
+
label: "Minimal Custom Element Base",
|
|
32
|
+
description: "An Ember component packaged as a custom element (web component)",
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* 1. Apply files
|
|
36
|
+
* a. Remove TS if needed
|
|
37
|
+
* 2. Update name(s)
|
|
38
|
+
* 3. Make publishable
|
|
39
|
+
* 4. Remove TS deps/files/config if needed
|
|
40
|
+
* 5. Upgrade in-range dependencies
|
|
41
|
+
* 6. Update an existing babel config, if any
|
|
42
|
+
*
|
|
43
|
+
* @param {import('#utils/project.js').Project} project
|
|
44
|
+
*/
|
|
45
|
+
async run(project) {
|
|
46
|
+
await applyFiles(project);
|
|
47
|
+
await updateName(project);
|
|
48
|
+
await makePublishable(project);
|
|
49
|
+
await makeJavaScript(project);
|
|
50
|
+
await upgradeDependencies(project);
|
|
51
|
+
await updateBabelConfig(project);
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* The tag a generated project registers: the package name without its scope.
|
|
57
|
+
*
|
|
58
|
+
* A custom element name must contain a hyphen,
|
|
59
|
+
* so an unhyphenated package name gets an `-element` suffix.
|
|
60
|
+
*
|
|
61
|
+
* @param {string} packageName
|
|
62
|
+
* @returns {string}
|
|
63
|
+
*/
|
|
64
|
+
export function tagNameFor(packageName) {
|
|
65
|
+
let name = packageName.replace(/^@[^/]+\//, "");
|
|
66
|
+
|
|
67
|
+
return name.includes("-") ? name : `${name}-element`;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* @param {import('#utils/project.js').Project} project
|
|
72
|
+
*/
|
|
73
|
+
async function applyFiles(project) {
|
|
74
|
+
let filePath = join(import.meta.dirname, "files");
|
|
75
|
+
|
|
76
|
+
await applyFolderTo(filePath, project);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Operates on known files where the name matters
|
|
81
|
+
*
|
|
82
|
+
* @param {import('#utils/project.js').Project} project
|
|
83
|
+
*/
|
|
84
|
+
async function updateName(project) {
|
|
85
|
+
await packageJson.modify((json) => {
|
|
86
|
+
json.name = project.desires.name;
|
|
87
|
+
}, project.directory);
|
|
88
|
+
|
|
89
|
+
let tagName = tagNameFor(project.desires.name);
|
|
90
|
+
|
|
91
|
+
for (let file of ["src/register.ts", "src/register.js", "README.md"]) {
|
|
92
|
+
await replaceInFile(project, file, TEMPLATE_TAG_NAME, tagName);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* @param {import('#utils/project.js').Project} project
|
|
98
|
+
* @param {string} relativePath
|
|
99
|
+
* @param {string} search
|
|
100
|
+
* @param {string} replacement
|
|
101
|
+
*/
|
|
102
|
+
async function replaceInFile(project, relativePath, search, replacement) {
|
|
103
|
+
if (!project.hasFile(relativePath)) return;
|
|
104
|
+
|
|
105
|
+
let path = project.path(relativePath);
|
|
106
|
+
let contents = await readFile(path, "utf-8");
|
|
107
|
+
|
|
108
|
+
await writeFile(path, contents.replaceAll(search, replacement));
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* The template's package.json is `private: true` so it can never be
|
|
113
|
+
* published from this repo; the generated library exists to be published,
|
|
114
|
+
* so the flag is removed entirely.
|
|
115
|
+
*
|
|
116
|
+
* @param {import('#utils/project.js').Project} project
|
|
117
|
+
*/
|
|
118
|
+
async function makePublishable(project) {
|
|
119
|
+
await packageJson.modify((json) => {
|
|
120
|
+
delete json.private;
|
|
121
|
+
}, project.directory);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* When the project is JavaScript (no typescript layer):
|
|
126
|
+
* - remove the TS toolchain
|
|
127
|
+
* - drop the tsconfig
|
|
128
|
+
* - point the build at the emitted `.js` entries
|
|
129
|
+
* (declarations can't be produced without types)
|
|
130
|
+
*
|
|
131
|
+
* @param {import('#utils/project.js').Project} project
|
|
132
|
+
*/
|
|
133
|
+
async function makeJavaScript(project) {
|
|
134
|
+
if (await project.hasOrWantsLayer("typescript")) return;
|
|
135
|
+
|
|
136
|
+
await packageJson.removeDevDependencies(
|
|
137
|
+
["@babel/plugin-transform-typescript", "@ember/library-tsconfig", "typescript"],
|
|
138
|
+
project.directory,
|
|
139
|
+
);
|
|
140
|
+
|
|
141
|
+
await project.removeFile("tsconfig.json");
|
|
142
|
+
|
|
143
|
+
await removeTypesExports(project);
|
|
144
|
+
await pointBuildAtJavaScript(project);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* No declarations are emitted for a JavaScript library, so the `types`
|
|
149
|
+
* export conditions would point at files that never exist.
|
|
150
|
+
*
|
|
151
|
+
* @param {import('#utils/project.js').Project} project
|
|
152
|
+
*/
|
|
153
|
+
async function removeTypesExports(project) {
|
|
154
|
+
await packageJson.modify((json) => {
|
|
155
|
+
for (let condition of Object.values(json.exports ?? {})) {
|
|
156
|
+
if (condition && typeof condition === "object") {
|
|
157
|
+
delete condition.types;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}, project.directory);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Rewrites the tsdown config so it builds the JavaScript entries and stops
|
|
165
|
+
* emitting declarations (defineConfig defaults to `dts: true`).
|
|
166
|
+
*
|
|
167
|
+
* @param {import('#utils/project.js').Project} project
|
|
168
|
+
*/
|
|
169
|
+
async function pointBuildAtJavaScript(project) {
|
|
170
|
+
let configPath = project.path("tsdown.config.js");
|
|
171
|
+
let contents = await readFile(configPath, "utf-8");
|
|
172
|
+
|
|
173
|
+
contents = contents.replace(
|
|
174
|
+
`entry: ["./src/index.ts", "./src/register.ts"],`,
|
|
175
|
+
`entry: ["./src/index.js", "./src/register.js"],\n dts: false,`,
|
|
176
|
+
);
|
|
177
|
+
|
|
178
|
+
await writeFile(configPath, contents);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Bumps in-range only.
|
|
183
|
+
* Majors will need to go through PR to this repo.
|
|
184
|
+
*
|
|
185
|
+
* @param {import('#utils/project.js').Project} project
|
|
186
|
+
*/
|
|
187
|
+
async function upgradeDependencies(project) {
|
|
188
|
+
let existing = await packageJson.read(project.directory);
|
|
189
|
+
|
|
190
|
+
await packageJson.modify(async (json) => {
|
|
191
|
+
if (json.dependencies) {
|
|
192
|
+
Object.assign(json.dependencies, await getLatest(existing.dependencies));
|
|
193
|
+
}
|
|
194
|
+
if (json.devDependencies) {
|
|
195
|
+
Object.assign(json.devDependencies, await getLatest(existing.devDependencies));
|
|
196
|
+
}
|
|
197
|
+
}, project.directory);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* The base doesn't emit a babel.config.js, but this can run over an
|
|
202
|
+
* existing project that has one -- and a JavaScript project's config
|
|
203
|
+
* must not reference the TS plugin.
|
|
204
|
+
*
|
|
205
|
+
* @param {import('#utils/project.js').Project} project
|
|
206
|
+
*/
|
|
207
|
+
async function updateBabelConfig(project) {
|
|
208
|
+
if (await project.hasOrWantsLayer("typescript")) return;
|
|
209
|
+
if (!project.hasFile("babel.config.js")) return;
|
|
210
|
+
|
|
211
|
+
await removeConfiguredPlugin(project, "@babel/plugin-transform-typescript");
|
|
212
|
+
}
|
|
@@ -4,18 +4,21 @@ A [Manifest V3](https://developer.chrome.com/docs/extensions/develop/migrate/wha
|
|
|
4
4
|
|
|
5
5
|
## Developing
|
|
6
6
|
|
|
7
|
-
The popup is a regular web page
|
|
7
|
+
The popup is a regular web page.
|
|
8
|
+
The fastest feedback loop is the vite dev server in a normal browser tab:
|
|
8
9
|
|
|
9
10
|
```bash
|
|
10
11
|
pnpm dev
|
|
11
12
|
```
|
|
12
13
|
|
|
13
|
-
To run as an
|
|
14
|
+
To run it as an extension, build in watch mode:
|
|
14
15
|
|
|
15
16
|
```bash
|
|
16
17
|
pnpm build:watch
|
|
17
18
|
```
|
|
18
19
|
|
|
20
|
+
Then load the `dist/` directory as an unpacked extension:
|
|
21
|
+
|
|
19
22
|
- **Chrome / Edge / Brave**: `chrome://extensions` → enable "Developer mode" → "Load unpacked" → select `dist/`
|
|
20
23
|
- **Firefox**: `about:debugging#/runtime/this-firefox` → "Load Temporary Add-on…" → select `dist/manifest.json`
|
|
21
24
|
|
|
@@ -23,9 +26,14 @@ After a rebuild, re-open the popup (or reload the extension) to see changes.
|
|
|
23
26
|
|
|
24
27
|
## Anatomy
|
|
25
28
|
|
|
26
|
-
- `public/manifest.json`
|
|
27
|
-
|
|
28
|
-
|
|
29
|
+
- `public/manifest.json` is the extension manifest. It is copied verbatim into `dist/`.
|
|
30
|
+
Add [`background`](https://developer.chrome.com/docs/extensions/reference/manifest/background),
|
|
31
|
+
[`content_scripts`](https://developer.chrome.com/docs/extensions/reference/manifest/content-scripts),
|
|
32
|
+
permissions, and icons here as your extension grows.
|
|
33
|
+
- `index.html` is the popup page (`action.default_popup`).
|
|
34
|
+
Extension pages forbid inline scripts, so the app boots from `app/boot.ts`.
|
|
35
|
+
- `app/` is a normal Ember app.
|
|
36
|
+
Extension pages have no URL bar, so routing uses `locationType: "none"`.
|
|
29
37
|
|
|
30
38
|
## Building for release
|
|
31
39
|
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Looking for services that come from addons?
|
|
3
3
|
*
|
|
4
|
+
* App-tree merging from libraries is not supported.
|
|
4
5
|
* See: https://github.com/embroider-build/embroider/issues/2659
|
|
5
6
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* For services, I highly recommend looking in to either of
|
|
7
|
+
* For services, look in to either of:
|
|
9
8
|
* - https://github.com/chancancode/ember-polaris-service-
|
|
10
9
|
* - https://ember-primitives.pages.dev/6-utils/createService.md
|
|
11
10
|
* - https://ember-primitives.pages.dev/6-utils/createAsyncService.md
|
|
@@ -10,9 +10,11 @@ const ENV: Config = {
|
|
|
10
10
|
environment: import.meta.env.DEV ? "development" : "production",
|
|
11
11
|
rootURL: "/",
|
|
12
12
|
/**
|
|
13
|
-
* Extension pages live at chrome-extension://<id>/index.html
|
|
14
|
-
* moz-extension://)
|
|
15
|
-
*
|
|
13
|
+
* Extension pages live at chrome-extension://<id>/index.html
|
|
14
|
+
* (or moz-extension://).
|
|
15
|
+
*
|
|
16
|
+
* History-based routing has nothing to bind to there.
|
|
17
|
+
* "none" keeps routing fully programmatic.
|
|
16
18
|
*/
|
|
17
19
|
locationType: "none",
|
|
18
20
|
EmberENV: {},
|
|
@@ -12,8 +12,8 @@ import { removeConfiguredPlugin } from "#utils/babel.js";
|
|
|
12
12
|
* whose popup is an Ember app:
|
|
13
13
|
* - type: "module" in package.json
|
|
14
14
|
* - public/manifest.json copied verbatim into dist
|
|
15
|
-
* - index.html popup booting from an external script
|
|
16
|
-
* forbid inline scripts via CSP)
|
|
15
|
+
* - index.html popup booting from an external script
|
|
16
|
+
* (extension pages forbid inline scripts via CSP)
|
|
17
17
|
* - No testing framework
|
|
18
18
|
* - No linting or formatting
|
|
19
19
|
* - No ember-welcome-page
|
|
@@ -25,8 +25,8 @@ export default {
|
|
|
25
25
|
/**
|
|
26
26
|
* 1. Apply files
|
|
27
27
|
* a. Remove TS if needed
|
|
28
|
-
* 2.
|
|
29
|
-
* 3.
|
|
28
|
+
* 2. Update name(s)
|
|
29
|
+
* 3. Remove TS deps/files if needed
|
|
30
30
|
* 4. Upgrade in-range dependencies
|
|
31
31
|
* 5. Update an existing babel config, if any
|
|
32
32
|
*
|
|
@@ -42,6 +42,8 @@ export default {
|
|
|
42
42
|
};
|
|
43
43
|
|
|
44
44
|
/**
|
|
45
|
+
* A JavaScript project's babel config must not reference the TS plugin.
|
|
46
|
+
*
|
|
45
47
|
* @param {import('#utils/project.js').Project} project
|
|
46
48
|
*/
|
|
47
49
|
async function updateBabelConfig(project) {
|
|
@@ -60,7 +62,9 @@ async function applyFiles(project) {
|
|
|
60
62
|
}
|
|
61
63
|
|
|
62
64
|
/**
|
|
63
|
-
* Operates on known files where the name matters
|
|
65
|
+
* Operates on known files where the name matters.
|
|
66
|
+
*
|
|
67
|
+
* The extension's display name lives in public/manifest.json.
|
|
64
68
|
*
|
|
65
69
|
* @param {import('#utils/project.js').Project} project
|
|
66
70
|
*/
|
|
@@ -86,10 +90,10 @@ async function makeJavaScript(project) {
|
|
|
86
90
|
if (await project.hasOrWantsLayer("typescript")) return;
|
|
87
91
|
|
|
88
92
|
/**
|
|
89
|
-
*
|
|
93
|
+
* Intellisense for JS needs some of these,
|
|
94
|
+
* but minimal means minimal.
|
|
90
95
|
*
|
|
91
|
-
*
|
|
92
|
-
* And we add a layer later for JSDoc ased TS or something
|
|
96
|
+
* A later layer for JSDoc-based TS can add them back.
|
|
93
97
|
*/
|
|
94
98
|
await packageJson.removeDevDependencies(
|
|
95
99
|
[
|
|
@@ -110,9 +114,10 @@ async function makeJavaScript(project) {
|
|
|
110
114
|
}, project.directory);
|
|
111
115
|
|
|
112
116
|
/**
|
|
113
|
-
* The import-rewriting pass only handles module files
|
|
114
|
-
*
|
|
115
|
-
*
|
|
117
|
+
* The import-rewriting pass only handles module files.
|
|
118
|
+
*
|
|
119
|
+
* The popup's <script src> points at the boot module by path,
|
|
120
|
+
* so it has to follow the .ts -> .js rename by hand.
|
|
116
121
|
*/
|
|
117
122
|
if (!project.hasFile("index.html")) return;
|
|
118
123
|
|
|
@@ -24,16 +24,17 @@ pnpm start
|
|
|
24
24
|
|
|
25
25
|
## Structure
|
|
26
26
|
|
|
27
|
-
- `src/`
|
|
28
|
-
(template-tag) and plain modules in `.ts`/`.js`.
|
|
29
|
-
- `src/index.ts`
|
|
30
|
-
must be re-exported from here
|
|
31
|
-
|
|
27
|
+
- `src/` is your library source.
|
|
28
|
+
Author components in `.gts`/`.gjs` (template-tag) and plain modules in `.ts`/`.js`.
|
|
29
|
+
- `src/index.ts` is the public entry point.
|
|
30
|
+
Everything a consumer can import must be re-exported from here,
|
|
31
|
+
or added as an entry in `tsdown.config.js`.
|
|
32
|
+
- `dist/` is the built output that gets published (git-ignored).
|
|
32
33
|
|
|
33
34
|
Declarations are emitted with
|
|
34
35
|
[isolated declarations](https://www.typescriptlang.org/tsconfig/#isolatedDeclarations),
|
|
35
|
-
so every exported value needs an explicit type annotation
|
|
36
|
-
annotate exported template-only components with `TOC<...>`.
|
|
36
|
+
so every exported value needs an explicit type annotation.
|
|
37
|
+
In particular, annotate exported template-only components with `TOC<...>`.
|
|
37
38
|
|
|
38
39
|
## Publishing
|
|
39
40
|
|
|
@@ -11,9 +11,9 @@ import { removeConfiguredPlugin } from "#utils/babel.js";
|
|
|
11
11
|
* Provides the absolute bare minimum for an Ember v2 library (addon):
|
|
12
12
|
* - type: "module" in package.json
|
|
13
13
|
* - built with tsdown + @nullvoxpopuli/ember-rolldown
|
|
14
|
-
* -
|
|
15
|
-
* - No babel.config.js
|
|
16
|
-
* and decorators
|
|
14
|
+
* - an empty src/ with an index entry
|
|
15
|
+
* - No babel.config.js
|
|
16
|
+
* (ember() covers TS stripping, template compilation, and decorators)
|
|
17
17
|
* - No testing framework
|
|
18
18
|
* - No linting or formatting
|
|
19
19
|
*
|
|
@@ -65,8 +65,10 @@ async function updateName(project) {
|
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
/**
|
|
68
|
-
* The template's package.json is `private: true
|
|
69
|
-
*
|
|
68
|
+
* The template's package.json is `private: true`,
|
|
69
|
+
* so it can never be published from this repo.
|
|
70
|
+
*
|
|
71
|
+
* The generated library exists to be published,
|
|
70
72
|
* so the flag is removed entirely.
|
|
71
73
|
*
|
|
72
74
|
* @param {import('#utils/project.js').Project} project
|
|
@@ -78,9 +80,11 @@ async function makePublishable(project) {
|
|
|
78
80
|
}
|
|
79
81
|
|
|
80
82
|
/**
|
|
81
|
-
* When the project is JavaScript (no typescript layer)
|
|
82
|
-
*
|
|
83
|
-
*
|
|
83
|
+
* When the project is JavaScript (no typescript layer):
|
|
84
|
+
* - remove the TS toolchain
|
|
85
|
+
* - drop the tsconfig
|
|
86
|
+
* - point the build at the emitted `.js` entry
|
|
87
|
+
* (declarations can't be produced without types)
|
|
84
88
|
*
|
|
85
89
|
* @param {import('#utils/project.js').Project} project
|
|
86
90
|
*/
|
|
@@ -99,8 +103,8 @@ async function makeJavaScript(project) {
|
|
|
99
103
|
}
|
|
100
104
|
|
|
101
105
|
/**
|
|
102
|
-
* No declarations are emitted for a JavaScript library,
|
|
103
|
-
* export conditions would point at files that never exist.
|
|
106
|
+
* No declarations are emitted for a JavaScript library,
|
|
107
|
+
* so the `types` export conditions would point at files that never exist.
|
|
104
108
|
*
|
|
105
109
|
* @param {import('#utils/project.js').Project} project
|
|
106
110
|
*/
|
|
@@ -115,8 +119,9 @@ async function removeTypesExports(project) {
|
|
|
115
119
|
}
|
|
116
120
|
|
|
117
121
|
/**
|
|
118
|
-
* Rewrites the tsdown config so it
|
|
119
|
-
*
|
|
122
|
+
* Rewrites the tsdown config so it:
|
|
123
|
+
* - builds the JavaScript entry
|
|
124
|
+
* - stops emitting declarations (defineConfig defaults to `dts: true`)
|
|
120
125
|
*
|
|
121
126
|
* @param {import('#utils/project.js').Project} project
|
|
122
127
|
*/
|
|
@@ -152,9 +157,10 @@ async function upgradeDependencies(project) {
|
|
|
152
157
|
}
|
|
153
158
|
|
|
154
159
|
/**
|
|
155
|
-
* The base doesn't emit a babel.config.js,
|
|
156
|
-
*
|
|
157
|
-
*
|
|
160
|
+
* The base doesn't emit a babel.config.js,
|
|
161
|
+
* but this can run over an existing project that has one.
|
|
162
|
+
*
|
|
163
|
+
* A JavaScript project's babel config must not reference the TS plugin.
|
|
158
164
|
*
|
|
159
165
|
* @param {import('#utils/project.js').Project} project
|
|
160
166
|
*/
|
package/src/cli/args.js
CHANGED
package/src/cli/generator.js
CHANGED
|
@@ -3,6 +3,7 @@ import { mkdir, rm } from "node:fs/promises";
|
|
|
3
3
|
import baseApp from "#bases/minimal-app";
|
|
4
4
|
import baseExtension from "#bases/minimal-extension";
|
|
5
5
|
import baseLibrary from "#bases/minimal-library";
|
|
6
|
+
import baseCustomElement from "#bases/minimal-custom-element";
|
|
6
7
|
import { consolidateLintingScripts } from "../consolidators/linting.js";
|
|
7
8
|
import { hasGit } from "#utils/git.js";
|
|
8
9
|
/**
|
|
@@ -28,6 +29,9 @@ export async function generateProject(project, replaceOrUpdate) {
|
|
|
28
29
|
case "extension":
|
|
29
30
|
await baseExtension.run(project);
|
|
30
31
|
break;
|
|
32
|
+
case "custom-element":
|
|
33
|
+
await baseCustomElement.run(project);
|
|
34
|
+
break;
|
|
31
35
|
}
|
|
32
36
|
|
|
33
37
|
/**
|