build: speed-up stylesheet building (#12426)

* Switches back from `dart-sass` to `node-sass` due to a pretty huge slow-down we noticed (can be revisited)
* No longer copies all SCSS files to the temporary `package` output just in favor of the demo-app (slows down unnecessarily). This now allows us to live-reload theme changes within a second.
* No longer rebuilds all package SCSS files twice for the ES5 output (rel: https://github.com/angular/material2/pull/7403)
This commit is contained in:
Paul Gschwendtner
2018-07-31 18:06:39 +02:00
committed by Jeremy Elbourn
parent 08e6653707
commit e4ac04d678
9 changed files with 103 additions and 161 deletions
+48 -29
View File
@@ -1,8 +1,8 @@
import {task} from 'gulp';
import {task, dest} from 'gulp';
import {tsBuildTask, copyTask, serverTask} from '../util/task_helpers';
import {join} from 'path';
import {
buildConfig, copyFiles, buildScssTask, sequenceTask, watchFiles
buildConfig, copyFiles, buildScssPipeline, sequenceTask, watchFiles
} from 'material2-build-tools';
import {
cdkPackage,
@@ -43,53 +43,35 @@ const vendorGlob = `+(${appVendors.join('|')})/**/*.+(html|css|js|map)`;
/** Glob that matches all assets that need to be copied to the output. */
const assetsGlob = join(appDir, `**/*.+(html|css|svg|ico)`);
task(':watch:devapp', () => {
watchFiles(join(appDir, '**/*.ts'), [':build:devapp:ts']);
watchFiles(join(appDir, '**/*.scss'), [':build:devapp:scss']);
watchFiles(join(appDir, '**/*.html'), [':build:devapp:assets']);
// Custom watchers for all packages that are used inside of the demo-app. This is necessary
// because we only want to build the changed package (using the build-no-bundles task).
watchFiles(join(cdkPackage.sourceDir, '**/*'), ['cdk:build-no-bundles']);
watchFiles(join(materialPackage.sourceDir, '**/!(*.scss)'), ['material:build-no-bundles']);
watchFiles(join(materialPackage.sourceDir, '**/*.scss'), [':build:devapp:material-with-styles']);
watchFiles(join(momentAdapterPackage.sourceDir, '**/*'),
['material-moment-adapter:build-no-bundles']);
watchFiles(join(materialExperimentalPackage.sourceDir, '**/*'),
['material-experimental:build-no-bundles']);
watchFiles(join(cdkExperimentalPackage.sourceDir, '**/*'),
['cdk-experimental:build-no-bundles']);
watchFiles(join(examplesPackage.sourceDir, '**/*'), ['material-examples:build-no-bundles']);
});
/** Path to the demo-app tsconfig file. */
const tsconfigPath = join(appDir, 'tsconfig-build.json');
task(':build:devapp:ts', tsBuildTask(tsconfigPath));
task(':build:devapp:scss', buildScssTask(outDir, appDir));
task(':build:devapp:assets', copyTask(assetsGlob, outDir));
task(':build:devapp:scss', () => buildScssPipeline(appDir).pipe(dest(outDir)));
task(':serve:devapp', serverTask(outDir, true));
// The themes for the demo-app are built by using the SCSS mixins from Material.
// Therefore when SCSS files have been changed, the custom theme needs to be rebuilt.
task(':build:devapp:material-with-styles', sequenceTask(
'material:build-no-bundles', ':build:devapp:scss'
));
task('build:devapp', sequenceTask(
'cdk:build-no-bundles',
'material:build-no-bundles',
'cdk-experimental:build-no-bundles',
'material-experimental:build-no-bundles',
'material-moment-adapter:build-no-bundles',
'build-examples-module', // The examples module needs to be built before building examples package
'build-examples-module',
// The examples module needs to be manually built before building examples package because
// when using the `no-bundles` task, the package-specific pre-build tasks won't be executed.
'material-examples:build-no-bundles',
[':build:devapp:assets', ':build:devapp:scss', ':build:devapp:ts']
));
task('serve:devapp', ['build:devapp'], sequenceTask([':serve:devapp', ':watch:devapp']));
/*
* Development App deployment tasks. These can be used to run the dev-app outside of our
* serve task with a middleware. e.g. on Firebase hosting.
*/
/** Task that copies all vendors into the demo-app package. Allows hosting the app on firebase. */
task('stage-deploy:devapp', ['build:devapp'], () => {
copyFiles(join(projectDir, 'node_modules'), vendorGlob, join(outDir, 'node_modules'));
@@ -118,3 +100,40 @@ task('deploy:devapp', ['stage-deploy:devapp'], () => {
.then(() => { console.log('Successfully deployed the demo-app to firebase'); process.exit(0); })
.catch((err: any) => { console.log(err); process.exit(1); });
});
/*
* Development app watch task. This task ensures that only the packages that have been affected
* by a file-change are being rebuilt. This speeds-up development and makes working on Material
* easier.
*/
task(':watch:devapp', () => {
watchFiles(join(appDir, '**/*.ts'), [':build:devapp:ts']);
watchFiles(join(appDir, '**/*.scss'), [':build:devapp:scss']);
watchFiles(join(appDir, '**/*.html'), [':build:devapp:assets']);
// Custom watchers for all packages that are used inside of the demo-app. This is necessary
// because we only want to build the changed package (using the build-no-bundles task).
// CDK package watchers.
watchFiles(join(cdkPackage.sourceDir, '**/*'), ['cdk:build-no-bundles']);
// Material package watchers.
watchFiles(join(materialPackage.sourceDir, '**/!(*-theme).scss'), ['material:build-no-bundles']);
watchFiles(join(materialPackage.sourceDir, '**/*-theme.scss'), [':build:devapp:scss']);
// Moment adapter package watchers
watchFiles(join(momentAdapterPackage.sourceDir, '**/*'),
['material-moment-adapter:build-no-bundles']);
// Material experimental package watchers
watchFiles(join(materialExperimentalPackage.sourceDir, '**/*'),
['material-experimental:build-no-bundles']);
// CDK experimental package watchers
watchFiles(join(cdkExperimentalPackage.sourceDir, '**/*'),
['cdk-experimental:build-no-bundles']);
// Example package watchers.
watchFiles(join(examplesPackage.sourceDir, '**/*'), ['material-examples:build-no-bundles']);
});
+8 -3
View File
@@ -19,14 +19,19 @@ const releasesDir = join(distDir, 'releases');
// Path to the release output of material.
const releasePath = join(releasesDir, 'material');
// The entry-point for the scss theming bundle.
const themingEntryPointPath = join(sourceDir, '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(outputDir, '**/theming/prebuilt/*.css?(.map)');
// Matches all SCSS files in the different packages.
const allScssGlob = join(buildConfig.packagesDir, '**/*.scss');
// Matches all SCSS files in the different packages. Note that this glob is not used to build
// the bundle. It's used to identify Sass files that shouldn't be included multiple times.
const allScssDedupeGlob = join(buildConfig.packagesDir, '**/*.scss');
// Pattern matching schematics files to be copied into the @angular/material package.
const schematicsGlobs = [
@@ -74,7 +79,7 @@ task('material:bundle-theming-scss', () => {
// Instantiates the SCSS bundler and bundles all imports of the specified entry point SCSS file.
// A glob of all SCSS files in the library will be passed to the bundler. The bundler takes an
// array of globs, which will match SCSS files that will be only included once in the bundle.
return new Bundler().Bundle(themingEntryPointPath, [allScssGlob]).then(result => {
return new Bundler().Bundle(themingEntryPointPath, [allScssDedupeGlob]).then(result => {
// The release directory is not created yet because the composing of the release happens when
// this task finishes.
mkdirpSync(releasePath);
@@ -0,0 +1,14 @@
import {src} from 'gulp';
import {join} from 'path';
// These imports lack of type definitions.
const gulpSass = require('gulp-sass');
const gulpIf = require('gulp-if');
const gulpCleanCss = require('gulp-clean-css');
/** Create a gulp task that builds SCSS files. */
export function buildScssPipeline(sourceDir: string, minifyOutput = false) {
return src(join(sourceDir, '**/*.scss'))
.pipe(gulpSass().on('error', gulpSass.logError))
.pipe(gulpIf(minifyOutput, gulpCleanCss()));
}
@@ -1,17 +0,0 @@
import {src, dest} from 'gulp';
import {join} from 'path';
// These imports lack of type definitions.
const gulpDartSass = require('gulp-dart-sass');
const gulpIf = require('gulp-if');
const gulpCleanCss = require('gulp-clean-css');
/** Create a gulp task that builds SCSS files. */
export function buildScssTask(outputDir: string, sourceDir: string, minifyOutput = false) {
return () => {
return src(join(sourceDir, '**/*.scss'))
.pipe(gulpDartSass.sync().on('error', gulpDartSass.logError))
.pipe(gulpIf(minifyOutput, gulpCleanCss()))
.pipe(dest(outputDir));
};
}
+8 -10
View File
@@ -2,12 +2,11 @@ import {dest, src, task} from 'gulp';
import {join} from 'path';
import {composeRelease} from '../build-release';
import {inlineResourcesForDirectory} from '../inline-resources';
import {buildScssTask} from './build-scss-task';
import {buildScssPipeline} from './build-scss-pipeline';
import {sequenceTask} from './sequence-task';
import {watchFiles} from './watch-files';
import {BuildPackage} from '../build-package';
// There are no type definitions available for these imports.
const htmlmin = require('gulp-htmlmin');
@@ -31,7 +30,7 @@ export function createPackageBuildTasks(buildPackage: BuildPackage, preBuildTask
const dependencyNames = buildPackage.dependencies.map(p => p.name);
// Glob that matches all style files that need to be copied to the package output.
const stylesGlob = join(buildPackage.sourceDir, '**/*.+(scss|css)');
const stylesGlob = join(buildPackage.sourceDir, '**/*.css');
// Glob that matches every HTML file in the current package.
const htmlGlob = join(buildPackage.sourceDir, '**/*.html');
@@ -90,17 +89,15 @@ export function createPackageBuildTasks(buildPackage: BuildPackage, preBuildTask
*/
task(`${taskName}:assets`, [
`${taskName}:assets:scss`,
`${taskName}:assets:es5-scss`,
`${taskName}:assets:copy-styles`,
`${taskName}:assets:html`
]);
task(`${taskName}:assets:scss`, buildScssTask(
buildPackage.outputDir, buildPackage.sourceDir, true)
);
task(`${taskName}:assets:es5-scss`, buildScssTask(
buildPackage.esm5OutputDir, buildPackage.sourceDir, true)
task(`${taskName}:assets:scss`, () => {
buildScssPipeline(buildPackage.sourceDir, true)
.pipe(dest(buildPackage.outputDir))
.pipe(dest(buildPackage.esm5OutputDir));
}
);
task(`${taskName}:assets:copy-styles`, () => {
@@ -108,6 +105,7 @@ export function createPackageBuildTasks(buildPackage: BuildPackage, preBuildTask
.pipe(dest(buildPackage.outputDir))
.pipe(dest(buildPackage.esm5OutputDir));
});
task(`${taskName}:assets:html`, () => {
return src(htmlGlob).pipe(htmlmin(htmlMinifierOptions))
.pipe(dest(buildPackage.outputDir))
+1 -1
View File
@@ -7,7 +7,7 @@ export * from './copy-files';
// Expose gulp utilities.
export * from './gulp/build-tasks-gulp';
export * from './gulp/build-scss-task';
export * from './gulp/build-scss-pipeline';
export * from './gulp/sequence-task';
export * from './gulp/trigger-livereload';
export * from './gulp/watch-files';