mirror of https://github.com/YunYouJun/valaxy
feat: refactor cli & add rss to hook build:after
This commit is contained in:
parent
b76f20e859
commit
84e52222b4
|
@ -5,7 +5,7 @@
|
|||
},
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"build": "npm run fuse && npm run build:ssg && npm run rss",
|
||||
"build": "npm run fuse && npm run build:ssg",
|
||||
"build:spa": "valaxy build",
|
||||
"build:ssg": "valaxy build --ssg --log=info",
|
||||
"dev": "nodemon -w \"../../packages/valaxy/dist/*.mjs\" --exec \"valaxy . --port 3333\"",
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
"type": "module",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "npm run build:ssg && npm run rss",
|
||||
"build": "npm run build:ssg",
|
||||
"build:spa": "valaxy build",
|
||||
"build:ssg": "valaxy build --ssg",
|
||||
"dev": "nodemon -w \"../packages/valaxy/dist/*.mjs\" --exec \"valaxy .\"",
|
||||
|
@ -23,7 +23,7 @@
|
|||
"@iconify-json/simple-icons": "^1.1.75",
|
||||
"nodemon": "^3.0.1",
|
||||
"vite": "^4.5.0",
|
||||
"vitepress": "1.0.0-rc.22",
|
||||
"vitepress": "1.0.0-rc.23",
|
||||
"vue": "^3.3.6"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -56,7 +56,7 @@ You can configure shortcut scripts in `package.json`. (**Suggested**)
|
|||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"build": "npm run build:ssg && npm run rss",
|
||||
"build": "npm run build:ssg",
|
||||
"build:spa": "valaxy build",
|
||||
"build:ssg": "valaxy build --ssg",
|
||||
"dev": "valaxy .",
|
||||
|
|
|
@ -107,7 +107,7 @@ export default defineSiteConfig({
|
|||
"theme": "yun"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "npm run fuse && npm run build:ssg && npm run rss",
|
||||
"build": "npm run fuse && npm run build:ssg",
|
||||
"build:ssg": "valaxy build --ssg",
|
||||
"fuse": "valaxy fuse",
|
||||
"rss": "valaxy rss"
|
||||
|
@ -291,6 +291,7 @@ export const install: UserModule = ({ isClient, app, router }) => {
|
|||
}
|
||||
}
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
::: en
|
||||
|
@ -329,6 +330,7 @@ export const install: UserModule = ({ isClient, app, router }) => {
|
|||
}
|
||||
}
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
More info see [vue-gtag-next](https://github.com/MatteoGabriele/vue-gtag-next).
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "npm run build:ssg && npm run rss",
|
||||
"build": "npm run build:ssg",
|
||||
"build:spa": "valaxy build",
|
||||
"build:ssg": "valaxy build --ssg",
|
||||
"dev": "valaxy",
|
||||
|
|
|
@ -12,9 +12,11 @@ const { t } = useI18n()
|
|||
<div />
|
||||
</template>
|
||||
<div text="center" m="t-20">
|
||||
<div text-4xl>
|
||||
<div i-ri-alarm-warning-line inline-block />
|
||||
<div class="not-found" title="404" font="mono">
|
||||
404
|
||||
</div>
|
||||
|
||||
<router-view />
|
||||
<router-view />
|
||||
<div>
|
||||
<button btn text-sm m="3 t8" @click="router.back()">
|
||||
|
@ -24,3 +26,10 @@ const { t } = useI18n()
|
|||
</div>
|
||||
</Layout>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.not-found {
|
||||
font-size: 10rem;
|
||||
text-shadow: 0 5px 10px rgba(0,0,0,.25), 0 20px 20px rgba(0,0,0,.15);
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -25,7 +25,6 @@ const { back } = useBack()
|
|||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
// inspired by https://codepen.io/pgalor/pen/OeRWJQ
|
||||
.not-found {
|
||||
font-size: 10rem;
|
||||
text-shadow: 0 5px 10px rgba(0,0,0,.25), 0 20px 20px rgba(0,0,0,.15);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#!/usr/bin/env node
|
||||
'use strict'
|
||||
|
||||
const { run } = require('../dist/node/cli.cjs')
|
||||
const { run } = require('../dist/node/cli/index.cjs')
|
||||
|
||||
function main() {
|
||||
run()
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#!/usr/bin/env node
|
||||
'use strict'
|
||||
|
||||
import { run } from '../dist/node/cli.mjs'
|
||||
import { run } from '../dist/node/cli/index.mjs'
|
||||
|
||||
function main() {
|
||||
run()
|
||||
|
|
|
@ -6,6 +6,8 @@ const router = useRouter()
|
|||
const route = useRoute()
|
||||
|
||||
onBeforeMount(() => {
|
||||
router.push('/')
|
||||
|
||||
// compatible for post url ends with slash
|
||||
if (route.path !== '/' && route.path.endsWith('/'))
|
||||
router.replace(route.path.slice(0, -1))
|
||||
|
|
|
@ -38,6 +38,7 @@ export function createValaxyNode(options: ResolvedValaxyOptions) {
|
|||
version,
|
||||
hooks,
|
||||
hook: hooks.hook,
|
||||
options,
|
||||
}
|
||||
|
||||
options.addons.forEach((addon) => {
|
||||
|
|
|
@ -1,261 +0,0 @@
|
|||
import path from 'node:path'
|
||||
import { exec } from 'node:child_process'
|
||||
import process from 'node:process'
|
||||
import os from 'node:os'
|
||||
import fs from 'fs-extra'
|
||||
import yargs from 'yargs'
|
||||
import type { InlineConfig, LogLevel } from 'vite'
|
||||
import { mergeConfig } from 'vite'
|
||||
|
||||
import consola from 'consola'
|
||||
|
||||
import { yellow } from 'kolorist'
|
||||
import { hideBin } from 'yargs/helpers'
|
||||
import qrcode from 'qrcode'
|
||||
import { version } from '../package.json'
|
||||
import { findFreePort } from './utils/net'
|
||||
import { resolveOptions } from './options'
|
||||
import { bindShortcut, initServer, printInfo } from './utils/cli'
|
||||
|
||||
// build
|
||||
import { build, postProcessForSSG, ssgBuild } from './build'
|
||||
|
||||
// rss
|
||||
import { build as rssBuild } from './rss'
|
||||
import { getIndexHtml, mergeViteConfigs } from './common'
|
||||
import { registerFuseCommand } from './cli/fuse'
|
||||
import { registerNewCommand } from './cli/new'
|
||||
|
||||
import { setEnv, setEnvProd } from './utils/env'
|
||||
import { commonOptions } from './cli/options'
|
||||
import { createValaxyNode } from './app'
|
||||
|
||||
export const cli = yargs(hideBin(process.argv)).scriptName('valaxy')
|
||||
.usage('$0 [args]')
|
||||
.version(version)
|
||||
.showHelpOnFail(false)
|
||||
.alias('h', 'help')
|
||||
.alias('v', 'version')
|
||||
|
||||
cli.command(
|
||||
'* [root]',
|
||||
'Start a local server for Valaxy',
|
||||
args =>
|
||||
commonOptions(args)
|
||||
.option('port', {
|
||||
alias: 'p',
|
||||
type: 'number',
|
||||
describe: 'port',
|
||||
})
|
||||
.option('open', {
|
||||
alias: 'o',
|
||||
default: false,
|
||||
type: 'boolean',
|
||||
describe: 'open in browser',
|
||||
})
|
||||
.option('remote', {
|
||||
default: true,
|
||||
type: 'boolean',
|
||||
describe: 'listen public host and enable remote control',
|
||||
})
|
||||
.option('log', {
|
||||
default: 'info',
|
||||
type: 'string',
|
||||
choices: ['error', 'warn', 'info', 'silent'],
|
||||
describe: 'log level',
|
||||
})
|
||||
.strict()
|
||||
.help()
|
||||
,
|
||||
async ({ root, port: userPort, open, remote, log }) => {
|
||||
setEnv()
|
||||
|
||||
if (!fs.existsSync(path.resolve(root, 'pages')))
|
||||
process.exit(0)
|
||||
|
||||
const port = userPort || await findFreePort(4859)
|
||||
const options = await resolveOptions({ userRoot: root })
|
||||
|
||||
createValaxyNode(options)
|
||||
|
||||
const viteConfig: InlineConfig = mergeConfig({
|
||||
// avoid load userRoot/vite.config.ts repeatedly
|
||||
configFile: path.resolve(options.clientRoot, 'vite.config.ts'),
|
||||
server: {
|
||||
watch: {
|
||||
// watch theme updated
|
||||
ignored: [`!${options.themeRoot}/**`, `${options.userRoot}/**.md`],
|
||||
},
|
||||
|
||||
port,
|
||||
strictPort: true,
|
||||
open,
|
||||
host: remote ? '0.0.0.0' : 'localhost',
|
||||
},
|
||||
logLevel: log as LogLevel,
|
||||
}, options.config.vite || {})
|
||||
|
||||
await initServer(options, viteConfig)
|
||||
printInfo(options, port, remote)
|
||||
|
||||
const SHORTCUTS = [
|
||||
{
|
||||
name: 'r',
|
||||
fullName: 'restart',
|
||||
action() {
|
||||
initServer(options, viteConfig)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'o',
|
||||
fullName: 'open',
|
||||
async action() {
|
||||
const { default: openBrowser } = await import('open')
|
||||
openBrowser(`http://localhost:${port}`)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'q',
|
||||
fullName: 'qr',
|
||||
action() {
|
||||
const addresses = Object.values(os.networkInterfaces())
|
||||
.flat()
|
||||
.filter(details => details?.family === 'IPv4' && !details.address.includes('127.0.0.1'))
|
||||
const remoteUrl = `http://${addresses[0]?.address || 'localhost'}:${port}`
|
||||
qrcode.toString(remoteUrl, { type: 'terminal' }, (err, qrCode) => {
|
||||
if (err)
|
||||
throw err
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(qrCode)
|
||||
})
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'e',
|
||||
fullName: 'edit',
|
||||
action() {
|
||||
exec(`code "${root}"`)
|
||||
},
|
||||
},
|
||||
]
|
||||
bindShortcut(SHORTCUTS)
|
||||
},
|
||||
)
|
||||
|
||||
cli.command(
|
||||
'build [root]',
|
||||
'build your blog to static content',
|
||||
args => commonOptions(args)
|
||||
.option('ssg', {
|
||||
alias: 's',
|
||||
type: 'boolean',
|
||||
// https://github.com/antfu/vite-ssg/pull/219
|
||||
// to be true, when vite-ssg export build
|
||||
default: false,
|
||||
describe: 'static site generate',
|
||||
})
|
||||
.option('output', {
|
||||
alias: 'o',
|
||||
type: 'string',
|
||||
default: 'dist',
|
||||
describe: 'output dir',
|
||||
})
|
||||
.option('log', {
|
||||
default: 'warn',
|
||||
type: 'string',
|
||||
choices: ['error', 'warn', 'info', 'silent'],
|
||||
describe: 'log level',
|
||||
})
|
||||
.strict()
|
||||
.help(),
|
||||
async ({ ssg, root, output, log }) => {
|
||||
setEnvProd()
|
||||
|
||||
const options = await resolveOptions({ userRoot: root }, 'build')
|
||||
printInfo(options)
|
||||
|
||||
const valaxyApp = createValaxyNode(options)
|
||||
// resolve options and create valaxy app
|
||||
await valaxyApp.hooks.callHook('options:resolved')
|
||||
|
||||
const valaxyViteConfig: InlineConfig = mergeConfig(await mergeViteConfigs(options, 'build'), options.config.vite || {})
|
||||
const viteConfig: InlineConfig = mergeConfig(
|
||||
valaxyViteConfig,
|
||||
{
|
||||
// avoid load userRoot/vite.config.ts repeatedly
|
||||
configFile: path.resolve(options.clientRoot, 'vite.config.ts'),
|
||||
build: {
|
||||
// make out dir empty, https://vitejs.dev/config/#build-emptyoutdir
|
||||
emptyOutDir: true,
|
||||
outDir: path.resolve(options.userRoot, output),
|
||||
},
|
||||
logLevel: log as LogLevel,
|
||||
},
|
||||
)
|
||||
// init config
|
||||
await valaxyApp.hooks.callHook('config:init')
|
||||
|
||||
// merge index.html
|
||||
const templatePath = path.resolve(options.clientRoot, 'template.html')
|
||||
const indexPath = path.resolve(options.clientRoot, 'index.html')
|
||||
if (fs.existsSync(templatePath))
|
||||
await fs.copyFile(templatePath, indexPath)
|
||||
const indexHtml = await getIndexHtml(options)
|
||||
await fs.writeFile(indexPath, indexHtml, 'utf-8')
|
||||
|
||||
// before build
|
||||
await valaxyApp.hooks.callHook('build:before')
|
||||
|
||||
try {
|
||||
if (ssg) {
|
||||
consola.info(`use ${yellow('vite-ssg')} to do ssg build...`)
|
||||
|
||||
try {
|
||||
await ssgBuild(options, viteConfig)
|
||||
await postProcessForSSG(options)
|
||||
}
|
||||
catch (e) {
|
||||
consola.error('[vite-ssg] An internal error occurred.')
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(e)
|
||||
}
|
||||
}
|
||||
else {
|
||||
consola.info('use vite do spa build...')
|
||||
await build(options, viteConfig)
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(e)
|
||||
}
|
||||
finally {
|
||||
// await fs.unlink(indexPath)
|
||||
await fs.copyFile(templatePath, indexPath)
|
||||
|
||||
// after build
|
||||
await valaxyApp.hooks.callHook('build:after')
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
cli.command(
|
||||
'rss [root]',
|
||||
'generate rss feed',
|
||||
args => commonOptions(args)
|
||||
.strict()
|
||||
.help(),
|
||||
async ({ root }) => {
|
||||
setEnvProd()
|
||||
consola.info('Generate RSS ...')
|
||||
const options = await resolveOptions({ userRoot: root }, 'build')
|
||||
await rssBuild(options)
|
||||
},
|
||||
)
|
||||
|
||||
registerNewCommand(cli)
|
||||
registerFuseCommand(cli)
|
||||
|
||||
export function run() {
|
||||
cli.help().parse()
|
||||
}
|
|
@ -0,0 +1,125 @@
|
|||
import path from 'node:path'
|
||||
import consola from 'consola'
|
||||
import type { InlineConfig, LogLevel } from 'vite'
|
||||
import { mergeConfig } from 'vite'
|
||||
import type yargs from 'yargs'
|
||||
import fs from 'fs-extra'
|
||||
import { yellow } from 'kolorist'
|
||||
import { build, postProcessForSSG, ssgBuild } from '../build'
|
||||
import { getIndexHtml, mergeViteConfigs, resolveOptions } from '..'
|
||||
import { createValaxyNode } from '../app'
|
||||
import type { ValaxyModule } from '../modules'
|
||||
import { setupModules } from '../modules'
|
||||
import { rssModule } from '../modules/rss'
|
||||
import { printInfo } from '../utils/cli'
|
||||
import { setEnvProd } from '../utils/env'
|
||||
import { commonOptions } from './options'
|
||||
|
||||
export function registerBuildCommand(cli: yargs.Argv) {
|
||||
cli.command(
|
||||
'build [root]',
|
||||
'build your blog to static content',
|
||||
args => commonOptions(args)
|
||||
.option('ssg', {
|
||||
alias: 's',
|
||||
type: 'boolean',
|
||||
// https://github.com/antfu/vite-ssg/pull/219
|
||||
// to be true, when vite-ssg export build
|
||||
default: false,
|
||||
describe: 'static site generate',
|
||||
})
|
||||
.option('output', {
|
||||
alias: 'o',
|
||||
type: 'string',
|
||||
default: 'dist',
|
||||
describe: 'output dir',
|
||||
})
|
||||
.option('log', {
|
||||
default: 'warn',
|
||||
type: 'string',
|
||||
choices: ['error', 'warn', 'info', 'silent'],
|
||||
describe: 'log level',
|
||||
})
|
||||
.strict()
|
||||
.help(),
|
||||
async ({ ssg, root, output, log }) => {
|
||||
setEnvProd()
|
||||
|
||||
const options = await resolveOptions({ userRoot: root }, 'build')
|
||||
printInfo(options)
|
||||
|
||||
const valaxyApp = createValaxyNode(options)
|
||||
// resolve options and create valaxy app
|
||||
await valaxyApp.hooks.callHook('options:resolved')
|
||||
|
||||
const modules: ValaxyModule[] = []
|
||||
if (options.config.modules.rss.enable)
|
||||
modules.push(rssModule)
|
||||
|
||||
// setup modules
|
||||
setupModules(
|
||||
valaxyApp,
|
||||
modules,
|
||||
)
|
||||
|
||||
const valaxyViteConfig: InlineConfig = mergeConfig(await mergeViteConfigs(options, 'build'), options.config.vite || {})
|
||||
const viteConfig: InlineConfig = mergeConfig(
|
||||
valaxyViteConfig,
|
||||
{
|
||||
// avoid load userRoot/vite.config.ts repeatedly
|
||||
configFile: path.resolve(options.clientRoot, 'vite.config.ts'),
|
||||
build: {
|
||||
// make out dir empty, https://vitejs.dev/config/#build-emptyoutdir
|
||||
emptyOutDir: true,
|
||||
outDir: path.resolve(options.userRoot, output),
|
||||
},
|
||||
logLevel: log as LogLevel,
|
||||
},
|
||||
)
|
||||
// init config
|
||||
await valaxyApp.hooks.callHook('config:init')
|
||||
|
||||
// merge index.html
|
||||
const templatePath = path.resolve(options.clientRoot, 'template.html')
|
||||
const indexPath = path.resolve(options.clientRoot, 'index.html')
|
||||
if (fs.existsSync(templatePath))
|
||||
await fs.copyFile(templatePath, indexPath)
|
||||
const indexHtml = await getIndexHtml(options)
|
||||
await fs.writeFile(indexPath, indexHtml, 'utf-8')
|
||||
|
||||
// before build
|
||||
await valaxyApp.hooks.callHook('build:before')
|
||||
|
||||
try {
|
||||
if (ssg) {
|
||||
consola.info(`use ${yellow('vite-ssg')} to do ssg build...`)
|
||||
|
||||
try {
|
||||
await ssgBuild(options, viteConfig)
|
||||
await postProcessForSSG(options)
|
||||
}
|
||||
catch (e) {
|
||||
consola.error('[vite-ssg] An internal error occurred.')
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(e)
|
||||
}
|
||||
}
|
||||
else {
|
||||
consola.info('use vite do spa build...')
|
||||
await build(options, viteConfig)
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(e)
|
||||
}
|
||||
finally {
|
||||
// await fs.unlink(indexPath)
|
||||
await fs.copyFile(templatePath, indexPath)
|
||||
|
||||
// after build
|
||||
await valaxyApp.hooks.callHook('build:after')
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
|
@ -0,0 +1,124 @@
|
|||
import path from 'node:path'
|
||||
import { exec } from 'node:child_process'
|
||||
import process from 'node:process'
|
||||
import os from 'node:os'
|
||||
import type yargs from 'yargs'
|
||||
import fs from 'fs-extra'
|
||||
import type { InlineConfig, LogLevel } from 'vite'
|
||||
import { mergeConfig } from 'vite'
|
||||
|
||||
import qrcode from 'qrcode'
|
||||
import { findFreePort } from '../utils/net'
|
||||
import { resolveOptions } from '../options'
|
||||
import { bindShortcut, initServer, printInfo } from '../utils/cli'
|
||||
|
||||
import { setEnv } from '../utils/env'
|
||||
import { commonOptions } from '../cli/options'
|
||||
import { createValaxyNode } from '../app'
|
||||
|
||||
export function registerDevCommand(cli: yargs.Argv) {
|
||||
cli.command(
|
||||
'* [root]',
|
||||
'Start a local server for Valaxy',
|
||||
args =>
|
||||
commonOptions(args)
|
||||
.option('port', {
|
||||
alias: 'p',
|
||||
type: 'number',
|
||||
describe: 'port',
|
||||
})
|
||||
.option('open', {
|
||||
alias: 'o',
|
||||
default: false,
|
||||
type: 'boolean',
|
||||
describe: 'open in browser',
|
||||
})
|
||||
.option('remote', {
|
||||
default: true,
|
||||
type: 'boolean',
|
||||
describe: 'listen public host and enable remote control',
|
||||
})
|
||||
.option('log', {
|
||||
default: 'info',
|
||||
type: 'string',
|
||||
choices: ['error', 'warn', 'info', 'silent'],
|
||||
describe: 'log level',
|
||||
})
|
||||
.strict()
|
||||
.help()
|
||||
,
|
||||
async ({ root, port: userPort, open, remote, log }) => {
|
||||
setEnv()
|
||||
|
||||
if (!fs.existsSync(path.resolve(root, 'pages')))
|
||||
process.exit(0)
|
||||
|
||||
const port = userPort || await findFreePort(4859)
|
||||
const options = await resolveOptions({ userRoot: root })
|
||||
|
||||
createValaxyNode(options)
|
||||
|
||||
const viteConfig: InlineConfig = mergeConfig({
|
||||
// avoid load userRoot/vite.config.ts repeatedly
|
||||
configFile: path.resolve(options.clientRoot, 'vite.config.ts'),
|
||||
server: {
|
||||
watch: {
|
||||
// watch theme updated
|
||||
ignored: [`!${options.themeRoot}/**`, `${options.userRoot}/**.md`],
|
||||
},
|
||||
|
||||
port,
|
||||
strictPort: true,
|
||||
open,
|
||||
host: remote ? '0.0.0.0' : 'localhost',
|
||||
},
|
||||
logLevel: log as LogLevel,
|
||||
}, options.config.vite || {})
|
||||
|
||||
await initServer(options, viteConfig)
|
||||
printInfo(options, port, remote)
|
||||
|
||||
const SHORTCUTS = [
|
||||
{
|
||||
name: 'r',
|
||||
fullName: 'restart',
|
||||
action() {
|
||||
initServer(options, viteConfig)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'o',
|
||||
fullName: 'open',
|
||||
async action() {
|
||||
const { default: openBrowser } = await import('open')
|
||||
openBrowser(`http://localhost:${port}`)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'q',
|
||||
fullName: 'qr',
|
||||
action() {
|
||||
const addresses = Object.values(os.networkInterfaces())
|
||||
.flat()
|
||||
.filter(details => details?.family === 'IPv4' && !details.address.includes('127.0.0.1'))
|
||||
const remoteUrl = `http://${addresses[0]?.address || 'localhost'}:${port}`
|
||||
qrcode.toString(remoteUrl, { type: 'terminal' }, (err, qrCode) => {
|
||||
if (err)
|
||||
throw err
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(qrCode)
|
||||
})
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'e',
|
||||
fullName: 'edit',
|
||||
action() {
|
||||
exec(`code "${root}"`)
|
||||
},
|
||||
},
|
||||
]
|
||||
bindShortcut(SHORTCUTS)
|
||||
},
|
||||
)
|
||||
}
|
|
@ -10,6 +10,7 @@ import type { Argv } from 'yargs'
|
|||
import type { FuseListItem } from 'valaxy/types'
|
||||
import { resolveOptions } from '../options'
|
||||
import { setEnvProd } from '../utils/env'
|
||||
import { defineValaxyModule } from '../modules'
|
||||
import { commonOptions } from './options'
|
||||
|
||||
/**
|
||||
|
@ -96,3 +97,15 @@ export function registerFuseCommand(cli: Argv<object>) {
|
|||
},
|
||||
)
|
||||
}
|
||||
|
||||
export const fuseModule = defineValaxyModule({
|
||||
extendCli(cli) {
|
||||
registerFuseCommand(cli)
|
||||
},
|
||||
|
||||
setup(node) {
|
||||
node.hook('build:before', () => {
|
||||
generateFuseList(node.options)
|
||||
})
|
||||
},
|
||||
})
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
import process from 'node:process'
|
||||
import yargs from 'yargs'
|
||||
|
||||
import { hideBin } from 'yargs/helpers'
|
||||
import { version } from '../../package.json'
|
||||
|
||||
// build
|
||||
|
||||
// rss
|
||||
import { rssModule } from '../modules/rss'
|
||||
import type { ValaxyModule } from '../modules'
|
||||
import { fuseModule } from './fuse'
|
||||
import { registerNewCommand } from './new'
|
||||
|
||||
import { registerBuildCommand } from './build'
|
||||
import { registerDevCommand } from './dev'
|
||||
|
||||
export const cli = yargs(hideBin(process.argv)).scriptName('valaxy')
|
||||
.usage('$0 [args]')
|
||||
.version(version)
|
||||
.showHelpOnFail(false)
|
||||
.alias('h', 'help')
|
||||
.alias('v', 'version')
|
||||
|
||||
registerDevCommand(cli)
|
||||
registerBuildCommand(cli)
|
||||
registerNewCommand(cli)
|
||||
|
||||
const modules: ValaxyModule[] = [
|
||||
rssModule,
|
||||
fuseModule,
|
||||
]
|
||||
|
||||
modules.forEach((module) => {
|
||||
module.extendCli?.(cli)
|
||||
})
|
||||
|
||||
export function run() {
|
||||
cli.help().parse()
|
||||
}
|
|
@ -129,6 +129,12 @@ export const defaultValaxyConfig: ValaxyNodeConfig = {
|
|||
// },
|
||||
runtimeConfig: { addons: {} },
|
||||
|
||||
modules: {
|
||||
rss: {
|
||||
enable: true,
|
||||
},
|
||||
},
|
||||
|
||||
features: {
|
||||
katex: true,
|
||||
},
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
# Modules
|
||||
|
||||
Internal modules which use hooks.
|
|
@ -0,0 +1,22 @@
|
|||
import type yargs from 'yargs'
|
||||
import type { ValaxyNode } from '..'
|
||||
|
||||
export interface ValaxyModule {
|
||||
extendCli?: (cli: yargs.Argv) => void
|
||||
setup?: (node: ValaxyNode) => void
|
||||
}
|
||||
|
||||
export function defineValaxyModule(
|
||||
module: ValaxyModule,
|
||||
) {
|
||||
return module
|
||||
}
|
||||
|
||||
export function setupModules(
|
||||
node: ValaxyNode,
|
||||
modules: ValaxyModule[],
|
||||
) {
|
||||
modules.forEach((module) => {
|
||||
module.setup?.(node)
|
||||
})
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
import { dirname, resolve } from 'node:path'
|
||||
import { readFile } from 'node:fs/promises'
|
||||
import { cyan, dim } from 'kolorist'
|
||||
import { cyan, dim, yellow } from 'kolorist'
|
||||
|
||||
import fg from 'fast-glob'
|
||||
import fs from 'fs-extra'
|
||||
|
@ -9,10 +9,13 @@ import MarkdownIt from 'markdown-it'
|
|||
import type { Author, FeedOptions, Item } from 'feed'
|
||||
import { Feed } from 'feed'
|
||||
import consola from 'consola'
|
||||
import type { ResolvedValaxyOptions } from './options'
|
||||
import { getCreatedTime, getUpdatedTime } from './utils/date'
|
||||
import { ensurePrefix, isExternal } from './utils'
|
||||
import { EXCERPT_SEPARATOR } from './constants'
|
||||
import { type ResolvedValaxyOptions, resolveOptions } from '../options'
|
||||
import { getCreatedTime, getUpdatedTime } from '../utils/date'
|
||||
import { ensurePrefix, isExternal } from '../utils'
|
||||
import { EXCERPT_SEPARATOR } from '../constants'
|
||||
import { commonOptions } from '../cli/options'
|
||||
import { setEnvProd } from '../utils/env'
|
||||
import { defineValaxyModule } from '.'
|
||||
|
||||
const markdown = MarkdownIt({
|
||||
html: true,
|
||||
|
@ -25,6 +28,8 @@ const markdown = MarkdownIt({
|
|||
* @param options
|
||||
*/
|
||||
export async function build(options: ResolvedValaxyOptions) {
|
||||
consola.info(`${yellow('RSS Generating ...')}`)
|
||||
|
||||
const { config } = options
|
||||
const siteConfig = config.siteConfig
|
||||
|
||||
|
@ -46,18 +51,23 @@ export async function build(options: ResolvedValaxyOptions) {
|
|||
consola.info(`RSS Site Url: ${cyan(siteUrl)}`)
|
||||
|
||||
const ccVersion = (siteConfig.license?.type === 'zero') ? '1.0' : '4.0'
|
||||
const feedNameMap: Record<string, string> = {
|
||||
atom: siteConfig.feed?.name ? `${siteConfig.feed?.name}.atom` : 'atom.xml',
|
||||
json: `${siteConfig.feed?.name || 'feed'}.json`,
|
||||
rss: `${siteConfig.feed?.name || 'feed'}.xml`,
|
||||
}
|
||||
|
||||
const feedOptions: FeedOptions = {
|
||||
title: siteConfig.title || 'Valaxy Blog',
|
||||
description: siteConfig.description,
|
||||
id: siteUrl || 'valaxy',
|
||||
link: siteUrl,
|
||||
copyright: `CC ${siteConfig.license?.type?.toUpperCase()} ${ccVersion} ${new Date().getFullYear()} © ${siteConfig.author?.name}`,
|
||||
feedLinks: {
|
||||
json: `${siteUrl}feed.json`,
|
||||
atom: `${siteUrl}feed.atom`,
|
||||
rss: `${siteUrl}feed.xml`,
|
||||
},
|
||||
feedLinks: {},
|
||||
}
|
||||
Object.keys(feedNameMap).forEach((key) => {
|
||||
feedOptions.feedLinks[key] = `${siteUrl}${feedNameMap[key]}`
|
||||
})
|
||||
|
||||
// generate
|
||||
const files = await fg(`${options.userRoot}/pages/posts/**/*.md`)
|
||||
|
@ -127,25 +137,50 @@ export async function build(options: ResolvedValaxyOptions) {
|
|||
posts.forEach(item => feed.addItem(item))
|
||||
// items.forEach(i=> console.log(i.title, i.date))
|
||||
|
||||
await fs.ensureDir(dirname(`./dist/${siteConfig.feed?.name} || 'feed.xml'`))
|
||||
await fs.ensureDir(dirname(`./dist/${feedNameMap.atom}`))
|
||||
const path = resolve(options.userRoot, './dist')
|
||||
|
||||
const types = ['xml', 'atom', 'json']
|
||||
const types = ['rss', 'atom', 'json']
|
||||
types.forEach((type) => {
|
||||
let data = ''
|
||||
let name = `${path}/${siteConfig.feed?.name || 'feed'}.${type}`
|
||||
if (type === 'xml') {
|
||||
const name = `${path}/${feedNameMap[type]}`
|
||||
if (type === 'rss')
|
||||
data = feed.rss2()
|
||||
}
|
||||
else if (type === 'atom') {
|
||||
if (!siteConfig.feed?.name)
|
||||
name = `${path}/atom.xml`
|
||||
else if (type === 'atom')
|
||||
data = feed.atom1()
|
||||
}
|
||||
else if (type === 'json') {
|
||||
else if (type === 'json')
|
||||
data = feed.json1()
|
||||
}
|
||||
|
||||
fs.writeFileSync(name, data, 'utf-8')
|
||||
consola.info(`${type}: ${dim(name)}`)
|
||||
})
|
||||
}
|
||||
|
||||
export const rssModule = defineValaxyModule({
|
||||
/**
|
||||
* valaxy rss
|
||||
* @param cli
|
||||
*/
|
||||
extendCli(cli) {
|
||||
cli.command(
|
||||
'rss [root]',
|
||||
'generate rss feed',
|
||||
args => commonOptions(args)
|
||||
.strict()
|
||||
.help(),
|
||||
async ({ root }) => {
|
||||
setEnvProd()
|
||||
const options = await resolveOptions({ userRoot: root }, 'build')
|
||||
await build(options)
|
||||
},
|
||||
)
|
||||
},
|
||||
|
||||
setup(node) {
|
||||
node.hook('build:after', () => {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log()
|
||||
build(node.options)
|
||||
})
|
||||
},
|
||||
})
|
|
@ -0,0 +1,3 @@
|
|||
# plugins
|
||||
|
||||
Custom Vite Plugins.
|
|
@ -31,9 +31,23 @@ export interface ValaxyNode {
|
|||
|
||||
hooks: Hookable<ValaxyHooks>
|
||||
hook: ValaxyNode['hooks']['hook']
|
||||
|
||||
options: ResolvedValaxyOptions
|
||||
}
|
||||
|
||||
export interface ValaxyExtendConfig {
|
||||
/**
|
||||
* internal modules
|
||||
*/
|
||||
modules: {
|
||||
rss: {
|
||||
/**
|
||||
* enable rss
|
||||
*/
|
||||
enable: boolean
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Markdown Feature
|
||||
*/
|
||||
|
|
|
@ -4,7 +4,7 @@ export default defineConfig((options) => {
|
|||
return {
|
||||
entry: [
|
||||
'node/index.ts',
|
||||
'node/cli.ts',
|
||||
'node/cli/index.ts',
|
||||
// 'client/index.ts',
|
||||
'types/index.ts',
|
||||
],
|
||||
|
|
|
@ -188,8 +188,8 @@ importers:
|
|||
specifier: ^4.5.0
|
||||
version: 4.5.0(@types/node@20.8.7)(sass@1.69.4)
|
||||
vitepress:
|
||||
specifier: 1.0.0-rc.22
|
||||
version: 1.0.0-rc.22(@types/node@20.8.7)(postcss@8.4.31)(search-insights@2.8.3)(typescript@5.2.2)
|
||||
specifier: 1.0.0-rc.23
|
||||
version: 1.0.0-rc.23(@types/node@20.8.7)(postcss@8.4.31)(search-insights@2.8.3)(typescript@5.2.2)
|
||||
vue:
|
||||
specifier: ^3.3.6
|
||||
version: 3.3.6(typescript@5.2.2)
|
||||
|
@ -10536,8 +10536,8 @@ packages:
|
|||
optionalDependencies:
|
||||
fsevents: 2.3.3
|
||||
|
||||
/vitepress@1.0.0-rc.22(@types/node@20.8.7)(postcss@8.4.31)(search-insights@2.8.3)(typescript@5.2.2):
|
||||
resolution: {integrity: sha512-n7le5iikCFgWMuX7sKfzDGJGlrsYQ5trG3S97BghNz2alOTr4Xp+GrB6ShwogUTX9gNgeNmrACjokhW55LNeBA==}
|
||||
/vitepress@1.0.0-rc.23(@types/node@20.8.7)(postcss@8.4.31)(search-insights@2.8.3)(typescript@5.2.2):
|
||||
resolution: {integrity: sha512-0YoBt8aFgbRt2JtYaCeTqq4W21q5lbGso+g1ZwkYYS35ExJxORssRJunhFuUcby8QeN4BP/88QDgsVSIVLAfXQ==}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
markdown-it-mathjax3: ^4.3.2
|
||||
|
|
Loading…
Reference in New Issue