Skip to content

Commit

Permalink
use staticInvoakables instead of staticHelpers, staticModifiers, and …
Browse files Browse the repository at this point in the history
…staticComponents
  • Loading branch information
mansona committed Dec 16, 2024
1 parent 88bedbb commit 230e133
Show file tree
Hide file tree
Showing 5 changed files with 101 additions and 49 deletions.
9 changes: 3 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,7 @@ You can pass options into Embroider by passing them into the `compatBuild` funct
return require('@embroider/compat').compatBuild(app, Webpack, {
// staticAddonTestSupportTrees: true,
// staticAddonTrees: true,
// staticHelpers: true,
// staticModifiers: true,
// staticComponents: true,
// staticInvokables: true,
// staticEmberSource: true,
// splitAtRoutes: ['route.name'], // can also be a RegExp
// packagerOptions: {
Expand All @@ -99,9 +97,8 @@ The recommended steps when introducing Embroider into an existing app are:

1. First make it work with no options. This is the mode that supports maximum backward compatibility. If you're hitting errors, first look at the "Compatibility with Classic Builds" section below.
2. Enable `staticAddonTestSupportTrees` and `staticAddonTrees` and test your application. This is usually safe, because most code in these trees gets consumed via `import` statements that we can analyze. But you might find exceptional cases where some code is doing a more dynamic thing.
3. Enable `staticHelpers` and `staticModifiers` and test. This is usually safe because addon helpers and modifiers get invoked declaratively in templates and we can see all invocations.
4. Enable `staticComponents`, and work to eliminate any resulting build warnings about dynamic component invocation. You may need to add `packageRules` that declare where invocations like `{{component someComponent}}` are getting `someComponent` from.
5. Once your app is working with all of the above, you can enable `splitAtRoutes` and add the `@embroider/router` and code splitting should work. See the packages/router/README.md for details and limitations.
3. Enable `staticInvokables` and work to eliminate any resulting build warnings about dynamic component invocation. You may need to add `packageRules` that declare where invocations like `{{component someComponent}}` are getting `someComponent` from.
4. Once your app is working with all of the above, you can enable `splitAtRoutes` and add the `@embroider/router` and code splitting should work. See the packages/router/README.md for details and limitations.

## Configuring asset URLs

Expand Down
56 changes: 43 additions & 13 deletions packages/compat/src/compat-app-builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ import { SyncDir } from './sync-dir';
export class CompatAppBuilder {
// for each relativePath, an Asset we have already emitted
private assets: Map<string, InternalAsset> = new Map();
private staticComponents = false;
private staticHelpers = false;
private staticModifiers = false;

constructor(
private root: string,
Expand All @@ -77,7 +80,39 @@ export class CompatAppBuilder {
private configTree: V1Config,
private synthVendor: Package,
private synthStyles: Package
) {}
) {
// staticInvokables always wins when configured
if (typeof options.staticInvokables !== 'undefined') {
if (
typeof options.staticComponents !== 'undefined' ||
typeof options.staticHelpers !== 'undefined' ||
typeof options.staticModifiers !== 'undefined'
) {
throw new Error(
'You cannot set `staticHelpers`, `staticComponents`, or `staticModifiers` if you have set `staticInvokables`. Delete these configs to continue.'
);
}
this.staticComponents = this.staticHelpers = this.staticModifiers = options.staticInvokables;
return;
}

if (typeof options.staticComponents !== 'undefined') {
// TODO it doesn't seem like we have any real deprecation functionality in this package yet.
// do we need it?
console.error(`Setting 'staticComponents' is deprecated. Use 'staticInvokables' instead`);
this.staticComponents = options.staticComponents;
}

if (typeof options.staticHelpers !== 'undefined') {
console.error(`Setting 'staticHelpers' is deprecated. Use 'staticInvokables' instead`);
this.staticHelpers = options.staticHelpers;
}

if (typeof options.staticModifiers !== 'undefined') {
console.error(`Setting 'staticModifiers' is deprecated. Use 'staticInvokables' instead`);
this.staticModifiers = options.staticModifiers;
}
}

@Memoize()
private fastbootJSSrcDir() {
Expand Down Expand Up @@ -269,9 +304,9 @@ export class CompatAppBuilder {
}

let options: CompatResolverOptions['options'] = {
staticHelpers: this.options.staticHelpers,
staticModifiers: this.options.staticModifiers,
staticComponents: this.options.staticComponents,
staticHelpers: this.staticHelpers,
staticModifiers: this.staticModifiers,
staticComponents: this.staticComponents,
allowUnsafeDynamicComponents: this.options.allowUnsafeDynamicComponents,
};

Expand Down Expand Up @@ -1021,12 +1056,7 @@ export class CompatAppBuilder {
transforms.push(macroPlugin as any);
}

if (
this.options.staticComponents ||
this.options.staticHelpers ||
this.options.staticModifiers ||
(globalThis as any).embroider_audit
) {
if (this.staticComponents || this.staticHelpers || this.staticModifiers || (globalThis as any).embroider_audit) {
let opts: ResolverTransformOptions = {
appRoot: resolverConfig.appRoot,
emberVersion: this.emberVersion(),
Expand Down Expand Up @@ -1211,13 +1241,13 @@ export class CompatAppBuilder {
let eagerModules: string[] = [];

let requiredAppFiles = [this.requiredOtherFiles(appFiles)];
if (!this.options.staticComponents) {
if (!this.staticComponents) {
requiredAppFiles.push(appFiles.components);
}
if (!this.options.staticHelpers) {
if (!this.staticHelpers) {
requiredAppFiles.push(appFiles.helpers);
}
if (!this.options.staticModifiers) {
if (!this.staticModifiers) {
requiredAppFiles.push(appFiles.modifiers);
}

Expand Down
21 changes: 18 additions & 3 deletions packages/compat/src/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,22 @@ export default interface Options extends CoreOptions {
// it on in production. But it can be helpful when testing how much of your
// app is able to work with staticComponents enabled.
allowUnsafeDynamicComponents?: boolean;

/**
* When true, we statically resolve all components, modifiers, and helpers (collectively
* knows as Invokables) at build time. This causes any unused Invokables to be left out
* of the build if they are unused i.e. "tree shaking".
*
* Defaults to false which gives you greater compatibility with classic Ember apps at the
* cost of bigger builds.
*
* This setting takes over from `staticHelpers`, `staticModifiers`, and `staticComponents`
* because the Developer Experience was less than ideal if any of these settings did not
* agree i.e. they all needed to be true or they all needed to be false.
*
* Enabling this is a prerequisite for route splitting.
*/
staticInvokables?: boolean;
}

const defaults = Object.assign(coreWithDefaults(), {
Expand All @@ -106,6 +122,7 @@ const defaults = Object.assign(coreWithDefaults(), {
workspaceDir: null,
packageRules: [],
allowUnsafeDynamicComponents: false,
staticInvokables: false,
});

export function optionsWithDefaults(options?: Options): Required<Options> {
Expand All @@ -121,9 +138,7 @@ export const recommendedOptions: { [name: string]: Options } = Object.freeze({
optimized: Object.freeze({
staticAddonTrees: true,
staticAddonTestSupportTrees: true,
staticHelpers: true,
staticModifiers: true,
staticComponents: true,
staticInvokables: true,
staticEmberSource: true,
allowUnsafeDynamicComponents: false,
}),
Expand Down
4 changes: 1 addition & 3 deletions packages/compat/src/template-tag-codemod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,7 @@ export default function templateTagCodemod(
compatBuild(emberApp, undefined, {
staticAddonTrees: true,
staticAddonTestSupportTrees: true,
staticComponents: true,
staticHelpers: true,
staticModifiers: true,
staticInvokables: true,
staticEmberSource: true,
amdCompatibility: {
es: [],
Expand Down
60 changes: 36 additions & 24 deletions packages/core/src/options.ts
Original file line number Diff line number Diff line change
@@ -1,32 +1,44 @@
export default interface Options {
// When true, we statically resolve all template helpers at build time. This
// causes unused helpers to be left out of the build ("tree shaking" of
// helpers).
//
// Defaults to false, which gives you greater compatibility with classic Ember
// apps at the cost of bigger builds.
//
// Enabling this is a prerequisite for route splitting.
/**
* When true, we statically resolve all template helpers at build time. This
* causes unused helpers to be left out of the build ("tree shaking" of
* helpers).
*
* Defaults to false, which gives you greater compatibility with classic Ember
* apps at the cost of bigger builds.
*
* Enabling this is a prerequisite for route splitting.
*
* @deprecated use staticInvokables instead
*/
staticHelpers?: boolean;

// When true, we statically resolve all modifiers at build time. This
// causes unused modifiers to be left out of the build ("tree shaking" of
// modifiers).
//
// Defaults to false, which gives you greater compatibility with classic Ember
// apps at the cost of bigger builds.
//
// Enabling this is a prerequisite for route splitting.
/**
* When true, we statically resolve all modifiers at build time. This
* causes unused modifiers to be left out of the build ("tree shaking" of
* modifiers).
*
* Defaults to false, which gives you greater compatibility with classic Ember
* apps at the cost of bigger builds.
*
* Enabling this is a prerequisite for route splitting.
*
* @deprecated use staticInvokables instead
*/
staticModifiers?: boolean;

// When true, we statically resolve all components at build time. This causes
// unused components to be left out of the build ("tree shaking" of
// components).
//
// Defaults to false, which gives you greater compatibility with classic Ember
// apps at the cost of bigger builds.
//
// Enabling this is a prerequisite for route splitting.
/**
* When true, we statically resolve all components at build time. This causes
* unused components to be left out of the build ("tree shaking" of
* components).
*
* Defaults to false, which gives you greater compatibility with classic Ember
* apps at the cost of bigger builds.
*
* Enabling this is a prerequisite for route splitting.
*
* @deprecated use staticInvokables instead
*/
staticComponents?: boolean;

// Enables per-route code splitting. Any route names that match these patterns
Expand Down

0 comments on commit 230e133

Please sign in to comment.