Skip to content

Commit

Permalink
First implementation of get lazy modules entries. (#1632)
Browse files Browse the repository at this point in the history
Fixes #1636.
  • Loading branch information
hansl authored Aug 19, 2016
1 parent 9d69748 commit 3b226be
Show file tree
Hide file tree
Showing 4 changed files with 127 additions and 22 deletions.
68 changes: 68 additions & 0 deletions addon/ng2/models/find-lazy-modules.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import * as fs from 'fs';
import * as glob from 'glob';
import * as path from 'path';
import * as ts from 'typescript';

import {Observable} from 'rxjs/Observable';
import {getSource, findNodes, getContentOfKeyLiteral} from '../utilities/ast-utils';


const loadChildrenRegex = /(\{[^{}]+?(loadChildren|['"]loadChildren['"])\s*:\s*)('[^']+'|"[^"]+")/gm;


interface Array<T> {
flatMap: <R>(mapFn: (item: T) => Array<R>) => Array<R>;
}
Array.prototype.flatMap = function<T, R>(mapFn: (item: T) => Array<R>): Array<R> {
if (!mapFn) {
return [];
}

return this.reduce((arr, current) => {
const result = mapFn.call(null, current);
return result !== undefined ? arr.concat(result) : arr;
}, []);
};


export function findLoadChildren(tsFilePath: string): string[] {
const source = getSource(tsFilePath);
const unique = {};

return findNodes(source, ts.SyntaxKind.ObjectLiteralExpression)
.flatMap(node => findNodes(node, ts.SyntaxKind.PropertyAssignment))
.filter((node: ts.PropertyAssignment) => {
const key = getContentOfKeyLiteral(source, node.name);
if (!key) {
// key is an expression, can't do anything.
return false;
}
return key == 'loadChildren'
})
// Remove initializers that are not files.
.filter((node: ts.PropertyAssignment) => {
return node.initializer.kind === ts.SyntaxKind.StringLiteral;
})
// Get the full text of the initiliazer.
.map((node: ts.PropertyAssignment) => {
return eval(node.initializer.getText(source));
})
.flatMap((value: string) => unique[value] ? undefined : unique[value] = value)
.map((moduleName: string) => moduleName.split('#')[0]);
}


export function findLazyModules(projectRoot: any): string[] {
const allTs = glob.sync(path.join(projectRoot, '/**/*.ts'));
const result = {};
allTs
.flatMap(tsPath => {
findLoadChildren(tsPath).forEach(moduleName => {
const fileName = path.resolve(path.dirname(tsPath), moduleName) + '.ts';
if (fs.existsSync(fileName)) {
result[moduleName] = fileName;
}
});
});
return result;
}
31 changes: 17 additions & 14 deletions addon/ng2/models/webpack-build-common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,26 @@ import * as path from 'path';
import * as CopyWebpackPlugin from 'copy-webpack-plugin';
import * as HtmlWebpackPlugin from 'html-webpack-plugin';
import * as webpack from 'webpack';
import { ForkCheckerPlugin } from 'awesome-typescript-loader';
import { CliConfig } from './config';
import * as atl from 'awesome-typescript-loader';

import {findLazyModules} from './find-lazy-modules';

export function getWebpackCommonConfig(projectRoot: string, sourceDir: string, outputDir: string) {

let outputPath: string = path.resolve(projectRoot, outputDir);
export function getWebpackCommonConfig(projectRoot: string, sourceDir: string, outputDir: string) {
const sourceRoot = path.resolve(projectRoot, sourceDir);
const outputPath = path.resolve(projectRoot, outputDir);
const lazyModules = findLazyModules(path.resolve(projectRoot, sourceDir));

return {
devtool: 'source-map',
resolve: {
extensions: ['', '.ts', '.js'],
root: path.resolve(projectRoot, `./${sourceDir}`)
root: sourceRoot
},
context: path.resolve(__dirname, './'),
entry: {
main: [path.resolve(projectRoot, `./${sourceDir}/main.ts`)],
polyfills: path.resolve(projectRoot, `./${sourceDir}/polyfills.ts`)
main: [path.join(sourceRoot, 'main.ts')],
polyfills: path.join(sourceRoot, 'polyfills.ts')
},
output: {
path: outputPath,
Expand All @@ -42,10 +45,9 @@ export function getWebpackCommonConfig(projectRoot: string, sourceDir: string, o
loader: 'awesome-typescript-loader',
query: {
useForkChecker: true,
tsconfig: path.resolve(projectRoot, `./${sourceDir}/tsconfig.json`)
tsconfig: path.resolve(sourceRoot, 'tsconfig.json')
}
},
{
}, {
loader: 'angular2-template-loader'
}
],
Expand All @@ -61,9 +63,10 @@ export function getWebpackCommonConfig(projectRoot: string, sourceDir: string, o
]
},
plugins: [
new ForkCheckerPlugin(),
new webpack.ContextReplacementPlugin(/.*/, sourceRoot, lazyModules),
new atl.ForkCheckerPlugin(),
new HtmlWebpackPlugin({
template: path.resolve(projectRoot, `./${sourceDir}/index.html`),
template: path.resolve(sourceRoot, 'index.html'),
chunksSortMode: 'dependency'
}),
new webpack.optimize.CommonsChunkPlugin({
Expand All @@ -79,7 +82,7 @@ export function getWebpackCommonConfig(projectRoot: string, sourceDir: string, o
context: path.resolve(projectRoot, './public'),
from: '**/*',
to: outputPath
}])
}]),
],
node: {
fs: 'empty',
Expand All @@ -90,4 +93,4 @@ export function getWebpackCommonConfig(projectRoot: string, sourceDir: string, o
setImmediate: false
}
}
};
}
48 changes: 40 additions & 8 deletions addon/ng2/utilities/ast-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,21 +57,37 @@ export function getSourceNodes(sourceFile: ts.SourceFile): Observable<ts.Node> {


/**
* Find all nodes from the AST in the subtree of node of SyntaxKind kind.
* @param node
* @param kind
* @return all nodes of kind, or [] if none is found
* Find all nodes from the AST in the subtree of node of SyntaxKind kind.
* @param node
* @param kind
* @param max The maximum number of items to return.
* @return all nodes of kind, or [] if none is found
*/
export function findNodes(node: ts.Node, kind: ts.SyntaxKind): ts.Node[] {
if (!node) {
export function findNodes(node: ts.Node, kind: ts.SyntaxKind, max: number = Infinity): ts.Node[] {
if (!node || max == 0) {
return [];
}

let arr: ts.Node[] = [];
if (node.kind === kind) {
arr.push(node);
max--;
}
if (max > 0) {
for (const child of node.getChildren()) {
findNodes(child, kind, max).forEach(node => {
if (max > 0) {
arr.push(node);
}
max--;
});

if (max <= 0) {
break;
}
}
}
return node.getChildren().reduce((foundNodes, child) =>
foundNodes.concat(findNodes(child, kind)), arr);
return arr;
}


Expand Down Expand Up @@ -111,9 +127,25 @@ export function insertAfterLastOccurrence(nodes: ts.Node[], toInsert: string,
}


export function getContentOfKeyLiteral(source: ts.SourceFile, node: ts.Node): string {
if (node.kind == ts.SyntaxKind.Identifier) {
return (<ts.Identifier>node).text;
} else if (node.kind == ts.SyntaxKind.StringLiteral) {
try {
return JSON.parse(node.getFullText(source))
} catch (e) {
return null;
}
} else {
return null;
}
}


export function getDecoratorMetadata(source: ts.SourceFile, identifier: string,
module: string): Observable<ts.Node> {
const symbols = new Symbols(source);

return getSourceNodes(source)
.filter(node => {
return node.kind == ts.SyntaxKind.Decorator
Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
},
"homepage": "https://github.com/angular/angular-cli",
"dependencies": {
"@angular/core": "^2.0.0-rc.5",
"@angular/tsc-wrapped": "^0.2.2",
"@types/lodash": "^4.0.25-alpha",
"@types/rimraf": "0.0.25-alpha",
Expand Down Expand Up @@ -81,6 +82,7 @@
"silent-error": "^1.0.0",
"source-map-loader": "^0.1.5",
"sourcemap-istanbul-instrumenter-loader": "^0.2.0",
"string-replace-loader": "^1.0.3",
"style-loader": "^0.13.1",
"stylus": "^0.54.5",
"stylus-loader": "^2.1.0",
Expand Down

0 comments on commit 3b226be

Please sign in to comment.