Last active
July 21, 2022 03:21
-
-
Save lukastaegert/fa8f7bbdc2caf4fb6797730f05e3f616 to your computer and use it in GitHub Desktop.
Rollup plugins to emit chunks and CSS assets from an HTML file and add an updated HTML file to the build, and to emit assets from a JS file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export const rollupLogo = "./logo.svg"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<link rel="stylesheet" type="text/css" href="styles.css" /> | |
<title>Plugin demo</title> | |
</head> | |
<body> | |
<script src="index.js" type="module"></script> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { rollupLogo } from "./assets.js"; | |
const image = document.createElement("img"); | |
image.src = rollupLogo; | |
document.body.appendChild(image); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"type": "module", | |
"scripts": { | |
"build": "rollup -c" | |
}, | |
"dependencies": { | |
"libxmljs2": "^0.25.1", | |
"rollup": "^2.6.0" | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import * as fs from "fs"; | |
import * as path from "path"; | |
import libXml from "libxmljs2"; | |
// This plugin takes the path of an HTML file, scans for script tags and emits | |
// those as chunks. Then it scans for stylesheets and emits those as assets. At | |
// last, it creates a rewritten HTML file with the paths to the new chunks and | |
// assets (by default containing content-hashed file names) and adds it to the | |
// bundle as well. | |
export default function buildFromHtml(htmlFile) { | |
const fileName = path.resolve(htmlFile); | |
const doc = libXml.parseHtml(fs.readFileSync(fileName, "utf8")); | |
const scriptFileReferences = new Map(); | |
const styleFileReferences = new Map(); | |
return { | |
name: "generate-html", | |
buildStart() { | |
for (const tag of doc.find("//script")) { | |
scriptFileReferences.set( | |
tag, | |
this.emitFile({ | |
type: "chunk", | |
id: tag.attr("src").value(), | |
}) | |
); | |
} | |
for (const tag of doc.find("//link[@rel='stylesheet']")) { | |
styleFileReferences.set( | |
tag, | |
this.emitFile({ | |
type: "asset", | |
name: path.basename(tag.attr("href").value()), | |
source: fs.readFileSync( | |
path.resolve(path.dirname(fileName), tag.attr("href").value()) | |
), | |
}) | |
); | |
} | |
}, | |
generateBundle() { | |
for (const [tag, referenceId] of scriptFileReferences) { | |
tag.attr("src", this.getFileName(referenceId)); | |
} | |
for (const [tag, referenceId] of styleFileReferences) { | |
tag.attr("href", this.getFileName(referenceId)); | |
} | |
this.emitFile({ | |
type: "asset", | |
source: doc.toString(false), | |
fileName: "index.html", | |
}); | |
}, | |
}; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import fs from "fs"; | |
import path from "path"; | |
import { rollup } from "rollup"; | |
// This plugin takes the path of a JavaScript file that exports some constants | |
// which are interpreted as relative paths to assets. These files are added to | |
// the Rollup bundle and the file is rewritten to point to the new assets (by | |
// default with content-hashed file names). | |
export default function emitAssetsFromFile(assetsFile) { | |
const fileName = path.resolve(assetsFile); | |
let assetFileFound = false; | |
return { | |
name: "emit-assets", | |
async load(id) { | |
if (id === fileName) { | |
assetFileFound = true; | |
// This will only run if you are using Node 13+ and either the fileName | |
// has an .mjs extension or you have "type": "module" in your | |
// package.json. Otherwise replace import with getExportsFromFile | |
// below. | |
// const assets = await getExportsFromFile(fileName); | |
const assets = await import(fileName); | |
return Object.keys(assets) | |
.map((assetKey) => { | |
const assetFileName = path.resolve(assets[assetKey]); | |
return `export const ${assetKey} = import.meta.ROLLUP_FILE_URL_${this.emitFile( | |
{ | |
type: "asset", | |
source: fs.readFileSync(path.resolve(assetFileName)), | |
name: path.basename(assetFileName), | |
} | |
)};`; | |
}) | |
.join("\n"); | |
} | |
}, | |
buildEnd() { | |
if (assetFileFound === false) { | |
throw new Error( | |
`Expected assets file "${fileName}" was not part of the module graph.` | |
); | |
} | |
}, | |
}; | |
} | |
// Helper to convert an ESM file to CJS, turn it into a function and run it to | |
// get its exports. | |
async function getExportsFromFile(fileName) { | |
const getAssets = new Function( | |
"module", | |
"exports", | |
( | |
await (await rollup({ input: fileName })).generate({ format: "cjs" }) | |
).output[0].code | |
); | |
const module = { exports: {} }; | |
getAssets(module, module.exports); | |
return module.exports; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import buildFromHtml from "./rollup-plugin-build-from-html.js"; | |
import emitAssetsFromFile from "./rollup-plugin-emit-assets-from-file.js"; | |
// See how we do not need an `input` option here at all! | |
// All chunks are created from the HTML file. | |
export default { | |
output: { | |
dir: "dist", | |
format: "esm", | |
}, | |
plugins: [buildFromHtml("index.html"), emitAssetsFromFile("assets.js")], | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
body { | |
color: blue; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment