Skip to content

CLI ​

Nine commands that scaffold modules, wire a language end to end, and keep the project tidy. It ships with the template and needs no global install.

Running it ​

bash
npm run smart-admin -- <command> [args]

The -- is npm's "pass the rest to the script" separator. Without it npm eats the flags itself.

Two commands have their own shortcut in package.json:

bash
npm run generate post
npm run analyze

The commands ​

CommandWhat it does
generate <name>Scaffolds a list module from its block in smart-admin.generate.json.
generate-form <name>Generates a form page from its block in smart-admin.form.json.
add-locale <code>Wires a new language end to end.
remove-locale <code>Strips a language completely, using its manifest.
analyzeReports components, fonts and translation coverage.
remove <target>Removes a file, refusing if anything still imports it.
restore <target>Puts one removed file back.
resetPuts every removed file back.
remove-backupsDeletes the backups themselves.

smart-admin --help prints that list. generate, generate-form, add-locale, remove-locale and remove-backups each take --help too; analyze, remove, restore and reset do not, and their usage is on the pages here.

Declare, do not guess ​

The two generators read a JSON file you write. Neither of them infers anything from a name.

generate reads the JSON type of each value in your sample row — a string is text, a number is a number, an object is nested. It never reads meaning out of a key: a field called cover is not an image and created_at is not a date until you say so in annotations. That is the whole point of the input file.

generate-form reads no API response at all, because a form is not derivable from one. Whether a field is required, how short it may be, which options it allows, which step it belongs to — none of that is ever in a response.

Both refuse rather than improvise. Ask for a block that is not there and the command names what it did find, prints the shortest block that would work, and writes nothing:

smart-admin.generate.json has no "widget" block.
  It declares: post

  Add one, then run this again. The shortest block that works:
    "widget": {
      "rowsPath": "data",
      "row": { "id": 1, "name": "Example" },
      "filterFields": []
    }

Both also have --dry-run, which prints the plan and writes nothing.

Two files, one committed ​

Each generator has an example file that ships with the template and a real file that does not:

Format reference, committedYour shapes, gitignored
smart-admin.generate.example.jsonsmart-admin.generate.json
smart-admin.form.example.jsonsmart-admin.form.json

On the first run the CLI copies the example to the real name and makes sure that path is in .gitignore, so a real API response never reaches your repository. It says so when it does:

Created smart-admin.generate.json from the example.

--dry-run will not create it — there would be nothing to dry-run against — and it says that too.

Backups ​

Everything that deletes takes a backup first, into .smart-admin/backups/{timestamp}/, keeping the original paths. .gitignore already covers that directory, and the CLI says so rather than adding a second rule.

--backup and --no-backup answer that question up front, so a script or a CI run never blocks waiting for a terminal that is not there. To keep backups out of non-development runs entirely, create .smart-admin/config.json:

json
{
  "backups": {
    "devOnly": true
  }
}

Backups are then skipped whenever NODE_ENV=production or CI is set. An explicit --backup still wins over it.

Restore one file with restore, all of them with reset, and delete the backups with remove-backups.

What it never generates ​

Permissions, the API call and its auth, the pagination request contract, what belongs in a store, and — for a form — the submit and load requests. None of them can be known from a sample row or a field list, so the generated page marks the spot instead: a list page carries a fetch data will be here marker, and a form page carries one for the submit and one for the load.

The CLI prints that list at the end of every generate, so it reads as a handover rather than an omission.

After generating ​

Restart the dev server. unplugin-vue-router builds its route table at boot, so a new page does not appear until it restarts. Every generate says so.

Translations are injected into every file in src/locales/: real words in the base language, the same words as placeholders in the other eight. Run analyze --locales to see what is still untranslated.

Where to go next ​