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: Change package build step to async flow #8093

Merged
merged 3 commits into from
Jan 4, 2019

Conversation

aduth
Copy link
Member

@aduth aduth commented Jul 20, 2018

This pull request seeks to adapt the package build script to perform builds in parallel, rather than in sequence. In practice, this unfortunately does not appear to make a significant difference, reducing the build time for me from about 12s to 10s. It seems that the style build takes a significant part of the time of package build.

Noting also that this is not a total conversion. getPackages should be made to be asynchronous, but is touched by other scripts as well. As such, it was decided to be left as a separate task.

Testing instructions:

There should be no regressions in the build of packages.

@aduth aduth added [Type] Build Tooling Issues or PRs related to build tooling npm Packages Related to npm packages labels Jul 20, 2018
@aduth aduth requested a review from youknowriad July 20, 2018 18:10
return Promise.all( [
...files.map( ( file ) => buildFile( file, true ) ),
buildPackageStyleIfApplicable(),
] ).then( () => {
Copy link
Contributor

Choose a reason for hiding this comment

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

This could be replaced with await ?

Copy link
Member Author

Choose a reason for hiding this comment

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

This could be replaced with await ?

Yep, updated in rebased 9feaf4a.

Copy link
Contributor

@youknowriad youknowriad left a comment

Choose a reason for hiding this comment

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

LGTM 👍

.forEach( buildPackage );
process.stdout.write( '\n' );

Promise.all( [
Copy link
Member

Choose a reason for hiding this comment

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

Shouldn't it be:

Promise.all( getPackages().map( buildPackage ) )...

?

Copy link
Member Author

Choose a reason for hiding this comment

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

Shouldn't it be:

Promise.all( getPackages().map( buildPackage ) )...

?

Updated in rebased 9feaf4a.

@@ -89,7 +89,6 @@
"concurrently": "3.5.0",
"core-js": "2.5.7",
"cross-env": "3.2.4",
"deasync": "0.1.13",
Copy link
Member

Choose a reason for hiding this comment

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

Nice 👍

@gziolo gziolo added this to the 3.4 milestone Jul 25, 2018
@pento pento modified the milestones: 3.4, 3.5 Jul 30, 2018
@gziolo
Copy link
Member

gziolo commented Aug 1, 2018

This one needs rebase and some adjustments after changes introduced in #8187 for RTL support for CSS.

@aduth aduth removed this from the 3.5 milestone Aug 7, 2018
@gziolo gziolo added this to the 3.8 milestone Aug 30, 2018
@youknowriad youknowriad modified the milestones: 3.8, 3.9 Sep 5, 2018
@youknowriad youknowriad removed this from the 3.9 milestone Sep 13, 2018
@aduth aduth force-pushed the update/async-package-build branch from c9b776b to 9feaf4a Compare January 4, 2019 14:44
@aduth
Copy link
Member Author

aduth commented Jan 4, 2019

I've finally brought this back up to date. Unfortunately it still doesn't seem to have much of an overall impact.

@gziolo
Copy link
Member

gziolo commented Jan 4, 2019

Feel free to merge when Travis is happy. It was already reviewed :)

I've finally brought this back up to date. Unfortunately it still doesn't seem to have much of an overall impact.

@noisysocks has PR opened which adds caching, maybe it will have an impact together.

@aduth
Copy link
Member Author

aduth commented Jan 4, 2019

I have two of my own remaining reservations:

  • I'm not sure about postcss().process being synchronous as it was refactored here. The function is a bit confusing, where it returns a "LazyResult" object which has both an evaluated css property but also is then-able. By the documentation of then, I'm inclined to think that it must be used if needing to account for asynchronous postcss plugins.
  • I'm not sure about unbounded concurrency for the build. It's probably not much of an issue to build our current set of modules in parallel, but it might be worth considering something like p-limit to batch a set maximum number of builds to occur at a time.

@aduth
Copy link
Member Author

aduth commented Jan 4, 2019

Ah, I guess I should have read those links more closely, as it answers my question quite concretely 😅

This is why this method is only for debug purpose, you should always use LazyResult#then.

http://api.postcss.org/LazyResult.html#css

See: http://api.postcss.org/LazyResult.html#css

>This is why this method is only for debug purpose, you should always use LazyResult#then.
Effectively unchanged, since stringification of the LazyResult object is aliased to the css property.

See: http://api.postcss.org/LazyResult.html#toString
@aduth
Copy link
Member Author

aduth commented Jan 4, 2019

LazyResult is now used as a thenable as of b6e7084.

I'm fine in the initial approach to have unbounded parallelization. This can be revisited if it's shown to be problematic.

@aduth aduth merged commit 4928f16 into master Jan 4, 2019
@aduth aduth deleted the update/async-package-build branch January 4, 2019 16:49
aduth added a commit that referenced this pull request Jan 4, 2019
@aduth
Copy link
Member Author

aduth commented Jan 4, 2019

There's a few issues here impacting (a) sourcemaps, (b) npm run dev regeneration, and (c) a possible race condition with writeFile.

I've proposed a revert at #13195

I have an in-progress branch with some partial fixes at fix/mkdirp-source-maps.

I'll leave a few follow-up comments here for more specific problems.

buildPaths.jsFiles.forEach( buildJsFile );
buildPaths.scssPackagePaths.forEach( buildPackageScss );
return Promise.all( [
...buildPaths.jsFiles.map( buildJsFile ),
Copy link
Member Author

@aduth aduth Jan 4, 2019

Choose a reason for hiding this comment

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

I was wrong in thinking that by the previous implementation using forEach, these were arrays, when in fact they're of type Set. Thus, rebuilds fail with an error:

[1] /Users/andrew/Documents/Code/vvv/www/editor/htdocs/wp-content/plugins/gutenberg/bin/packages/build.js:100
[1] 		...buildPaths.jsFiles.map( buildJsFile ),
[1] 		                      ^
[1] 
[1] TypeError: buildPaths.jsFiles.map(...) is not a function or its return value is not iterable
[1]     at buildFiles (/Users/andrew/Documents/Code/vvv/www/editor/htdocs/wp-content/plugins/gutenberg/bin/packages/build.js:100:25)
[1]     at Object.<anonymous> (/Users/andrew/Documents/Code/vvv/www/editor/htdocs/wp-content/plugins/gutenberg/bin/packages/build.js:234:2)
[1]     at Module._compile (internal/modules/cjs/loader.js:689:30)
[1]     at Object.Module._extensions..js (internal/modules/cjs/loader.js:700:10)
[1]     at Module.load (internal/modules/cjs/loader.js:599:32)
[1]     at tryModuleLoad (internal/modules/cjs/loader.js:538:12)
[1]     at Function.Module._load (internal/modules/cjs/loader.js:530:3)
[1]     at Function.Module.runMain (internal/modules/cjs/loader.js:742:12)
[1]     at startup (internal/bootstrap/node.js:282:19)
[1]     at bootstrapNodeJSCore (internal/bootstrap/node.js:743:3)

Two alternatives are:

  • Don't track them as a Set, rather as an array and guarantee uniqueness before pushing to array.
  • Convert Set to array at this line before the map, i.e. ...[ ...buildPaths.jsFiles ].map( buildJsFile ),

fs.writeFileSync( destPath, transformed.code + '\n//# sourceMappingURL=' + path.basename( destPath ) + '.map' );
await mkdirp( path.dirname( destPath ) );
const transformed = await transformFile( file, babelOptions );
writeFile( destPath + '.map', JSON.stringify( transformed.map ) );
Copy link
Member Author

Choose a reason for hiding this comment

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

These are asynchronous tasks and should have await, preferably in parallel as await Promise.all between writing the map file and the original source.

const transformed = babel.transformFileSync( file, babelOptions );
fs.writeFileSync( destPath + '.map', JSON.stringify( transformed.map ) );
fs.writeFileSync( destPath, transformed.code + '\n//# sourceMappingURL=' + path.basename( destPath ) + '.map' );
await mkdirp( path.dirname( destPath ) );
Copy link
Member Author

@aduth aduth Jan 4, 2019

Choose a reason for hiding this comment

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

I'm seeing varied results in attributing this to be a cause, but I was seeing some improvement by switching this back to its synchronous form.

Possibly related: https://github.com/substack/node-mkdirp/issues/154

Viable substitute module: https://www.npmjs.com/package/make-dir

@talldan
Copy link
Contributor

talldan commented Jan 7, 2019

I had a similar attempt at this over christmas (didn't realise this PR existed). I also didn't see any real improvement in build times, so didn't bother tidying things up:
#13104

It'll be worth keeping an eye on node 10's promise based filesystem apis. They're currently marked as experimental, hopefully in a not too distant future version they'll become stable:
https://nodejs.org/docs/latest-v10.x/api/fs.html#fs_fs_promises_api

aduth added a commit that referenced this pull request Jan 7, 2019
@youknowriad youknowriad added this to the 4.9 (Gutenberg) milestone Jan 18, 2019
youknowriad pushed a commit that referenced this pull request Mar 6, 2019
* Build: Change package build step to async flow

* Build: Trigger LazyResult#then for postcss.process

See: http://api.postcss.org/LazyResult.html#css

>This is why this method is only for debug purpose, you should always use LazyResult#then.

* Build: Consistently use css property for stringified result

Effectively unchanged, since stringification of the LazyResult object is aliased to the css property.

See: http://api.postcss.org/LazyResult.html#toString
youknowriad pushed a commit that referenced this pull request Mar 6, 2019
youknowriad pushed a commit that referenced this pull request Mar 6, 2019
* Build: Change package build step to async flow

* Build: Trigger LazyResult#then for postcss.process

See: http://api.postcss.org/LazyResult.html#css

>This is why this method is only for debug purpose, you should always use LazyResult#then.

* Build: Consistently use css property for stringified result

Effectively unchanged, since stringification of the LazyResult object is aliased to the css property.

See: http://api.postcss.org/LazyResult.html#toString
youknowriad pushed a commit that referenced this pull request Mar 6, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
npm Packages Related to npm packages [Type] Build Tooling Issues or PRs related to build tooling
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants