-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
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
experimentalCodeSplitting chunkNaming #1995
Comments
Opening up the chunk aliasing hook to plugins sounds like it could be sensible. |
One thing to note is that even with a hook, determining the correct hash would need to know all the details of the modules and their transformations.... so perhaps this is something we should implement as an option internally for that reason? |
That would be reasonable as well. |
I had some thoughts about this as well and I actually agree with you, @guybedford. My suggestion would be to combine this feature with a way to specify output chunk names. If we provide a way to specify these names (and paths?) that allows for a "hash" placeholder (+ possibly a length for the hash), we would not even need a new config option. As for the hashing itself, I think an algorithm similar to the chunking algorithm might do the trick:
To achieve this, we could first render all chunks (without adjusting import files), then calculate the content hashes and the resulting hashes, then traverse the top level statements again to adjust the import files. Just some vague ideas, no work has been done in this direction by myself. |
Also I am now convinced this is something that is much easier to do in core rollup than in a plugin. |
The approach described in #1995 (comment) sounds great to me. One of the issues I'm running into here is that we create chunk names as part of the So the API is: rollup.rollup(...): {
chunks: {
[name: chunkName]: {
imports: string[],
exports: string[],
modules: string[]
}
},
generate: () => {
[chunkName: string]: { code, map, ast }
};
write: () => void
} where the import ids include external Ids, but also other chunk ids, which may in turn be dependent on hashing or chunk naming. What we probably need to do is flip this API around something like: rollup.rollup(...): {
generate: () => {
[name: chunkName]: {
code: string;
map: SourceMap;
ast: Ast;
imports: string[];
exports: string[];
modules: string[];
}
},
write: () => <as above>
} so that the chunk information is only provided after the write call is run. Let me know how that sounds! |
@lukastaegert any feedback on this one? Happy to get to work on it if it seems good. |
Will need to think a little more about this (only have a phone available right now). So you still want the My only wish is to consider not closing any doors to finally making the non-chunking code a special case of the chunking one as the current code duplication here is painful. Also, might be helpful to put some thoughts into what the config file API for providing chunk names could look like before we go too deep into this. My initial thoughts were to enable a third form of the Otherwise, please go ahead! |
Yes exactly
We can potentially make the corresponding API change in the non-code splitting case so that there remains a rough compatbility. Perhaps with the previous bundle
I really like this suggestion, the only issue is how to use it to name chunks. Perhaps we could have a separate rollup.rollup({
input: {
'entryOne.js': 'path/to/entry1.js',
'entryTwo.js': 'path/to/entry2.js'
}, // while still supporting the array form
output: {
dir: 'dist',
chunkNames: 'chunk-[hash].js' // or a function hook
}
}); Let me know how that seems. |
The current non-code-splitting API is rollup.rollup(...): {
imports: string[],
exports: string[],
modules: ModuleJSON[],
generate: () => {
[chunkName: string]: { code, map, ast }
};
write: () => void
}
rollup.rollup(...): {
imports?: string[], // only added if we have a single entry point
exports?: string[], // only added if we have a single entry point
modules: ModuleJSON[],
generate: () => {
code?: string // only added if we have a single entry point
map?: SourceMap // only added if we have a single entry point
[name: chunkName]: { // for single entry points, this just reflects the one created chunk
code: string;
map: SourceMap;
imports: string[];
exports: string[];
modules: string[];
}
},
write: () => void
}
Yes, that seems nice! The only thing where we are wasting flexibility is if we specify the file names for the chunks in the input options instead of the output options. If we create several versions in one run (e.g. an ESM and an CJS version), the entry chunk names would still need to be the same (even though you may want to have e.g. |
@lukastaegert note that I also mistyped the Looking more closely at the watcher API it seems like the watcher does use this ModuleJSON before write, but I don't see why the code at https://github.com/rollup/rollup/blob/master/src/watch/index.ts#L200 couldn't be moved to after write at https://github.com/rollup/rollup/blob/master/src/watch/index.ts#L223? The ModuleJSON does contain ID information, so we'd need to provide this after write/generate for code splitting, and it would be nice to keep the correlation between the APIs. If so, my suggestion would be for the API: Single-file case: interface OuptputChunk {
code: string;
map: SourceMap;
imports: string[];
exports: string[];
modules: ModuleJSON[];
};
rollup.rollup(...): {
// --- these to be deprecated: ---
imports: string[];
exports: string[];
modules: ModuleJSON[];
generate: () => OutputChunk;
write: () => OutputChunk;
} Code-splitting case: rollup.rollup(...): {
generate: () => {
[chunkName: string]: OutputChunk;
};
write: () => {
[chunkName: string]: OutputChunk;
};
} Let me know if that seems like it might be an ok approach? As a reminder - all this is necessary because the hash calculations in chunk dependency trees mean that the rendered output of one chunk affects the import ids of another. |
I still think it might be useful to have a list of included modules available after Otherwise I am ok with this API. We just need to communicate well that once the |
To quote the important bits from my previous comment...
Otherwise we can diverge between code-splitting and non-code-splitting as well here. There could also be the option to return an object when not code splitting too to get the APIs on the same footing. |
It does? Looks only like module ids to me which are basically the names of source files, aren't they?
But really, I'm not attached to this. We could just leave out this information until someone tells us why it was better it was included or which were the important parts they relied on.
Yes, that was the direction I was thinking of. |
@lukastaegert you're right yes, its specifically in how to name the chunks to list this information in the code splitting case that is the problem, not in the ModuleJSON[] output itself. We could always choose not to deprecate I must admit I do still like returning the single chunk in the single-file case for ease of use in the API to not have to think about output file names in pure in-memory generation cases. Think we've discussed this enough though - will try to get to actually writing code :P Thanks for feedback |
👍 |
PR created at #2068. |
Merged in e96f3fa. |
Is it possible to change the extension to |
I would like to have a way of adding hashes to chunkNames to have the ability to set long caches on files in production use cases. Currently chunkNames are generated based on a counter and I do not see a good way of tying into this for changing fileNames.
Without
experimentalCodeSplitting
you could use a plugin that would use theonwrite
lifecycle function. Now that files are referenced between each other this is no longer an option.I assume resolution would either be a change to lifecycle events to allow for filename changes or to provide some other mechanism to change chunk names.
The text was updated successfully, but these errors were encountered: