[scss] Adds autoprefixer support and improves watcher (#21656)

This adds support for autoprefixer which we have been using in Webpack.

Additionally, we have improved the watching functionality and now update builds based directly on their dependencies an not an assumption that the files are children.

Signed-off-by: Tyler Smalley <tyler.smalley@elastic.co>
This commit is contained in:
Tyler Smalley 2018-08-10 14:24:14 -07:00 committed by GitHub
parent d605a9c10e
commit 8769110adf
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 135 additions and 75 deletions

2
.browserslistrc Normal file
View file

@ -0,0 +1,2 @@
last 2 versions
> 5%

View file

@ -79,7 +79,7 @@
"angular-route": "1.4.7", "angular-route": "1.4.7",
"angular-sanitize": "1.5.7", "angular-sanitize": "1.5.7",
"angular-sortable-view": "0.0.15", "angular-sortable-view": "0.0.15",
"autoprefixer": "6.5.4", "autoprefixer": "^9.1.0",
"babel-core": "6.21.0", "babel-core": "6.21.0",
"babel-loader": "7.1.2", "babel-loader": "7.1.2",
"babel-polyfill": "6.20.0", "babel-polyfill": "6.20.0",
@ -317,6 +317,7 @@
"nock": "8.0.0", "nock": "8.0.0",
"node-sass": "^4.9.0", "node-sass": "^4.9.0",
"pixelmatch": "4.0.2", "pixelmatch": "4.0.2",
"postcss": "^7.0.2",
"prettier": "^1.14.0", "prettier": "^1.14.0",
"proxyquire": "1.7.11", "proxyquire": "1.7.11",
"simple-git": "1.37.0", "simple-git": "1.37.0",

View file

@ -29,15 +29,12 @@ export const TranspileScssTask = {
const { spec$ } = findPluginSpecs({ plugins: { scanDirs, paths: [] } }); const { spec$ } = findPluginSpecs({ plugins: { scanDirs, paths: [] } });
const enabledPlugins = await spec$.pipe(toArray()).toPromise(); const enabledPlugins = await spec$.pipe(toArray()).toPromise();
function onSuccess(builder) { try {
log.info(`Compiled SCSS: ${builder.source}`); const bundles = await buildAll(enabledPlugins);
bundles.forEach(bundle => log.info(`Compiled SCSS: ${bundle.source}`));
} catch (error) {
const { message, line, file } = error;
throw new Error(`${message} on line ${line} of ${file}`);
} }
function onError(builder, e) {
log.error(`Compiling SCSS failed: ${builder.source}`);
throw e;
}
await buildAll(enabledPlugins, { onSuccess, onError });
} }
}; };

View file

@ -21,16 +21,16 @@ import path from 'path';
import { promisify } from 'util'; import { promisify } from 'util';
import fs from 'fs'; import fs from 'fs';
import sass from 'node-sass'; import sass from 'node-sass';
import minimatch from 'minimatch'; import autoprefixer from 'autoprefixer';
import postcss from 'postcss';
const renderSass = promisify(sass.render); const renderSass = promisify(sass.render);
const writeFile = promisify(fs.writeFile); const writeFile = promisify(fs.writeFile);
export class Build { export class Build {
constructor(source, options = {}) { constructor(source) {
this.source = source; this.source = source;
this.onSuccess = options.onSuccess || (() => {}); this.includedFiles = [source];
this.onError = options.onError || (() => {});
} }
outputPath() { outputPath() {
@ -46,8 +46,8 @@ export class Build {
return path.join(path.dirname(this.source), '**', '*.s{a,c}ss'); return path.join(path.dirname(this.source), '**', '*.s{a,c}ss');
} }
async buildIfInPath(path) { async buildIfIncluded(path) {
if (minimatch(path, this.getGlob())) { if (this.includedFiles && this.includedFiles.includes(path)) {
await this.build(); await this.build();
return true; return true;
} }
@ -60,23 +60,20 @@ export class Build {
*/ */
async build() { async build() {
try { const outFile = this.outputPath();
const outFile = this.outputPath(); const rendered = await renderSass({
file: this.source,
outFile,
sourceMap: true,
sourceMapEmbed: true,
});
const rendered = await renderSass({
file: this.source,
outFile,
sourceMap: true,
sourceMapEmbed: true,
sourceComments: true,
});
await writeFile(outFile, rendered.css); const prefixed = postcss([ autoprefixer ]).process(rendered.css);
this.onSuccess(this); this.includedFiles = rendered.stats.includedFiles;
} catch(e) {
this.onError(this, e); await writeFile(outFile, prefixed.css);
}
return this; return this;
} }

View file

@ -38,7 +38,6 @@ describe('SASS builder', () => {
expect(sass.render.mock.calls[0][0]).toEqual({ expect(sass.render.mock.calls[0][0]).toEqual({
file: '/foo/style.sass', file: '/foo/style.sass',
outFile: '/foo/style.css', outFile: '/foo/style.css',
sourceComments: true,
sourceMap: true, sourceMap: true,
sourceMapEmbed: true sourceMapEmbed: true
}); });

View file

@ -20,19 +20,18 @@
import { Build } from './build'; import { Build } from './build';
import { collectUiExports } from '../../ui/ui_exports'; import { collectUiExports } from '../../ui/ui_exports';
export function buildAll(enabledPluginSpecs, { onSuccess, onError }) { export async function buildAll(enabledPluginSpecs) {
const { uiAppSpecs = [] } = collectUiExports(enabledPluginSpecs); const { uiAppSpecs = [] } = collectUiExports(enabledPluginSpecs);
const bundles = await Promise.all(uiAppSpecs.map(async uiAppSpec => {
return Promise.all(uiAppSpecs.reduce((acc, uiAppSpec) => {
if (!uiAppSpec.styleSheetPath) { if (!uiAppSpec.styleSheetPath) {
return acc; return;
} }
const builder = new Build(uiAppSpec.styleSheetPath, { const bundle = new Build(uiAppSpec.styleSheetPath);
onSuccess, await bundle.build();
onError,
});
return [...acc, builder.build()]; return bundle;
}, [])); }));
}
return bundles.filter(v => v);
}

View file

@ -36,18 +36,23 @@ export async function sassMixin(kbnServer, server, config) {
} }
const { buildAll } = require('./build_all'); const { buildAll } = require('./build_all');
let scssBundles = [];
let trackedFiles = new Set();
function onSuccess(builder) { try {
server.log(['info', 'scss'], `Compiled CSS: ${builder.source}`); scssBundles = await buildAll(kbnServer.pluginSpecs);
scssBundles.forEach(bundle => {
bundle.includedFiles.forEach(file => trackedFiles.add(file));
server.log(['info', 'scss'], `Compiled CSS: ${bundle.source}`);
});
} catch(error) {
const { message, line, file } = error;
trackedFiles.add(file);
server.log(['warning', 'scss'], `${message} on line ${line} of ${file}`);
} }
function onError(builder, error) {
server.log(['warning', 'scss'], `Compiling CSS failed: ${builder.source}`);
server.log(['warning', 'scss'], error);
}
const scssBundles = await buildAll(kbnServer.pluginSpecs, { onSuccess, onError });
/** /**
* Setup Watchers * Setup Watchers
@ -62,15 +67,51 @@ export async function sassMixin(kbnServer, server, config) {
const { FSWatcher } = require('chokidar'); const { FSWatcher } = require('chokidar');
const watcher = new FSWatcher({ ignoreInitial: true }); const watcher = new FSWatcher({ ignoreInitial: true });
scssBundles.forEach(bundle => { watcher.add([...trackedFiles]);
watcher.add(bundle.getGlob());
});
watcher.on('all', async (event, path) => { watcher.on('all', async (event, path) => {
for (let i = 0; i < scssBundles.length; i++) { const currentlyTrackedFiles = new Set();
if (await scssBundles[i].buildIfInPath(path)) {
server.log(['debug', 'scss'], `${path} triggered ${event}`);
// build bundles containing the changed file
await Promise.all(scssBundles.map(async bundle => {
try {
if (await bundle.buildIfIncluded(path)) {
bundle.includedFiles.forEach(file => currentlyTrackedFiles.add(file));
server.log(['info', 'scss'], `Compiled ${bundle.source} due to change in ${path}`);
}
} catch(error) {
const { message, line, file } = error;
currentlyTrackedFiles.add(file);
server.log(['warning', 'scss'], `${message} on line ${line} of ${file}`);
}
}, []));
/**
* update watchers
*/
// un-watch files no longer included in any bundle
trackedFiles.forEach(file => {
if (currentlyTrackedFiles.has(file)) {
return; return;
} }
}
watcher.unwatch(file);
server.log(['debug', 'scss'], `No longer watching ${file}`);
});
// watch files not previously included in any bundle
currentlyTrackedFiles.forEach(file => {
if (trackedFiles.has(file)) {
return;
}
watcher.add(file);
server.log(['debug', 'scss'], `Now watching ${file}`);
});
trackedFiles = currentlyTrackedFiles;
}); });
} }

View file

@ -1109,17 +1109,6 @@ autolinker@~0.15.0:
version "0.15.3" version "0.15.3"
resolved "https://registry.yarnpkg.com/autolinker/-/autolinker-0.15.3.tgz#342417d8f2f3461b14cf09088d5edf8791dc9832" resolved "https://registry.yarnpkg.com/autolinker/-/autolinker-0.15.3.tgz#342417d8f2f3461b14cf09088d5edf8791dc9832"
autoprefixer@6.5.4:
version "6.5.4"
resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-6.5.4.tgz#1386eb6708ccff36aefff70adc694ecfd60af1b0"
dependencies:
browserslist "~1.4.0"
caniuse-db "^1.0.30000597"
normalize-range "^0.1.2"
num2fraction "^1.2.2"
postcss "^5.2.6"
postcss-value-parser "^3.2.3"
autoprefixer@^6.3.1: autoprefixer@^6.3.1:
version "6.7.7" version "6.7.7"
resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-6.7.7.tgz#1dbd1c835658e35ce3f9984099db00585c782014" resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-6.7.7.tgz#1dbd1c835658e35ce3f9984099db00585c782014"
@ -1131,6 +1120,17 @@ autoprefixer@^6.3.1:
postcss "^5.2.16" postcss "^5.2.16"
postcss-value-parser "^3.2.3" postcss-value-parser "^3.2.3"
autoprefixer@^9.1.0:
version "9.1.0"
resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.1.0.tgz#566a70d1148046b96b31efa08090f1999ffb6d8c"
dependencies:
browserslist "^4.0.1"
caniuse-lite "^1.0.30000872"
normalize-range "^0.1.2"
num2fraction "^1.2.2"
postcss "^7.0.2"
postcss-value-parser "^3.2.3"
aws-sign2@~0.6.0: aws-sign2@~0.6.0:
version "0.6.0" version "0.6.0"
resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f" resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f"
@ -2277,11 +2277,13 @@ browserslist@^1.3.6, browserslist@^1.4.0, browserslist@^1.5.2, browserslist@^1.7
caniuse-db "^1.0.30000639" caniuse-db "^1.0.30000639"
electron-to-chromium "^1.2.7" electron-to-chromium "^1.2.7"
browserslist@~1.4.0: browserslist@^4.0.1:
version "1.4.0" version "4.0.1"
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-1.4.0.tgz#9cfdcf5384d9158f5b70da2aa00b30e8ff019049" resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.0.1.tgz#61c05ce2a5843c7d96166408bc23d58b5416e818"
dependencies: dependencies:
caniuse-db "^1.0.30000539" caniuse-lite "^1.0.30000865"
electron-to-chromium "^1.3.52"
node-releases "^1.0.0-alpha.10"
bser@^2.0.0: bser@^2.0.0:
version "2.0.0" version "2.0.0"
@ -2527,10 +2529,14 @@ caniuse-api@^1.5.2:
lodash.memoize "^4.1.2" lodash.memoize "^4.1.2"
lodash.uniq "^4.5.0" lodash.uniq "^4.5.0"
caniuse-db@^1.0.30000529, caniuse-db@^1.0.30000539, caniuse-db@^1.0.30000597, caniuse-db@^1.0.30000634, caniuse-db@^1.0.30000639: caniuse-db@^1.0.30000529, caniuse-db@^1.0.30000634, caniuse-db@^1.0.30000639:
version "1.0.30000815" version "1.0.30000815"
resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000815.tgz#0e218fa133d0d071c886aa041b435258cc746891" resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000815.tgz#0e218fa133d0d071c886aa041b435258cc746891"
caniuse-lite@^1.0.30000865, caniuse-lite@^1.0.30000872:
version "1.0.30000874"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000874.tgz#a641b1f1c420d58d9b132920ef6ba87bbdcd2223"
capture-stack-trace@^1.0.0: capture-stack-trace@^1.0.0:
version "1.0.0" version "1.0.0"
resolved "https://registry.yarnpkg.com/capture-stack-trace/-/capture-stack-trace-1.0.0.tgz#4a6fa07399c26bba47f0b2496b4d0fb408c5550d" resolved "https://registry.yarnpkg.com/capture-stack-trace/-/capture-stack-trace-1.0.0.tgz#4a6fa07399c26bba47f0b2496b4d0fb408c5550d"
@ -4311,6 +4317,10 @@ electron-to-chromium@^1.2.7:
version "1.3.39" version "1.3.39"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.39.tgz#d7a4696409ca0995e2750156da612c221afad84d" resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.39.tgz#d7a4696409ca0995e2750156da612c221afad84d"
electron-to-chromium@^1.3.52:
version "1.3.56"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.56.tgz#aad1420d23e9dd8cd2fc2bc53f4928adcf85f02f"
elegant-spinner@^1.0.1: elegant-spinner@^1.0.1:
version "1.0.1" version "1.0.1"
resolved "https://registry.yarnpkg.com/elegant-spinner/-/elegant-spinner-1.0.1.tgz#db043521c95d7e303fd8f345bedc3349cfb0729e" resolved "https://registry.yarnpkg.com/elegant-spinner/-/elegant-spinner-1.0.1.tgz#db043521c95d7e303fd8f345bedc3349cfb0729e"
@ -9405,6 +9415,12 @@ node-pre-gyp@^0.6.39:
tar "^2.2.1" tar "^2.2.1"
tar-pack "^3.4.0" tar-pack "^3.4.0"
node-releases@^1.0.0-alpha.10:
version "1.0.0-alpha.10"
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.0.0-alpha.10.tgz#61c8d5f9b5b2e05d84eba941d05b6f5202f68a2a"
dependencies:
semver "^5.3.0"
node-sass@^4.9.0: node-sass@^4.9.0:
version "4.9.0" version "4.9.0"
resolved "https://registry.yarnpkg.com/node-sass/-/node-sass-4.9.0.tgz#d1b8aa855d98ed684d6848db929a20771cc2ae52" resolved "https://registry.yarnpkg.com/node-sass/-/node-sass-4.9.0.tgz#d1b8aa855d98ed684d6848db929a20771cc2ae52"
@ -10501,7 +10517,7 @@ postcss-zindex@^2.0.1:
postcss "^5.0.4" postcss "^5.0.4"
uniqs "^2.0.0" uniqs "^2.0.0"
postcss@^5.0.10, postcss@^5.0.11, postcss@^5.0.12, postcss@^5.0.13, postcss@^5.0.14, postcss@^5.0.16, postcss@^5.0.2, postcss@^5.0.4, postcss@^5.0.5, postcss@^5.0.6, postcss@^5.0.8, postcss@^5.2.16, postcss@^5.2.6: postcss@^5.0.10, postcss@^5.0.11, postcss@^5.0.12, postcss@^5.0.13, postcss@^5.0.14, postcss@^5.0.16, postcss@^5.0.2, postcss@^5.0.4, postcss@^5.0.5, postcss@^5.0.6, postcss@^5.0.8, postcss@^5.2.16:
version "5.2.18" version "5.2.18"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-5.2.18.tgz#badfa1497d46244f6390f58b319830d9107853c5" resolved "https://registry.yarnpkg.com/postcss/-/postcss-5.2.18.tgz#badfa1497d46244f6390f58b319830d9107853c5"
dependencies: dependencies:
@ -10518,6 +10534,14 @@ postcss@^6.0.1, postcss@^6.0.2:
source-map "^0.6.1" source-map "^0.6.1"
supports-color "^5.3.0" supports-color "^5.3.0"
postcss@^7.0.2:
version "7.0.2"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.2.tgz#7b5a109de356804e27f95a960bef0e4d5bc9bb18"
dependencies:
chalk "^2.4.1"
source-map "^0.6.1"
supports-color "^5.4.0"
prelude-ls@~1.1.2: prelude-ls@~1.1.2:
version "1.1.2" version "1.1.2"
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54"
@ -12928,7 +12952,7 @@ supports-color@^4.2.1:
dependencies: dependencies:
has-flag "^2.0.0" has-flag "^2.0.0"
supports-color@^5.1.0: supports-color@^5.1.0, supports-color@^5.4.0:
version "5.4.0" version "5.4.0"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.4.0.tgz#1c6b337402c2137605efe19f10fec390f6faab54" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.4.0.tgz#1c6b337402c2137605efe19f10fec390f6faab54"
dependencies: dependencies: