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

View file

@ -29,15 +29,12 @@ export const TranspileScssTask = {
const { spec$ } = findPluginSpecs({ plugins: { scanDirs, paths: [] } });
const enabledPlugins = await spec$.pipe(toArray()).toPromise();
function onSuccess(builder) {
log.info(`Compiled SCSS: ${builder.source}`);
try {
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 fs from 'fs';
import sass from 'node-sass';
import minimatch from 'minimatch';
import autoprefixer from 'autoprefixer';
import postcss from 'postcss';
const renderSass = promisify(sass.render);
const writeFile = promisify(fs.writeFile);
export class Build {
constructor(source, options = {}) {
constructor(source) {
this.source = source;
this.onSuccess = options.onSuccess || (() => {});
this.onError = options.onError || (() => {});
this.includedFiles = [source];
}
outputPath() {
@ -46,8 +46,8 @@ export class Build {
return path.join(path.dirname(this.source), '**', '*.s{a,c}ss');
}
async buildIfInPath(path) {
if (minimatch(path, this.getGlob())) {
async buildIfIncluded(path) {
if (this.includedFiles && this.includedFiles.includes(path)) {
await this.build();
return true;
}
@ -60,23 +60,20 @@ export class 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);
} catch(e) {
this.onError(this, e);
}
this.includedFiles = rendered.stats.includedFiles;
await writeFile(outFile, prefixed.css);
return this;
}

View file

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

View file

@ -20,19 +20,18 @@
import { Build } from './build';
import { collectUiExports } from '../../ui/ui_exports';
export function buildAll(enabledPluginSpecs, { onSuccess, onError }) {
export async function buildAll(enabledPluginSpecs) {
const { uiAppSpecs = [] } = collectUiExports(enabledPluginSpecs);
return Promise.all(uiAppSpecs.reduce((acc, uiAppSpec) => {
const bundles = await Promise.all(uiAppSpecs.map(async uiAppSpec => {
if (!uiAppSpec.styleSheetPath) {
return acc;
return;
}
const builder = new Build(uiAppSpec.styleSheetPath, {
onSuccess,
onError,
});
const bundle = new Build(uiAppSpec.styleSheetPath);
await bundle.build();
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');
let scssBundles = [];
let trackedFiles = new Set();
function onSuccess(builder) {
server.log(['info', 'scss'], `Compiled CSS: ${builder.source}`);
try {
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
@ -62,15 +67,51 @@ export async function sassMixin(kbnServer, server, config) {
const { FSWatcher } = require('chokidar');
const watcher = new FSWatcher({ ignoreInitial: true });
scssBundles.forEach(bundle => {
watcher.add(bundle.getGlob());
});
watcher.add([...trackedFiles]);
watcher.on('all', async (event, path) => {
for (let i = 0; i < scssBundles.length; i++) {
if (await scssBundles[i].buildIfInPath(path)) {
const currentlyTrackedFiles = new Set();
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;
}
}
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"
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:
version "6.7.7"
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-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:
version "0.6.0"
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"
electron-to-chromium "^1.2.7"
browserslist@~1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-1.4.0.tgz#9cfdcf5384d9158f5b70da2aa00b30e8ff019049"
browserslist@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.0.1.tgz#61c05ce2a5843c7d96166408bc23d58b5416e818"
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:
version "2.0.0"
@ -2527,10 +2529,14 @@ caniuse-api@^1.5.2:
lodash.memoize "^4.1.2"
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"
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:
version "1.0.0"
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"
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:
version "1.0.1"
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-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:
version "4.9.0"
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"
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"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-5.2.18.tgz#badfa1497d46244f6390f58b319830d9107853c5"
dependencies:
@ -10518,6 +10534,14 @@ postcss@^6.0.1, postcss@^6.0.2:
source-map "^0.6.1"
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:
version "1.1.2"
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54"
@ -12928,7 +12952,7 @@ supports-color@^4.2.1:
dependencies:
has-flag "^2.0.0"
supports-color@^5.1.0:
supports-color@^5.1.0, supports-color@^5.4.0:
version "5.4.0"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.4.0.tgz#1c6b337402c2137605efe19f10fec390f6faab54"
dependencies: