Skip to content

Commit

Permalink
Build Tooling: Optimize build by spawning worker pool (#15230)
Browse files Browse the repository at this point in the history
* Build Tooling: Create worker pool for build

* Build Tooling: Define build concurrency explicitly

* Revert "Build Tooling: Define build concurrency explicitly"

This reverts commit 4338f9e.

* Build Tooling: Implement build files sourcing as stream

* Build Tooling: Reinstate error handling to build script

* Build Tooling: Log build error to stderr

Co-Authored-By: Daniel Richards <[email protected]>

* Build: Assign non-zero exit code on build error

Co-Authored-By: Daniel Richards <[email protected]>
  • Loading branch information
aduth and talldan authored May 30, 2019
1 parent 1a6660c commit 5c38808
Show file tree
Hide file tree
Showing 4 changed files with 327 additions and 214 deletions.
159 changes: 159 additions & 0 deletions bin/packages/build-worker.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
/**
* External dependencies
*/
const { promisify } = require( 'util' );
const fs = require( 'fs' );
const path = require( 'path' );
const babel = require( '@babel/core' );
const makeDir = require( 'make-dir' );
const sass = require( 'node-sass' );
const postcss = require( 'postcss' );

/**
* Internal dependencies
*/
const getBabelConfig = require( './get-babel-config' );

/**
* Path to packages directory.
*
* @type {string}
*/
const PACKAGES_DIR = path.resolve( __dirname, '../../packages' );

/**
* Mapping of JavaScript environments to corresponding build output.
*
* @type {Object}
*/
const JS_ENVIRONMENTS = {
main: 'build',
module: 'build-module',
};

/**
* Promisified fs.readFile.
*
* @type {Function}
*/
const readFile = promisify( fs.readFile );

/**
* Promisified fs.writeFile.
*
* @type {Function}
*/
const writeFile = promisify( fs.writeFile );

/**
* Promisified sass.render.
*
* @type {Function}
*/
const renderSass = promisify( sass.render );

/**
* Get the package name for a specified file
*
* @param {string} file File name
* @return {string} Package name
*/
function getPackageName( file ) {
return path.relative( PACKAGES_DIR, file ).split( path.sep )[ 0 ];
}

/**
* Get Build Path for a specified file.
*
* @param {string} file File to build
* @param {string} buildFolder Output folder
* @return {string} Build path
*/
function getBuildPath( file, buildFolder ) {
const pkgName = getPackageName( file );
const pkgSrcPath = path.resolve( PACKAGES_DIR, pkgName, 'src' );
const pkgBuildPath = path.resolve( PACKAGES_DIR, pkgName, buildFolder );
const relativeToSrcPath = path.relative( pkgSrcPath, file );
return path.resolve( pkgBuildPath, relativeToSrcPath );
}

/**
* Object of build tasks per file extension.
*
* @type {Object<string,Function>}
*/
const BUILD_TASK_BY_EXTENSION = {
async '.scss'( file ) {
const outputFile = getBuildPath( file.replace( '.scss', '.css' ), 'build-style' );
const outputFileRTL = getBuildPath( file.replace( '.scss', '-rtl.css' ), 'build-style' );

const [ , contents ] = await Promise.all( [
makeDir( path.dirname( outputFile ) ),
readFile( file, 'utf8' ),
] );

const builtSass = await renderSass( {
file,
includePaths: [ path.resolve( __dirname, '../../assets/stylesheets' ) ],
data: (
[
'colors',
'breakpoints',
'variables',
'mixins',
'animations',
'z-index',
].map( ( imported ) => `@import "${ imported }";` ).join( ' ' ) +
contents
),
} );

const result = await postcss( require( './post-css-config' ) ).process( builtSass.css, {
from: 'src/app.css',
to: 'dest/app.css',
} );

const resultRTL = await postcss( [ require( 'rtlcss' )() ] ).process( result.css, {
from: 'src/app.css',
to: 'dest/app.css',
} );

await Promise.all( [
writeFile( outputFile, result.css ),
writeFile( outputFileRTL, resultRTL.css ),
] );
},

async '.js'( file ) {
for ( const [ environment, buildDir ] of Object.entries( JS_ENVIRONMENTS ) ) {
const destPath = getBuildPath( file, buildDir );
const babelOptions = getBabelConfig( environment, file.replace( PACKAGES_DIR, '@wordpress' ) );

const [ , transformed ] = await Promise.all( [
makeDir( path.dirname( destPath ) ),
babel.transformFileAsync( file, babelOptions ),
] );

await Promise.all( [
writeFile( destPath + '.map', JSON.stringify( transformed.map ) ),
writeFile( destPath, transformed.code + '\n//# sourceMappingURL=' + path.basename( destPath ) + '.map' ),
] );
}
},
};

module.exports = async ( file, callback ) => {
const extension = path.extname( file );
const task = BUILD_TASK_BY_EXTENSION[ extension ];

if ( ! task ) {
return;
}

try {
await task( file );
callback();
} catch ( error ) {
callback( error );
}
};
Loading

0 comments on commit 5c38808

Please sign in to comment.