diff --git a/docs/devGuide/development/workflow.md b/docs/devGuide/development/workflow.md index 121cc783f2..3134ca52a4 100644 --- a/docs/devGuide/development/workflow.md +++ b/docs/devGuide/development/workflow.md @@ -171,6 +171,17 @@ Hence, if you need to view the latest frontend changes (relating to `packages/co 1. Run `npm run build:web` in the root directory, which builds the above bundles, then run your markbind-cli commandcommand of choice. + + + + +##### `markbind serve -d` + +`markbind serve -d` adds the necessary webpack middlewares to the development server to compile the bundles for `markbind-core-web` and `markbind-vue-components`, and enables live and hot reloading for frontend source files. + +Note that the command is only applicable for local development, and does not work when you install MarkBind from npm, as it relies on developmental dependencies. + +
## Testing diff --git a/package-lock.json b/package-lock.json index 230cc41c4b..4c41508784 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21913,7 +21913,7 @@ "cheerio": "^0.22.0", "chokidar": "^3.3.0", "colors": "1.4.0", - "commander": "^8.1.0", + "commander": "^14.0.3", "figlet": "^1.9.4", "find-up": "^4.1.0", "fs-extra": "^9.0.1", @@ -21967,6 +21967,15 @@ "node": ">=8" } }, + "packages/cli/node_modules/commander": { + "version": "14.0.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.3.tgz", + "integrity": "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==", + "license": "MIT", + "engines": { + "node": ">=20" + } + }, "packages/cli/node_modules/file-stream-rotator": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/file-stream-rotator/-/file-stream-rotator-0.6.1.tgz", diff --git a/packages/cli/index.ts b/packages/cli/index.ts index a98e0ad53c..408bcf8f80 100755 --- a/packages/cli/index.ts +++ b/packages/cli/index.ts @@ -1,7 +1,8 @@ #!/usr/bin/env node // Entry file for MarkBind project -import { program } from 'commander'; +import { program, Option } from 'commander'; +import chalk from 'chalk'; import * as logger from './src/util/logger.js'; import { build } from './src/cmd/build.js'; import { deploy } from './src/cmd/deploy.js'; @@ -24,7 +25,12 @@ function printHeader() { program .addHelpText('beforeAll', printHeader()) - .showHelpAfterError('(run "markbind --help" to list commands)'); + .showHelpAfterError('(run "markbind --help" to list commands)') + .configureHelp({ + styleTitle: str => chalk.bold.cyan(str), + styleUsage: str => chalk.white(str), + styleOptionText: str => chalk.yellow(str), + }); program .allowUnknownOption() @@ -35,30 +41,56 @@ program .version(CLI_VERSION); program + .commandsGroup('Setup Commands') .command('init [root]') .option('-c, --convert', 'convert a GitHub wiki or docs folder to a MarkBind website') .option('-t, --template ', 'initialise markbind with a specified template', 'default') .alias('i') + .summary('init a markbind site') .description('init a markbind website project') .action((root, options) => { init(root, options); }); program + .commandsGroup('Site Commands') .command('serve [root]') .alias('s') - .option('-f, --force-reload', 'force a full reload of all site files when a file is changed') - .option('-n, --no-open', 'do not automatically open the site in browser') - .option('-o, --one-page [file]', 'build and serve only a single page in the site initially,' - + 'building more pages when they are navigated to. Also lazily rebuilds only the page being viewed when' - + 'there are changes to the source files (if needed), building others when navigated to') - .option('-b, --background-build', 'when --one-page is specified, enhances one-page serve by building' - + 'remaining pages in the background') - .option('-p, --port ', 'port for server to listen on (Default is 8080)') - .option('-s, --site-config ', 'specify the site config file (default: site.json)') - .option('-d, --dev', 'development mode, enabling live & hot reload for frontend source files.') - .option('-a, --address
', 'specify the server address/host (Default is 127.0.0.1)') - .description('build then serve a website from a directory') + .summary('Build then serve a website from a directory') + .description('Build and serve a website from a directory') + + .optionsGroup('Build Options') + .addOption( + program.createOption('-f, --force-reload', + 'force a full reload of all site files when a file is changed') + .conflicts('onePage')) + + .addOption( + program.createOption('-o, --one-page [file]', + 'build and serve only a single page in the site initially, ' + + 'building more pages when they are navigated to. Also lazily rebuilds only ' + + 'the page being viewed when there are changes to the source files (if needed), ' + + 'building others when navigated to')) + + .addOption( + program.createOption('-b, --background-build', + 'when --one-page is specified, enhances one-page serve by building ' + + 'remaining pages in the background')) + + .optionsGroup('Server Options') + .addOption( + program.createOption('-n, --no-open', 'do not automatically open the site in browser')) + .addOption( + program.createOption('-p, --port ', 'port for server to listen on (Default is 8080)')) + .addOption( + program.createOption('-a, --address
', 'specify the server address/host (Default is 127.0.0.1)')) + .addOption( + program.createOption('-s, --site-config ', 'specify the site config file (default: site.json)')) + + // Development mode is hidden as it is not user facing and only works during local development + .addOption( + new Option('-d, --dev', 'development mode, enabling live & hot reload for frontend source files.') + .hideHelp()) .action((userSpecifiedRoot, options) => { serve(userSpecifiedRoot, options); }); @@ -69,7 +101,8 @@ program .option('--baseUrl [baseUrl]', 'optional flag which overrides baseUrl in site.json, leave argument empty for empty baseUrl') .option('-s, --site-config ', 'specify the site config file (default: site.json)') - .description('build a website') + .summary('Build a website') + .description('Build a website') .action((userSpecifiedRoot, output, options) => { build(userSpecifiedRoot, output, options); }); @@ -80,7 +113,8 @@ program .option('-c, --ci [githubTokenName]', 'deploy the site in CI Environment [GITHUB_TOKEN]') .option('-n, --no-build', 'do not automatically build the site before deployment') .option('-s, --site-config ', 'specify the site config file (default: site.json)') - .description('deploy the latest build of the site to the repo\'s Github pages') + .summary('Deploy the latest build of the site to GitHub Pages') + .description('Deploy the latest build of the site to the repo\'s GitHub Pages') .action((userSpecifiedRoot, options) => { deploy(userSpecifiedRoot, options); }); diff --git a/packages/cli/package.json b/packages/cli/package.json index 96f6fd46e2..614afeb065 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -39,7 +39,7 @@ "cheerio": "^0.22.0", "chokidar": "^3.3.0", "colors": "1.4.0", - "commander": "^8.1.0", + "commander": "^14.0.3", "figlet": "^1.9.4", "find-up": "^4.1.0", "fs-extra": "^9.0.1", @@ -50,18 +50,18 @@ "winston-daily-rotate-file": "^5.0.0" }, "devDependencies": { + "@babel/core": "^7.29.0", + "@babel/preset-env": "^7.29.0", + "@babel/preset-typescript": "^7.28.5", "@types/jest": "^29.4.6", "@types/lodash": "^4.17.15", "@types/url-parse": "^1.4.8", + "babel-jest": "^29.7.0", "diff": "^8.0.3", "ignore": "^7.0.5", "istextorbinary": "^9.5.0", "jest": "^29.7.0", "memfs": "^4.56.2", - "walk-sync": "^2.0.2", - "@babel/core": "^7.29.0", - "@babel/preset-env": "^7.29.0", - "@babel/preset-typescript": "^7.28.5", - "babel-jest": "^29.7.0" + "walk-sync": "^2.0.2" } } diff --git a/packages/cli/src/cmd/serve.ts b/packages/cli/src/cmd/serve.ts index 1a5e0e6adf..e645bfb381 100755 --- a/packages/cli/src/cmd/serve.ts +++ b/packages/cli/src/cmd/serve.ts @@ -43,12 +43,6 @@ function serve(userSpecifiedRoot: string, options: any) { let rootFolder; try { rootFolder = cliUtil.findRootFolder(userSpecifiedRoot, options.siteConfig); - - if (options.forceReload && options.onePage) { - logger.error('Oops! You shouldn\'t need to use the --force-reload option with --one-page.'); - process.exitCode = 1; - process.exit(); - } } catch (error) { if (_.isError(error)) { logger.error(error.message);