angular / angular-cli

CLI tool for Angular
https://cli.angular.io
MIT License
26.76k stars 11.98k forks source link

Lazy loading is not working together with 'import *' syntax #2496

Closed areijngoudt closed 7 years ago

areijngoudt commented 8 years ago

Please provide us with the following information:

OS?

Mac OSX El Capitan

Versions.

angular-cli: 1.0.0-beta.16 node: 5.7.1 os: darwin x64

Repro steps.

Was this an app that wasn't created using the CLI? What change did you do on your code? etc. The app was not created using the CLI. When upgrading to Angular 2 I choose to use the CLI as serving and building tool

I have this route in my app.routing.ts:

const ROUTES: Routes = [
    { path: '', redirectTo: 'analyse', pathMatch: 'full' },
    { path: 'annotate', component: AnnotateComponent },
    { path: 'fraud', component: FraudComponent },
    { path: 'info',  loadChildren: 'app/info/info.module#InfoModule'  },
];```

the InfoModule should be loaded lazily when navigating to it's path. But even in de --prod build there's no seperate bundle. The InfoModule is still part of the main.bundle.js.

Note that I'm still importing the InfoModule in the app.module.ts otherwise the info route does not work at all.
aaronleestic commented 7 years ago

@filipesilva thanks for all your hardwork on improving the cli. Do you or anyone know whether this bug is on the angular-cli side or on the angular framework side? If the latter, I might look to open a bug on their github issues instead.

vthinkxie commented 7 years ago

Lazy loading is still not work [angular-cli beta.24]

serhiisol commented 7 years ago

super urgent ticket :)

achimha commented 7 years ago

I solved it by getting rid of everything importing moment.js. Could not find any other way.

deebloo commented 7 years ago

It seems that importing any lib via * as thing. Will cause bundles not to be created

tomson7777 commented 7 years ago

@deebloo but you mean using in lazy modules only? or wherever you use "import " in app, it will crush creating bundles?

i am trying to add lazy load, i have no errors and Augury dev tool shows that i have lazy route. But when i enter a lazy module, then in Network in dev tools, i don't see any bundle being downloaded.

It's normal? i see only main.bundle.js

deebloo commented 7 years ago

Whenever you use import * (at least in my experience)

tomson7777 commented 7 years ago

@deebloo but only in our app, or in Node_modules too? if in Node_modules too, then it's impossible to use lazy load...

deebloo commented 7 years ago

@tomasznastaly I cannot speak with 100% certainty but that is what it seems like

tomson7777 commented 7 years ago

@deebloo

I removed * from my moment usages. No errors, Augury shows the route is lazy, i can enter these module. But still the separated bundle is not created, only main.bundle.js on app loading: /

i use Angular 2.4.1 and Angular-CLI-1.0.0.25-5 you achieved working lazy routes?

achimha commented 7 years ago

Look for 3rd party modules that perform such imports. Best is to strip them out until you get the lazy route bundles and then isolate the offending one.

To use moment.js, add it as a script to your angular-cli config and do

declare const moment: any;

in your components. This works around the problem.

tomson7777 commented 7 years ago

@achimha How to strip them out? i don't want to interfere into node_modules file. I have +100 usages of "import *" in node modules.

I added moment to scripts and declare to typings

achimha commented 7 years ago

If you're not importing the "wrong" way, then it must be one of your third party modules. The only way to find it is by commenting code out until bundles get generated. I am not aware of an easier way. It's a major PITA and I do not understand the root of the problem now whether it can/will every be fixed.

deebloo commented 7 years ago

I believe it is a webpack issue. @TheLarkInn is the bundles not being created when using * a cli problem or a webpack problem?

born2net commented 7 years ago

problem

I am using ng-cli with lazy loading:

...
{path: 'studioweb', pathMatch: 'full', redirectTo: '/App1/Dashboard'},  // IE/FF compatibility
    {
        path: 'App1', component: Appwrap,
        children: [
            {path: '', component: Appwrap, canActivate: [AuthService]},
            {path: 'Dashboard', component: Dashboard, data: {title: 'Dashboard'}, canActivate: [AuthService]},
            {path: 'Campaigns', loadChildren: '../app/campaigns/index#CampaignsLazyModule', data: {title: 'Campaigns'}, canActivate: [AuthService]},
            {path: 'Fasterq', loadChildren: '../app/fasterq/index#FasterqLazyModule', data: {title: 'Fasterq'}, canActivate: [AuthService]},
...

I generate the build dist with:

ng build --target=production --base-href ./

and I don't see any chunks. and while all "seems" to work, I am not sure lazy loading is working, almost as if Webpack bundles it all in?!?!?!

How can I confirm if lazy loading is working? Why are chunks not created? bug?

OS?

angular-cli: 1.0.0-beta.25.5 node: 6.5.0 os: win32 x64 @angular/common: 2.4.4 @angular/compiler: 2.4.4 @angular/core: 2.4.4 @angular/forms: 2.4.4 @angular/http: 2.4.4 @angular/language-service: 2.4.4 @angular/platform-browser: 2.4.4 @angular/platform-browser-dynamic: 2.4.4 @angular/router: 3.2.1 @angular/compiler-cli: 2.4.4

snap:

nochunks

Angular 2 Kitchen sink: http://ng2.javascriptninja.io and source@ https://github.com/born2net/Angular-kitchen-sink Regards,

Sean

achimha commented 7 years ago

It doesn't matter if the offending import is in a lazy bundle, the main bundle or a 3rd party module. As soon as it appears somewhere, bundling is broken.

born2net commented 7 years ago

yes I do have the following all over my code:

import * as Immutable from "immutable";
import * as _ from "lodash";
import * as moment_ from "moment";

Angular 2 Kitchen sink: http://ng2.javascriptninja.io and source@ https://github.com/born2net/Angular-kitchen-sink Regards,

Sean

rodneyjoyce commented 7 years ago

I can confirm this behaviour too in CLI 25.5 - lazy loading and chunking work fine until I add any of these in a Feature module and then chunking stops chunking so to speak... import { Moment } from 'moment'; import { MomentModule } from 'angular2-moment';

rodneyjoyce commented 7 years ago

FYI, for those who are using Angular2-moment and moment, I have come to the conclusion that while I can get moment to work (with Locales, using the workarounds above) - it is not possible to use with angular2-moment pipes at this stage: https://github.com/urish/angular2-moment/issues/114

intellix commented 7 years ago

Not a fix for import * as breaking Lazy loading, but I have a workaround for those using angular2-moment.

I was previously using angular2-moment for the DateFormatPipe (for cross-browser formatting). That adds 50kb of code for one pipe and currently breaks Lazy-loading: screenshot 2017-01-21 17 23 07

Solution: switch to date-fns instead, it's modern, modular, smaller and works with lazy-loading:

Site: https://date-fns.org/ Project: https://github.com/date-fns/date-fns Example pipe for formatting a date:

import { Pipe, PipeTransform } from '@angular/core';
import { format } from 'date-fns';

@Pipe({
  name: 'fnsDateFormat'
})
export class DateFormatPipe implements PipeTransform {
  transform(value: Date | string | number, ...args: any[]): any {
    if (!value) return '';
    return format(value, args[0]);
  }
}

And from switching, now it uses 27.8kb and I have lazy-loading again: screenshot 2017-01-21 17 39 04

rodneyjoyce commented 7 years ago

Yes, I did the exact same thing.

filipesilva commented 7 years ago

https://github.com/angular/angular-cli/pull/4153 should fix this problem.

jwuliger commented 7 years ago

@born2net Are you using the current master directly with something like npm link angular-cli or traditionally installing/using the CLI? Thanks!

born2net commented 7 years ago

ha sorry I installed via npm, I figured it was latest as I saw .26, I guess its its not published yet? if so I will wait, np

jwuliger commented 7 years ago

@born2net You can do what I have been doing to use the latest changes in my project.

Check out: https://github.com/angular/angular-cli#development-hints-for-hacking-on-angular-cli

I am setting up to test this new change myself.

born2net commented 7 years ago

tried it but I could not get the symlink to work. prob cause I am on windows, will wait for npm relase to check, tx!

rodneyjoyce commented 7 years ago

FYI, here is another TimeAgo filter if you are looking to swap Moment for DateFNS and need a pipe for the template (including localisation). This replaces the angular2-moment pipes which are not currently compatible with chunking Usage: <div>Date with TimeAgo DateFNS Pipe : {{this.exampleDateTime | timeAgo : true }}</div>

import { Pipe, PipeTransform } from '@angular/core';
import * as distanceInWordsToNow from 'date-fns/distance_in_words_to_now'
import * as esLocale from 'date-fns/locale/es/index.js'

@Pipe({
    name: 'timeAgo'
})
export class TimeAgoPipe implements PipeTransform {
    transform(value: Date | string | number, ...args: any[]): any {
        if (!value) return '';
        return distanceInWordsToNow(value, { addSuffix: args[0], locale: esLocale });
    }
}
born2net commented 7 years ago

seems like .28 fixed chunks, but AOT broken so can't 100% test yet.

born2net commented 7 years ago

looks like build .28-3 still does not generate any chunks for lazy loading so .28 worked with chunks (had diff issues) and 28-3 looks good (no crashes) but no chunks just want to make sure devs are aware of this regards

Sean

JiriBalcar commented 7 years ago

@born2net for me it does and I have lot of import * as moment in my code. Try to update @ngtools/webpack to latest version.

born2net commented 7 years ago

ha ok... let me try

artaommahe commented 7 years ago

@filipesilva i'm trying to migrate to @ngtools/webpack usage (without ng-cli) instead of ATL and with #4153 changes (1.2.7 lib vesrion) there is no lazy routes chunks on build. As i investigated this check never passes https://github.com/angular/angular-cli/blob/29b134d7018c7d4e2eed74715b30b28e56fdcd49/packages/%40ngtools/webpack/src/plugin.ts#L247 Does not see any @angular/core/src/linker resource value here. If i comment it out, bundles created but with a lot of overhead as i understand (included all imported modules despite they are included in main bundle). Tried 1.2.4/3 - does not work too, no chunks at all. Cleared all export default/import * from code.

everything i added to webpack config related to @ngtools/webpack

        {
          test: /\.ts$/,
          use: [
            '@ngtools/webpack',
          ]
        },
...
    plugins: [
      new AotPlugin({
        tsConfigPath: 'tsconfig.json',
        entryModule: path.resolve(CONFIG.APP_PATH, 'app-module', 'module#AppModule'),
        skipCodeGeneration: true, // for dev mode
      }),

@angular/compiler-cli version 2.4.6

Update: added new issue with this bug https://github.com/angular/angular-cli/issues/4431

kossov commented 7 years ago

try this: app.module

import { QuickStatsModule } from './quick-stats/quick-stats.module';

const appRoutes: Routes = [
        { path: 'quick-stats', loadChildren: () => QuickStatsModule },
];

imports: [
    BrowserModule,
    HttpModule,
    RouterModule.forRoot(appRoutes)
]

quick-stats.module

const ROUTES = [
    { path: '', component: QuickStatsComponent },
];

@NgModule({
    imports: [
        CommonModule,
        RouterModule.forChild(ROUTES)
    ],
    declarations: [
            QuickStatsComponent,
        ],
        exports: [QuickStatsComponent]
})

This worked out for me. Source

kuncevic commented 7 years ago

avoid wildcard imports e.g.:

import * as moment from 'moment' instead you need to include import into angular-cli.json e.g.:

"scripts": [ "../node_modules/moment/moment.js" ] and then add typing for moment e.g.:

declare var moment: any;

How would you do lazy loading in such case, say you have lazy loaded component that rely on moment, you do load moment with a scripts like above + "lazy": true https://github.com/angular/angular-cli/wiki/stories-global-scripts so you got moment.bundle.js produced. Then how would moment.bundle.js figure out when to get loaded?

I tried to do something like that with powerbi-client and have an issue https://github.com/angular/angular-cli/issues/6018

angular-automatic-lock-bot[bot] commented 5 years ago

This issue has been automatically locked due to inactivity. Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.