Skip to content

[FIX] generateResourcesJson: Make resources.json generation deterministic #551

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

Merged
merged 5 commits into from
Nov 30, 2020

Conversation

RandomByte
Copy link
Member

@RandomByte RandomByte commented Nov 24, 2020

Stop analyzing debug-resources if they correspond to a non-debug resource.

Only analyze the non-debug resource and copy any dependency information to the corresponding debug-resource.

While this might not be the best approach given that analyzing the source ("debug") version of a resource might result in finding more dependencies (i.e. those mangled during minification), this change ensures that we generate the same resources.json, independently from the order of debug and non-debug resources supplied to the resourceListCreator processor.

Resolves SAP/ui5-tooling#274

@RandomByte RandomByte force-pushed the resources-json-generation-consistency branch from 9093861 to 245b592 Compare November 24, 2020 19:03
@coveralls
Copy link

coveralls commented Nov 24, 2020

Coverage Status

Coverage increased (+0.005%) to 92.96% when pulling 44af975 on resources-json-generation-consistency into e9458e7 on master.

@RandomByte
Copy link
Member Author

Obviously still missing dedicated tests for the added code and parameters.

We could not measure any immediate performance improvement.

We also discussed alternative implementations. Including one even more similar to how Maven does it, where we generate the resources.json information during the bundling (where no debug files exist yet) and enrich it with the debug file information at a later point. Either while they are being created or in a separate task. But this would be a bigger effort than what this PR does.

let info = this._dependencyInfos.get(name);
if ( info == null ) {
// console.log("analyzing ", name);
let dbgResource;
if (options && options.preferDebugResources) {
Copy link
Member

Choose a reason for hiding this comment

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

This feels somehow wrong. Complicating the ResourcePool for a late task by adding difficult to understand logic that's not needed in earlier tasks.

Maybe thinking of tasks in a more holistic way would be better. Currently, we see tasks as modifying or creating files, but maybe they rather should be transformations of the project (or the projects build results) into another, consistent build result.

With that interpretation, an early task would determine dependencies on the original sources and store them in an early version of the resources.json.

createDebugFiles, when executed, would have to update that file. The logic which files will be copied and which not, would then be isolated in the createDebugFiles task (or processor, I don't know) and not being spread across tasks.

All bundling task obviously also would have to update any existing resources.json.

Well, but even with that approach, encapsulation would not be a no-brainer. All the mentioned tasks would have to know where a resources.json files can exist (library, component, theme).

// not-minified content of a resource.
const dbgName = ResourceInfoList.getDebugName(name);
if (dbgName && (!options.debugBundleFilter || !options.debugBundleFilter.matches(dbgName))) {
dbgResource = this._resourcesByName.get(dbgName);
Copy link
Member

Choose a reason for hiding this comment

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

Making findResource async was meant as a preparation to later switch from a prepare and wrap approach to a direct access via the fs adapters. But I guess you wanted to avoid the (ugly) try catch.

Copy link
Member Author

Choose a reason for hiding this comment

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

Maybe that's the best approach then? Rewriting the ResourcePool to tightly integrate with ui5-fs. Also, adding a new Class in ui5-fs to store metadata like the AST (or plain dependency information?) per-resource.

Every task modifying a resource should update this metadata or at least invalidate it in some way.

Then there would still be a final resource.json-generation task, but instead of analyzing resources it would use the metadata already available for most of them.

promises.push(
this.enrichWithDependencyInfo(info)
);
if ( (!info.isDebug || debugBundleFilter.matches(name)) ) {
Copy link
Member

Choose a reason for hiding this comment

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

Isn't this strange now to focus on non-debug resources here, but then in the ResourcePool doing the opposite and prefer the debug resource?

My statement that we should run over the non-debug sources was motivated by the fact that not every resources has a related dbg-resource.

But couldn't we check that here in the ResourceCollector and keep the logic out of the pool?

Copy link
Member Author

Choose a reason for hiding this comment

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

As discussed, the mentioned change in ResourcePool has been retracted from this PR. Just to have it documented somewhere I created #553

@RandomByte RandomByte force-pushed the resources-json-generation-consistency branch from 245b592 to 374e0c0 Compare November 26, 2020 14:40
…stic

Stop analyzing debug-resources if they correspond to a non-debug
resource.

Only analyze the non-debug resource and copy any dependency information
to the corresponding debug-resource.

While this might not be the best approach given that analyzing the
source ("debug") version of a resource might result in finding more
dependencies (i.e. those mangled during minification), this change
ensures that we generate the same resources.json, independently
from the order of debug and non-debug resources supplied to the
resourceListCreator processor.

Resolves SAP/ui5-tooling#274
@RandomByte RandomByte force-pushed the resources-json-generation-consistency branch 2 times, most recently from a279872 to 7ec38a4 Compare November 26, 2020 14:45
@RandomByte RandomByte marked this pull request as ready for review November 26, 2020 16:06
RandomByte added a commit that referenced this pull request Nov 26, 2020
…e content

Possible follow up of #551 to
improve dependency analysis.

JSModuleAnalyzer has trouble detecting some dependencies in minified
code if they have been "mangled". E.g. in case jQuery is not named
jQuery anymore.

This change solves that by trying to retrieve the debug ("source")
content of a resource to analyze that instead of the minified version.
However, integrating this on the ResourcePool level is not ideal and a
more general solution to this problem should be preferred.

Therefore this PR should only act as an illustration of the discussions
and thoughts. Currently it should not be merged.
RandomByte added a commit that referenced this pull request Nov 26, 2020
…e content

Possible follow up of #551 to
improve dependency analysis.

JSModuleAnalyzer has trouble detecting some dependencies in minified
code if they have been "mangled". E.g. in case jQuery is not named
jQuery anymore.

This change solves that by trying to retrieve the debug ("source")
content of a resource to analyze that instead of the minified version.
However, integrating this on the ResourcePool level is not ideal and a
more general solution to this problem should be preferred.

Therefore this PR should only act as an illustration of the discussions
and thoughts. Currently it should not be merged.
tobiasso85
tobiasso85 previously approved these changes Nov 30, 2020
Copy link
Contributor

@tobiasso85 tobiasso85 left a comment

Choose a reason for hiding this comment

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

LGTM

this.enrichWithDependencyInfo(info)
);
if ( (!info.isDebug || debugBundleFilter.matches(name)) ) {
// Only analyze non-debug files which are not special debug bundles (like sap-ui-core-dbg.js)
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
// Only analyze non-debug files which are not special debug bundles (like sap-ui-core-dbg.js)
// Only analyze non-debug files and special debug bundles (like sap-ui-core-dbg.js)

or am I wrong?

Copy link
Member Author

Choose a reason for hiding this comment

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

Absolutely right 👍

@@ -253,19 +272,17 @@ class ResourceCollector {

groupResourcesByComponents(options) {
Copy link
Member

Choose a reason for hiding this comment

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

options could be removed completely, right?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes 🙌

const enrichWithDependencyInfoStub = sinon.stub(resourceCollector, "enrichWithDependencyInfo")
.callsFake((resourceInfo) => {
// Simulate enriching resource info with dependency info to test whether it gets shared
// with the dbg resource alter on
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
// with the dbg resource alter on
// with the dbg resource later on

Copy link
Member Author

Choose a reason for hiding this comment

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

Done

Comment on lines 245 to 246
newDbgInfo.copyFrom(null, nonDbgInfo);
newDbgInfo.copyFrom(null, dbgInfo);
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
newDbgInfo.copyFrom(null, nonDbgInfo);
newDbgInfo.copyFrom(null, dbgInfo);
newDbgInfo.copyFrom(null, nonDbgInfo); // First copy info of analysis from non-dbg file (included, required, condRequired, ...)
newDbgInfo.copyFrom(null, dbgInfo); // Then copy over info from dbg file to properly set name, isDebug, ...

Copy link
Member Author

Choose a reason for hiding this comment

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

Done

Copy link
Member

@codeworrior codeworrior left a comment

Choose a reason for hiding this comment

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

LGTM

@RandomByte RandomByte merged commit 26eb89a into master Nov 30, 2020
@RandomByte RandomByte deleted the resources-json-generation-consistency branch November 30, 2020 14:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

resourceListCreator: Different order of input resources leads to different results
5 participants