Last active
June 12, 2018 09:10
-
-
Save mgechev/63d374d51ac846797879a0cdc9c3b97c to your computer and use it in GitHub Desktop.
Lazy loading in Angular Seed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | |
} | |
} | |
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)); | |
}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import * as gulp from 'gulp'; | |
import * as gulpLoadPlugins from 'gulp-load-plugins'; | |
import * as merge from 'merge-stream'; | |
import { join } from 'path'; | |
import { getBundlesFsPath } from '../../utils/project/bundles'; | |
import Config from '../../config'; | |
const plugins = <any>gulpLoadPlugins(); | |
const getTask = (target: string, destDir: string) => { | |
return gulp.src(join(destDir, target)) | |
.pipe(plugins.uglify({ | |
compress: { screw_ie8: true }, | |
mangle: { screw_ie8: true }, | |
output: { screw_ie8: true } | |
})) | |
.pipe(gulp.dest(destDir)); | |
}; | |
export = (done: any) => { | |
const streams = [ | |
getTask(Config.JS_PROD_APP_BUNDLE, Config.JS_DEST), | |
getTask(Config.JS_PROD_SHIMS_BUNDLE, Config.JS_DEST) | |
]; | |
getBundlesFsPath(Config.BUNDLES) | |
.forEach((f: string) => { | |
const path = join(Config.JS_DEST, '..', Config.BOOTSTRAP_DIR); | |
streams.push(getTask(f, path)); | |
}); | |
return merge(...streams); | |
}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ... | |
BUNDLES: any[] = [ | |
{ name: 'intro', path: 'app/+intro/intro' }, | |
{ name: 'main', path: 'app/+main/main' } | |
]; | |
SYSTEM_CONFIG: any = { | |
defaultJSExtensions: true, | |
packageConfigPaths: [ | |
`${this.APP_BASE}node_modules/@ngrx/*/package.json`, | |
`${this.APP_BASE}node_modules/*/package.json`, | |
`${this.APP_BASE}node_modules/aspect.js/package.json`, | |
`${this.APP_BASE}node_modules/@ngrx/store/package.json`, | |
`${this.APP_BASE}node_modules/**/package.json`, | |
`${this.APP_BASE}node_modules/@angular/*/package.json` | |
], | |
packages: { | |
'jstimezonedetect': { | |
main: 'dist/jstz.js', | |
format: 'cjs', | |
defaultExtension: 'js' | |
} | |
}, | |
paths: { | |
'app/*': `${this.APP_BASE}app/*/index`, | |
[this.BOOTSTRAP_MODULE]: `${this.APP_BASE}${this.BOOTSTRAP_MODULE}`, | |
'@angular/core': `${this.APP_BASE}node_modules/@angular/core/bundles/core.umd.js`, | |
'@angular/common': `${this.APP_BASE}node_modules/@angular/common/bundles/common.umd.js`, | |
'@angular/compiler': `${this.APP_BASE}node_modules/@angular/compiler/bundles/compiler.umd.js`, | |
'@angular/http': `${this.APP_BASE}node_modules/@angular/http/bundles/http.umd.js`, | |
'@angular/router': `${this.APP_BASE}node_modules/@angular/router/bundles/router.umd.js`, | |
'@angular/forms': `${this.APP_BASE}node_modules/@angular/forms/bundles/forms.umd.js`, | |
'@angular/platform-browser': `${this.APP_BASE}node_modules/@angular/platform-browser/bundles/platform-browser.umd.js`, | |
'@angular/platform-browser-dynamic': | |
`${this.APP_BASE}node_modules/@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js`, | |
'rxjs/*': `${this.APP_BASE}node_modules/rxjs/*`, | |
'tracking': `${this.APP_BASE}node_modules/tracking/build/tracking.js`, | |
'load-image/*': `${this.APP_BASE}node_modules/blueimp-load-image/js/*`, | |
'tracking-face': `${this.APP_BASE}node_modules/tracking/build/data/face.js`, | |
'*': `${this.APP_BASE}node_modules/*` | |
} | |
}; | |
RESOURCES = join(this.PROJECT_ROOT, 'resources'); | |
SYSTEM_BUILDER_CONFIG: any = { | |
defaultJSExtensions: true, | |
base: this.PROJECT_ROOT, | |
packageConfigPaths: [ | |
join(this.PROJECT_ROOT, 'node_modules', '*', 'package.json'), | |
join(this.PROJECT_ROOT, 'node_modules', '@ngrx', '*', 'package.json'), | |
join(this.PROJECT_ROOT, 'node_modules', '@angular', '*', 'package.json') | |
], | |
paths: { | |
// Note that for multiple apps this configuration need to be updated | |
// You will have to include entries for each individual application in | |
// `src/client`. | |
[`${this.TMP_DIR}/*`]: `${this.TMP_DIR}/*`, | |
'bp-meta': `${this.APP_BASE}app/utils/bp-meta`, | |
'tracking': 'node_modules/tracking/build/tracking-min.js', | |
'tracking-face': 'node_modules/tracking/build/data/face-min.js', | |
'load-image/*': `node_modules/blueimp-load-image/js/*`, | |
'*': 'node_modules/*' | |
}, | |
meta: { | |
'*.json': { | |
format: 'json' | |
} | |
}, | |
packages: { | |
'@angular/core': { | |
main: 'index.js', | |
defaultExtension: 'js' | |
}, | |
'@angular/compiler': { | |
main: 'index.js', | |
defaultExtension: 'js' | |
}, | |
'@angular/common': { | |
main: 'index.js', | |
defaultExtension: 'js' | |
}, | |
'@angular/http': { | |
main: 'index.js', | |
defaultExtension: 'js' | |
}, | |
'@angular/forms': { | |
main: 'index.js', | |
defaultExtension: 'js' | |
}, | |
'@angular/platform-browser': { | |
main: 'index.js', | |
defaultExtension: 'js' | |
}, | |
'@angular/platform-browser-dynamic': { | |
main: 'index.js', | |
defaultExtension: 'js' | |
}, | |
'@angular/router-deprecated': { | |
main: 'index.js', | |
defaultExtension: 'js' | |
}, | |
'@angular/router': { | |
main: 'index.js', | |
defaultExtension: 'js' | |
}, | |
'jstimezonedetect': { | |
main: 'dist/jstz.min.js', | |
format: 'cjs', | |
defaultExtension: 'js' | |
}, | |
'immutable': { | |
main: 'dist/immutable.js' | |
}, | |
'angular2-jwt': { | |
main: 'angular2-jwt.js' | |
}, | |
'aspect.js': { | |
main: 'aspect.js' | |
}, | |
'aspect.js-angular': { | |
main: 'index.js' | |
}, | |
'@ngrx/store': { | |
main: 'index.js', | |
defaultExtension: 'js' | |
}, | |
'@ngrx/core': { | |
main: 'index.js', | |
defaultExtension: 'js' | |
}, | |
'platform': { | |
main: 'platform.js' | |
}, | |
'reflect-metadata': { | |
main: 'Reflect.js' | |
}, | |
'rxjs': { | |
defaultExtension: 'js' | |
} | |
} | |
}; | |
//... |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment