Files
quartz-website/quartz/plugins/loader/install-plugins.ts
T
saberzero1 5b34917e98 feat: support npm scoped package specifiers for plugins
Plugins can now be referenced as "@quartz-community/<name>" in
quartz.config.yaml and via 'quartz plugin add'. The npm path skips
git installation and resolves from node_modules.

Changes:
- gitLoader.ts: detect @scope/name as npm package in parsePluginSource()
- config-loader.ts: skip git install for npm packages, read manifests
  from node_modules via createRequire
- install-plugins.ts: filter npm packages from prebuild, fallback to
  YAML config parsing to avoid loading full quartz.ts
- plugin-data.js: npm detection in CLI parseGitSource()
- plugin-git-handlers.js: npm install path in handlePluginAdd()
- package.json: add missing hast-util-from-html dependency
2026-07-23 01:17:53 +02:00

80 lines
2.6 KiB
JavaScript

#!/usr/bin/env node
import fs from "fs"
import path from "path"
import YAML from "yaml"
import { installPlugins, parsePluginSource } from "./gitLoader.js"
import type { PluginSource, QuartzPluginsJson } from "./types.js"
function resolveConfigPath(): string {
const configYamlPath = path.join(process.cwd(), "quartz.config.yaml")
const defaultConfigYamlPath = path.join(process.cwd(), "quartz.config.default.yaml")
const legacyPluginsJsonPath = path.join(process.cwd(), "quartz.plugins.json")
const legacyDefaultPluginsJsonPath = path.join(process.cwd(), "quartz.plugins.default.json")
if (fs.existsSync(configYamlPath)) return configYamlPath
if (fs.existsSync(legacyPluginsJsonPath)) return legacyPluginsJsonPath
if (fs.existsSync(defaultConfigYamlPath)) return defaultConfigYamlPath
if (fs.existsSync(legacyDefaultPluginsJsonPath)) return legacyDefaultPluginsJsonPath
return configYamlPath
}
function readPluginsJson(): QuartzPluginsJson | null {
const configPath = resolveConfigPath()
if (!fs.existsSync(configPath)) return null
const raw = fs.readFileSync(configPath, "utf-8")
if (configPath.endsWith(".yaml") || configPath.endsWith(".yml")) {
return YAML.parse(raw)
}
return JSON.parse(raw)
}
async function getExternalPluginSources(): Promise<PluginSource[]> {
try {
const module = await import("../../../quartz.js")
const config = module.default ?? module
const externalPlugins = config.externalPlugins
if (Array.isArray(externalPlugins) && externalPlugins.length > 0) {
return externalPlugins as PluginSource[]
}
} catch {
// fall back to config yaml parsing
}
const pluginsJson = readPluginsJson()
const entries = pluginsJson?.plugins ?? []
return entries.filter((entry) => entry.enabled !== false).map((entry) => entry.source)
}
async function main() {
const externalPlugins = await getExternalPluginSources()
if (externalPlugins.length === 0) {
console.log("No external plugins to install.")
return
}
const specs = externalPlugins
.map((source: PluginSource) => parsePluginSource(source))
.filter((spec) => !spec.npmPackage)
if (specs.length === 0) {
console.log("No external Git plugins to install.")
return
}
console.log(`Installing ${specs.length} plugin(s) from Git...`)
const installed = await installPlugins(specs, { verbose: true })
if (installed.size === externalPlugins.length) {
console.log("✓ All plugins installed successfully")
} else {
console.error(`✗ Only ${installed.size}/${externalPlugins.length} plugins installed`)
process.exit(1)
}
}
main().catch((err) => {
console.error("Failed to install plugins:", err)
process.exit(1)
})