Welcome to our application!
Loading chart library...
{{else if this.chartLoader.isError}}Error loading chart: {{this.chartLoader.error.message}}
{{else if this.chartLoader.isResolved}} {{/if}} } ``` **Note**: Always model promise state (loading/error/resolved) using `getPromiseState` from `reactiveweb/promise` to handle slow networks and errors properly. Dynamic imports reduce initial bundle size by 30-50%, improving Time to Interactive. ### 2.3 Use Embroider Build Pipeline **Impact: CRITICAL (Modern build system with better performance)** Use Embroider, Ember's modern build pipeline, with Vite for faster builds, better tree-shaking, and smaller bundles. **Incorrect: classic build pipeline** ```javascript // ember-cli-build.js const EmberApp = require('ember-cli/lib/broccoli/ember-app'); module.exports = function (defaults) { const app = new EmberApp(defaults, {}); return app.toTree(); }; ``` **Correct: Embroider with Vite** ```javascript // ember-cli-build.js const EmberApp = require('ember-cli/lib/broccoli/ember-app'); const { compatBuild } = require('@embroider/compat'); module.exports = async function (defaults) { const { buildOnce } = await import('@embroider/vite'); let app = new EmberApp(defaults, { // Add options here }); return compatBuild(app, buildOnce); }; ``` **For stricter static analysis: optimized mode** ```javascript // ember-cli-build.js const EmberApp = require('ember-cli/lib/broccoli/ember-app'); const { compatBuild } = require('@embroider/compat'); module.exports = async function (defaults) { const { buildOnce } = await import('@embroider/vite'); let app = new EmberApp(defaults, { // Add options here }); return compatBuild(app, buildOnce, { // Enable static analysis for better tree-shaking staticAddonTestSupportTrees: true, staticAddonTrees: true, staticHelpers: true, staticModifiers: true, staticComponents: true, }); }; ``` Embroider provides a modern build pipeline with Vite that offers faster builds and better optimization compared to the classic Ember CLI build system. Reference: [https://github.com/embroider-build/embroider](https://github.com/embroider-build/embroider) --- ## 3. Component and Reactivity Optimization **Impact: HIGH** Proper use of Glimmer components, modern file conventions, tracked properties, and avoiding unnecessary recomputation improves rendering performance. ### 3.1 Avoid Constructors in Components **Impact: HIGH (Prevents infinite render loops and simplifies code)** **Strongly discourage constructor usage.** Modern Ember components rarely need constructors. Use class fields, @service decorators, and getPromiseState for initialization instead. Constructors with function calls that set tracked state can cause infinite render loops. - [Ember Octane Guide](https://guides.emberjs.com/release/upgrading/current-edition/) - [warp-drive/reactiveweb](https://github.com/emberjs/data/tree/main/packages/reactiveweb) **Incorrect: using constructor** ```glimmer-js // app/components/user-profile.gjs import Component from '@glimmer/component'; import { tracked } from '@glimmer/tracking'; import { service } from '@ember/service'; class UserProfile extends Component { constructor() { super(...arguments); // Anti-pattern: Manual service lookup this.store = this.owner.lookup('service:store'); this.router = this.owner.lookup('service:router'); // Anti-pattern: Imperative initialization this.data = null; this.isLoading = false; this.error = null; // Anti-pattern: Side effects in constructor this.loadUserData(); } async loadUserData() { this.isLoading = true; try { this.data = await this.store.request({ url: `/users/${this.args.userId}`, }); } catch (e) { this.error = e; } finally { this.isLoading = false; } } {{#if this.isLoading}}{{@user.email}}
{{@user.email}}
{{#if @user.avatarUrl}}Total: {{this.statistics.total}}
Published: {{this.statistics.published}}
Drafts: {{this.statistics.drafts}}
Showing {{this.resultsCount}} results
{{#each this.items as |item|}}{{@user.email}}
{{u.bio}}
{{u.email}}
<:actions as |u|> <:footer as |u|>{{@user.email}}