Skip to content

Default and export naming fixes - #2001

Merged
lukastaegert merged 3 commits into
masterfrom
default-identifier-renaming
Feb 25, 2018
Merged

Default and export naming fixes#2001
lukastaegert merged 3 commits into
masterfrom
default-identifier-renaming

Conversation

@guybedford

Copy link
Copy Markdown
Contributor

This fixes #1996 along with some other cases around export default and named exports:

  • The issue was the fact that default exports get a temporary reassignment tracking variable. So the fix was to ensure this variable supports safeName and doesn't get a safe name when there's an original reassignment.
  • There was an issue with the CJS and AMD export mode on chunks being set to auto. Internal chunks need to always use named exports for consistency with the interfaces, which fixed a missed test case as well.
  • ensureExport now takes an export name argument. Export names can in theory be arbitrary, but when they match up with the exact signature of a chunk we allow chunks to become entry point chunks. So ensuring export name consistency helps ensure we don't create unnecessary facades.
  • Removed an unused code path in ensureExport
  • Default exports are now called default by default, while we were using their import aliases before.

The depths of these cases keeps expanding... I'm sure it will continue to! But as long as we put equal effort into refactoring and fixes we should be on a good footing (and project sponsorship has been a huge help to justify this time input!!).

@anandthakker

anandthakker commented Feb 21, 2018

Copy link
Copy Markdown
Contributor

@guybedford Tried this out over in mapbox/mapbox-gl-js#6196 and I'm seeing:

exports.* = commonjsGlobal;
exports.*$1 = unwrapExports;
exports.*$2 = createCommonjsModule;

in chunk1.js

super(name, exportDefaultDeclaration, exportDefaultDeclaration.declaration);
this.isDefault = true;
this.hasId = !!(<FunctionDeclaration | ClassDeclaration>exportDefaultDeclaration.declaration).id;
this.exportName = 'default';

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

How hard would it be to include the filename of the module as part of this name, e.g., my_module$default for the default export of my-module.js? Seems like this could make for easier debugging in some cases.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The reason we use the initial name is because this stage of the algorithm is still attempting to determine if the chunk is an entry point module itself (entry.js), or if it is a chunk (chunk[i].js). Ideally the algorithm could do the export naming after this stage in the process in which case we can better handle naming definitely. I will look into a refactor along these lines, but perhaps not just yet.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

(So basically in the scenario that the chunk is an entry point, we need it to do the correct naming as the entry point would expect)

@anandthakker

Copy link
Copy Markdown
Contributor
diff --git a/src/Chunk.ts b/src/Chunk.ts
index 6c01905c..69b6eea4 100644
--- a/src/Chunk.ts
+++ b/src/Chunk.ts
@@ -146,9 +146,10 @@ export default class Chunk {
                }

                let i = 0;
-               safeExportName = exportName;
+               const baseExportName = exportName === '*' ? '_namespace' : exportName;
+               safeExportName = baseExportName;
                while (this.exports[safeExportName]) {
-                       safeExportName = exportName + '$' + ++i;
+                       safeExportName = baseExportName + '$' + ++i;
                }
                variable.exportName = safeExportName;

Fixes the above for me

@guybedford

Copy link
Copy Markdown
Contributor Author

@anandthakker any chance of a test case? I take it you have a namespace import across a chunk boundary?

@anandthakker

Copy link
Copy Markdown
Contributor

@guybedford y, I'll try to reduce a test case. We don't have an explicit namespace import -- from the variable names (commonjsGlobal, unwrapExports, createCommonjsModule), my guess is that this is coming from a module produced by https://github.com/rollup/rollup-plugin-commonjs

@guybedford

Copy link
Copy Markdown
Contributor Author

Sure no stress, I'll run it on my test case here for that too and see what I can find.

@anandthakker

Copy link
Copy Markdown
Contributor

@guybedford

Copy link
Copy Markdown
Contributor Author

@anandthakker amazing thanks for isolating - my CJS case here didn't catch it.

@guybedford

Copy link
Copy Markdown
Contributor Author

@anandthakker I've included the fix here. Thanks again for the test cases.

@anandthakker

Copy link
Copy Markdown
Contributor

@guybedford thanks! Confirmed that it's working in practice over at https://github.com/mapbox/mapbox-gl-js/tree/6fa5becea62ac5a58a5eb1572fb764c64e50fa36

@anandthakker

Copy link
Copy Markdown
Contributor

(By the way, @guybedford, you can also see there the hacky way we're using code splitting to approximate the new Worker() strategy under discussion over at #1029)

@lukastaegert lukastaegert added this to the 0.56.3 milestone Feb 22, 2018

@lukastaegert lukastaegert left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Great work!

Comment thread src/Chunk.ts Outdated
this.entryModule = undefined;
this.isEntryModuleFacade = false;
if (orderedModules.length === 0)
this.isEntryModuleFacade = true;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This would easily merge with the previous assignment.

Comment thread src/Chunk.ts Outdated
ensureExport (module: Module | ExternalModule, variable: Variable): string {
ensureExport (module: Module | ExternalModule, variable: Variable, exportName: string): string {
// assert(module.chunk === this || module.isExternal);
let safeExportName = this.exportedVariables.get(variable);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Maybe we should actually call this this.exportedVariableNames to make clear what we are mapping the variables to.

Comment thread src/Chunk.ts
}

return safeExportName;
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

👍

Comment thread src/ast/scopes/Scope.ts Outdated

// we can disregard exports.foo etc
if (declaration.exportName && declaration.isReassigned && !declaration.isId)
if (declaration.exportName && (declaration.isDefault || declaration.isReassigned && !declaration.isId))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The non-use of more parentheses here makes me a little uneasy (sorry, but I'm one of those people who need to look into an operator precedence table to see that && binds more strongly than ||).

@lukastaegert lukastaegert left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Awesome! I also very much like the additional private modifiers that will help us keep the API surface small.

@arackaf

arackaf commented Feb 24, 2018

Copy link
Copy Markdown

I'm trying to test this branch out, but I can't quite get npm to install it - can anyone here possibly lend a hand? As far as I can tell, this is what I want

npm i https://github.com/rollup/rollup.git#default-identifier-renaming --save

but npm doesn't seem to like it (nor plenty of the variations on that theme which I've also tried)

This seems to fail too :(

npm i rollup/rollup#default-identifier-renaming --save

@lukastaegert

Copy link
Copy Markdown
Member

Hi @arackaf,

you should probably check your npm version. As rollup relies on its prepare script being executed to build its bundle, direct Github installation will only work for npm versions 5.0.0 and later. As I just confirmed, npm i rollup/rollup#default-identifier-renaming --save should work with current npm versions.

Nevertheless, I am about to release this branch now anyway 😉

@lukastaegert
lukastaegert merged commit db17e0f into master Feb 25, 2018
@lukastaegert
lukastaegert deleted the default-identifier-renaming branch February 25, 2018 18:32
@arackaf

arackaf commented Feb 25, 2018

Copy link
Copy Markdown

Aha! Thanks Lukas. I'm still too scared to go back in the npm 5 waters. I reverted back to the comfort and safety of npm 4 since many of the 5 bugs affected me directly.

@guybedford

Copy link
Copy Markdown
Contributor Author

@arackaf for future reference try git://github.com/rollup/rollup#default-identifier-renaming.

@lukastaegert

Copy link
Copy Markdown
Member

@arackaf Might be worth giving npm@5 another shot. A lot has been fixed and improved since 5.0.0. We're using it at work for two large projects and after some initial hickups, it's now been smooth riding for quite a few months now. The performance benefits are nothing to sneeze at 😉

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.

Code splitting with 'amd' output with default export from common chunk causes incorrect import from dependent chunks

4 participants