Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Build: Add building/watching support to Gutenberg packages #6708

Merged
merged 3 commits into from
May 25, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
build
build-module
coverage
node_modules
vendor
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Directories/files that may be generated by this project
build
build-module
coverage
/hooks
node_modules
Expand Down
142 changes: 142 additions & 0 deletions bin/packages/build.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
/**
* script to build WordPress packages into `build/` directory.
*
* Example:
* node ./scripts/build.js
*/

/**
* External Dependenceis
*/
const fs = require( 'fs' );
const path = require( 'path' );
const glob = require( 'glob' );
const babel = require( 'babel-core' );
const chalk = require( 'chalk' );
const mkdirp = require( 'mkdirp' );

/**
* Internal dependencies
*/
const getPackages = require( './get-packages' );

/**
* Module Constants
*/
const PACKAGES_DIR = path.resolve( __dirname, '../../packages' );
const SRC_DIR = 'src';
const BUILD_DIR = {
main: 'build',
module: 'build-module',
};
const DONE = chalk.reset.inverse.bold.green( ' DONE ' );

/**
* Babel Configuration
*/
const babelDefaultConfig = require( '@wordpress/babel-preset-default' );
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should load setup from package.json - we use some overrides.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should use a separate config here. The root config could contain things we don't want here.

For example: generating the "messages.pot" file should not happen here but should happen when webpack performs the building (it's not something we want to include per module).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this is also what I figured out when trying to update this config yesterday.

I published new version of Babel preset to include missing async generator functions plugin.

Copy link
Contributor Author

@youknowriad youknowriad May 22, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wondering something though about the "messages.pot" generation :). babel may change variable names and function names and this could cause the make-pot to fail and not find the right strings. So in the end it might be better to include it here?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#6893 will cover the support for async generator functions.

babelDefaultConfig.babelrc = false;
const presetEnvConfig = babelDefaultConfig.presets[ 0 ][ 1 ];
const babelConfigs = {
main: Object.assign(
{},
babelDefaultConfig,
{ presets: [
[ 'env', Object.assign(
{},
presetEnvConfig,
{ modules: 'commonjs' },
) ],
] }
),
module: babelDefaultConfig,
};

/**
* 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_DIR );
const pkgBuildPath = path.resolve( PACKAGES_DIR, pkgName, buildFolder );
const relativeToSrcPath = path.relative( pkgSrcPath, file );
return path.resolve( pkgBuildPath, relativeToSrcPath );
}

/**
* Build a file for the required environments (node and ES5)
*
* @param {string} file File path to build
* @param {boolean} silent Show logs
*/
function buildFile( file, silent ) {
buildFileFor( file, silent, 'main' );
buildFileFor( file, silent, 'module' );
}

/**
* Build a file for a specific environment
*
* @param {string} file File path to build
* @param {boolean} silent Show logs
* @param {string} environment Dist environment (node or es5)
*/
function buildFileFor( file, silent, environment ) {
const buildDir = BUILD_DIR[ environment ];
const destPath = getBuildPath( file, buildDir );
const babelOptions = babelConfigs[ environment ];

mkdirp.sync( path.dirname( destPath ) );
const transformed = babel.transformFileSync( file, babelOptions ).code;
fs.writeFileSync( destPath, transformed );
if ( ! silent ) {
process.stdout.write(
chalk.green( ' \u2022 ' ) +
path.relative( PACKAGES_DIR, file ) +
chalk.green( ' \u21D2 ' ) +
path.relative( PACKAGES_DIR, destPath ) +
'\n'
);
}
}

/**
* Build the provided package path
*
* @param {string} packagePath absolute package path
*/
function buildPackage( packagePath ) {
const srcDir = path.resolve( packagePath, SRC_DIR );
const files = glob.sync( srcDir + '/**/*.js', { nodir: true } )
.filter( ( file ) => ! /\.test\.js/.test( file ) );

process.stdout.write( `${ path.basename( packagePath ) }\n` );

files.forEach( ( file ) => buildFile( file, true ) );
process.stdout.write( `${ DONE }\n` );
}

const files = process.argv.slice( 2 );

if ( files.length ) {
files.forEach( buildFile );
} else {
process.stdout.write( chalk.inverse( '>> Building packages \n' ) );
getPackages()
.forEach( buildPackage );
process.stdout.write( '\n' );
}
24 changes: 24 additions & 0 deletions bin/packages/get-packages.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/**
* External Dependenceis
*/
const fs = require( 'fs' );
const path = require( 'path' );

/**
* Module Constants
*/
const PACKAGES_DIR = path.resolve( __dirname, '../../packages' );

/**
* Returns the absolute path of all WordPress packages
*
* @return {Array} Package paths
*/
function getPackages() {
return fs
.readdirSync( PACKAGES_DIR )
.map( ( file ) => path.resolve( PACKAGES_DIR, file ) )
.filter( ( f ) => fs.lstatSync( path.resolve( f ) ).isDirectory() );
}

module.exports = getPackages;
66 changes: 66 additions & 0 deletions bin/packages/watch.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/**
* External dependencies
*/
const fs = require( 'fs' );
const { execSync } = require( 'child_process' );
const path = require( 'path' );
const chalk = require( 'chalk' );

/**
* Internal dependencies
*/
const getPackages = require( './get-packages' );

const BUILD_CMD = `node ${ path.resolve( __dirname, './build.js' ) }`;

let filesToBuild = new Map();

const exists = ( filename ) => {
try {
return fs.statSync( filename ).isFile();
} catch ( e ) {}
return false;
};
const rebuild = ( filename ) => filesToBuild.set( filename, true );

getPackages().forEach( ( p ) => {
const srcDir = path.resolve( p, 'src' );
try {
fs.accessSync( srcDir, fs.F_OK );
fs.watch( path.resolve( p, 'src' ), { recursive: true }, ( event, filename ) => {
const filePath = path.resolve( srcDir, filename );

if ( ( event === 'change' || event === 'rename' ) && exists( filePath ) ) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

According to https://nodejs.org/docs/latest/api/fs.html#fs_fs_watch_filename_options_listener change and rename are the only two possible options for event this can probably be shortened to exists( filePath ).

// eslint-disable-next-line no-console
console.log( chalk.green( '->' ), `${ event }: ${ filename }` );
rebuild( filePath );
} else {
const buildFile = path.resolve( srcDir, '..', 'build', filename );
try {
fs.unlinkSync( buildFile );
process.stdout.write(
chalk.red( ' \u2022 ' ) +
path.relative( path.resolve( srcDir, '..', '..' ), buildFile ) +
' (deleted)' +
'\n'
);
} catch ( e ) {}
}
} );
} catch ( e ) {
// doesn't exist
}
} );

setInterval( () => {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be worth considering replacing this with a debounced function that's triggered in rebuild. Not really a major thing though.

const files = Array.from( filesToBuild.keys() );
if ( files.length ) {
filesToBuild = new Map();
try {
execSync( `${ BUILD_CMD } ${ files.join( ' ' ) }`, { stdio: [ 0, 1, 2 ] } );
} catch ( e ) {}
}
}, 100 );

// eslint-disable-next-line no-console
console.log( chalk.red( '->' ), chalk.cyan( 'Watching for changes...' ) );
8 changes: 5 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -123,12 +123,14 @@
},
"scripts": {
"prebuild": "check-node-version --package",
"build": "cross-env NODE_ENV=production webpack",
"build:packages": "rimraf ./packages/*/build ./packages/*/build-module && node ./bin/packages/build.js",
"build": "npm run build:packages && cross-env NODE_ENV=production webpack",
"lint": "eslint .",
"lint:fix": "eslint . --fix",
"lint-php": "docker-compose run --rm composer run-script lint",
"predev": "check-node-version --package",
"dev": "cross-env webpack --watch",
"dev": "npm run build:packages && concurrently \"cross-env webpack --watch\" \"npm run dev:packages\"",
"dev:packages": "node ./bin/packages/watch.js",
"test": "npm run lint && npm run test-unit",
"test-php": "npm run lint-php && npm run test-unit-php",
"ci": "concurrently \"npm run lint && npm run build\" \"npm run test-unit:coverage-ci\"",
Expand All @@ -137,7 +139,7 @@
"fixtures:generate": "npm run fixtures:server-registered && cross-env GENERATE_MISSING_FIXTURES=y npm run test-unit",
"fixtures:regenerate": "npm run fixtures:clean && npm run fixtures:generate",
"package-plugin": "./bin/build-plugin-zip.sh",
"postinstall": "lerna bootstrap --hoist",
"postinstall": "lerna bootstrap --hoist && npm run build:packages",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We might need it later when we start referencing internal packages. This was the case for WordPress/packages at least.

"pot-to-php": "./bin/pot-to-php.js",
"publish:check": "lerna updated",
"publish:dev": "lerna publish --npm-tag next",
Expand Down
3 changes: 2 additions & 1 deletion packages/date/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@
"bugs": {
"url": "https://github.com/WordPress/gutenberg/issues"
},
"main": "src/index.js",
"main": "build/index.js",
"module": "build-module/index.js",
"dependencies": {
"moment": "2.22.1",
"moment-timezone": "0.5.16"
Expand Down
3 changes: 2 additions & 1 deletion packages/dom/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
"bugs": {
"url": "https://github.com/WordPress/gutenberg/issues"
},
"main": "src/index.js",
"main": "build/index.js",
"module": "build-module/index.js",
"dependencies": {
"element-closest": "2.0.2",
"lodash": "4.17.5",
Expand Down
3 changes: 2 additions & 1 deletion packages/element/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
"bugs": {
"url": "https://github.com/WordPress/gutenberg/issues"
},
"main": "src/index.js",
"main": "build/index.js",
"module": "build-module/index.js",
"dependencies": {
"@wordpress/is-shallow-equal": "1.0.2",
"lodash": "4.17.5",
Expand Down
1 change: 1 addition & 0 deletions packages/postcss-themes/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"author": "WordPress",
"license": "GPL-2.0-or-later",
"keywords": [
"wordpress",
"postcss",
"css",
"postcss-plugin",
Expand Down