embroider-build / embroider

Compiling Ember apps into spec-compliant, modern Javascript.
MIT License
330 stars 137 forks source link

lazy loading with splitAtRoutes don't working #143

Closed villander closed 1 year ago

villander commented 5 years ago

I'm using ember-cli 3.9.0 and embroider 3.4.0

My app have 2 namespaces admin and merchant and index route for login, the lazy loading don't working when I split by ['admin', 'merchant'] neither with ['merchant.child-routes]. Nothing is lazy loading when I did this configuration. But it's works with a new ember app, take a look please @ef4

my router.js

import EmberRouter from '@embroider/router';
import { inject as service } from '@ember/service';
import config from './config/environment';

const Router = EmberRouter.extend({
  location: config.locationType,
  rootURL: config.rootURL,
  metrics: service(),
  router: service(),

  init() {
    this._super(...arguments);

    this.on('routeDidChange', () => {
      const page = this.router.currentURL;
      const title = this.router.currentRouteName || 'unknown';

      this.metrics.trackPage({ page, title });
    });
  }
});

Router.map(function () {
  this.route('index', { path: '/' });

  this.route('merchant', function () {
    this.route('dashboard');
    this.route('virtual-terminal');
    this.route('batches');
    this.route('users');
    this.route('settings', function () {
      this.route('processors', function () {
        this.route('show', { path: '/:processor_id' });
      });
    });
    this.route('insurances', function () {
      this.route('policies', function () {
        this.route('show', { path: '/:id' });
      });
      this.route('quotes');
      this.route('new-policy');
    });
    this.route('chargebacks', function () {
      this.route('show', { path: '/:id' });
    });
    this.route('chargebacks-alerts', function () {
      this.route('show', { path: '/:id' });
    });
    this.route('check-transactions', function () {
      this.route('show', { path: '/:id' });
    });
    this.route('3d-secure', function () {
      this.route('show', { path: '/:id' });
    });
    this.route('kount', function () {
      this.route('show', { path: '/:id' });
    });
    this.route('confirmation', function () {
      this.route('show', { path: '/:id' });
    });
    this.route('subscriptions', function () {
      this.route('show', { path: '/:id' });
    });
    this.route('wallet-transactions', function () {
      this.route('show', { path: '/:id' });
    });
    this.route('vcards', function () {
      this.route('virtual-credit-cards', function () {
        this.route('new');

        this.route('list',  { path: '/' }, function () {
          this.route('show', { path: '/:id' });
        });
      });
      this.route('transactions', function () {
        this.route('show', { path: '/:id' });

        this.route('list',  { path: '/' }, function () {
          this.route('show', { path: '/:id' });
        });
      });
    });

    this.route('transactions', function () {
      this.route('show', { path: '/:id' });
    });
  });

  this.route('admin', function () {
    this.route('dashboard');
    this.route('merchants');
    this.route('transactions', function () {
      this.route('show', { path: '/:id' });
    });
    this.route('merchant', { path: '/merchants/:id' }, function () {
      this.route('processors', function () {
        this.route('show', { path: '/:processor_id' });
        this.route('new');
      });
      this.route('providers', function () {
        this.route('show', { path: '/:provider_id' });
        this.route('new');
      });
    });
    this.route('merchant.users', { path: '/merchants/:merchant_id/users' });
    this.route('batches');
    this.route('insurances', function () {
      this.route('policies', function () {
        this.route('show', { path: '/:id' });
      });
      this.route('quotes');
    });
    this.route('chargebacks', function () {
      this.route('show', { path: '/:id' });
    });
    this.route('chargebacks-alerts', function () {
      this.route('show', { path: '/:id' });
    });
    this.route('check-transactions', function () {
      this.route('show', { path: '/:id' });
    });
    this.route('3d-secure', function () {
      this.route('show', { path: '/:id' });
    });
    this.route('kount', function () {
      this.route('show', { path: '/:id' });
    });
    this.route('confirmation', function () {
      this.route('show', { path: '/:id' });
    });
    this.route('admins');
    this.route('subscriptions', function () {
      this.route('show', { path: '/:id' });
    });
    this.route('wallet-transactions', function () {
      this.route('show', { path: '/:id' });
    });
    this.route('vcards', function () {
      this.route('virtual-credit-cards', function () {

        this.route('list',  { path: '/' }, function () {
          this.route('show', { path: '/:id' });
        });
      });
    });
  });
  this.route('not-found', { path: '/*path' });
  this.route('forgot-password');
  this.route('reset-password');
  this.route('expired-password');
});

export default Router;

my ember-cli-build


'use strict';

const EmberApp = require('ember-cli/lib/broccoli/ember-app');
const Funnel = require('broccoli-funnel');

module.exports = function (defaults) {
  let app = new EmberApp(defaults, {
    'ember-cli-babel': {
      includePolyfill: true,
    },
    sassOptions: {
      includePaths: [
        'node_modules/'
      ]
    },
    ace: {
      themes: ['ambiance', 'chaos', 'monokai'],
      modes: ['html'],
      workers: ['html'],
      exts: ['language_tools'],
    },

    flatpickr: {
      theme: 'airbnb'
    },
    sourcemaps: {
      enabled: true,
      extensions: ['js']
    }
  });

  // Use `app.import` to add additional libraries to the generated
  // output files.
  //
  // If you need to use different assets in different
  // environments, specify an object as the first parameter. That
  // object's keys should be the environment name and the values
  // should be the asset to use in that environment.
  //
  // If the library that you are including contains AMD or ES6
  // modules that you would like to import into your application
  // please specify an object with the list of modules as keys
  // along with the exports of each module as its value.

  app.import('node_modules/country-region-selector/dist/crs.min.js');
  app.import('node_modules/awesomplete/awesomplete.css');
  app.import('node_modules/flag-icon-css/css/flag-icon.css');

  // TODO: this libary was built with mindset of global scope (i.e: list.scss, forms.scss)
  // which has the disadvantage of stupidly overwriting our work instead of choosing where and when to overwrite

  let flagsAssets = new Funnel('node_modules/flag-icon-css/flags', {
    srcDir: '/',
    include: ['**/*.svg', '**/*.png'],
    destDir: 'flags'
  });

  const Webpack = require('@embroider/webpack').Webpack;
  // return require('@embroider/compat').compatBuild(app, Webpack, {
  //   extraPublicTrees: [paycertifyAssets, flagsAssets]
  // });

  const { V1Addon } = require('@embroider/compat');
  return require('@embroider/compat').compatBuild(app, Webpack, {
    extraPublicTrees: [flagsAssets],
    compatAdapters: new Map([[
      'ember-i18n', class extends V1Addon {
        get pacakgeJSON() {
          let pkg = super.packageJSON;
          let meta = pkg['ember-addon'];
          meta['implicit-modules'] = meta['implicit-modules'].filter(m => ![
            './legacy/helper',
            './legacy/initializer',
            './legacy/stream',
          ].includes(m));
          return pkg;
        }
        get v2Tree() {
          return new Funnel(super.v2Tree, {
            exclude: [
              '_app_/initializers/ember-i18n-legacy-helper.js',
            ]
          });
        }
      }
    ]]),

    // Each of these entries can be a string or RegExp. Any route names that
    // match will get split out of the initial app payload. When you split at a
    // route, that route and all its child routes will be lazily loaded on
    // demand.
    splitAtRoutes: ['merchant.dashboard', 'merchant.virtual-terminal', 'merchant.batches', 'merchant.users', 'merchant.settings', 'merchant.insurances', 'merchant.vcards']
  });

  // return app.toTree([paycertifyAssets, flagsAssets]);
};
ef4 commented 5 years ago

You need to turn on staticAddonTrees, staticComponents, and staticHelpers to get the full benefit of splitAtRoutes.

On Sat, Apr 20, 2019 at 6:36 PM Michael Villander notifications@github.com wrote:

I'm using ember-cli 3.9.0 and embroider 3.4.0

My app have 2 namespaces admin and merchant and index route for login, the lazy loading don't working when I split by ['admin', 'merchant'] neither with ['merchant.child-routes]. Nothing is lazy loading when I did this configuration. take a look please

my router.js

import EmberRouter from '@embroider/router';import { inject as service } from '@ember/service';import config from './config/environment'; const Router = EmberRouter.extend({ location: config.locationType, rootURL: config.rootURL, metrics: service(), router: service(),

init() { this._super(...arguments);

this.on('routeDidChange', () => {
  const page = this.router.currentURL;
  const title = this.router.currentRouteName || 'unknown';

  this.metrics.trackPage({ page, title });
});

} }); Router.map(function () { this.route('index', { path: '/' });

this.route('merchant', function () { this.route('dashboard'); this.route('virtual-terminal'); this.route('batches'); this.route('users'); this.route('settings', function () { this.route('processors', function () { this.route('show', { path: '/:processor_id' }); }); }); this.route('insurances', function () { this.route('policies', function () { this.route('show', { path: '/:id' }); }); this.route('quotes'); this.route('new-policy'); }); this.route('chargebacks', function () { this.route('show', { path: '/:id' }); }); this.route('chargebacks-alerts', function () { this.route('show', { path: '/:id' }); }); this.route('check-transactions', function () { this.route('show', { path: '/:id' }); }); this.route('3d-secure', function () { this.route('show', { path: '/:id' }); }); this.route('kount', function () { this.route('show', { path: '/:id' }); }); this.route('confirmation', function () { this.route('show', { path: '/:id' }); }); this.route('subscriptions', function () { this.route('show', { path: '/:id' }); }); this.route('wallet-transactions', function () { this.route('show', { path: '/:id' }); }); this.route('vcards', function () { this.route('virtual-credit-cards', function () { this.route('new');

    this.route('list',  { path: '/' }, function () {
      this.route('show', { path: '/:id' });
    });
  });
  this.route('transactions', function () {
    this.route('show', { path: '/:id' });

    this.route('list',  { path: '/' }, function () {
      this.route('show', { path: '/:id' });
    });
  });
});

this.route('transactions', function () {
  this.route('show', { path: '/:id' });
});

});

this.route('admin', function () { this.route('dashboard'); this.route('merchants'); this.route('transactions', function () { this.route('show', { path: '/:id' }); }); this.route('merchant', { path: '/merchants/:id' }, function () { this.route('processors', function () { this.route('show', { path: '/:processor_id' }); this.route('new'); }); this.route('providers', function () { this.route('show', { path: '/:provider_id' }); this.route('new'); }); }); this.route('merchant.users', { path: '/merchants/:merchant_id/users' }); this.route('batches'); this.route('insurances', function () { this.route('policies', function () { this.route('show', { path: '/:id' }); }); this.route('quotes'); }); this.route('chargebacks', function () { this.route('show', { path: '/:id' }); }); this.route('chargebacks-alerts', function () { this.route('show', { path: '/:id' }); }); this.route('check-transactions', function () { this.route('show', { path: '/:id' }); }); this.route('3d-secure', function () { this.route('show', { path: '/:id' }); }); this.route('kount', function () { this.route('show', { path: '/:id' }); }); this.route('confirmation', function () { this.route('show', { path: '/:id' }); }); this.route('admins'); this.route('subscriptions', function () { this.route('show', { path: '/:id' }); }); this.route('wallet-transactions', function () { this.route('show', { path: '/:id' }); }); this.route('vcards', function () { this.route('virtual-credit-cards', function () {

    this.route('list',  { path: '/' }, function () {
      this.route('show', { path: '/:id' });
    });
  });
});

}); this.route('not-found', { path: '/*path' }); this.route('forgot-password'); this.route('reset-password'); this.route('expired-password'); }); export default Router;

my ember-cli-build

'use strict'; const EmberApp = require('ember-cli/lib/broccoli/ember-app');const Funnel = require('broccoli-funnel');

module.exports = function (defaults) { let app = new EmberApp(defaults, { 'ember-cli-babel': { includePolyfill: true, }, sassOptions: { includePaths: [ 'node_modules/' ] }, ace: { themes: ['ambiance', 'chaos', 'monokai'], modes: ['html'], workers: ['html'], exts: ['language_tools'], },

flatpickr: {
  theme: 'airbnb'
},
sourcemaps: {
  enabled: true,
  extensions: ['js']
}

});

// Use app.import to add additional libraries to the generated // output files. // // If you need to use different assets in different // environments, specify an object as the first parameter. That // object's keys should be the environment name and the values // should be the asset to use in that environment. // // If the library that you are including contains AMD or ES6 // modules that you would like to import into your application // please specify an object with the list of modules as keys // along with the exports of each module as its value.

app.import('node_modules/country-region-selector/dist/crs.min.js'); app.import('node_modules/awesomplete/awesomplete.css'); app.import('node_modules/flag-icon-css/css/flag-icon.css');

// TODO: this libary was built with mindset of global scope (i.e: list.scss, forms.scss) // which has the disadvantage of stupidly overwriting our work instead of choosing where and when to overwrite let paycertifyAssets = new Funnel('node_modules/@paycertify/assets', { srcDir: '/', include: ['*/.svg', '*/.png'], destDir: '/assets/' });

let flagsAssets = new Funnel('node_modules/flag-icon-css/flags', { srcDir: '/', include: ['*/.svg', '*/.png'], destDir: 'flags' });

const Webpack = require('@embroider/webpack').Webpack; // return require('@embroider/compat').compatBuild(app, Webpack, { // extraPublicTrees: [paycertifyAssets, flagsAssets] // });

const { V1Addon } = require('@embroider/compat'); return require('@embroider/compat').compatBuild(app, Webpack, { extraPublicTrees: [paycertifyAssets, flagsAssets], compatAdapters: new Map([[ 'ember-i18n', class extends V1Addon { get pacakgeJSON() { let pkg = super.packageJSON; let meta = pkg['ember-addon']; meta['implicit-modules'] = meta['implicit-modules'].filter(m => ![ './legacy/helper', './legacy/initializer', './legacy/stream', ].includes(m)); return pkg; } get v2Tree() { return new Funnel(super.v2Tree, { exclude: [ 'app/initializers/ember-i18n-legacy-helper.js', ] }); } } ]]),

// Each of these entries can be a string or RegExp. Any route names that
// match will get split out of the initial app payload. When you split at a
// route, that route and all its child routes will be lazily loaded on
// demand.
splitAtRoutes: ['merchant.dashboard', 'merchant.virtual-terminal', 'merchant.batches', 'merchant.users', 'merchant.settings', 'merchant.insurances', 'merchant.vcards']

});

// return app.toTree([paycertifyAssets, flagsAssets]); };

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/embroider-build/embroider/issues/143, or mute the thread https://github.com/notifications/unsubscribe-auth/AACN6MXOOCDG66IS5UX4TJLPROLGPANCNFSM4HHKRJ3Q .

villander commented 5 years ago

using staticAddonTrees I have this error on my browser. What I need to exclude this error from ember-i18n?

image

villander commented 5 years ago

without lazy loading my first load has bundle of 1.9 MB

with most of routes I have my first load with bundle of 1.8 MB

I can't see any improvements with route code splitting. Let me know if I'm doing some thing wrong buddy.

ember-cli-build.js

'use strict';

const EmberApp = require('ember-cli/lib/broccoli/ember-app');
const Funnel = require('broccoli-funnel');

const LAZY_ROUTES = [
  // MERCHANT ROUTES
  'merchant.dashboard',
  'merchant.virtual-terminal',
  'merchant.batches',
  'merchant.users',
  'merchant.settings',
  'merchant.insurances',
  'merchant.vcards',
  'merchant.chargebacks',
  'merchant.chargebacks-alerts',
  'merchant.check-transactions',
  'merchant.3d-secure',
  'merchant.kount',
  'merchant.confirmation',
  'merchant.subscriptions',
  'merchant.wallet-transactions',
  'merchant.transactions',
  // ADMIN ROUTES
  'admin.dashboard',
  'admin.merchants',
  'admin.merchant',
  'admin.batches',
  'admin.admins',
  'admin.insurances',
  'admin.vcards',
  'admin.chargebacks',
  'admin.chargebacks-alerts',
  'admin.check-transactions',
  'admin.3d-secure',
  'admin.kount',
  'admin.confirmation',
  'admin.subscriptions',
  'admin.wallet-transactions',
  'admin.transactions'
];

module.exports = function (defaults) {
  let app = new EmberApp(defaults, {
    'ember-cli-babel': {
      includePolyfill: true,
    },
    sassOptions: {
      includePaths: [
        'node_modules/'
      ]
    },
    ace: {
      themes: ['ambiance', 'chaos', 'monokai'],
      modes: ['html'],
      workers: ['html'],
      exts: ['language_tools'],
    },

    flatpickr: {
      theme: 'airbnb'
    },
    sourcemaps: {
      enabled: true,
      extensions: ['js']
    }
  });

  // Use `app.import` to add additional libraries to the generated
  // output files.
  //
  // If you need to use different assets in different
  // environments, specify an object as the first parameter. That
  // object's keys should be the environment name and the values
  // should be the asset to use in that environment.
  //
  // If the library that you are including contains AMD or ES6
  // modules that you would like to import into your application
  // please specify an object with the list of modules as keys
  // along with the exports of each module as its value.

  app.import('node_modules/country-region-selector/dist/crs.min.js');
  app.import('node_modules/awesomplete/awesomplete.css');
  app.import('node_modules/flag-icon-css/css/flag-icon.css');

  // TODO: this libary was built with mindset of global scope (i.e: list.scss, forms.scss)
  // which has the disadvantage of stupidly overwriting our work instead of choosing where and when to overwrite
  let paycertifyAssets = new Funnel('node_modules/@paycertify/assets', {
    srcDir: '/',
    include: ['**/*.svg', '**/*.png'],
    destDir: '/assets/'
  });

  let flagsAssets = new Funnel('node_modules/flag-icon-css/flags', {
    srcDir: '/',
    include: ['**/*.svg', '**/*.png'],
    destDir: 'flags'
  });

  if (process.env.CLASSIC) {
    return app.toTree();
  }

  const Webpack = require('@embroider/webpack').Webpack;
  // return require('@embroider/compat').compatBuild(app, Webpack, {
  //   extraPublicTrees: [paycertifyAssets, flagsAssets]
  // });

  const { V1Addon } = require('@embroider/compat');
  return require('@embroider/compat').compatBuild(app, Webpack, {
    extraPublicTrees: [paycertifyAssets, flagsAssets],
    compatAdapters: new Map([[
      'ember-i18n', class extends V1Addon {
        get pacakgeJSON() {
          let pkg = super.packageJSON;
          let meta = pkg['ember-addon'];
          meta['implicit-modules'] = meta['implicit-modules'].filter(m => ![
            './legacy/helper',
            './legacy/initializer',
            './legacy/stream',
          ].includes(m));
          return pkg;
        }
        get v2Tree() {
          return new Funnel(super.v2Tree, {
            exclude: [
              '_app_/initializers/ember-i18n-legacy-helper.js',
            ]
          });
        }
      }
    ]]),

    // The default settings give maximum compatability, and they work fine here,
    // but we are also going to enable some optimizations.

    // These two flags are used when building classic addons to v2 format. They
    // cause any unused Javascript modules these addon trees to not be included
    // in the build. Most addons are fine with this, but some are not, so this
    // is an opt-in optmization.
    // staticAddonTestSupportTrees: true,
    // staticAddonTrees: true,

    // Resolve all helpers (in app and all addons) at build time. Unused helpers
    // will not be included. This is usually a safe optimization, as there are
    // not common ways of dynamically referring to helpers in templates.
    staticHelpers: true,

    // Resolve all components (in app and all addons) at build time. Unused
    // components will not be included. This is generally not a safe
    // optimization unless you also deal with any dynamic component warnings by
    // providing packageRules.
    staticComponents: true,

    // Each of these entries can be a string or RegExp. Any route names that
    // match will get split out of the initial app payload. When you split at a
    // route, that route and all its child routes will be lazily loaded on
    // demand.
    splitAtRoutes: LAZY_ROUTES
  });

  // return app.toTree([paycertifyAssets, flagsAssets]);
};
ef4 commented 5 years ago

We can't work magic, if your app is written such that a large number of dependencies are always used immediately we can't split them out. And most Ember apps will have a lot of things like that, mostly just because up until now there was no incentive to make things lazier.

For example, the libraries you are app.import()ing are always going to load eagerly, because there's no way to know which routes need them. If you switch those to import via ember-auto-import, and if they're only imported by certain routes, they can get out of the initial page load.

(Embroider doesn't actually need ember-auto-import to make direct imports from node_modules work, but we use its presence as an opt-in for that behavior, which allows us to keep all the app code we support working exactly the same under embroider as under regular ember-cli.)

The best way to get your initial bundle size smaller is to examine in detail what's taking up the bytes. There are two things to look at. The first is what goes into all the chunks that webpack is generating for us. So add webpack-bundle-analyzer to you app and configure it:

const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;

require('@embroider/compat').compatBuild(app, Webpack, {
    packagerOptions: {
      webpackConfig: {
         plugins: [new BundleAnalyzerPlugin()]
      }
    }
}

When you run ember s you will get a report opened automatically in your browser.

The second thing to look at is what things are going into the legacy vendor.js file. It doesn't pass through webpack so webpack-bundle-analyzer can't tell you about it. Instead, set the environment variable EMBROIDER_CONCAT_STATS=true to get a printout in your terminal after the build.

villander commented 5 years ago

sure @ef4, I'll to do all the things that you tell me, and let you know what happened.

I thinks that's a good idea make lazy loading of modules with ember-auto-import as well.

// app/index/route.js
beforeModel() {
  ...
  return import('libphonenumber').then((module) => {
    // do sth with the loaded module
  });
},

We can't work magic, if your app is written such that a large number of dependencies are always used immediately we can't split them out. And most Ember apps will have a lot of things like that, mostly just because up until now there was no incentive to make things lazier.

This shows us how much code splitting if used correctly, you can have a big impact on loading time, if used improperly can bring complexity without good results. And again the separation of concerns becomes relevant here, where the architecture will always be above code splitting, three shaking, and so on. These features come to help, but they don't do the magic alone. Having the Embroider working with Ember engines will help us a lot to isolate responsibilities, concepts and have a new philosophy of building complex apps with Ember.js where we will begin to worry about details that were previously ignored

villander commented 5 years ago

@ef4 the part inside the red rectangle are the bundles of each route, which shows when the split of routes was insignificant in this specific case.

this image is after run ember build --prod.

Captura de Tela 2019-04-20 às 23 31 55

Some things will be needed:

1) Lazy loading of node modules

2) Remove some configurations/constants used in "app/utils" (us-map.js for example) from the front end and move to the backend

3) Wait for embroider support code splitting of CSS by components/routes

4) Wait for Ember Data to work with code splitting/tree-shaking internally.

ef4 commented 5 years ago

1) Lazy loading of node modules

This already works. But you need to use ember-auto-import and import directly from node_modules.

I'm guessing chunk.b74a6... is one of your entrypoint chunks? (Meaning it is in a script tag in dist/index.html.) If so, why does it have highcharts.js? Maybe you're using ember-highcharts? That would eagerly load it unnecessarily. That's an example of the kind of thing we need to clean up to get smaller payloads.

Remove some configurations/constants used in "app/utils" (us-map.js for example) from the front end and move to the backend

They can stay in the frontend as long as they're imported where they're actually used. For example, if us-map.js is a file that's only needed by a particularly component, make sure it's imported directly by that component, and then it will lazily load when the component does.

villander commented 5 years ago

Yup chunk.b74a6... is the first load ( in dist/index.html). I'm using highcharts directly by npm. Even using charts in many screens on my app I can to do lazy loading him

void-mAlex commented 1 year ago

@villander doing some pruning of issues so closing this issue as the original subject seems to have been addressed (split at routes not working) please feel free to open a new issue about any unresolved topics

ahemed-haneen commented 1 year ago

We can't work magic, if your app is written such that a large number of dependencies are always used immediately we can't split them out. And most Ember apps will have a lot of things like that, mostly just because up until now there was no incentive to make things lazier.

For example, the libraries you are app.import()ing are always going to load eagerly, because there's no way to know which routes need them. If you switch those to import via ember-auto-import, and if they're only imported by certain routes, they can get out of the initial page load.

(Embroider doesn't actually need ember-auto-import to make direct imports from node_modules work, but we use its presence as an opt-in for that behavior, which allows us to keep all the app code we support working exactly the same under embroider as under regular ember-cli.)

The best way to get your initial bundle size smaller is to examine in detail what's taking up the bytes. There are two things to look at. The first is what goes into all the chunks that webpack is generating for us. So add webpack-bundle-analyzer to you app and configure it:

const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;

require('@embroider/compat').compatBuild(app, Webpack, {
    packagerOptions: {
      webpackConfig: {
         plugins: [new BundleAnalyzerPlugin()]
      }
    }
}

When you run ember s you will get a report opened automatically in your browser.

The second thing to look at is what things are going into the legacy vendor.js file. It doesn't pass through webpack so webpack-bundle-analyzer can't tell you about it. Instead, set the environment variable EMBROIDER_CONCAT_STATS=true to get a printout in your terminal after the build.

i'm not sure if this method works now. report is not getting opened automatically. any ideas why?

ember Version: 4.12 webpack-bundle-analyzer version: 4.8.0

void-mAlex commented 1 year ago

@ahemed-haneen have you used the openAnalyzer option for the plugin? have you seen the documentation around the analyzer found at https://github.com/embroider-build/embroider/blob/main/docs/analyzing.md

ahemed-haneen commented 1 year ago

@ahemed-haneen have you used the openAnalyzer option for the plugin? have you seen the documentation around the analyzer found at https://github.com/embroider-build/embroider/blob/main/docs/analyzing.md

openAnalyzer i did try but the instance that i'm running on is a vs codeserver and that was why the tab wasn't auto opening as there is no chrome in there. the issue is solved.