We ship rollup-plugin-index-html which, for multiple rollup builds, is able to output a single index.html file containing both build outputs. One version with modern js syntax and esm, and one version with es5 and systemjs for older browsers.
It's kind of a hacky solution, relying on an array of rollup configs. Now that we can have plugins per output I'm looking to update our solution to utilize this instead. For the html part I'd like to to use @rollup/plugin-html.
One problem I'm running into right now is that it's not possible to collect multiple bundles into one index.html.
Add the ability to collect multiple bundles into one index.html file. For example:
import html from '@rollup/plugin-html';
export default {
input: 'src/app.js',
output: [
{
format: 'esm',
dir: 'output',
},
{
format: 'system',
dir: 'output/legacy',
},
],
plugins: [
html({
template({ attributes, bundles, files, publicPath, title }) {
return `
<html>
<body>
<script type="module" src="${bundles[0]['app.js'].fileName}"></script>
<script nomodule src="s.js"></script>
<script nomodule src="${bundles[1]['app.js'].fileName}"></script>
</body>
</html>
`;
}
})
]
}
Right now, the generateBundle hook is used to which is of course called for each separate bundle.
A possible solution could be to use another hook which has the information of all the generated bundles. I couldn't find a suitable hook for this unfortunately.
Another solution could be to inspect the amount of generated bundles, and only output the index.html (and call the template function) when all the bundles have been collected.
@lukastaegert this is an interesting scenario. We don't currently have a hook that provides info for all bundles, and buildEnd is called before generate. To implement this feature we need to collect all of the assets from all of the outputs. Is this an opportunity for a new hook or is there another way to go about this?
@lukastaegert would be great if you have a chance to look at this :)
Having an overview over all outputs is technically not possible because internally, multiple outputs are just handled by calling generate multiple times on the output of rollup.rollup, and how would you know which call is the last one? This would be a drastic change in Rollup's architecture and how Rollup is used in general.
What you could do instead is adding output plugins that "know about each other":
import html from '@rollup/plugin-html';
const htmlPlugin = html({
template({ attributes, bundles, files, publicPath, title }) {
return `
<html>
<body>
<script type="module" src="${bundles[0]['app.js'].fileName}"></script>
<script nomodule src="s.js"></script>
<script nomodule src="${bundles[1]['app.js'].fileName}"></script>
</body>
</html>
`;
}
});
export default {
input: 'src/app.js',
output: [
{
format: 'esm',
dir: 'output',
plugins: [htmlPlugin.addOutput()]
},
{
format: 'system',
dir: 'output/legacy',
plugins: [htmlPlugin.addOutput()]
},
],
plugins: [htmlPlugin]
}
This is a solution that would work today, but it is still kinda hacky to properly combine the outputs. A "nicer" solution would be for plugins to be able to call bundle.generate themselves, e.g. in the buildEnd hook. I.e. we add a context function so that in the build hook, you can call this.generateBundle({format: 'esm'}) to receive a Promise with a generated bundle (that is not written to disk. But I guess the plugin wants to do this themselves anyway?).
Then you could have a config like this:
import html from '@rollup/plugin-html';
export default {
input: 'src/app.js',
plugins: [
html({
template({ attributes, bundles, files, publicPath, title }) {
return `
<html>
<body>
<script type="module" src="${bundles[0]['app.js'].fileName}"></script>
<script nomodule src="s.js"></script>
<script nomodule src="${bundles[1]['app.js'].fileName}"></script>
</body>
</html>
`;
},
dir: 'output',
output: [{format: 'esm', subDir: '.'}, {format: 'system', subDir: 'legacy'}]
})
]
}
Thus you would have a config without any output at all while an adapted output config could be moved into the plugin.
Yet another addition to streamline the first approach could be to add a "config-file-only" hook to Rollup's CLI that receives the whole config file with input and outputs and is allowed to do transformations on it like injecting per-output marker plugins.
The addOutput approach is actually something that webpack-plugin-serve is using to attach itself to multiple compiler/config instances. In practice, it works very nicely.
Im using a similar approach now as well, I guess its the best we can do. Do you think this is something we could add to the html plugin?
yeah I've actually started work on that last night. I need to write some tests but the change was relatively easy.
I created a plugin which can fulfill the original request in the issue https://github.com/stalniy/rollup-plugin-legacy-bundle
It adds legacy build chunks to the original bundle, so they can be collected by standard rollup HTML plugin
update:
It uses es chunks and their source maps as inputs to produce a legacy build. The good point is that it doesn’t generate unnecessary assets as in version with multiple outputs
@LarsDenBakker would the plugin that @stalniy created solve the use case for you?
Closing as stale. Please ping me to reopen.
Sorry I missed your other message. I actually implemented this in https://github.com/open-wc/open-wc/tree/master/packages/rollup-plugin-html which solves my use case.
@LarsDenBakker This is exactly I was looking for awesome! You folks from the open-wc are doing the right things! 👏
Most helpful comment
Sorry I missed your other message. I actually implemented this in https://github.com/open-wc/open-wc/tree/master/packages/rollup-plugin-html which solves my use case.