2023-04-20 17:14:30 +02:00
|
|
|
import fs from "node:fs"
|
2019-09-13 13:49:11 +02:00
|
|
|
|
|
|
|
|
function toDot(modules, output) {
|
|
|
|
|
let buffer = "digraph G {\n"
|
|
|
|
|
buffer += "edge [dir=back]\n"
|
|
|
|
|
|
2023-09-07 17:56:39 +02:00
|
|
|
for (const m of modules) {
|
|
|
|
|
for (const dep of m.deps) {
|
2021-02-03 17:13:38 +01:00
|
|
|
buffer += `"${dep}" -> "${m.id}"\n`
|
2023-09-07 17:56:39 +02:00
|
|
|
}
|
|
|
|
|
}
|
2019-09-13 13:49:11 +02:00
|
|
|
buffer += "}\n"
|
2022-12-27 15:37:40 +01:00
|
|
|
fs.writeFileSync(output, buffer, { encoding: "utf8" })
|
2019-09-13 13:49:11 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function prune(modules) {
|
2022-12-27 15:37:40 +01:00
|
|
|
let avail = modules.filter((m) => m.deps.length == 0)
|
2019-09-13 13:49:11 +02:00
|
|
|
if (!avail.length) {
|
2022-12-27 15:37:40 +01:00
|
|
|
return
|
2019-09-13 13:49:11 +02:00
|
|
|
}
|
|
|
|
|
|
2022-12-27 15:37:40 +01:00
|
|
|
let id = avail[0].id
|
|
|
|
|
// console.log("pruning", id);
|
|
|
|
|
let index = modules.indexOf(avail[0])
|
|
|
|
|
modules.splice(index, 1)
|
2023-09-07 17:56:39 +02:00
|
|
|
for (const m of modules) {
|
2022-12-27 15:37:40 +01:00
|
|
|
m.deps = m.deps.filter((dep) => dep != id)
|
2023-09-07 17:56:39 +02:00
|
|
|
}
|
2022-12-27 15:37:40 +01:00
|
|
|
prune(modules)
|
2019-09-13 13:49:11 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getPrefix(ids) {
|
|
|
|
|
if (ids.length < 2) {
|
2022-12-27 15:37:40 +01:00
|
|
|
return ""
|
2019-09-13 13:49:11 +02:00
|
|
|
}
|
|
|
|
|
return ids.reduce((prefix, val) => {
|
|
|
|
|
while (val.indexOf(prefix) != 0) {
|
2022-12-27 15:37:40 +01:00
|
|
|
prefix = prefix.substring(0, prefix.length - 1)
|
2019-09-13 13:49:11 +02:00
|
|
|
}
|
2022-12-27 15:37:40 +01:00
|
|
|
return prefix
|
|
|
|
|
})
|
2019-09-13 13:49:11 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Plugin which will generate .dot file with dependency graph
|
2024-07-05 19:02:03 +02:00
|
|
|
* @param options {{exclude: string, output: string, prune: boolean, prefix: string}}
|
2019-09-13 13:49:11 +02:00
|
|
|
*/
|
2024-07-05 19:02:03 +02:00
|
|
|
export default function plugin(options) {
|
2022-12-27 15:37:40 +01:00
|
|
|
let exclude = (str) => options.exclude && str.match(options.exclude)
|
2019-09-13 13:49:11 +02:00
|
|
|
let output = options.output
|
|
|
|
|
if (!output) throw new Error("Please specify output file")
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
generateBundle(bundleOptions, bundle, isWrite) {
|
2022-12-27 15:37:40 +01:00
|
|
|
let ids = []
|
2019-09-13 13:49:11 +02:00
|
|
|
for (const moduleId of this.moduleIds) {
|
|
|
|
|
if (!exclude(moduleId)) {
|
2022-12-27 15:37:40 +01:00
|
|
|
ids.push(moduleId)
|
2019-09-13 13:49:11 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-27 15:37:40 +01:00
|
|
|
let prefix = options.prefix || getPrefix(ids)
|
|
|
|
|
let strip = (str) => (str.startsWith(prefix) ? str.substring(prefix.length) : str)
|
2019-09-13 13:49:11 +02:00
|
|
|
|
2022-12-27 15:37:40 +01:00
|
|
|
let modules = []
|
2023-09-07 17:56:39 +02:00
|
|
|
for (const id of ids) {
|
2019-09-13 13:49:11 +02:00
|
|
|
let m = {
|
|
|
|
|
id: strip(id),
|
2022-12-27 15:37:40 +01:00
|
|
|
deps: this.getModuleInfo(id)
|
|
|
|
|
.importedIds.filter((x) => !exclude(x))
|
|
|
|
|
.concat(this.getModuleInfo(id).dynamicImporters.filter((x) => !exclude(x)))
|
|
|
|
|
.map(strip),
|
2019-09-13 13:49:11 +02:00
|
|
|
}
|
|
|
|
|
if (exclude(m.id)) {
|
2023-09-07 17:56:39 +02:00
|
|
|
continue
|
2019-09-13 13:49:11 +02:00
|
|
|
}
|
2022-12-27 15:37:40 +01:00
|
|
|
modules.push(m)
|
2023-09-07 17:56:39 +02:00
|
|
|
}
|
2019-09-13 13:49:11 +02:00
|
|
|
if (options.prune) {
|
2022-12-27 15:37:40 +01:00
|
|
|
prune(modules)
|
2019-09-13 13:49:11 +02:00
|
|
|
}
|
2022-12-27 15:37:40 +01:00
|
|
|
toDot(modules, output)
|
|
|
|
|
},
|
2019-09-13 13:49:11 +02:00
|
|
|
}
|
2022-12-27 15:37:40 +01:00
|
|
|
}
|