Skip to content

Initial dynamic import support #9515

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

Merged
merged 3 commits into from
Feb 16, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions packages/@angular/cli/lib/config/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,14 @@
"description": "Name and corresponding file for environment config.",
"type": "object",
"additionalProperties": true
},
"lazyModules": {
"description": "List of additional NgModule files that will be lazy loaded. (lazy router modules with be discovered automatically)",
"type": "array",
"items": {
"type": "string",
"minLength": 1
}
}
},
"additionalProperties": false
Expand Down
12 changes: 12 additions & 0 deletions packages/@angular/cli/models/webpack-configs/typescript.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,17 @@ function _createAotPlugin(wco: WebpackConfigOptions, options: any, useMain = tru
}

if (AngularCompilerPlugin.isSupported()) {
const additionalLazyModules: { [module: string]: string } = {};
if (appConfig.lazyModules) {
for (const lazyModule of appConfig.lazyModules) {
additionalLazyModules[lazyModule] = path.resolve(
projectRoot,
appConfig.root,
lazyModule,
);
}
}

const pluginOptions: AngularCompilerPluginOptions = Object.assign({}, {
mainPath: useMain ? path.join(projectRoot, appConfig.root, appConfig.main) : undefined,
i18nInFile: buildOptions.i18nFile,
Expand All @@ -92,6 +103,7 @@ function _createAotPlugin(wco: WebpackConfigOptions, options: any, useMain = tru
missingTranslation: buildOptions.missingTranslation,
hostReplacementPaths,
sourceMap: buildOptions.sourcemaps,
additionalLazyModules,
}, options);
return new AngularCompilerPlugin(pluginOptions);
} else {
Expand Down
15 changes: 11 additions & 4 deletions packages/@ngtools/webpack/src/angular_compiler_plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,9 @@ export interface AngularCompilerPluginOptions {
missingTranslation?: string;
platform?: PLATFORM;

// added to the list of lazy routes
additionalLazyModules?: { [module: string]: string };

// Use tsconfig to include path globs.
compilerOptions?: ts.CompilerOptions;
}
Expand Down Expand Up @@ -447,19 +450,20 @@ export class AngularCompilerPlugin implements Tapable {
.forEach(lazyRouteKey => {
const [lazyRouteModule, moduleName] = lazyRouteKey.split('#');

if (!lazyRouteModule || !moduleName) {
if (!lazyRouteModule) {
return;
}

const lazyRouteTSFile = discoveredLazyRoutes[lazyRouteKey];
const lazyRouteTSFile = discoveredLazyRoutes[lazyRouteKey].replace(/\\/g, '/');
let modulePath: string, moduleKey: string;

if (this._JitMode) {
modulePath = lazyRouteTSFile;
moduleKey = lazyRouteKey;
moduleKey = `${lazyRouteModule}${moduleName ? '#' + moduleName : ''}`;
} else {
modulePath = lazyRouteTSFile.replace(/(\.d)?\.ts$/, `.ngfactory.js`);
moduleKey = `${lazyRouteModule}.ngfactory#${moduleName}NgFactory`;
const factoryModuleName = moduleName ? `#${moduleName}NgFactory` : '';
moduleKey = `${lazyRouteModule}.ngfactory${factoryModuleName}`;
}

if (moduleKey in this._lazyRoutes) {
Expand Down Expand Up @@ -760,6 +764,9 @@ export class AngularCompilerPlugin implements Tapable {
} else if (changedTsFiles.length > 0) {
this._processLazyRoutes(this._findLazyRoutesInAst(changedTsFiles));
}
if (this._options.additionalLazyModules) {
this._processLazyRoutes(this._options.additionalLazyModules);
}
}
})
.then(() => {
Expand Down
46 changes: 46 additions & 0 deletions tests/e2e/tests/build/dynamic-import.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import * as fs from 'fs';
import { writeFile } from '../../utils/fs';
import { ng } from '../../utils/process';
import { updateJsonFile } from '../../utils/project';


export default async function() {
// Add a lazy module
await ng('generate', 'module', 'lazy');
await updateJsonFile('.angular-cli.json', configJson => {
const app = configJson['apps'][0];
app['lazyModules'] = [
'app/lazy/lazy.module'
];
});

// Update the app component to use the lazy module
await writeFile('src/app/app.component.ts', `
import { Component, SystemJsNgModuleLoader } from '@angular/core';

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
title = 'app';
constructor(loader: SystemJsNgModuleLoader) {
// Module will be split at build time and loaded when requested below
loader.load('app/lazy/lazy.module#LazyModule')
.then((factory) => { /* Use factory here */ });
}
}
`);

// Build and look for the split lazy module
await ng('build');
for (const file of fs.readdirSync('./dist')) {
if (file === 'lazy.module.chunk.js') {
// Lazy module chunk was found and succesfully split
return;
}
}

throw new Error('Lazy module chunk not created');
}