build: dynamic build config for packaging (#4939)

* build: dynamic build config for packaging

* Make discussed changes
This commit is contained in:
Paul Gschwendtner
2017-06-08 20:24:58 +02:00
committed by Andrew Seguin
parent 22e14490d2
commit bae213d5f7
25 changed files with 241 additions and 125 deletions
-44
View File
@@ -1,44 +0,0 @@
import {join} from 'path';
export const MATERIAL_VERSION = require('../../package.json').version;
export const PROJECT_ROOT = join(__dirname, '../..');
export const SOURCE_ROOT = join(PROJECT_ROOT, 'src');
/** Root build output directory */
export const DIST_ROOT = join(PROJECT_ROOT, 'dist');
/** Output subdirectory where all bundles will be written (flat ES modules and UMD) */
export const DIST_BUNDLES = join(DIST_ROOT, 'bundles');
/** Output subdirectory where all library artifacts will be written (compiled JS, CSS, etc.) */
export const DIST_MATERIAL = join(DIST_ROOT, 'packages', 'material');
export const DIST_CDK = join(DIST_ROOT, 'packages', 'cdk');
export const DIST_DEMOAPP = join(DIST_ROOT, 'packages', 'demo-app');
export const DIST_E2EAPP = join(DIST_ROOT, 'packages', 'e2e-app');
export const DIST_EXAMPLES = join(DIST_ROOT, 'packages', 'examples');
export const DIST_RELEASES = join(DIST_ROOT, 'releases');
export const COVERAGE_RESULT_FILE = join(DIST_ROOT, 'coverage', 'coverage-summary.json');
export const HTML_MINIFIER_OPTIONS = {
collapseWhitespace: true,
removeComments: true,
caseSensitive: true,
removeAttributeQuotes: false
};
/** Packages that will be published to NPM by the release task. */
export const RELEASE_PACKAGES = [
'cdk',
'material',
];
export const LICENSE_BANNER = `/**
* @license Angular Material v${MATERIAL_VERSION}
* Copyright (c) 2017 Google, Inc. https://material.angular.io/
* License: MIT
*/`;
export const COMPONENTS_DIR = join(SOURCE_ROOT, 'lib');
+1 -1
View File
@@ -1,6 +1,6 @@
import {createPackageBuildTasks} from './packaging/build-tasks-gulp';
/** Create gulp tasks to build the different packages in the project. */
// Create gulp tasks to build the different packages in the project.
createPackageBuildTasks('cdk');
createPackageBuildTasks('material', ['cdk']);
createPackageBuildTasks('material-examples', ['material']);
+8 -5
View File
@@ -1,24 +1,27 @@
import {join} from 'path';
import {ScriptTarget, ModuleKind} from 'typescript';
import {DIST_BUNDLES} from '../build-config';
import {uglifyJsFile} from './minify-sources';
import {createRollupBundle} from './rollup-helpers';
import {remapSourcemap} from './sourcemap-remap';
import {transpileFile} from './typescript-transpile';
import {buildConfig} from './build-config';
// There are no type definitions available for these imports.
const uglify = require('uglify-js');
const sorcery = require('sorcery');
/** Directory where all bundles will be created in. */
const bundlesDir = join(buildConfig.outputDir, 'bundles');
/** Builds the bundles for the specified package. */
export async function buildPackageBundles(entryFile: string, packageName: string) {
const moduleName = `ng.${packageName}`;
// List of paths to the package bundles.
const fesm2015File = join(DIST_BUNDLES, `${packageName}.js`);
const fesm2014File = join(DIST_BUNDLES, `${packageName}.es5.js`);
const umdFile = join(DIST_BUNDLES, `${packageName}.umd.js`);
const umdMinFile = join(DIST_BUNDLES, `${packageName}.umd.min.js`);
const fesm2015File = join(bundlesDir, `${packageName}.js`);
const fesm2014File = join(bundlesDir, `${packageName}.es5.js`);
const umdFile = join(bundlesDir, `${packageName}.umd.js`);
const umdMinFile = join(bundlesDir, `${packageName}.umd.min.js`);
// Build FESM-2015 bundle file.
await createRollupBundle({
+25
View File
@@ -0,0 +1,25 @@
import {findBuildConfig} from './find-build-config';
export interface BuildConfig {
/** Current version of the project. */
projectVersion: string;
/** Path to the root of the project. */
projectDir: string;
/** Path to the directory where all packages are living. */
packagesDir: string;
/** Path to the directory where the output will be stored. */
outputDir: string;
/** License banner that will be placed inside of every bundle. */
licenseBanner: string;
}
// Search for a build config by walking up the current working directory of the Node process.
const buildConfigPath = findBuildConfig();
if (!buildConfigPath) {
throw 'Material2 Build tools were not able to find a build config. ' +
'Please create a "build-config.js" file in your project.';
}
// Load the config file using a basic CommonJS import.
export const buildConfig = require(buildConfigPath) as BuildConfig;
+13 -8
View File
@@ -1,11 +1,16 @@
import {join} from 'path';
import {DIST_BUNDLES, DIST_ROOT, SOURCE_ROOT, PROJECT_ROOT} from '../build-config';
import {copyFiles} from '../util/copy-files';
import {addPureAnnotationsToFile} from './pure-annotations';
import {updatePackageVersion} from './package-versions';
import {inlinePackageMetadataFiles} from './metadata-inlining';
import {createTypingsReexportFile} from './typings-reexport';
import {createMetadataReexportFile} from './metadata-reexport';
import {buildConfig} from './build-config';
const {packagesDir, outputDir, projectDir} = buildConfig;
/** Directory where all bundles will be created in. */
const bundlesDir = join(outputDir, 'bundles');
/**
* Copies different output files into a folder structure that follows the `angular/angular`
@@ -14,17 +19,17 @@ import {createMetadataReexportFile} from './metadata-reexport';
*/
export function composeRelease(packageName: string) {
// To avoid refactoring of the project the package material will map to the source path `lib/`.
const sourcePath = join(SOURCE_ROOT, packageName === 'material' ? 'lib' : packageName);
const packagePath = join(DIST_ROOT, 'packages', packageName);
const releasePath = join(DIST_ROOT, 'releases', packageName);
const sourcePath = join(packagesDir, packageName === 'material' ? 'lib' : packageName);
const packagePath = join(outputDir, 'packages', packageName);
const releasePath = join(outputDir, 'releases', packageName);
inlinePackageMetadataFiles(packagePath);
copyFiles(packagePath, '**/*.+(d.ts|metadata.json)', join(releasePath, 'typings'));
copyFiles(DIST_BUNDLES, `${packageName}.umd?(.min).js?(.map)`, join(releasePath, 'bundles'));
copyFiles(DIST_BUNDLES, `${packageName}?(.es5).js?(.map)`, join(releasePath, '@angular'));
copyFiles(PROJECT_ROOT, 'LICENSE', releasePath);
copyFiles(SOURCE_ROOT, 'README.md', releasePath);
copyFiles(bundlesDir, `${packageName}.umd?(.min).js?(.map)`, join(releasePath, 'bundles'));
copyFiles(bundlesDir, `${packageName}?(.es5).js?(.map)`, join(releasePath, '@angular'));
copyFiles(projectDir, 'LICENSE', releasePath);
copyFiles(packagesDir, 'README.md', releasePath);
copyFiles(sourcePath, 'package.json', releasePath);
updatePackageVersion(releasePath);
+13 -4
View File
@@ -1,7 +1,7 @@
import {task, watch, src, dest} from 'gulp';
import {join} from 'path';
import {main as tsc} from '@angular/tsc-wrapped';
import {SOURCE_ROOT, DIST_ROOT, HTML_MINIFIER_OPTIONS} from '../build-config';
import {buildConfig} from './build-config';
import {sequenceTask, sassBuildTask, copyTask, triggerLivereload} from '../util/task_helpers';
import {composeRelease} from './build-release';
import {buildPackageBundles} from './build-bundles';
@@ -10,6 +10,15 @@ import {inlineResourcesForDirectory} from './inline-resources';
// There are no type definitions available for these imports.
const htmlmin = require('gulp-htmlmin');
const {packagesDir, outputDir} = buildConfig;
const htmlMinifierOptions = {
collapseWhitespace: true,
removeComments: true,
caseSensitive: true,
removeAttributeQuotes: false
};
/**
* Creates a set of gulp tasks that can build the specified package.
* @param packageName Name of the package. Needs to be similar to the directory name in `src/`.
@@ -17,8 +26,8 @@ const htmlmin = require('gulp-htmlmin');
*/
export function createPackageBuildTasks(packageName: string, requiredPackages: string[] = []) {
// To avoid refactoring of the project the package material will map to the source path `lib/`.
const packageRoot = join(SOURCE_ROOT, packageName === 'material' ? 'lib' : packageName);
const packageOut = join(DIST_ROOT, 'packages', packageName);
const packageRoot = join(packagesDir, packageName === 'material' ? 'lib' : packageName);
const packageOut = join(outputDir, 'packages', packageName);
const tsconfigBuild = join(packageRoot, 'tsconfig-build.json');
const tsconfigTests = join(packageRoot, 'tsconfig-tests.json');
@@ -81,7 +90,7 @@ export function createPackageBuildTasks(packageName: string, requiredPackages: s
task(`${packageName}:assets:scss`, sassBuildTask(packageOut, packageRoot, true));
task(`${packageName}:assets:copy-styles`, copyTask(stylesGlob, packageOut));
task(`${packageName}:assets:html`, () => {
return src(htmlGlob).pipe(htmlmin(HTML_MINIFIER_OPTIONS)).pipe(dest(packageOut));
return src(htmlGlob).pipe(htmlmin(htmlMinifierOptions)).pipe(dest(packageOut));
});
task(`${packageName}:assets:inline`, () => inlineResourcesForDirectory(packageOut));
+22
View File
@@ -0,0 +1,22 @@
import {resolve, dirname, join} from 'path';
import {existsSync} from 'fs';
/** Name of the build config file. */
const BUILD_CONFIG_FILENAME = 'build-config.js';
/** Method that searches for a build config file that will be used for packaging. */
export function findBuildConfig(): string {
let currentDir = process.cwd();
while (!existsSync(resolve(currentDir, BUILD_CONFIG_FILENAME))) {
let parentDir = dirname(currentDir);
if (parentDir === currentDir) {
return null;
}
currentDir = parentDir;
}
return join(currentDir, BUILD_CONFIG_FILENAME);
}
+5 -2
View File
@@ -1,6 +1,9 @@
import {writeFileSync} from 'fs';
import {join} from 'path';
import {MATERIAL_VERSION} from '../build-config';
import {buildConfig} from './build-config';
/** Version of the project that will be used to replace the placeholder. */
const {projectVersion} = buildConfig;
/** Updates the `package.json` file of the specified package. Replaces the version placeholder. */
export function updatePackageVersion(packageDir: string) {
@@ -8,7 +11,7 @@ export function updatePackageVersion(packageDir: string) {
const packageConfig = require(packagePath);
// Replace the `0.0.0-PLACEHOLDER` version name with the version of the root package.json file.
packageConfig.version = packageConfig.version.replace('0.0.0-PLACEHOLDER', MATERIAL_VERSION);
packageConfig.version = packageConfig.version.replace('0.0.0-PLACEHOLDER', projectVersion);
writeFileSync(packagePath, JSON.stringify(packageConfig, null, 2));
}
+2 -2
View File
@@ -1,4 +1,4 @@
import {LICENSE_BANNER} from '../build-config';
import {buildConfig} from './build-config';
// There are no type definitions available for these imports.
const rollup = require('rollup');
@@ -69,7 +69,7 @@ export function createRollupBundle(config: BundleConfig): Promise<any> {
// Keep the moduleId empty because we don't want to force developers to a specific moduleId.
moduleId: '',
moduleName: config.moduleName || 'ng.material',
banner: LICENSE_BANNER,
banner: buildConfig.licenseBanner,
format: config.format,
dest: config.dest,
globals: ROLLUP_GLOBALS,
+2 -2
View File
@@ -1,10 +1,10 @@
import {writeFileSync} from 'fs';
import {LICENSE_BANNER} from '../build-config';
import {buildConfig} from './build-config';
import {join} from 'path';
/** Create a typing file that links to the bundled definitions of NGC. */
export function createTypingsReexportFile(outputDir: string, entryName: string) {
writeFileSync(join(outputDir, `${entryName}.d.ts`),
LICENSE_BANNER + '\nexport * from "./typings/index";'
buildConfig.licenseBanner + '\nexport * from "./typings/index";'
);
}
+13 -4
View File
@@ -1,10 +1,19 @@
import {task} from 'gulp';
import {copySync} from 'fs-extra';
import {DIST_DEMOAPP, DIST_RELEASES} from '../build-config';
import {sequenceTask, execNodeTask} from '../util/task_helpers';
import {join} from 'path';
import {buildConfig} from '../packaging/build-config';
const tsconfigFile = join(DIST_DEMOAPP, 'tsconfig-aot.json');
const {outputDir} = buildConfig;
/** Path to the directory where all releases are living. */
const releasesDir = join(outputDir, 'releases');
/** Path to the demo-app output directory. */
const demoAppOut = join(outputDir, 'packages', 'demo-app');
/** Path to the tsconfig file that builds the AOT files. */
const tsconfigFile = join(demoAppOut, 'tsconfig-aot.json');
/** Builds the demo-app and material. To be able to run NGC, apply the metadata workaround. */
task('aot:deps', sequenceTask(
@@ -16,8 +25,8 @@ task('aot:deps', sequenceTask(
// As a workaround for https://github.com/angular/angular/issues/12249, we need to
// copy the Material and CDK ESM output inside of the demo-app output.
task('aot:copy-release', () => {
copySync(join(DIST_RELEASES, 'material'), join(DIST_DEMOAPP, 'material'));
copySync(join(DIST_RELEASES, 'cdk'), join(DIST_DEMOAPP, 'cdk'));
copySync(join(releasesDir, 'material'), join(demoAppOut, 'material'));
copySync(join(releasesDir, 'cdk'), join(demoAppOut, 'cdk'));
});
/** Build the demo-app and a release to confirm that the library is AOT-compatible. */
+2 -2
View File
@@ -1,7 +1,7 @@
import {task} from 'gulp';
import {DIST_ROOT} from '../build-config';
import {cleanTask} from '../util/task_helpers';
import {buildConfig} from '../packaging/build-config';
/** Deletes the dist/ directory. */
task('clean', cleanTask(DIST_ROOT));
task('clean', cleanTask(buildConfig.outputDir));
+7 -3
View File
@@ -1,12 +1,16 @@
import {task} from 'gulp';
import {join} from 'path';
import {existsSync} from 'fs-extra';
import {COVERAGE_RESULT_FILE} from '../build-config';
import {spawnSync} from 'child_process';
import {isTravisMasterBuild} from '../util/travis-ci';
import {openFirebaseDashboardApp} from '../util/firebase';
import {buildConfig} from '../packaging/build-config';
/** Path to the file that includes all coverage information form Karma. */
const coverageResultFile = join(buildConfig.outputDir, 'coverage/coverage-summary.json');
task('coverage:upload', () => {
if (!existsSync(COVERAGE_RESULT_FILE)) {
if (!existsSync(coverageResultFile)) {
throw new Error('No coverage file has been found!');
}
@@ -14,7 +18,7 @@ task('coverage:upload', () => {
throw new Error('Coverage results will be only uploaded inside of Travis Push builds.');
}
let results = require(COVERAGE_RESULT_FILE)['total'];
let results = require(coverageResultFile)['total'];
// To reduce database payload, the covered lines won't be pushed to the Firebase database.
delete results['linesCovered'];
+16 -8
View File
@@ -1,17 +1,25 @@
import {task, watch} from 'gulp';
import {DIST_ROOT, SOURCE_ROOT, PROJECT_ROOT, DIST_BUNDLES, DIST_MATERIAL} from '../build-config';
import {
sassBuildTask, tsBuildTask, copyTask, buildAppTask, sequenceTask, triggerLivereload,
serverTask
} from '../util/task_helpers';
import {join} from 'path';
import {copyFiles} from '../util/copy-files';
import {buildConfig} from '../packaging/build-config';
// These imports don't have any typings provided.
const firebaseTools = require('firebase-tools');
const appDir = join(SOURCE_ROOT, 'demo-app');
const outDir = join(DIST_ROOT, 'packages', 'demo-app');
const {outputDir, packagesDir, projectDir} = buildConfig;
/** Path to the directory where all bundles live. */
const bundlesDir = join(outputDir, 'bundles');
const appDir = join(packagesDir, 'demo-app');
const outDir = join(outputDir, 'packages', 'demo-app');
/** Path to the output of the Material package. */
const materialOutPath = join(outputDir, 'packages', 'material');
/** Array of vendors that are required to serve the demo-app. */
const appVendors = [
@@ -29,7 +37,7 @@ task(':watch:devapp', () => {
// The themes for the demo-app are built by the demo-app using the SCSS mixins from Material.
// Therefore when the CSS files have been changed the SCSS mixins have been refreshed and
// copied over. Rebuilt the theme CSS using the updated SCSS mixins.
watch(join(DIST_MATERIAL, '**/*.css'), [':build:devapp:scss', triggerLivereload]);
watch(join(materialOutPath, '**/*.css'), [':build:devapp:scss', triggerLivereload]);
});
/** Path to the demo-app tsconfig file. */
@@ -48,9 +56,9 @@ task('serve:devapp', ['build:devapp'], sequenceTask(
/** Task that copies all vendors into the demo-app package. Allows hosting the app on firebase. */
task('stage-deploy:devapp', ['build:devapp'], () => {
copyFiles(join(PROJECT_ROOT, 'node_modules'), vendorGlob, join(outDir, 'node_modules'));
copyFiles(DIST_BUNDLES, '*.+(js|map)', join(outDir, 'dist/bundles'));
copyFiles(DIST_MATERIAL, '**/prebuilt/*.+(css|map)', join(outDir, 'dist/packages/material'));
copyFiles(join(projectDir, 'node_modules'), vendorGlob, join(outDir, 'node_modules'));
copyFiles(bundlesDir, '*.+(js|map)', join(outDir, 'dist/bundles'));
copyFiles(materialOutPath, '**/prebuilt/*.+(css|map)', join(outDir, 'dist/packages/material'));
});
/**
@@ -58,7 +66,7 @@ task('stage-deploy:devapp', ['build:devapp'], () => {
* set for project directory using the Firebase CLI.
*/
task('deploy:devapp', ['stage-deploy:devapp'], () => {
return firebaseTools.deploy({cwd: PROJECT_ROOT, only: 'hosting'})
return firebaseTools.deploy({cwd: projectDir, only: 'hosting'})
// Firebase tools opens a persistent websocket connection and the process will never exit.
.then(() => { console.log('Successfully deployed the demo-app to firebase'); process.exit(0); })
.catch((err: any) => { console.log(err); process.exit(1); });
+14 -4
View File
@@ -1,7 +1,7 @@
import {task, src, dest} from 'gulp';
import {Dgeni} from 'dgeni';
import * as path from 'path';
import {DIST_ROOT, HTML_MINIFIER_OPTIONS, SOURCE_ROOT} from '../build-config';
import {buildConfig} from '../packaging/build-config';
// There are no type definitions available for these imports.
const markdown = require('gulp-markdown');
@@ -13,7 +13,9 @@ const htmlmin = require('gulp-htmlmin');
const hljs = require('highlight.js');
const dom = require('gulp-dom');
const DIST_DOCS = path.join(DIST_ROOT, 'docs');
const {outputDir, packagesDir} = buildConfig;
const DIST_DOCS = path.join(outputDir, 'docs');
// Our docs contain comments of the form `<!-- example(...) -->` which serve as placeholders where
// example code should be inserted. We replace these comments with divs that have a
@@ -48,6 +50,14 @@ const MARKDOWN_TAGS_TO_CLASS_ALIAS = [
'code',
];
// Options for the html-minifier that minifies the generated HTML files.
const htmlMinifierOptions = {
collapseWhitespace: true,
removeComments: true,
caseSensitive: true,
removeAttributeQuotes: false
};
/** Generate all docs content. */
task('docs', [
'markdown-docs',
@@ -105,13 +115,13 @@ task('api-docs', () => {
/** Generates minified html api docs. */
task('minified-api-docs', ['api-docs'], () => {
return src('dist/docs/api/*.html')
.pipe(htmlmin(HTML_MINIFIER_OPTIONS))
.pipe(htmlmin(htmlMinifierOptions))
.pipe(dest('dist/docs/api/'));
});
/** Copies example sources to be used as plunker assets for the docs site. */
task('plunker-example-assets', () => {
src(path.join(SOURCE_ROOT, 'material-examples', '**/*'))
src(path.join(packagesDir, 'material-examples', '**/*'))
.pipe(dest(path.join(DIST_DOCS, 'plunker', 'examples')));
});
+11 -6
View File
@@ -1,16 +1,21 @@
import {task, watch} from 'gulp';
import {join} from 'path';
import {SOURCE_ROOT, DIST_E2EAPP, PROJECT_ROOT, DIST_RELEASES} from '../build-config';
import {ngcBuildTask, copyTask, execNodeTask, sequenceTask, serverTask} from '../util/task_helpers';
import {copySync} from 'fs-extra';
import {buildConfig} from '../packaging/build-config';
// There are no type definitions available for these imports.
const gulpConnect = require('gulp-connect');
const appDir = join(SOURCE_ROOT, 'e2e-app');
const outDir = DIST_E2EAPP;
const {outputDir, packagesDir, projectDir} = buildConfig;
const PROTRACTOR_CONFIG_PATH = join(PROJECT_ROOT, 'test/protractor.conf.js');
/** Path to the directory where all releases are created. */
const releasesDir = join(outputDir, 'releases');
const appDir = join(packagesDir, 'e2e-app');
const outDir = join(outputDir, 'packages', 'e2e-app');
const PROTRACTOR_CONFIG_PATH = join(projectDir, 'test/protractor.conf.js');
const tsconfigPath = join(outDir, 'tsconfig-build.json');
/** Glob that matches all files that need to be copied to the output folder. */
@@ -69,7 +74,7 @@ task('serve:e2eapp:watch', ['serve:e2eapp', 'material:watch', ':watch:e2eapp']);
// As a workaround for https://github.com/angular/angular/issues/12249, we need to
// copy the Material and CDK ESM output inside of the demo-app output.
task('e2e-app:copy-release', () => {
copySync(join(DIST_RELEASES, 'material'), join(outDir, 'material'));
copySync(join(DIST_RELEASES, 'cdk'), join(outDir, 'cdk'));
copySync(join(releasesDir, 'material'), join(outDir, 'material'));
copySync(join(releasesDir, 'cdk'), join(outDir, 'cdk'));
});
+9 -2
View File
@@ -1,6 +1,7 @@
import {task} from 'gulp';
import {execNodeTask} from '../util/task_helpers';
import {DIST_MATERIAL, DIST_CDK} from '../build-config';
import {join} from 'path';
import {buildConfig} from '../packaging/build-config';
/** Glob that matches all SCSS or CSS files that should be linted. */
const stylesGlob = '+(tools|src)/**/*.+(css|scss)';
@@ -10,11 +11,17 @@ const tsLintBaseFlags = [
'-c', 'tslint.json', '+(src|e2e|tools)/**/*.ts', '--exclude', '**/node_modules/**/*'
];
/** Path to the output of the Material package. */
const materialOutPath = join(buildConfig.outputDir, 'packages', 'material');
/** Path to the output of the CDK package. */
const cdkOutPath = join(buildConfig.outputDir, 'packages', 'cdk');
task('lint', ['tslint', 'stylelint', 'madge']);
/** Task that runs madge to detect circular dependencies. */
task('madge', ['material:clean-build'], execNodeTask(
'madge', ['--circular', DIST_MATERIAL, DIST_CDK])
'madge', ['--circular', materialOutPath, cdkOutPath])
);
/** Task to lint Angular Material's scss stylesheets. */
+12 -5
View File
@@ -3,22 +3,29 @@ import {join} from 'path';
import {writeFileSync} from 'fs';
import {Bundler} from 'scss-bundle';
import {sequenceTask} from '../util/task_helpers';
import {COMPONENTS_DIR, DIST_MATERIAL, DIST_RELEASES} from '../build-config';
import {composeRelease} from '../packaging/build-release';
import {buildConfig} from '../packaging/build-config';
// There are no type definitions available for these imports.
const gulpRename = require('gulp-rename');
const {packagesDir, outputDir} = buildConfig;
/** Path to the directory where all releases are created. */
const releasesDir = join(outputDir, 'releases');
// Path to the sources of the Material package.
const materialPath = join(packagesDir, 'lib');
// Path to the release output of material.
const releasePath = join(DIST_RELEASES, 'material');
const releasePath = join(releasesDir, 'material');
// The entry-point for the scss theming bundle.
const themingEntryPointPath = join(COMPONENTS_DIR, 'core', 'theming', '_all-theme.scss');
const themingEntryPointPath = join(materialPath, 'core', 'theming', '_all-theme.scss');
// Output path for the scss theming bundle.
const themingBundlePath = join(releasePath, '_theming.scss');
// Matches all pre-built theme css files
const prebuiltThemeGlob = join(DIST_MATERIAL, '**/theming/prebuilt/*.css?(.map)');
const prebuiltThemeGlob = join(materialPath, '**/theming/prebuilt/*.css?(.map)');
// Matches all SCSS files in the library.
const allScssGlob = join(COMPONENTS_DIR, '**/*.scss');
const allScssGlob = join(materialPath, '**/*.scss');
/**
* Overwrite the release task for the material package. The material release will include special
+3 -2
View File
@@ -1,12 +1,13 @@
import {task} from 'gulp';
import {join} from 'path';
import {statSync} from 'fs';
import {DIST_ROOT} from '../build-config';
import {spawnSync} from 'child_process';
import {isTravisMasterBuild} from '../util/travis-ci';
import {openFirebaseDashboardApp} from '../util/firebase';
import {buildConfig} from '../packaging/build-config';
const bundlesDir = join(DIST_ROOT, 'bundles');
/** Path to the directory where all bundles are living. */
const bundlesDir = join(buildConfig.outputDir, 'bundles');
/** Task which runs test against the size of material. */
task('payload', ['material:clean-build'], () => {
+11 -5
View File
@@ -3,17 +3,23 @@ import {existsSync, statSync} from 'fs-extra';
import {join} from 'path';
import {task} from 'gulp';
import {execTask, sequenceTask} from '../util/task_helpers';
import {DIST_RELEASES, RELEASE_PACKAGES} from '../build-config';
import {buildConfig} from '../packaging/build-config';
import {yellow, green, red, grey} from 'chalk';
import * as minimist from 'minimist';
/** Packages that will be published to NPM by the release task. */
export const releasePackages = [
'cdk',
'material',
];
/** Parse command-line arguments for release task. */
const argv = minimist(process.argv.slice(3));
/** Task that builds all releases that will be published. */
task(':publish:build-releases', sequenceTask(
'clean',
RELEASE_PACKAGES.map(packageName => `${packageName}:build-release`)
releasePackages.map(packageName => `${packageName}:build-release`)
));
/** Make sure we're logged in. */
@@ -26,7 +32,7 @@ task(':publish:logout', execTask('npm', ['logout']));
function _execNpmPublish(label: string, packageName: string): Promise<{}> {
const packageDir = join(DIST_RELEASES, packageName);
const packageDir = join(buildConfig.outputDir, 'releases', packageName);
if (!statSync(packageDir).isDirectory()) {
return;
@@ -83,12 +89,12 @@ task(':publish', async () => {
}
console.log('');
if (RELEASE_PACKAGES.length > 1) {
if (releasePackages.length > 1) {
console.warn(red('Warning: Multiple packages will be released if proceeding.'));
}
// Iterate over every declared release package and publish it on NPM.
for (const packageName of RELEASE_PACKAGES) {
for (const packageName of releasePackages) {
await _execNpmPublish(label, packageName);
}
+6 -4
View File
@@ -1,11 +1,13 @@
import {join} from 'path';
import {task, watch} from 'gulp';
import {PROJECT_ROOT, SOURCE_ROOT} from '../build-config';
import {sequenceTask} from '../util/task_helpers';
import {buildConfig} from '../packaging/build-config';
// There are no type definitions available for these imports.
const runSequence = require('run-sequence');
const {packagesDir, projectDir} = buildConfig;
/** Builds everything that is necessary for karma. */
task(':test:build', sequenceTask(
'clean',
@@ -22,7 +24,7 @@ task('test:single-run', [':test:build'], (done: () => void) => {
let karma = require('karma');
new karma.Server({
configFile: join(PROJECT_ROOT, 'test/karma.conf.js'),
configFile: join(projectDir, 'test/karma.conf.js'),
singleRun: true
}, (exitCode: number) => {
// Immediately exit the process if Karma reported errors, because due to
@@ -43,13 +45,13 @@ task('test:single-run', [':test:build'], (done: () => void) => {
* This task should be used when running unit tests locally.
*/
task('test', [':test:build'], () => {
let patternRoot = join(SOURCE_ROOT, '**/*');
let patternRoot = join(packagesDir, '**/*');
// Load karma not outside. Karma pollutes Promise with a different implementation.
let karma = require('karma');
// Configure the Karma server and override the autoWatch and singleRun just in case.
let server = new karma.Server({
configFile: join(PROJECT_ROOT, 'test/karma.conf.js'),
configFile: join(projectDir, 'test/karma.conf.js'),
autoWatch: false,
singleRun: false
});
+10 -5
View File
@@ -1,11 +1,16 @@
import {task} from 'gulp';
import {DIST_RELEASES, DIST_ROOT, SOURCE_ROOT} from '../build-config';
import {ngcBuildTask, tsBuildTask, copyTask, sequenceTask, execTask} from '../util/task_helpers';
import {join} from 'path';
import {copySync} from 'fs-extra';
import {buildConfig} from '../packaging/build-config';
const appDir = join(SOURCE_ROOT, 'universal-app');
const outDir = join(DIST_ROOT, 'packages', 'universal-app');
const {outputDir, packagesDir} = buildConfig;
/** Path to the directory where all releases are created. */
const releasesDir = join(outputDir, 'releases');
const appDir = join(packagesDir, 'universal-app');
const outDir = join(outputDir, 'packages', 'universal-app');
// Paths to the different tsconfig files of the Universal app.
// Building the sources in the output directory is part of the workaround for
@@ -44,6 +49,6 @@ task('universal:build-prerender-ts', tsBuildTask(tsconfigPrerenderPath));
// 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'));
copySync(join(releasesDir, 'material'), join(outDir, 'material'));
copySync(join(releasesDir, 'cdk'), join(outDir, 'cdk'));
});
+8 -4
View File
@@ -1,9 +1,13 @@
import {task} from 'gulp';
import {DIST_RELEASES, RELEASE_PACKAGES} from '../build-config';
import {readFileSync} from 'fs';
import {join} from 'path';
import {green, red} from 'chalk';
import {sequenceTask} from '../util/task_helpers';
import {releasePackages} from './publish';
import {buildConfig} from '../packaging/build-config';
/** Path to the directory where all releases are created. */
const releasesDir = join(buildConfig.outputDir, 'releases');
/** RegExp that matches Angular component inline styles that contain a sourcemap reference. */
const inlineStylesSourcemapRegex = /styles: ?\[["'].*sourceMappingURL=.*["']/;
@@ -15,10 +19,10 @@ task('validate-release', sequenceTask(':publish:build-releases', 'validate-relea
/** Task that checks the release bundles for any common mistakes before releasing to the public. */
task('validate-release:check-bundles', () => {
const bundleFailures = RELEASE_PACKAGES
.map(packageName => join(DIST_RELEASES, packageName, '@angular', `${packageName}.js`))
const bundleFailures = releasePackages
.map(packageName => join(releasesDir, packageName, '@angular', `${packageName}.js`))
.map(packageBundle => checkPackageBundle(packageBundle))
.map((failures, index) => ({failures, packageName: RELEASE_PACKAGES[index]}));
.map((failures, index) => ({failures, packageName: releasePackages[index]}));
bundleFailures.forEach(({failures, packageName}) => {
failures.forEach(failure => console.error(red(`Failure (${packageName}): ${failure}`)));
+5 -3
View File
@@ -2,8 +2,8 @@ import * as child_process from 'child_process';
import * as fs from 'fs';
import * as gulp from 'gulp';
import * as path from 'path';
import {PROJECT_ROOT} from '../build-config';
import {yellow} from 'chalk';
import {buildConfig} from '../packaging/build-config';
/* Those imports lack typings. */
const gulpClean = require('gulp-clean');
@@ -17,6 +17,8 @@ const gulpCleanCss = require('gulp-clean-css');
const resolveBin = require('resolve-bin');
const httpRewrite = require('http-rewrite-middleware');
const {projectDir} = buildConfig;
/** If the string passed in is a glob, returns it, otherwise append '**\/*' to it. */
function _globify(maybeGlob: string, suffix = '**/*') {
if (maybeGlob.indexOf('*') != -1) {
@@ -157,11 +159,11 @@ export function buildAppTask(appName: string) {
*/
export function serverTask(packagePath: string, livereload = true) {
// The http-rewrite-middlware only supports relative paths as rewrite destinations.
let relativePath = path.relative(PROJECT_ROOT, packagePath);
const relativePath = path.relative(projectDir, packagePath);
return () => {
gulpConnect.server({
root: PROJECT_ROOT,
root: projectDir,
livereload: livereload,
port: 4200,
fallback: path.join(packagePath, 'index.html'),