Getting started
Everything on the other pages starts with one binary,
cnc: it scaffolds an app, serves it while you edit, runs its tests
and ships it. A command line is not something a page can run, so the steps below are terminal
output, shortened.
1. cnc new — a working app
No account and no network needed. The tree has a page, a layout, a schema with seed rows, two services, and a test beside the page and the service.
$ cnc new app shop
created app in ~/shop
$ cd shop && find . -type f -not -name '.*' | sort
./blocks/index.html
./blocks/index.mjs
./blocks/index.test.ts
./cnc.json
./migrations/001-starter.json
./seeds/User.json
./seeds/_Translation.json
./services/greeter.json
./services/greeter.mjs
./services/greeter.test.ts
./services/heartbeat.json
./services/heartbeat.mjs
./templates/default.html
./tsconfig.json
2. cnc dev — serve it and edit
Open the address and edit a file. Save
blocks/about.html
and /about exists; an open page reloads by itself. A file that
does not compile breaks only its own route, which answers with the file and the reason, and the
next save is the fix.
$ cnc dev
cnc dev: closure held in memory
cnc dev: serving ~/shop on http://localhost:3000
cnc dev: the registry is https://cloud.clickncode.com (the built-in default)
$ curl -i http://localhost:3000/broken
HTTP/1.1 500 Internal Server Error
content-type: text/plain; charset=utf-8
blocks/broken.html: cannot compile: return (((()
3. cnc test — check it
A test sits beside what it tests and says its kind by the function it calls:
test.block
asks for a page through the whole serving path,
test.widget,
test.service
and test.browser
do the same for theirs. Each test gets a freshly seeded database of its own.
// blocks/index.test.ts — beside the page it tests
import { test } from '@cnc/test'
test.block('the page answers', async (t) => {
const page = await t.get('/')
t.expect(page.status).to.equal(200)
t.expect(page.find('h1').exists).to.be.true
})
$ cnc test
✓ blocks/index.test.ts the page answers
✓ blocks/index.test.ts a visitor is nobody, and a person is who they are
✓ services/greeter.test.ts greet says hello to whoever is named
✓ services/greeter.test.ts the greeting is the secret the deployment holds
✓ services/greeter.test.ts lookup reaches the host greeter.json declares, faked here
5 passed, 0 failed, 0 skipped, 1.0s
4. cnc deploy — ship it
Sign in once, then deploy: the app is served from the hosted platform with its own database.
Deploying keeps a version private; publishing it to the registry lets other people find it,
fork it with cnc new, or depend on it as a module.
$ cnc login # asks for your address and password
$ cnc deploy # sends the tree, privately, and prints its address
$ cnc deploy --host shop.example.com
$ cnc registry publish # puts this version in front of people
$ cnc version patch # the next change: bump, then deploy again