-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
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
add the ability to rewrite modules in-place #1922
Conversation
Turns out the the folders are not preserved: "app/index.js" => "index.js". I will work on that next. |
58a6c3b
to
601f886
Compare
Added another option to enable original directory structure. |
08ed72d
to
c66aef5
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've included some feedback here, let me know your thoughts.
src/Graph.ts
Outdated
curEntry.isEntryPoint = true; | ||
curEntryHash = randomUint8Array(10); | ||
visit(curEntry); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems like this is done to ensure that no chunking happens right?
I think it can be done more easily by altering the visit function itself to do something like:
if (!preserveModules)
Uint8ArrayXor(module.entryPointsHash, curEntryHash);
else if (isZero(module.entryPointsHash))
module.entryPointsHash = randomUint8Array(10);
then I think that would be all there is too it without any extra loops or need to track modules.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perfect! It got a lot simpler with this change.
src/Graph.ts
Outdated
preservedModules.forEach(module => { | ||
if (entryModules.indexOf(module) === -1) | ||
entryModules.push(module); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is just "all modules" right? If so it should be possible to generate from Object.values(this.graph) + this.externals?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
removed with your other suggested change.
src/Graph.ts
Outdated
@@ -396,7 +421,7 @@ export default class Graph { | |||
chunkList.forEach(chunk => { | |||
// generate the imports and exports for the output chunk file | |||
if (chunk.entryModule) { | |||
const entryName = generateChunkName(chunk.entryModule.id, chunkNames, true); | |||
const entryName = generateChunkName(chunk.entryModule.id, chunkNames, true, inputRelativeDir); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this a mandatory option then? Is there not a way to deduce the lowest base by default if this is not provided?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since commondir
is not widely maintained and a small piece of code, do you think we could just inline the implementation?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I could do that. Are you sure I should just copy paste? I would argue that we depend on it until we need to fix something, then copy. @lukastaegert care to tie-break?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I must admit I did not read everything here. Looking at commondir, it relies on nodes path.resolve
which we do not have available in a browser build—even though we have our own polyfill for that (damn, we REALLY need a test for this. You should see a warning about "path" being external when building rollup with this setup—this is always BAD). Thus I fear this needs to go into our own code base somehow.
However I am happy for every bit of functionality we can extract from Graphs.ts and put into other files and for me, this is a clear candidate for the "utils" folder.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ported into the utils folder.
0a319a1
to
d3006af
Compare
d3006af
to
086baab
Compare
It's pretty awesome how small this feature has got. And it definitely preserves the original pathnames ok with directory creation etc? |
From my testing, yes. It does get weird if your entry file imports from '../../../../../x', then your output dir will look pretty strange, but it should still work and be "correct". |
c9647d3
to
803d043
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking good.
@lukastaegert would be interested to hear your thoughts here as well.
src/utils/commondir.ts
Outdated
@@ -0,0 +1,21 @@ | |||
// ported from https://github.com/substack/node-commondir | |||
export default function commondir (relfiles: string[]) { | |||
var files = relfiles; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps just name the argument files
/
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
src/utils/commondir.ts
Outdated
export default function commondir (relfiles: string[]) { | ||
var files = relfiles; | ||
|
||
var res = files.slice(1).reduce(function (ps, file) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const
and arrow function can be used.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
src/utils/commondir.ts
Outdated
var res = files.slice(1).reduce(function (ps, file) { | ||
if (!file.match(/^([A-Za-z]:)?\/|\\/)) { | ||
throw new Error('relative path without a basedir'); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we know that our inputs will pass this, it may be possible to remove this check.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
removed
src/utils/commondir.ts
Outdated
throw new Error('relative path without a basedir'); | ||
} | ||
|
||
var xs = file.split(/\/+|\\+/); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
src/utils/commondir.ts
Outdated
for ( | ||
var i = 0; | ||
ps[i] === xs[i] && i < Math.min(ps.length, xs.length); | ||
i++ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tailing semicolon.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
compiler didn't like that
name = path.relative(inputRelativeDir, id).replace(/\\/g, '/'); | ||
} else { | ||
name = path.basename(id); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Check indentation here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One thing I observed that I think we should definitely improve is the fact that if a module imports something from outside the common directory of the entry points (i.e. if the entry point imports something that starts with ../
), new files and folders are created outside the intended target directory. This can definitely leave a mess on an unsuspecting user's system. In my opinion there are two possible solutions
- throw an error if something like this would happen (probably not ideal), or
- find the common root directory not among the entry points but among the generated chunk file names.
To achieve the latter, we could do the following:
- use
generateChunkName
only for the non-path-preserving case (and remove the last argument) - if we preserve paths/modules, we use the completed
chunks
object to build a new object with correct paths (possibly extract a helper method here)
This is just a rough idea, some fine-tuning may be necessary.
Sure thing. Was a little busy the last days to get my own PR in order. Will probably take a look at this evening or tomorrow. I think this could become on of the core features of 0.57.0! |
BTW some of the chunking form tests seem to be broken. And this should probably be rebased against the current master soon. |
@lukastaegert I discovered a bug, so I added more test cases. I'm trying to diagnose it now. |
e061cc2
to
3849e93
Compare
@lukastaegert @guybedford Turns out it might not be a bug, but an understanding issue. It has to do with what's going on in \test\chunking-form\samples\chunking-reexport. The way it's collapsing reexports there is unexpected to me, and probably not desirable for this new feature. I would love some pointers. |
@kellyselden can you link me to the test case that is failing? I just re-ran the CI here and it seems nothing is breaking specifically. If I can follow the exact simplified scenario I may be able to suggest further. |
@guybedford https://github.com/rollup/rollup/pull/1922/files#diff-c7e8e1a25cc0ed7f80f7f0df33f956c7R7 |
7481a1e
to
5ede078
Compare
@guybedford I added the test for export aliases. Since there are still two commits, I added the test to the first one, and export aliases worked as expected. Then I had to modify the test to remove the aliases once your commit was added on top. You probably already knew this, I just wanted to point it out in case you didn't. |
5ede078
to
f837ca7
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry for not getting to this sooner. This works nicely now! As this is an experimental feature anyway, I'll merge this into the next release, we can always fledge out any last details later.
This option is still not documented on the site? It seems that i just should try it ;/ |
I think we should document this now actually. A documentation PR is more than welcome! |
Closes #1878.
This turned out to be remarkably simpler once @guybedford laid the foundational work with dynamic imports and chunking. I essentially tapped into the dynamic imports system and made every import behave like a dynamic import.
To try this out, all you have to do is add the
experimentalPreserveModules
to your existingexperimentalCodeSplitting
setup. Then, the directory tree should be preserved in your output dir.