Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 0 additions & 76 deletions text/0507-embroider-v2-package-format.md
Original file line number Diff line number Diff line change
Expand Up @@ -313,82 +313,6 @@ In today’s v1 addon packages, the `index.js` file is the main entrypoint that

It is no longer the `main` entrypoint of the package (see **Own Javascript**). Instead, it’s located via the `build` key in **Ember package metadata**, which should point at a Javascript file. `build` is optional — if you don’t have anything to say, you don’t need the file.

It is now an ECMA module, not a CJS file. The default export is a class that implements your build hooks (there is no required base class).

Here is a list of build hooks, each of which will have its own section below.

- configure
- configureDependencies
- skipBabel

I will describe the hooks using TypeScript signatures for precision. This does not imply anything about us actually using TypeScript to implement them. Each package has two type variables:

- `PackageOptions` is the interface for what options you accept from packages that depend on you. It's your package's build-time public API.
- `OwnConfig` is the interface for the configuration that you want to send to your own code, which your code can access via the `getOwnConfig` macro. This is how you influence your runtime code from the build hooks.

### Build Hook: configure

```ts
interface ConfigurationRequest<PackageOptions> = {
options: PackageOptions,
fromPackageName: string,
fromPackageRoot: string,
};
configure<PackageOptions, OwnConfig>(
requests: ConfigurationRequest<PackageOptions>[]
): OwnConfig
```

The configure hook receives an array of configuration requests. Each request contain the `PackageOptions` that a package that depends on this addon has sent to this addon. It also includes the `fromPackageName` and `fromPackageRoot` (the full path on disk to the requesting package) so that any configuration errors can blame the proper source.

`configure` deals with an array because multiple packages may depend on a single copy of our package. But our package can only be configured in one way (for example, we are either going to include some extra code or strip it out via the macro system, but we can't do both).

Addons are encouraged to merge configuration requests intelligently to try to satisfy all requesters. If it's impossible to do so, you can throw an error that explains the problem.

The `OwnConfig` return value must be JSON-serializable. It becomes available to your **Own Javascript** via the `getOwnConfig` macro, so that it can influence what code is conditionally compiled out of the build.

### Build Hook: configureDependencies

```ts
configureDependencies(): {
[dependencyName: string]: PackageOptionsForDependency | "disabled"
}
```

The `configureDependencies` hook is how you send configuration down to your own dependencies. For each package in your **allowed dependencies** you may return either the `PackageOptions` expected by that package, or the string `"disabled"`.

Any dependencies that you don't mention are considered active, but don't receive any configuration from you.

Any dependency for which you provide `PackageOptions` is active, and will receive those `PackageOptions` in its own `configure` hook.

If you set a package to `"disabled"`, it will not become active _because of your addon_. It may still become active if another package depends on it and leave it active.

When and only when a package is active:

- all standard Ember module types (`your-package/components/*.js`, `your-package/services/*.js`, etc) from its **Own Javascript** _that cannot be statically ruled out as unnecessary_ are included in the build as if some application code has `import`ed them. (What counts as “cannot be statically ruled out” is free to change as apps adopt increasingly static practices. This doesn’t break any already published packages, it just makes builds that consume them more efficient.)
- all of the package's **Implicit Dependencies** are included in the build.
- all **App Javascript** is included in the build.
- all **Assets** are included in the build.
- the package's **Active Dependencies** become active recursively.

Whether or not a package is active:

- directly-imported **Own Javascript** and **CSS** are available to any other package as described in those sections. The rationale for allowing `import` of non-active packages is that (1) we follow node module resolution and node module resolution doesn’t care about our notion of “active”, and (2) `import` is an explicit request to use the module in question. It’s not surprising that it would work, it would be more surprising if it didn’t.

The `configureDependencies` hook is the _only_ way to disable child packages. The package hooks are implemented as a class with no base class. There is no `super` to manipulate to interfere with your children’s hooks.

### Build Hook: skipBabel

```ts
skipBabel(): { package: string, semverRange?: string }[]
```

By default, all imported dependencies (and their recursive imported dependencies) go through the app's babel config. This ensures browser compatibility safety. However, we provide `skipBabel` as an opt-out to work around transpilation problems in cases where the developer has verified that transpilation of a given package isn't needed.

`skipBabel` returns a list of package names and optionally semver ranges. If no range is included, it defaults to `*`. This is a place where you're allowed to mentioned packages that are _not_ in your **allowed dependencies** because it may be necessary to talk about deeper dependencies within them. The `skipBabel` settings for all active addons are combined and if any addon skips babel for a given package & version, that causes the package to not be transpiled.

The semver range is useful to disambiguate if there are multiple versions of the same package involved in the app, and in cases where a developer has manually verified that transpilation isn't needed, it's good practice to use the semver range so that `skipBabel` doesn't accidentally apply to a future version of the package that may indeed need transpilation.

## What about Test Support?

v1 packages can provide `treeForTestSupport`, `treeForAddonTestSupport`, and `app.import` with `type="test"`. All of these features are dropped.
Expand Down
Loading