Commit 9596055e authored by Robert Knight's avatar Robert Knight

Change SASS processing pipeline to match h, lms projects

Change the SASS processing pipeline to match the h and lms projects. The
purpose of this is cross-project consistency for easier maintenance,
consistent processing of SASS files from the upcoming pattern library
and to enable us to use the new SASS module system [1]

The main changes are:

 - Use Dart Sass (the canonical SASS implementation) instead of node-sass.

   This removes a native dependency which occassionally causes build
   headaches (eg. when the installed Node version changes) and will also enable
   us to make use of the new SASS module system.

 - Use a small utility module, `create-style-bundle.js`, that calls the SASS
   compiler directly instead of using gulp plugins. This simplifies
   understanding the build process by removing dependencies and is
   consistent with the h and lms projects.

   This module was copied from the hypothesis/lms repo and modified to
   add the `postcss-url` URL rewriting plugin that the previous
   gulp-sass based pipeline had.

[1] http://sass.logdown.com/posts/7858341-the-module-system-is-launched
parent bc30c556
......@@ -2,23 +2,20 @@
'use strict';
const { mkdirSync } = require('fs');
const path = require('path');
const changed = require('gulp-changed');
const commander = require('commander');
const debounce = require('lodash.debounce');
const gulp = require('gulp');
const gulpIf = require('gulp-if');
const gulpUtil = require('gulp-util');
const postcss = require('gulp-postcss');
const postcssURL = require('postcss-url');
const replace = require('gulp-replace');
const rename = require('gulp-rename');
const sass = require('gulp-sass');
const sourcemaps = require('gulp-sourcemaps');
const through = require('through2');
const createBundle = require('./scripts/gulp/create-bundle');
const createStyleBundle = require('./scripts/gulp/create-style-bundle');
const manifest = require('./scripts/gulp/manifest');
const servePackage = require('./scripts/gulp/serve-package');
const vendorBundles = require('./scripts/gulp/vendor-bundles');
......@@ -56,10 +53,6 @@ function parseCommandLine() {
const taskArgs = parseCommandLine();
function isSASSFile(file) {
return file.path.match(/\.scss$/);
}
function getEnv(key) {
if (!process.env.hasOwnProperty(key)) {
throw new Error(`Environment variable ${key} is not set`);
......@@ -175,7 +168,7 @@ gulp.task(
})
);
const styleFiles = [
const cssBundles = [
// H
'./src/styles/annotator/annotator.scss',
'./src/styles/annotator/pdfjs-overrides.scss',
......@@ -189,35 +182,21 @@ const styleFiles = [
];
gulp.task('build-css', function() {
// Rewrite font URLs to look for fonts in 'build/fonts' instead of
// 'build/styles/fonts'
function rewriteCSSURL(asset) {
return asset.url.replace(/^fonts\//, '../fonts/');
}
const sassOpts = {
outputStyle: IS_PRODUCTION_BUILD ? 'compressed' : 'nested',
};
const cssURLRewriter = postcssURL({
url: rewriteCSSURL,
});
return gulp
.src(styleFiles)
.pipe(sourcemaps.init())
.pipe(gulpIf(isSASSFile, sass(sassOpts).on('error', sass.logError)))
.pipe(postcss([require('autoprefixer'), cssURLRewriter]))
.pipe(sourcemaps.write('.'))
.pipe(gulp.dest(STYLE_DIR));
mkdirSync(STYLE_DIR, { recursive: true });
const bundles = cssBundles.map(entry =>
createStyleBundle({
input: entry,
output: `${STYLE_DIR}/${path.basename(entry, path.extname(entry))}.css`,
minify: IS_PRODUCTION_BUILD,
})
);
return Promise.all(bundles);
});
gulp.task(
'watch-css',
gulp.series('build-css', function watchCSS() {
const vendorCSS = styleFiles.filter(function(path) {
return path.endsWith('.css');
});
const vendorCSS = cssBundles.filter(path => path.endsWith('.css'));
const styleFileGlobs = vendorCSS.concat('./src/styles/**/*.scss');
gulp.watch(styleFileGlobs, gulp.task('build-css'));
......
......@@ -64,7 +64,6 @@
"gulp-postcss": "^8.0.0",
"gulp-rename": "^1.2.2",
"gulp-replace": "^1.0.0",
"gulp-sass": "^4.0.2",
"gulp-sourcemaps": "^2.6.4",
"gulp-util": "^3.0.7",
"hammerjs": "^2.0.4",
......@@ -99,6 +98,7 @@
"request": "^2.76.0",
"reselect": "^4.0.0",
"retry": "^0.12.0",
"sass": "^1.23.0",
"scroll-into-view": "^1.8.2",
"seamless-immutable": "^7.1.4",
"shallowequal": "^1.1.0",
......
'use strict';
const fs = require('fs');
const path = require('path');
const autoprefixer = require('autoprefixer');
const postcss = require('postcss');
const postcssURL = require('postcss-url');
const sass = require('sass');
/**
* @typedef Options
* @prop {string} input - Input file path
* @prop {boolean} minify - Whether to minify the generated bundle
* @prop {string} output - Output file path
*/
/**
* Compile a SASS file and postprocess the result.
*
* @param {Options} options - Object specifying the input and output paths and
* whether to minify the result.
* @return {Promise} Promise for completion of the build.
*/
async function compileSass({ input, minify, output }) {
const sourcemapPath = output + '.map';
let result = sass.renderSync({
file: input,
includePaths: [path.dirname(input), 'node_modules'],
outputStyle: minify ? 'compressed' : 'expanded',
sourceMap: sourcemapPath,
});
// Rewrite font URLs to look for fonts in 'build/fonts' instead of
// 'build/styles/fonts'
function rewriteCSSURL(asset) {
return asset.url.replace(/^fonts\//, '../fonts/');
}
const cssURLRewriter = postcssURL({
url: rewriteCSSURL,
});
const postcssPlugins = [autoprefixer, cssURLRewriter];
result = await postcss(postcssPlugins).process(result.css, {
from: output,
to: output,
map: {
inline: false,
prev: result.map.toString(),
},
});
fs.writeFileSync(output, result.css);
fs.writeFileSync(sourcemapPath, result.map.toString());
}
module.exports = compileSass;
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment