-
Notifications
You must be signed in to change notification settings - Fork 1.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Lazy loading support with Aot #1714
Conversation
…se the dependencies, change html to call init
…side of lazy modules
@dfaglioni I currently have the master branch. With your changes does that mean when i do a serve.prod my lazy load child routes will work? I had to take them out previously because they only worked with npm run start and not npm run serve.prod. So I'm guessing they now work in the bundle? and will this improve the speed of my app? |
That's right, previously they only worked in dev. Now in my branch, I changed to generate a bundle for each lazy module (only with the dependencies that doesn't exists in main bundle). The lazy task considers folders with prefix plus and builds a bundle. Yet, I have one problem, it have to work with windows! |
Hi
Thank you for doing this work.
It will really help me. My apps very slow on initial load.
I have Windows :(
Can you let me know when I can try it. I can try it in Windows on the weekend.
Mark
On 13 Dec 2016, at 20:39, Mark <notifications@github.com<mailto:notifications@github.com>> wrote:
@dfaglioni<https://github.com/dfaglioni> I currently have the master branch. With your changes does that mean when i do a serve.prod my lazy load child routes will work? I had to take them out previously because they only worked with npm run start and not npm run serve.prod. So I'm guessing they now work in the bundle? and will this improve the speed of my app?
-
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub<#1714 (comment)>, or mute the thread<https://github.com/notifications/unsubscribe-auth/AEbHhodHrzUMPATyXkOJn_BO0eFslHGFks5rHwJfgaJpZM4LL-Fr>.
|
@dfaglioni thanks for the effort! I'd suggest to keep it in a separate branch which we keep in sync with master because a lot of developers will experience problems following the convention that you've introduced. Also, do you think we can change the prefix from I also did some work regarding bundling for an internal project, I can share my progress here later today. |
Here's my import { appendFileSync } from 'fs';
import { join } from 'path';
import * as utils from 'gulp-util';
import * as Builder from 'systemjs-builder';
import Config from '../../config';
const BUNDLER_OPTIONS = {
format: 'cjs',
minify: true,
mangle: true
};
interface Bundle {
path: string;
module: string;
}
class BundleNode {
children: BundleNode[] = [];
constructor(public path: string) {}
isParent(node: BundleNode) {
return node.path.startsWith(this.path);
}
}
// Prefix tree for proper bundling order
class BundleTree {
roots: BundleNode[] = [];
static buildTree(paths: string[]) {
const tree = new BundleTree();
paths.forEach((p: string) => {
if (p === '/') {
throw new Error('Invalid "/" path');
}
});
paths.sort((a: string, b: string) => a.split('/').length - b.split('/').length)
.forEach(p => tree.addNode(new BundleNode(p)));
return tree;
}
addNode(node: BundleNode) {
if (!this.roots.length) {
this.roots.push(node);
} else {
const added = this.roots.some((root: BundleNode) => this.addNodeHelper(node, root));
if (!added) {
this.roots.push(node);
}
}
}
private addNodeHelper(node: BundleNode, context: BundleNode): boolean {
const added: boolean = context.children.reduce((a: boolean, c: BundleNode) => {
return a || this.addNodeHelper(node, c);
}, false);
if (!added && context.isParent(node)) {
context.children.push(node);
return true;
}
return added;
}
}
const normalizeConfig = (bundles: any[]) => {
bundles = bundles.map((b: any) => b.path);
return bundles.map((b: string) => {
if (!b.endsWith('.js')) {
b += '.module.ngfactory.js';
}
return b;
});
};
const config = JSON.parse(JSON.stringify(Config.SYSTEM_BUILDER_CONFIG));
delete config.paths;
const addExtensions = `
$traceurRuntime = {
typeof: function (a) {
return typeof a;
}
};
System.config(${JSON.stringify(config, null, 2)});
`;
const bundleMain = () => {
const builder = new Builder(Config.SYSTEM_BUILDER_CONFIG);
const mainpath = join(Config.TMP_DIR, Config.BOOTSTRAP_FACTORY_PROD_MODULE);
const outpath = join(Config.JS_DEST, Config.JS_PROD_APP_BUNDLE);
utils.log('Bundling the bootstrap bundle');
return builder
.bundle(mainpath,
outpath,
Object.assign({ format: 'umd', sourceMaps: true }, BUNDLER_OPTIONS))
.then((res: any) => {
utils.log('The bootstrap bundle is ready!');
appendFileSync(outpath, `\nSystem.import('${mainpath}.js');${addExtensions}`);
return res.modules;
});
};
const bundleModule = (bundle: string, exclude: string[]): Promise<string[]> => {
utils.log('Bundling module with entry file', bundle);
let builder = new Builder(Config.SYSTEM_BUILDER_CONFIG);
let all = join(Config.TMP_DIR, Config.BOOTSTRAP_DIR);
let bootstrap = join(Config.TMP_DIR, Config.BOOTSTRAP_DIR, bundle);
const parts = bundle.split('/');
parts.pop();
let bootstrapDir = join(Config.TMP_DIR, Config.BOOTSTRAP_DIR, parts.join('/'));
let expression = `${bootstrap} - (${all}/**/*.js - ${bootstrapDir}/**/*.js)`;
if (exclude.length) {
expression += ` - ${exclude.join(' - ')}`;
}
return builder
.buildStatic(
expression,
join(Config.JS_DEST, '..', Config.BOOTSTRAP_DIR, bundle),
Object.assign({}, BUNDLER_OPTIONS, { format: 'umd', sourceMaps: true }))
.then((res: any) => {
utils.log('Bundling of', bundle, 'completed!');
return res;
});
};
const bundleModules = (roots: BundleNode[], exclude: string[]): Promise<any> => {
return Promise.all(roots.map((node: BundleNode) =>
bundleModule(node.path, exclude)
.then((directExclude: string[]) => {
return bundleModules(node.children, exclude.concat(directExclude));
})));
};
/**
* Executes the build process, bundling the JavaScript files using the SystemJS builder.
*/
export = (done: any) => {
const config = normalizeConfig(Config.BUNDLES);
const bundleTree = BundleTree.buildTree(config);
bundleMain()
.then((bundled: string[]) => bundleModules(bundleTree.roots, bundled))
.then(() => {
let builder = new Builder(Config.SYSTEM_BUILDER_CONFIG);
return builder
.buildStatic(join(Config.TMP_DIR, Config.MINI_APP_MODULE),
join(Config.JS_DEST, Config.MINI_APP_BUNDLE),
BUNDLER_OPTIONS);
})
.then(() => done())
.catch((e: any) => done(e));
}; |
I can change the prefix for anything. |
Yes, using a parameter sounds like a better idea. Do you want to provide explicit configuration for the bundles as well? The cons of using prefix is that we introduce another convention, a pro is that we simplify configuration. Still, I think it's a better idea to keep the configuration explicit and use explicit bundle configuration, similar to the example above. |
I created a property on seed config (LAZY_MATCH_EXPRESSION) to use on lazy task for define the folders that are lazy. |
@dfaglioni looks good and I see that the build is passing now. Would you only drop the |
@dfaglioni Its in node modules. Its not my service. This is the screen shot of the node module and project config: |
@dfaglioni Seems to be an issue with extracting the node module for metadata which is part of ng2-metadata module. I've found the file its looking for: |
@markoddi01 Are you importing like this? |
@dfaglioni Fixed that by following the bottom part of this link: https://www.npmjs.com/package/ng2-metadata I now have another issues seems to be with my other module angular2-google-maps: |
@markoddi01 Turn off the minify for while |
@dfaglioni it now opens the browser and shows console errors. Git bash seems to work fine now that minify was taken out. The app doesnt show the homepage, just the bootstrap css background blue. This is the current browser errors: |
@markoddi01 Is this returning the index on the get of router_link? |
@dfaglioni I'm not sure. Heres some screen shots: |
@markoddi01 Look at network ... |
@dfaglioni network screen: Network Router link response: |
@markoddi01 I want to see the response body. |
@dfaglioni above in the second screen shot is the response body. Looks like its returning the index on router link |
@markoddi01 |
@dfaglioni okay, thank you. Let me know if you can. |
@dfaglioni I have no idea why it occurs. could it be something to do with the lazy load in the seed file or my project config settings with the 2 node modules I add? I've tried a few things and still not luck. I will try again tomorrow. Could you recreate my issue for the router link? |
I will try today. |
@dfaglioni I'm free all evening to try get over this last hurdle. |
@dfaglioni any luck? I couldnt get it working. You free today to help? |
@markoddi01 Hey, Sorry, I'm so busy. I'm changing my system to test, but I'm having others types of errors. I'm going to close the PR for while. |
Hi, @dfaglioni Happy new year. I've not been coding for the last 12 days, in order to allow you to get ahead with the AOT work. How have you got on with this work? My branch is still in the above state from when we last spoke. I remember us being very close with the AOT production build. |
Hi, @dfaglioni I've tried your solution but still it's not working. npm run build.prod command is executed successfully without any error. Will you help me in that? |
production build does not work in the |
Hi @markoddi01 and @@dfaglioni, |
I suggest to use angular-cli that uses webpack instead systemjs who is the problem of the slow initialize. |
Really sad this never got merged. AOT with lazy loading is the killer feature that is driving everyone to webpack. SystemJS has some advantages though, like you can build projects completely separately and then load them together and they will share dependencies. That's a big use case for me. |
I had to change two major things. First: The SYSTEM_BUILDER_CONFIG to get working the build.bundles.app.ts with bundle (to expose the dependencies), in the previous version the dependencies had a loading error. Two: Included the SystemJS in production, to use on index to load the main app, and exposes for angular to load and compile the lazy module. I removed the app.js from the index.
I created a task to build the lazy bundle, only with theirs dependencies (build.bundles.app.lazy). All folders with + prefix will be considerate lazy modules.
I created two lazy modules, lazy-about and lazy, both has e2e tests to proof the solution.