From fb5520cebf76efe88a8bde5e6d71cff246e58144 Mon Sep 17 00:00:00 2001 From: Paul Gschwendtner Date: Tue, 30 May 2017 18:22:18 +0200 Subject: [PATCH] build: move server rendering to dist (#4822) * build: move server rendering to dist * Verifying that Material works with `platform-server` now happens in the `dist/` folder (instead of the src/ folder) * Adds a gulp task to build the universal application. In the future serving the app will be also part of this * Address comments --- scripts/ci/build-and-test.sh | 2 +- scripts/ci/prerender.sh | 23 ------------ src/universal-app/main.ts | 1 + src/universal-app/prerender.ts | 7 ++-- src/universal-app/tsconfig-build.json | 29 +++++++++++++++ src/universal-app/tsconfig-ngc.json | 23 ------------ src/universal-app/tsconfig-prerender.json | 28 ++++++++++----- tools/gulp/gulpfile.ts | 1 + tools/gulp/tasks/ci.ts | 3 ++ tools/gulp/tasks/universal.ts | 44 +++++++++++++++++++++++ tools/gulp/util/task_helpers.ts | 4 +++ 11 files changed, 106 insertions(+), 59 deletions(-) delete mode 100755 scripts/ci/prerender.sh create mode 100644 src/universal-app/main.ts create mode 100644 src/universal-app/tsconfig-build.json delete mode 100644 src/universal-app/tsconfig-ngc.json create mode 100644 tools/gulp/tasks/universal.ts diff --git a/scripts/ci/build-and-test.sh b/scripts/ci/build-and-test.sh index 4de825b5051..229a702f4a5 100755 --- a/scripts/ci/build-and-test.sh +++ b/scripts/ci/build-and-test.sh @@ -42,7 +42,7 @@ elif is_closure_compiler; then elif is_unit; then $(npm bin)/gulp ci:test elif is_prerender; then - ./scripts/ci/prerender.sh + $(npm bin)/gulp ci:prerender fi # Upload coverage results if those are present. diff --git a/scripts/ci/prerender.sh b/scripts/ci/prerender.sh deleted file mode 100755 index 40ae3167000..00000000000 --- a/scripts/ci/prerender.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/env bash - -### Pre-renders the app under src/universal-app with platform-server and dumps the -### output to stdout. - -# Go to the project root directory -cd $(dirname $0)/../.. - -# Build the @angular/material package and copy it into node_modules. -# This is a workaround for https://github.com/angular/angular/issues/12249 -rm -rf ./node_modules/@angular/material -gulp material:build-release -cp -r ./dist/releases/material ./node_modules/@angular/ - -# Compile the kitchen sink app (the generated ngfactories are consumed by the prerender script) -$(npm bin)/ngc -p src/universal-app/tsconfig-ngc.json - -# Run the prerender script. -# This does not use ts-node because some of the generated ngfactory.ts files are written into a -# directory called "node_modules"; ts-node intentionally will not treat any file inside of a -# "node_modules" directory as TypeScript (with the opinion that node_modules should only contain JS) -$(npm bin)/tsc -p src/universal-app/tsconfig-prerender.json -node ./src/universal-app/dist/prerender.js diff --git a/src/universal-app/main.ts b/src/universal-app/main.ts new file mode 100644 index 00000000000..a605538f8e9 --- /dev/null +++ b/src/universal-app/main.ts @@ -0,0 +1 @@ +export * from './kitchen-sink/kitchen-sink'; diff --git a/src/universal-app/prerender.ts b/src/universal-app/prerender.ts index f3aceac66d0..9b347978c1a 100644 --- a/src/universal-app/prerender.ts +++ b/src/universal-app/prerender.ts @@ -1,15 +1,16 @@ import 'reflect-metadata'; -require('zone.js/dist/zone-node.js'); +import 'zone.js'; import {enableProdMode} from '@angular/core'; import {renderModuleFactory} from '@angular/platform-server'; -import {KitchenSinkServerModuleNgFactory} from './dist/aot/kitchen-sink/kitchen-sink.ngfactory'; +import {join} from 'path'; import {readFileSync} from 'fs-extra'; +import {KitchenSinkServerModuleNgFactory} from './kitchen-sink/kitchen-sink.ngfactory'; enableProdMode(); const result = renderModuleFactory(KitchenSinkServerModuleNgFactory, { - document: readFileSync('src/universal-app/index.html', 'utf-8') + document: readFileSync(join(__dirname, 'index.html'), 'utf-8') }); result.then(html => console.log(html)); diff --git a/src/universal-app/tsconfig-build.json b/src/universal-app/tsconfig-build.json new file mode 100644 index 00000000000..0e9e03a620c --- /dev/null +++ b/src/universal-app/tsconfig-build.json @@ -0,0 +1,29 @@ +// TypeScript config file that is used to compile the universal-app. +{ + "compilerOptions": { + "declaration": true, + "stripInternal": false, + "experimentalDecorators": true, + "module": "commonjs", + "moduleResolution": "node", + "outDir": "../../dist/packages/universal-app", + "rootDir": ".", + "sourceMap": true, + "target": "es2015", + "lib": ["es2015", "dom"], + "skipLibCheck": true, + "types": [], + "baseUrl": ".", + "paths": { + "@angular/material": ["./material"], + "@angular/cdk": ["./cdk"] + } + }, + "files": [ + "main.ts" + ], + "angularCompilerOptions": { + "annotateForClosureCompiler": true, + "genDir": "../../dist/packages/universal-app" + } +} diff --git a/src/universal-app/tsconfig-ngc.json b/src/universal-app/tsconfig-ngc.json deleted file mode 100644 index df92f94b317..00000000000 --- a/src/universal-app/tsconfig-ngc.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "compilerOptions": { - "module": "es2015", - "moduleResolution": "node", - "target": "es6", - "noImplicitAny": false, - "sourceMap": false, - "experimentalDecorators": true, - "outDir": "dist", - "declaration": true, - "typeRoots": ["node_modules/@types"] - }, - "exclude": [ - "node_modules", - "dist", - "prerender.ts" - ], - "angularCompilerOptions": { - "annotationsAs": "static fields", - "annotateForClosureCompiler": true, - "genDir": "./dist/aot" - } -} diff --git a/src/universal-app/tsconfig-prerender.json b/src/universal-app/tsconfig-prerender.json index 26d012ee682..4dc36103d8c 100644 --- a/src/universal-app/tsconfig-prerender.json +++ b/src/universal-app/tsconfig-prerender.json @@ -1,15 +1,25 @@ +// TypeScript config file that is used to compile the files that prerender the Universal app. { "compilerOptions": { - "lib": ["es2015", "dom"], - "target": "es6", + "declaration": false, + "stripInternal": false, + "experimentalDecorators": true, "module": "commonjs", "moduleResolution": "node", - "outDir": "dist", - "noEmitOnError": true, - "noImplicitAny": true, - "sourceMap": false, - "experimentalDecorators": true, - "types": ["node"] + "outDir": ".", + "rootDir": ".", + "sourceMap": true, + "target": "es2015", + "lib": ["es2015", "dom"], + "skipLibCheck": true, + "types": [], + "baseUrl": ".", + "paths": { + "@angular/material": ["./material"], + "@angular/cdk": ["./cdk"] + } }, - "files": ["prerender.ts"] + "files": [ + "prerender.ts" + ] } diff --git a/tools/gulp/gulpfile.ts b/tools/gulp/gulpfile.ts index f1ddbd2d5ff..7d731d625a7 100644 --- a/tools/gulp/gulpfile.ts +++ b/tools/gulp/gulpfile.ts @@ -19,3 +19,4 @@ import './tasks/aot'; import './tasks/payload'; import './tasks/coverage'; import './tasks/material-release'; +import './tasks/universal'; diff --git a/tools/gulp/tasks/ci.ts b/tools/gulp/tasks/ci.ts index 2eaeb98059f..1ab0914413f 100644 --- a/tools/gulp/tasks/ci.ts +++ b/tools/gulp/tasks/ci.ts @@ -16,3 +16,6 @@ task('ci:payload', ['payload']); /** Task that uploads the coverage results to a firebase database. */ task('ci:coverage', ['coverage:upload']); + +/** Task that verifies if all Material components are working with platform-server.*/ +task('ci:prerender', ['universal:test-prerender']); diff --git a/tools/gulp/tasks/universal.ts b/tools/gulp/tasks/universal.ts new file mode 100644 index 00000000000..9a8428fb9f1 --- /dev/null +++ b/tools/gulp/tasks/universal.ts @@ -0,0 +1,44 @@ +import {task} from 'gulp'; +import {DIST_RELEASES, DIST_ROOT, SOURCE_ROOT} from '../constants'; +import {ngcBuildTask, tsBuildTask, copyTask, sequenceTask, execTask} from '../util/task_helpers'; +import {join} from 'path'; +import {copySync} from 'fs-extra'; + +const appDir = join(SOURCE_ROOT, 'universal-app'); +const outDir = join(DIST_ROOT, 'packages', 'universal-app'); + +/** Path to the universal-app tsconfig files. */ +const tsconfigAppPath = join(appDir, 'tsconfig-build.json'); +const tsconfigPrerenderPath = join(outDir, 'tsconfig-prerender.json'); + +/** Glob that matches all assets that need to copied to the dist. */ +const assetsGlob = join(appDir, '**/*.+(html|css|json)'); + +/** Path to the file that prerenders the universal app using platform-server. */ +const prerenderFile = join(appDir, 'prerender.ts'); + +/** Path to the compiled prerender file. Running this file just dumps the HTML output for now. */ +const prerenderOutFile = join(outDir, 'prerender.js'); + +task('universal:test-prerender', ['universal:build'], execTask('node', [prerenderOutFile])); + +task('universal:build', sequenceTask( + 'clean', + ['material:build-release', 'cdk:build-release'], + 'universal:copy-release', + ['universal:build-app-ts', 'universal:copy-app-assets', 'universal:copy-prerender-source'], + 'universal:build-prerender-ts' +)); + +task('universal:build-app-ts', ngcBuildTask(tsconfigAppPath)); +task('universal:copy-app-assets', copyTask(assetsGlob, outDir)); + +task('universal:build-prerender-ts', tsBuildTask(tsconfigPrerenderPath)); +task('universal:copy-prerender-source', copyTask(prerenderFile, outDir)); + +// As a workaround for https://github.com/angular/angular/issues/12249, we need to +// copy the Material and CDK ESM output inside of the universal-app output. +task('universal:copy-release', () => { + copySync(join(DIST_RELEASES, 'material'), join(outDir, 'material')); + copySync(join(DIST_RELEASES, 'cdk'), join(outDir, 'cdk')); +}); diff --git a/tools/gulp/util/task_helpers.ts b/tools/gulp/util/task_helpers.ts index e88dffd4c17..28a5eba7309 100644 --- a/tools/gulp/util/task_helpers.ts +++ b/tools/gulp/util/task_helpers.ts @@ -37,6 +37,10 @@ export function tsBuildTask(tsConfigPath: string) { return execNodeTask('typescript', 'tsc', ['-p', tsConfigPath]); } +/** Creates a task that runs the Angular compiler CLI. */ +export function ngcBuildTask(tsConfigPath: string) { + return execNodeTask('@angular/compiler-cli', 'ngc', ['-p', tsConfigPath]); +} /** Create a SASS Build Task. */ export function sassBuildTask(dest: string, root: string, minify = false) {