build(docs-infra): switch docs examples to Ivy (#36143)

The docs examples are switched to Ivy. On CI, the tests are run with
both Ivy and ViewEngine.

Partially addresses:
[FW-1609](https://angular-team.atlassian.net/browse/FW-1609)

PR Close #36143
This commit is contained in:
George Kalpakas 2020-04-06 22:57:58 +03:00 committed by Kara Erickson
parent 09c84169d5
commit aece3669e5
23 changed files with 146 additions and 121 deletions

View File

@ -455,7 +455,7 @@ jobs:
test_docs_examples:
parameters:
ivy:
viewengine:
type: boolean
default: false
executor:
@ -471,7 +471,7 @@ jobs:
# Run examples tests. The "CIRCLE_NODE_INDEX" will be set if "parallelism" is enabled.
# Since the parallelism is set to "5", there will be five parallel CircleCI containers.
# with either "0", "1", etc as node index. This can be passed to the "--shard" argument.
- run: yarn --cwd aio example-e2e --setup --local <<# parameters.ivy >>--ivy<</ parameters.ivy >> --cliSpecsConcurrency=5 --shard=${CIRCLE_NODE_INDEX}/${CIRCLE_NODE_TOTAL} --retry 2
- run: yarn --cwd aio example-e2e --setup --local <<# parameters.viewengine >>--viewengine<</ parameters.viewengine >> --cliSpecsConcurrency=5 --shard=${CIRCLE_NODE_INDEX}/${CIRCLE_NODE_TOTAL} --retry 2
# This job should only be run on PR builds, where `CI_PULL_REQUEST` is not `false`.
aio_preview:
@ -823,8 +823,8 @@ workflows:
requires:
- build-npm-packages
- test_docs_examples:
name: test_docs_examples_ivy
ivy: true
name: test_docs_examples_viewengine
viewengine: true
requires:
- build-npm-packages
- aio_preview:
@ -851,7 +851,7 @@ workflows:
- test_aio_local
- test_aio_local_viewengine
- test_docs_examples
- test_docs_examples_ivy
- test_docs_examples_viewengine
# Get the artifacts to publish from the build-packages-dist job
# since the publishing script expects the legacy outputs layout.
- build-npm-packages

View File

@ -18,8 +18,8 @@ Here are the most important tasks you might need to use:
* `yarn build` - create a production build of the application (after installing dependencies, boilerplate, etc).
* `yarn build-local` - same as `build`, but use `setup-local` instead of `setup`.
* `yarn build-local-with-viewengine` - same as `build-local`, but in addition also turns on `ViewEngine` mode in aio.
(Note: Docs examples run in `ViewEngine` mode by default. To turn on `ivy` mode in examples, see `yarn boilerplate:add` below.)
* `yarn build-local-with-viewengine` - same as `build-local`, but in addition also turns on `ViewEngine` (pre-Ivy) mode in aio.
(Note: To turn on `ViewEngine` mode in docs examples, see `yarn boilerplate:add:viewengine` below.)
* `yarn start` - run a development web server that watches the files; then builds the doc-viewer and reloads the page, as necessary.
* `yarn serve-and-sync` - run both the `docs-watch` and `start` in the same console.
@ -34,7 +34,7 @@ Here are the most important tasks you might need to use:
* `yarn docs-test` - run the unit tests for the doc generation code.
* `yarn boilerplate:add` - generate all the boilerplate code for the examples, so that they can be run locally.
* `yarn boilerplate:add:ivy` - same as `boilerplate:add` but also turns on `ivy` mode.
* `yarn boilerplate:add:viewengine` - same as `boilerplate:add` but also turns on `ViewEngine` (pre-Ivy) mode.
* `yarn boilerplate:remove` - remove all the boilerplate code that was added via `yarn boilerplate:add`.
* `yarn generate-stackblitz` - generate the stackblitz files that are used by the `live-example` tags in the docs.
@ -44,7 +44,7 @@ Here are the most important tasks you might need to use:
- `--setup`: generate boilerplate, force webdriver update & other setup, then run tests.
- `--local`: run e2e tests with the local version of Angular contained in the "dist" folder.
_Requires `--setup` in order to take effect._
- `--ivy`: run e2e tests in `ivy` mode.
- `--viewengine`: run e2e tests in `ViewEngine` (pre-Ivy) mode.
- `--filter=foo`: limit e2e tests to those containing the word "foo".
> **Note for Windows users**

View File

@ -1,13 +0,0 @@
{
"e2e": [
{
"cmd": "yarn",
"args": [
"e2e",
"--protractor-config=e2e/protractor-puppeteer.conf.js",
"--no-webdriver-update",
"--port={PORT}"
]
}
]
}

View File

@ -12,15 +12,15 @@
],
"noImplicitAny": true,
"skipLibCheck": true,
"suppressImplicitAnyIndexErrors": true
"suppressImplicitAnyIndexErrors": true,
"typeRoots": [
"node_modules/@types"
]
},
"compileOnSave": true,
"exclude": [
"node_modules/*",
"**/*-aot.ts",
"aot/**/*"
],
"angularCompilerOptions": {
"enableIvy": false
}
}
]
}

View File

@ -1,11 +1,11 @@
// #docregion
import nodeResolve from 'rollup-plugin-node-resolve'
import commonjs from 'rollup-plugin-commonjs';
import uglify from 'rollup-plugin-uglify'
import commonjs from 'rollup-plugin-commonjs';
import uglify from 'rollup-plugin-uglify'
//paths are relative to the execution path
export default {
input: 'app/main-aot.js',
input: 'app/main.js',
output: {
file: 'aot/dist/build.js', // output a single application bundle
format: 'iife',

View File

@ -6,20 +6,23 @@
"sourceMap": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"lib": ["es2015", "dom"],
"lib": [
"es2015",
"dom"
],
"removeComments": false,
"noImplicitAny": true,
"skipLibCheck": true,
"suppressImplicitAnyIndexErrors": true
"suppressImplicitAnyIndexErrors": true,
"typeRoots": [
"node_modules/@types"
]
},
"files": [
"app/app.module.ts",
"app/main-aot.ts"
"app/main.ts"
],
"angularCompilerOptions": {
"skipMetadataEmit" : true,
"enableIvy": false,
}
"skipMetadataEmit": true
}
}

View File

@ -12,14 +12,14 @@
],
"noImplicitAny": true,
"skipLibCheck": true,
"suppressImplicitAnyIndexErrors": true
"suppressImplicitAnyIndexErrors": true,
"typeRoots": [
"node_modules/@types"
]
},
"compileOnSave": true,
"exclude": [
"node_modules/*",
"**/*-aot.ts"
],
"angularCompilerOptions": {
"enableIvy": false
}
}
]
}

View File

@ -12,14 +12,14 @@
],
"noImplicitAny": true,
"skipLibCheck": true,
"suppressImplicitAnyIndexErrors": true
"suppressImplicitAnyIndexErrors": true,
"typeRoots": [
"node_modules/@types"
]
},
"compileOnSave": true,
"exclude": [
"node_modules/*",
"**/*-aot.ts"
],
"angularCompilerOptions": {
"enableIvy": false
}
}
]
}

View File

@ -66,7 +66,7 @@
"preserve-and-sync": "yarn docs",
"serve-and-sync": "run-p \"start\" \"docs-watch --watch-only\"",
"boilerplate:add": "node ./tools/examples/example-boilerplate add",
"boilerplate:add:ivy": "yarn boilerplate:add --ivy",
"boilerplate:add:viewengine": "yarn boilerplate:add --viewengine",
"boilerplate:remove": "node ./tools/examples/example-boilerplate remove",
"boilerplate:test": "node tools/examples/test.js",
"generate-stackblitz": "node ./tools/stackblitz-builder/generateStackblitz",

View File

@ -1,7 +1,7 @@
{
"scripts": [
{ "name": "ng", "command": "ng" },
{ "name": "build", "command": "ng build --prod" },
{ "name": "build", "command": "ng build" },
{ "name": "start", "command": "ng serve" },
{ "name": "test", "command": "ng test" },
{ "name": "lint", "command": "ng lint" },

View File

@ -1,7 +1,7 @@
{
"scripts": [
{ "name": "ng", "command": "ng" },
{ "name": "build", "command": "ng build --prod" },
{ "name": "build", "command": "ng build" },
{ "name": "start", "command": "ng serve" },
{ "name": "test", "command": "ng test" },
{ "name": "lint", "command": "ng lint" },

View File

@ -1,7 +1,7 @@
{
"scripts": [
{ "name": "ng", "command": "ng" },
{ "name": "build", "command": "ng build --prod" },
{ "name": "build", "command": "ng build" },
{ "name": "start", "command": "ng serve" },
{ "name": "test", "command": "ng test" },
{ "name": "lint", "command": "ng lint" },

View File

@ -2,7 +2,7 @@
"scripts": [
{ "name": "start", "command": "ng serve" },
{ "name": "start:fr", "command": "ng serve --configuration=fr" },
{ "name": "build", "command": "ng build --prod" },
{ "name": "build", "command": "ng build" },
{ "name": "build:fr", "command": "ng build --configuration=production-fr" },
{ "name": "test", "command": "ng test" },
{ "name": "lint", "command": "ng lint" },

View File

@ -1,7 +1,7 @@
{
"scripts": [
{ "name": "ng", "command": "ng" },
{ "name": "build", "command": "ng build --prod" },
{ "name": "build", "command": "ng build" },
{ "name": "build:lib", "command": "ng build my-lib" },
{ "name": "start", "command": "ng serve" },
{ "name": "test", "command": "ng test" },

View File

@ -32,12 +32,12 @@ Currently you will find the next project types:
* cli - For CLI based examples. This is the default one, to be used in the majority of the examples.
* getting-started - CLI-based with its own set of styles.
* i18n - CLI-based with additional scripts for internationalization.
* ivy - CLI-based with additional configuration for running the examples with the Ivy renderer and ngstc compiler.
* schematics - CLI-based with additional scripts for building schematics.
* service-worker - CLI-based with additional packages and configuration for service workers.
* systemjs - Currently in deprecation, only used in a few examples.
* testing - CLI-based with additional styles for jasmine testing.
* universal - CLI-based with an extra server target.
* viewengine - Additional configuration for running CLI-/SystemJS-based examples with `ViewEngine` (the pre-Ivy compiler/renderer).
There is also a `common` folder that contains files used in all different examples.

View File

@ -50,11 +50,6 @@ BOILERPLATE_PATHS['getting-started'] = [
'src/styles.css'
];
BOILERPLATE_PATHS.ivy = {
systemjs: ['rollup-config.js', 'tsconfig-aot.json'],
cli: ['tsconfig.app.json']
};
BOILERPLATE_PATHS.schematics = [
...cliRelativePath,
'angular.json'
@ -65,13 +60,18 @@ BOILERPLATE_PATHS['cli-ajs'] = [
'package.json'
];
BOILERPLATE_PATHS.viewengine = {
systemjs: ['rollup-config.js', 'tsconfig-aot.json'],
cli: ['tsconfig.json']
};
const EXAMPLE_CONFIG_FILENAME = 'example-config.json';
class ExampleBoilerPlate {
/**
* Add boilerplate files to all the examples
*/
add(ivy = false) {
add(viewengine = false) {
// Get all the examples folders, indicated by those that contain a `example-config.json` file
const exampleFolders =
this.getFoldersContaining(EXAMPLES_BASE_PATH, EXAMPLE_CONFIG_FILENAME, 'node_modules');
@ -82,7 +82,7 @@ class ExampleBoilerPlate {
`Perhaps you need to run "yarn example-use-npm" or "yarn example-use-local" to install the dependencies?`);
}
if (ivy) {
if (!viewengine) {
shelljs.exec(`yarn --cwd ${SHARED_PATH} ngcc --properties es2015 browser module main --first-only --create-ivy-entry-points`);
}
@ -107,13 +107,13 @@ class ExampleBoilerPlate {
BOILERPLATE_PATHS.common.forEach(filePath => this.copyFile(BOILERPLATE_COMMON_BASE_PATH, exampleFolder, filePath));
}
// Copy Ivy specific files
if (ivy) {
const ivyBoilerPlateType = boilerPlateType === 'systemjs' ? 'systemjs' : 'cli';
const ivyBoilerPlateBasePath =
path.resolve(BOILERPLATE_BASE_PATH, 'ivy', ivyBoilerPlateType);
BOILERPLATE_PATHS.ivy[ivyBoilerPlateType].forEach(
filePath => this.copyFile(ivyBoilerPlateBasePath, exampleFolder, filePath));
// Copy ViewEngine (pre-Ivy) specific files
if (viewengine) {
const veBoilerPlateType = boilerPlateType === 'systemjs' ? 'systemjs' : 'cli';
const veBoilerPlateBasePath =
path.resolve(BOILERPLATE_BASE_PATH, 'viewengine', veBoilerPlateType);
BOILERPLATE_PATHS.viewengine[veBoilerPlateType].forEach(
filePath => this.copyFile(veBoilerPlateBasePath, exampleFolder, filePath));
}
});
}
@ -125,7 +125,7 @@ class ExampleBoilerPlate {
main() {
yargs.usage('$0 <cmd> [args]')
.command('add', 'add the boilerplate to each example', (yrgs) => this.add(yrgs.argv.ivy))
.command('add', 'add the boilerplate to each example', yrgs => this.add(yrgs.argv.viewengine))
.command('remove', 'remove the boilerplate from each example', () => this.remove())
.demandCommand(1, 'Please supply a command from the list above')
.argv;

View File

@ -14,18 +14,29 @@ describe('example-boilerplate tool', () => {
i18n: 2,
universal: 2,
systemjs: 7,
common: 1
common: 1,
viewengine: {
cli: 1,
systemjs: 2,
},
};
const exampleFolders = ['a/b', 'c/d'];
beforeEach(() => {
spyOn(fs, 'ensureSymlinkSync');
spyOn(fs, 'existsSync').and.returnValue(true);
spyOn(shelljs, 'exec');
spyOn(exampleBoilerPlate, 'copyFile');
spyOn(exampleBoilerPlate, 'getFoldersContaining').and.returnValue(exampleFolders);
spyOn(exampleBoilerPlate, 'loadJsonFile').and.returnValue({});
});
it('should run `ngcc`', () => {
exampleBoilerPlate.add();
expect(shelljs.exec).toHaveBeenCalledWith(
`yarn --cwd ${sharedDir} ngcc --properties es2015 browser module main --first-only --create-ivy-entry-points`);
});
it('should process all the example folders', () => {
const examplesDir = path.resolve(__dirname, '../../content/examples');
exampleBoilerPlate.add();
@ -50,7 +61,7 @@ describe('example-boilerplate tool', () => {
it('should copy all the source boilerplate files for systemjs', () => {
const boilerplateDir = path.resolve(sharedDir, 'boilerplate');
exampleBoilerPlate.loadJsonFile.and.callFake(filePath => filePath.indexOf('a/b') !== -1 ? { projectType: 'systemjs' } : {})
exampleBoilerPlate.loadJsonFile.and.callFake(filePath => filePath.indexOf('a/b') !== -1 ? { projectType: 'systemjs' } : {});
exampleBoilerPlate.add();
expect(exampleBoilerPlate.copyFile).toHaveBeenCalledTimes(
(BPFiles.cli) +
@ -110,6 +121,38 @@ describe('example-boilerplate tool', () => {
expect(exampleBoilerPlate.loadJsonFile).toHaveBeenCalledWith(path.resolve('a/b/example-config.json'));
expect(exampleBoilerPlate.loadJsonFile).toHaveBeenCalledWith(path.resolve('c/d/example-config.json'));
});
describe('(viewengine: true)', () => {
it('should not run `ngcc`', () => {
exampleBoilerPlate.add(true);
expect(shelljs.exec).not.toHaveBeenCalled();
});
it('should copy all the source boilerplate files for systemjs', () => {
const boilerplateDir = path.resolve(sharedDir, 'boilerplate');
exampleBoilerPlate.loadJsonFile.and.callFake(filePath => filePath.indexOf('a/b') !== -1 ? { projectType: 'systemjs' } : {});
exampleBoilerPlate.add(true);
expect(exampleBoilerPlate.copyFile).toHaveBeenCalledTimes(
(BPFiles.cli + BPFiles.viewengine.cli) +
(BPFiles.systemjs + BPFiles.viewengine.systemjs) +
(BPFiles.common * exampleFolders.length)
);
// for example
expect(exampleBoilerPlate.copyFile).toHaveBeenCalledWith(`${boilerplateDir}/viewengine/systemjs`, 'a/b', 'tsconfig-aot.json');
});
it('should copy all the source boilerplate files for cli', () => {
const boilerplateDir = path.resolve(sharedDir, 'boilerplate');
exampleBoilerPlate.add(true);
expect(exampleBoilerPlate.copyFile).toHaveBeenCalledTimes(
(BPFiles.cli * exampleFolders.length) +
(BPFiles.viewengine.cli * exampleFolders.length) +
(BPFiles.common * exampleFolders.length)
);
// for example
expect(exampleBoilerPlate.copyFile).toHaveBeenCalledWith(`${boilerplateDir}/viewengine/cli`, 'a/b', 'tsconfig.json');
});
});
});
describe('remove', () => {

View File

@ -28,7 +28,7 @@ const fixmeIvyExamples = [
'i18n',
];
if (argv.ivy) {
if (!argv.viewengine) {
IGNORED_EXAMPLES.push(...fixmeIvyExamples);
}
@ -46,7 +46,7 @@ if (argv.ivy) {
* Must be used in conjunction with --setup as this is when the packages are copied.
* e.g. --setup --local
*
* --ivy to turn on `ivy` mode
* --viewengine to turn on `ViewEngine` mode
*
* --shard to shard the specs into groups to allow you to run them in parallel
* e.g. --shard=0/2 // the even specs: 0, 2, 4, etc
@ -64,7 +64,7 @@ function runE2e() {
// Run setup.
console.log('runE2e: setup boilerplate');
const installPackagesCommand = `example-use-${argv.local ? 'local' : 'npm'}`;
const addBoilerplateCommand = `boilerplate:add${argv.ivy ? ':ivy' : ''}`;
const addBoilerplateCommand = `boilerplate:add${argv.viewengine ? ':viewengine' : ''}`;
shelljs.exec(`yarn ${installPackagesCommand}`, {cwd: AIO_PATH});
shelljs.exec(`yarn ${addBoilerplateCommand}`, {cwd: AIO_PATH});
}
@ -185,7 +185,7 @@ function runE2eTestsSystemJS(appDir, outputFile) {
// Only run AOT tests in ViewEngine mode. The current AOT setup does not work in Ivy.
// See https://github.com/angular/angular/issues/35989.
if (!argv.ivy && fs.existsSync(appDir + '/aot/index.html')) {
if (argv.viewengine && fs.existsSync(appDir + '/aot/index.html')) {
run = run.then((ok) => ok && runProtractorAoT(appDir, outputFile));
}
return run;
@ -311,7 +311,7 @@ function reportStatus(status, outputFile) {
IGNORED_EXAMPLES.filter(example => !fixmeIvyExamples.find(ex => ex.startsWith(example)))
.forEach(function(val) { log.push(' ' + val); });
if (argv.ivy) {
if (!argv.viewengine) {
log.push('');
log.push('Suites ignored due to breakage with Ivy:');
fixmeIvyExamples.forEach(function(val) { log.push(' ' + val); });

View File

@ -20,7 +20,6 @@
]
},
"angularCompilerOptions": {
"enableIvy": false,
"fullTemplateTypeCheck": true,
"strictInjectionParameters": true
}

View File

@ -1,33 +0,0 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "./out-tsc/app",
"types": []
},
"files": [
"src/main.ts",
"src/polyfills.ts"
],
"include": [
"src/**/*.d.ts"
],
"exclude": [
"src/test.ts",
"src/**/*.spec.ts",
"src/**/*-specs.ts",
"src/**/*.avoid.ts",
"src/**/*.0.ts",
"src/**/*.1.ts",
"src/**/*.1b.ts",
"src/**/*.2.ts",
"src/**/*.3.ts",
"src/**/*.4.ts",
"src/**/*.5.ts",
"src/**/*.6.ts",
"src/**/*.7.ts",
"src/**/testing"
],
"angularCompilerOptions": {
"enableIvy": true
}
}

View File

@ -0,0 +1,27 @@
{
"compileOnSave": false,
"compilerOptions": {
"baseUrl": "./",
"outDir": "./dist/out-tsc",
"sourceMap": true,
"declaration": false,
"downlevelIteration": true,
"experimentalDecorators": true,
"module": "esnext",
"moduleResolution": "node",
"importHelpers": true,
"target": "es2015",
"typeRoots": [
"node_modules/@types"
],
"lib": [
"es2018",
"dom"
]
},
"angularCompilerOptions": {
"enableIvy": false,
"fullTemplateTypeCheck": true,
"strictInjectionParameters": true
}
}

View File

@ -5,7 +5,7 @@ import uglify from 'rollup-plugin-uglify'
//paths are relative to the execution path
export default {
input: 'app/main.js',
input: 'app/main-aot.js',
output: {
file: 'aot/dist/build.js', // output a single application bundle
format: 'iife',
@ -13,7 +13,7 @@ export default {
sourcemapFile: 'aot/dist/build.js.map'
},
plugins: [
nodeResolve({ jsnext: true, module: true }),
nodeResolve({jsnext: true, module: true}),
commonjs({
include: ['node_modules/rxjs/**']
}),

View File

@ -7,24 +7,23 @@
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"lib": [
"es2018",
"es2015",
"dom"
],
"removeComments": false,
"noImplicitAny": true,
"skipLibCheck": true,
"suppressImplicitAnyIndexErrors": true,
"importHelpers": true,
"typeRoots": [
"node_modules/@types"
]
},
"files": [
"app/app.module.ts",
"app/main.ts"
"app/main-aot.ts"
],
"angularCompilerOptions": {
"skipMetadataEmit": true,
"enableIvy": true
"enableIvy": false,
"skipMetadataEmit": true
}
}