Skip to content

Commit f94576b

Browse files
Alan AgiusKeen Yee Liau
Alan Agius
authored and
Keen Yee Liau
committed
feat(@schematics/angular): experimentalIvy should generates backwards compatible solution
Usage: ``` ng new foo --experimentalIvy ``` Users will need to use `ngcc` so to process code coming from NPM and produce the equivalent Ivy version. This needs to be done once after installing the node packages. ``` node_modules/.bin/ivy-ngcc ``` `ngtsc` compilter will then be used when building using the `--aot` or `--prod` flag. Fixes #13024
1 parent f8bf4ea commit f94576b

File tree

4 files changed

+65
-22
lines changed

4 files changed

+65
-22
lines changed
Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,12 @@
1-
<%= experimentalIvy ? '// ' : '' %>import { enableProdMode } from '@angular/core';
2-
<%= experimentalIvy ? '// ' : '' %>import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
3-
<%= experimentalIvy ? '// ' : '' %>
4-
<%= experimentalIvy ? '// ' : '' %>import { AppModule } from './app/app.module';
5-
<%= experimentalIvy ? '// ' : '' %>import { environment } from './environments/environment';
6-
<%= experimentalIvy ? '// ' : '' %>
7-
<%= experimentalIvy ? '// ' : '' %>if (environment.production) {
8-
<%= experimentalIvy ? '// ' : '' %> enableProdMode();
9-
<%= experimentalIvy ? '// ' : '' %>}
10-
<%= experimentalIvy ? '// ' : '' %>
11-
<%= experimentalIvy ? '// ' : '' %>platformBrowserDynamic().bootstrapModule(AppModule)
12-
<%= experimentalIvy ? '// ' : '' %> .catch(err => console.error(err));
13-
<% if (experimentalIvy) { %>
14-
import { AppComponent } from './app/app.component';
15-
import { ɵrenderComponent as renderComponent } from '@angular/core';
1+
import { enableProdMode } from '@angular/core';
2+
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
163

17-
renderComponent(AppComponent);
4+
import { AppModule } from './app/app.module';
5+
import { environment } from './environments/environment';
186

19-
<% } %>
7+
if (environment.production) {
8+
enableProdMode();
9+
}
10+
11+
platformBrowserDynamic().bootstrapModule(AppModule)
12+
.catch(err => console.error(err));

packages/schematics/angular/application/index.ts

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,15 @@
55
* Use of this source code is governed by an MIT-style license that can be
66
* found in the LICENSE file at https://angular.io/license
77
*/
8-
import { JsonObject, join, normalize, relative, strings } from '@angular-devkit/core';
8+
import {
9+
JsonObject,
10+
JsonParseMode,
11+
join,
12+
normalize,
13+
parseJsonAst,
14+
relative,
15+
strings,
16+
} from '@angular-devkit/core';
917
import {
1018
MergeStrategy,
1119
Rule,
@@ -30,6 +38,7 @@ import {
3038
getWorkspace,
3139
} from '../utility/config';
3240
import { NodeDependencyType, addPackageJsonDependency } from '../utility/dependencies';
41+
import { findPropertyInAstObject, insertPropertyInAstObjectInOrder } from '../utility/json-utils';
3342
import { latestVersions } from '../utility/latest-versions';
3443
import { applyLintFix } from '../utility/lint-fix';
3544
import { validateProjectName } from '../utility/validation';
@@ -94,6 +103,40 @@ function addDependenciesToPackageJson(options: ApplicationOptions) {
94103
};
95104
}
96105

106+
function addPostInstallScript() {
107+
return (host: Tree) => {
108+
const pkgJsonPath = '/package.json';
109+
const buffer = host.read(pkgJsonPath);
110+
if (!buffer) {
111+
throw new SchematicsException('Could not read package.json.');
112+
}
113+
114+
const packageJsonAst = parseJsonAst(buffer.toString(), JsonParseMode.Strict);
115+
if (packageJsonAst.kind !== 'object') {
116+
throw new SchematicsException('Invalid package.json. Was expecting an object.');
117+
}
118+
119+
const scriptsNode = findPropertyInAstObject(packageJsonAst, 'scripts');
120+
if (scriptsNode && scriptsNode.kind === 'object') {
121+
const recorder = host.beginUpdate(pkgJsonPath);
122+
const postInstall = findPropertyInAstObject(scriptsNode, 'postinstall');
123+
124+
if (!postInstall) {
125+
// postinstall script not found, add it.
126+
insertPropertyInAstObjectInOrder(
127+
recorder,
128+
scriptsNode,
129+
'postinstall',
130+
'ivy-ngcc',
131+
4,
132+
);
133+
}
134+
135+
host.commitUpdate(recorder);
136+
}
137+
};
138+
}
139+
97140
function addAppToWorkspaceFile(options: ApplicationOptions, workspace: WorkspaceSchema): Rule {
98141
// TODO: use JsonAST
99142
// const workspacePath = '/angular.json';
@@ -372,6 +415,7 @@ export default function (options: ApplicationOptions): Rule {
372415
move(sourceDir),
373416
]), MergeStrategy.Overwrite),
374417
options.minimal ? noop() : schematic('e2e', e2eOptions),
418+
options.experimentalIvy ? addPostInstallScript() : noop(),
375419
options.skipPackageJson ? noop() : addDependenciesToPackageJson(options),
376420
options.lintFix ? applyLintFix(sourceDir) : noop(),
377421
]);

packages/schematics/angular/application/index_spec.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,12 @@ describe('Application Schematic', () => {
190190
expect(pkg.devDependencies['typescript']).toEqual(latestVersions.TypeScript);
191191
});
192192

193+
it(`should add a postinstall in package.json when 'experimentalIvy'`, () => {
194+
const tree = schematicRunner.runSchematic('application', { ...defaultOptions, experimentalIvy: true }, workspaceTree);
195+
const pkg = JSON.parse(tree.readContent('/package.json'));
196+
expect(pkg.scripts.postinstall).toEqual('ivy-ngcc');
197+
});
198+
193199
it(`should not override existing users dependencies`, () => {
194200
const oldPackageJson = workspaceTree.readContent('package.json');
195201
workspaceTree.overwrite('package.json', oldPackageJson.replace(

packages/schematics/angular/application/other-files/app.module.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
1-
<% if (!experimentalIvy) { %>import { BrowserModule } from '@angular/platform-browser';<% } %>
1+
import { BrowserModule } from '@angular/platform-browser';
22
import { NgModule } from '@angular/core';
3-
<% if (routing && !experimentalIvy) { %>
3+
<% if (routing) { %>
44
import { AppRoutingModule } from './app-routing.module';<% } %>
55
import { AppComponent } from './app.component';
66

77
@NgModule({
88
declarations: [
99
AppComponent
1010
],
11-
imports: [<% if (!experimentalIvy) { %>
11+
imports: [
1212
BrowserModule<% if (routing) { %>,
1313
AppRoutingModule<% } %>
14-
<% } %>],
14+
],
1515
providers: [],
1616
bootstrap: [AppComponent]
1717
})

0 commit comments

Comments
 (0)