mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
build: ship esm bundle (#3443)
* build: ship esm bundle * Now ships a Flat / ESM bundle (similar as for Angular 4+ releases) * In future PRs we will remove the single ES-files and can just link to the ES bundle (as in angular/angular). * Use template strings for diagnostic
This commit is contained in:
committed by
mmalerba
parent
f526c9de87
commit
b810e11fa4
@@ -41,6 +41,7 @@
|
||||
"@angular/platform-browser-dynamic": "^2.3.0",
|
||||
"@angular/platform-server": "^2.3.0",
|
||||
"@angular/router": "^3.3.0",
|
||||
"@types/chalk": "^0.4.31",
|
||||
"@types/fs-extra": "0.0.37",
|
||||
"@types/glob": "^5.0.30",
|
||||
"@types/gulp": "^3.8.32",
|
||||
@@ -54,6 +55,7 @@
|
||||
"autoprefixer": "^6.7.6",
|
||||
"axe-core": "^2.1.7",
|
||||
"axe-webdriverjs": "^0.5.0",
|
||||
"chalk": "^1.1.3",
|
||||
"conventional-changelog": "^1.1.0",
|
||||
"dgeni": "^0.4.7",
|
||||
"dgeni-packages": "^0.16.5",
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"declaration": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"lib": ["es6", "es2015", "dom"],
|
||||
"module": "es2015",
|
||||
"moduleResolution": "node",
|
||||
"noEmitOnError": true,
|
||||
"noImplicitAny": true,
|
||||
"outDir": "../../dist/@angular/material",
|
||||
"rootDir": ".",
|
||||
"sourceMap": true,
|
||||
"target": "es5",
|
||||
"inlineSources": true,
|
||||
"stripInternal": false,
|
||||
"typeRoots": [
|
||||
"../../node_modules/@types/!(node)"
|
||||
]
|
||||
},
|
||||
"exclude": [
|
||||
/* Exclude testing utilities in releases. */
|
||||
"core/testing/",
|
||||
|
||||
"**/*.spec.*",
|
||||
"system-config-spec.ts"
|
||||
],
|
||||
"angularCompilerOptions": {
|
||||
"genDir": "../../dist/@angular/material",
|
||||
"skipTemplateCodegen": true,
|
||||
"debug": true
|
||||
}
|
||||
}
|
||||
@@ -4,19 +4,17 @@
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"lib": ["es6", "es2015", "dom"],
|
||||
"module": "commonjs",
|
||||
"module": "es2015",
|
||||
"moduleResolution": "node",
|
||||
"noEmitOnError": true,
|
||||
"noImplicitAny": true,
|
||||
"outDir": "../../dist/@angular/material",
|
||||
"rootDir": ".",
|
||||
"sourceMap": true,
|
||||
"target": "es5",
|
||||
"target": "es6",
|
||||
"inlineSources": true,
|
||||
"stripInternal": false,
|
||||
"baseUrl": "",
|
||||
"paths": {
|
||||
},
|
||||
"typeRoots": [
|
||||
"../../node_modules/@types/!(node)"
|
||||
],
|
||||
|
||||
@@ -12,7 +12,7 @@ task('aot:copy', [':build:devapp:scss', ':build:devapp:assets']);
|
||||
*/
|
||||
task('aot:prepare', sequenceTask(
|
||||
'clean',
|
||||
['aot:copy', 'build:components:release', ':build:components:ngc'])
|
||||
['aot:copy', 'build:components', ':build:components:ngc'])
|
||||
);
|
||||
|
||||
/** Builds the demo-app with the Angular compiler to verify that all components work. */
|
||||
|
||||
+113
-102
@@ -1,32 +1,96 @@
|
||||
import {task, watch, src, dest} from 'gulp';
|
||||
import {ScriptTarget, ModuleKind} from 'typescript';
|
||||
import * as path from 'path';
|
||||
|
||||
import {
|
||||
DIST_COMPONENTS_ROOT, PROJECT_ROOT, COMPONENTS_DIR, HTML_MINIFIER_OPTIONS, LICENSE_BANNER
|
||||
} from '../constants';
|
||||
import {
|
||||
sassBuildTask, tsBuildTask, execNodeTask, copyTask, sequenceTask,
|
||||
sassBuildTask, tsBuildTask, execNodeTask, sequenceTask,
|
||||
triggerLivereload
|
||||
} from '../util/task_helpers';
|
||||
|
||||
// No typings for these.
|
||||
// There are no type definitions available for these imports.
|
||||
const inlineResources = require('../../../scripts/release/inline-resources');
|
||||
const gulpRollup = require('gulp-better-rollup');
|
||||
const gulpMinifyCss = require('gulp-clean-css');
|
||||
const gulpMinifyHtml = require('gulp-htmlmin');
|
||||
const gulpIf = require('gulp-if');
|
||||
|
||||
/** Path to tsconfig file for the components. */
|
||||
const tsconfigPath = path.join(COMPONENTS_DIR, 'tsconfig.json');
|
||||
|
||||
// NOTE: there are two build "modes" in this file, based on which tsconfig is used.
|
||||
// When `tsconfig.json` is used, we are outputting ES6 modules and a UMD bundle. This is used
|
||||
// for serving and for release.
|
||||
//
|
||||
// When `tsconfig-spec.json` is used, we are outputting CommonJS modules. This is used
|
||||
// for unit tests (karma).
|
||||
/** Asset files to be added to the components output. */
|
||||
const assetFiles = [
|
||||
path.join(COMPONENTS_DIR, '**/*.html'),
|
||||
path.join(COMPONENTS_DIR, 'package.json'),
|
||||
path.join(PROJECT_ROOT, 'README.md'),
|
||||
path.join(PROJECT_ROOT, 'LICENSE'),
|
||||
];
|
||||
|
||||
/** Path to the tsconfig used for ESM output. */
|
||||
const tsconfigPath = path.relative(PROJECT_ROOT, path.join(COMPONENTS_DIR, 'tsconfig-srcs.json'));
|
||||
/** Builds components to UMD bundle. */
|
||||
task('build:components', [':build:components:bundle:umd']);
|
||||
|
||||
/** Builds components for Angular Material releases */
|
||||
task(':build:components:release', sequenceTask(
|
||||
':build:components:bundle:umd',
|
||||
':build:components:bundle:esm',
|
||||
':build:components:ngc'
|
||||
));
|
||||
|
||||
/** Builds components typescript in ES5, ES6 target. For specs Karma needs CJS output. */
|
||||
task(':build:components:ts:es5', tsBuildTask(tsconfigPath, { target: ScriptTarget.ES5 }));
|
||||
task(':build:components:ts:es6', tsBuildTask(tsconfigPath, { target: ScriptTarget.ES6 }));
|
||||
task(':build:components:ts:spec', tsBuildTask(tsconfigPath, {
|
||||
target: ScriptTarget.ES5, module: ModuleKind.CommonJS
|
||||
}));
|
||||
|
||||
/** Tasks to create a UMD or ES bundle */
|
||||
task(':build:components:bundle:umd', sequenceTask(
|
||||
':build:components:ts:es5', ':build:components:inline', ':build:components:rollup:umd'
|
||||
));
|
||||
|
||||
task(':build:components:bundle:esm', sequenceTask(
|
||||
':build:components:ts:es6', ':build:components:inline', ':build:components:rollup:esm'
|
||||
));
|
||||
|
||||
/** Copies all component assets to the build output. */
|
||||
task(':build:components:assets', () => {
|
||||
return src(assetFiles)
|
||||
.pipe(gulpIf(/.html$/, gulpMinifyHtml(HTML_MINIFIER_OPTIONS)))
|
||||
.pipe(dest(DIST_COMPONENTS_ROOT));
|
||||
});
|
||||
|
||||
/** Compiles the components SCSS into minified CSS. */
|
||||
task(':build:components:scss', sassBuildTask(DIST_COMPONENTS_ROOT, COMPONENTS_DIR, true));
|
||||
|
||||
/** Builds a ES6 bundle for all components. */
|
||||
task(':build:components:rollup:esm', () => {
|
||||
return src(path.join(DIST_COMPONENTS_ROOT, 'index.js'))
|
||||
.pipe(createRollupBundle('es', 'material.js'))
|
||||
.pipe(dest(path.join(DIST_COMPONENTS_ROOT, 'bundles')));
|
||||
});
|
||||
|
||||
/** Builds a UMD bundle (ES5) for all components. */
|
||||
task(':build:components:rollup:umd', () => {
|
||||
return src(path.join(DIST_COMPONENTS_ROOT, 'index.js'))
|
||||
.pipe(createRollupBundle('umd', 'material.umd.js'))
|
||||
.pipe(dest(path.join(DIST_COMPONENTS_ROOT, 'bundles')));
|
||||
});
|
||||
|
||||
|
||||
/** Builds components with resources (html, css) inlined into the built JS. */
|
||||
task(':build:components:inline', sequenceTask(
|
||||
[':build:components:scss', ':build:components:assets'],
|
||||
':inline-resources',
|
||||
));
|
||||
|
||||
/** Inlines resources (html, css) into the JS output. */
|
||||
task(':inline-resources', () => inlineResources(DIST_COMPONENTS_ROOT));
|
||||
|
||||
/** Generates metadata.json files for all of the components. */
|
||||
task(':build:components:ngc', ['build:components'], execNodeTask(
|
||||
'@angular/compiler-cli', 'ngc', ['-p', tsconfigPath]
|
||||
));
|
||||
|
||||
/** [Watch task] Rebuilds (ESM output) whenever ts, scss, or html sources change. */
|
||||
task(':watch:components', () => {
|
||||
@@ -35,105 +99,52 @@ task(':watch:components', () => {
|
||||
watch(path.join(COMPONENTS_DIR, '**/*.html'), ['build:components', triggerLivereload]);
|
||||
});
|
||||
|
||||
const ROLLUP_GLOBALS = {
|
||||
// Angular dependencies
|
||||
'@angular/core': 'ng.core',
|
||||
'@angular/common': 'ng.common',
|
||||
'@angular/forms': 'ng.forms',
|
||||
'@angular/http': 'ng.http',
|
||||
'@angular/platform-browser': 'ng.platformBrowser',
|
||||
'@angular/platform-browser-dynamic': 'ng.platformBrowserDynamic',
|
||||
|
||||
/** Builds component typescript only (ESM output). */
|
||||
task(':build:components:ts', tsBuildTask(path.join(COMPONENTS_DIR, 'tsconfig-srcs.json')));
|
||||
// Rxjs dependencies
|
||||
'rxjs/Subject': 'Rx',
|
||||
'rxjs/add/observable/fromEvent': 'Rx.Observable',
|
||||
'rxjs/add/observable/forkJoin': 'Rx.Observable',
|
||||
'rxjs/add/observable/of': 'Rx.Observable',
|
||||
'rxjs/add/observable/merge': 'Rx.Observable',
|
||||
'rxjs/add/observable/throw': 'Rx.Observable',
|
||||
'rxjs/add/operator/auditTime': 'Rx.Observable.prototype',
|
||||
'rxjs/add/operator/toPromise': 'Rx.Observable.prototype',
|
||||
'rxjs/add/operator/map': 'Rx.Observable.prototype',
|
||||
'rxjs/add/operator/filter': 'Rx.Observable.prototype',
|
||||
'rxjs/add/operator/do': 'Rx.Observable.prototype',
|
||||
'rxjs/add/operator/share': 'Rx.Observable.prototype',
|
||||
'rxjs/add/operator/finally': 'Rx.Observable.prototype',
|
||||
'rxjs/add/operator/catch': 'Rx.Observable.prototype',
|
||||
'rxjs/add/operator/first': 'Rx.Observable.prototype',
|
||||
'rxjs/add/operator/startWith': 'Rx.Observable.prototype',
|
||||
'rxjs/add/operator/switchMap': 'Rx.Observable.prototype',
|
||||
'rxjs/Observable': 'Rx'
|
||||
};
|
||||
|
||||
/** Builds components typescript for tests (CJS output). */
|
||||
task(':build:components:spec', tsBuildTask(COMPONENTS_DIR));
|
||||
|
||||
/** Copies assets (html, markdown) to build output. */
|
||||
task(':build:components:assets', copyTask([
|
||||
path.join(COMPONENTS_DIR, '**/*.!(ts|spec.ts)'),
|
||||
path.join(PROJECT_ROOT, 'README.md'),
|
||||
path.join(PROJECT_ROOT, 'LICENSE'),
|
||||
], DIST_COMPONENTS_ROOT));
|
||||
|
||||
/** Minifies the HTML and CSS assets in the distribution folder. */
|
||||
task(':build:components:assets:minify', () => {
|
||||
return src('**/*.+(html|css)', { cwd: DIST_COMPONENTS_ROOT})
|
||||
.pipe(gulpIf(/.css$/, gulpMinifyCss(), gulpMinifyHtml(HTML_MINIFIER_OPTIONS)))
|
||||
.pipe(dest(DIST_COMPONENTS_ROOT));
|
||||
});
|
||||
|
||||
/** Builds scss into css. */
|
||||
task(':build:components:scss', sassBuildTask(DIST_COMPONENTS_ROOT, COMPONENTS_DIR));
|
||||
|
||||
/** Builds the UMD bundle for all of Angular Material. */
|
||||
task(':build:components:rollup', () => {
|
||||
const globals: {[name: string]: string} = {
|
||||
// Angular dependencies
|
||||
'@angular/core': 'ng.core',
|
||||
'@angular/common': 'ng.common',
|
||||
'@angular/forms': 'ng.forms',
|
||||
'@angular/http': 'ng.http',
|
||||
'@angular/platform-browser': 'ng.platformBrowser',
|
||||
'@angular/platform-browser-dynamic': 'ng.platformBrowserDynamic',
|
||||
|
||||
// Rxjs dependencies
|
||||
'rxjs/Subject': 'Rx',
|
||||
'rxjs/add/observable/fromEvent': 'Rx.Observable',
|
||||
'rxjs/add/observable/forkJoin': 'Rx.Observable',
|
||||
'rxjs/add/observable/of': 'Rx.Observable',
|
||||
'rxjs/add/observable/merge': 'Rx.Observable',
|
||||
'rxjs/add/observable/throw': 'Rx.Observable',
|
||||
'rxjs/add/operator/auditTime': 'Rx.Observable.prototype',
|
||||
'rxjs/add/operator/toPromise': 'Rx.Observable.prototype',
|
||||
'rxjs/add/operator/map': 'Rx.Observable.prototype',
|
||||
'rxjs/add/operator/filter': 'Rx.Observable.prototype',
|
||||
'rxjs/add/operator/do': 'Rx.Observable.prototype',
|
||||
'rxjs/add/operator/share': 'Rx.Observable.prototype',
|
||||
'rxjs/add/operator/finally': 'Rx.Observable.prototype',
|
||||
'rxjs/add/operator/catch': 'Rx.Observable.prototype',
|
||||
'rxjs/add/operator/first': 'Rx.Observable.prototype',
|
||||
'rxjs/add/operator/startWith': 'Rx.Observable.prototype',
|
||||
'rxjs/add/operator/switchMap': 'Rx.Observable.prototype',
|
||||
'rxjs/Observable': 'Rx'
|
||||
};
|
||||
|
||||
const rollupOptions = {
|
||||
/** Creates a rollup bundles of the Material components.*/
|
||||
function createRollupBundle(format: string, outFile: string) {
|
||||
let rollupOptions = {
|
||||
context: 'this',
|
||||
external: Object.keys(globals)
|
||||
external: Object.keys(ROLLUP_GLOBALS)
|
||||
};
|
||||
|
||||
const rollupGenerateOptions = {
|
||||
let rollupGenerateOptions = {
|
||||
// Keep the moduleId empty because we don't want to force developers to a specific moduleId.
|
||||
moduleId: '',
|
||||
moduleName: 'ng.material',
|
||||
format: 'umd',
|
||||
globals,
|
||||
banner: LICENSE_BANNER,
|
||||
dest: 'material.umd.js'
|
||||
format: format,
|
||||
dest: outFile,
|
||||
globals: ROLLUP_GLOBALS,
|
||||
};
|
||||
|
||||
return src(path.join(DIST_COMPONENTS_ROOT, 'index.js'))
|
||||
.pipe(gulpRollup(rollupOptions, rollupGenerateOptions))
|
||||
.pipe(dest(path.join(DIST_COMPONENTS_ROOT, 'bundles')));
|
||||
});
|
||||
|
||||
/** Builds components with resources (html, css) inlined into the built JS (ESM output). */
|
||||
task(':build:components:inline', sequenceTask(
|
||||
[':build:components:ts', ':build:components:scss', ':build:components:assets'],
|
||||
':inline-resources',
|
||||
));
|
||||
|
||||
/** Builds components with minified HTML and CSS inlined into the built JS. */
|
||||
task(':build:components:inline:release', sequenceTask(
|
||||
[':build:components:ts', ':build:components:scss', ':build:components:assets'],
|
||||
':build:components:assets:minify',
|
||||
':inline-resources'
|
||||
));
|
||||
|
||||
/** Inlines resources (html, css) into the JS output (for either ESM or CJS output). */
|
||||
task(':inline-resources', () => inlineResources(DIST_COMPONENTS_ROOT));
|
||||
|
||||
/** Builds components to ESM output and UMD bundle. */
|
||||
task('build:components', sequenceTask(':build:components:inline', ':build:components:rollup'));
|
||||
task('build:components:release', sequenceTask(
|
||||
':build:components:inline:release', ':build:components:rollup'
|
||||
));
|
||||
|
||||
/** Generates metadata.json files for all of the components. */
|
||||
task(':build:components:ngc', ['build:components:release'], execNodeTask(
|
||||
'@angular/compiler-cli', 'ngc', ['-p', tsconfigPath]
|
||||
));
|
||||
return gulpRollup(rollupOptions, rollupGenerateOptions);
|
||||
}
|
||||
|
||||
@@ -17,9 +17,11 @@ task(':watch:devapp', () => {
|
||||
watch(path.join(appDir, '**/*.html'), [':build:devapp:assets', triggerLivereload]);
|
||||
});
|
||||
|
||||
/** Path to the demo-app tsconfig file. */
|
||||
const tsconfigPath = path.join(appDir, 'tsconfig.json');
|
||||
|
||||
task(':build:devapp:vendor', vendorTask());
|
||||
task(':build:devapp:ts', tsBuildTask(appDir));
|
||||
task(':build:devapp:ts', tsBuildTask(tsconfigPath));
|
||||
task(':build:devapp:scss', sassBuildTask(outDir, appDir));
|
||||
task(':build:devapp:assets', copyTask(appDir, outDir));
|
||||
task('build:devapp', buildAppTask('devapp'));
|
||||
|
||||
@@ -3,7 +3,7 @@ import {Dgeni} from 'dgeni';
|
||||
import * as path from 'path';
|
||||
import {HTML_MINIFIER_OPTIONS} from '../constants';
|
||||
|
||||
// Node packages that lack of types.
|
||||
// There are no type definitions available for these imports.
|
||||
const markdown = require('gulp-markdown');
|
||||
const transform = require('gulp-transform');
|
||||
const highlight = require('gulp-highlight-files');
|
||||
|
||||
@@ -14,6 +14,8 @@ const appDir = path.join(SOURCE_ROOT, 'e2e-app');
|
||||
const outDir = DIST_ROOT;
|
||||
const PROTRACTOR_CONFIG_PATH = path.join(PROJECT_ROOT, 'test/protractor.conf.js');
|
||||
|
||||
const tsconfigPath = path.join(appDir, 'tsconfig.json');
|
||||
|
||||
task(':watch:e2eapp', () => {
|
||||
watch(path.join(appDir, '**/*.ts'), [':build:e2eapp:ts']);
|
||||
watch(path.join(appDir, '**/*.html'), [':build:e2eapp:assets']);
|
||||
@@ -23,7 +25,7 @@ task(':watch:e2eapp', () => {
|
||||
task(':build:e2eapp:vendor', vendorTask());
|
||||
|
||||
/** Builds e2e app ts to js. */
|
||||
task(':build:e2eapp:ts', tsBuildTask(appDir));
|
||||
task(':build:e2eapp:ts', tsBuildTask(tsconfigPath));
|
||||
|
||||
/** Copies e2e app assets (html, css) to build output. */
|
||||
task(':build:e2eapp:assets', copyTask(appDir, outDir));
|
||||
|
||||
@@ -6,7 +6,7 @@ import {spawnSync} from 'child_process';
|
||||
import {isTravisPushBuild} from '../util/travis-ci';
|
||||
import {openFirebaseDashboardDatabase} from '../util/firebase';
|
||||
|
||||
// Those imports lack types.
|
||||
// There are no type definitions available for these imports.
|
||||
const uglifyJs = require('uglify-js');
|
||||
|
||||
const BUNDLE_PATH = join(DIST_COMPONENTS_ROOT, 'bundles', 'material.umd.js');
|
||||
|
||||
@@ -19,7 +19,7 @@ task('build:release', function(done: () => void) {
|
||||
// Synchronously run those tasks.
|
||||
gulpRunSequence(
|
||||
'clean',
|
||||
':build:components:ngc',
|
||||
':build:components:release',
|
||||
':build:release:clean-spec',
|
||||
done
|
||||
);
|
||||
|
||||
@@ -29,7 +29,7 @@ gulp.task(':test:deps', sequenceTask(
|
||||
':build:test:vendor',
|
||||
':build:components:assets',
|
||||
':build:components:scss',
|
||||
':build:components:spec',
|
||||
':build:components:ts:spec',
|
||||
]
|
||||
));
|
||||
|
||||
@@ -84,7 +84,7 @@ gulp.task('test', [':test:deps'], () => {
|
||||
server.on('browser_register', runTests);
|
||||
|
||||
// Watch for file changes, rebuild and run the tests.
|
||||
gulp.watch(patternRoot + '.ts', () => runSequence(':build:components:spec', runTests));
|
||||
gulp.watch(patternRoot + '.ts', () => runSequence(':build:components:ts:spec', runTests));
|
||||
gulp.watch(patternRoot + '.scss', () => runSequence(':build:components:scss', runTests));
|
||||
gulp.watch(patternRoot + '.html', () => runSequence(':build:components:assets', runTests));
|
||||
});
|
||||
|
||||
@@ -3,19 +3,21 @@ import * as fs from 'fs';
|
||||
import * as gulp from 'gulp';
|
||||
import * as path from 'path';
|
||||
import {NPM_VENDOR_FILES, PROJECT_ROOT, DIST_ROOT} from '../constants';
|
||||
import {CompilerOptions} from 'typescript';
|
||||
import {compileProject} from './ts-compiler';
|
||||
|
||||
|
||||
/** Those imports lack typings. */
|
||||
/* Those imports lack typings. */
|
||||
const gulpClean = require('gulp-clean');
|
||||
const gulpMerge = require('merge2');
|
||||
const gulpRunSequence = require('run-sequence');
|
||||
const gulpSass = require('gulp-sass');
|
||||
const gulpSourcemaps = require('gulp-sourcemaps');
|
||||
const gulpConnect = require('gulp-connect');
|
||||
const gulpIf = require('gulp-if');
|
||||
const gulpCleanCss = require('gulp-clean-css');
|
||||
|
||||
const resolveBin = require('resolve-bin');
|
||||
|
||||
|
||||
|
||||
/** If the string passed in is a glob, returns it, otherwise append '**\/*' to it. */
|
||||
function _globify(maybeGlob: string, suffix = '**/*') {
|
||||
if (maybeGlob.indexOf('*') != -1) {
|
||||
@@ -32,17 +34,20 @@ function _globify(maybeGlob: string, suffix = '**/*') {
|
||||
|
||||
|
||||
/** Creates a task that runs the TypeScript compiler */
|
||||
export function tsBuildTask(tsConfigPath: string) {
|
||||
return execNodeTask('typescript', 'tsc', ['-p', tsConfigPath]);
|
||||
export function tsBuildTask(tsConfigPath: string, extraOptions?: CompilerOptions) {
|
||||
return () => {
|
||||
compileProject(tsConfigPath, extraOptions);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/** Create a SASS Build Task. */
|
||||
export function sassBuildTask(dest: string, root: string) {
|
||||
export function sassBuildTask(dest: string, root: string, minify = false) {
|
||||
return () => {
|
||||
return gulp.src(_globify(root, '**/*.scss'))
|
||||
.pipe(gulpSourcemaps.init())
|
||||
.pipe(gulpSourcemaps.init({ loadMaps: true }))
|
||||
.pipe(gulpSass().on('error', gulpSass.logError))
|
||||
.pipe(gulpIf(minify, gulpCleanCss()))
|
||||
.pipe(gulpSourcemaps.write('.'))
|
||||
.pipe(gulp.dest(dest));
|
||||
};
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
import * as ts from 'typescript';
|
||||
import * as path from 'path';
|
||||
import * as chalk from 'chalk';
|
||||
|
||||
/** Compiles a TypeScript project with possible extra options. */
|
||||
export function compileProject(project: string, options: ts.CompilerOptions) {
|
||||
let parsed = parseProjectConfig(project, options);
|
||||
let program = ts.createProgram(parsed.fileNames, parsed.options);
|
||||
|
||||
// Report any invalid TypeScript options for the project.
|
||||
checkDiagnostics(program.getOptionsDiagnostics());
|
||||
|
||||
let emitResult = program.emit();
|
||||
|
||||
checkDiagnostics(emitResult.diagnostics);
|
||||
}
|
||||
|
||||
/** Parses a TypeScript project configuration. */
|
||||
function parseProjectConfig(project: string, options: ts.CompilerOptions) {
|
||||
let config = ts.readConfigFile(project, ts.sys.readFile).config;
|
||||
let basePath = path.dirname(project);
|
||||
|
||||
let host = {
|
||||
useCaseSensitiveFileNames: true,
|
||||
fileExists: ts.sys.fileExists,
|
||||
readDirectory: ts.sys.readDirectory,
|
||||
readFile: ts.sys.readFile
|
||||
};
|
||||
|
||||
return ts.parseJsonConfigFileContent(config, host, basePath, options);
|
||||
}
|
||||
|
||||
/** Formats the TypeScript diagnostics into a error string. */
|
||||
export function formatDiagnostics(diagnostics: ts.Diagnostic[]): string {
|
||||
return diagnostics.map(diagnostic => {
|
||||
let res = ts.DiagnosticCategory[diagnostic.category];
|
||||
|
||||
if (diagnostic.file) {
|
||||
let {line, character} = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start);
|
||||
|
||||
res += ` at ${diagnostic.file.fileName}(${line + 1},${character + 1}):`;
|
||||
}
|
||||
res += ` ${ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n')}`;
|
||||
|
||||
return res;
|
||||
}).join('\n');
|
||||
}
|
||||
|
||||
/** Checks diagnostics and throws errors if present. */
|
||||
export function checkDiagnostics(diagnostics: ts.Diagnostic[]) {
|
||||
if (diagnostics && diagnostics.length && diagnostics[0]) {
|
||||
console.error(formatDiagnostics(diagnostics));
|
||||
console.error(chalk.red('TypeScript compilation failed. Exiting process.'));
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user