A partial re-write
Formidable has been in the works for some time now. Everytime I use it, I always find an easy or better way of implementing some of its features.
In the past week I made some important changes to the framework's core, and in this article I will be discussing these new changes.
New Installer
The Formidable installer is no longer a part of the craftsman
cli, instead, its a standalone package which you can install independently of the craftsman
cli which makes it much easier to maintain.
The new and improved installer allows you to base off your new application on the dev
branch and you can now install a new application in the current directory.
The onboarding process has been improved to include inertia
:
The new installer now lets you select your preferred frontend framework during the onboarding process.
React
and Vue
use Inertia under the hood, while Imba
is native to Formidable.
When choosing Imba
, you also get to choose between creating a Single-page Application and a Blank canvas. The Single-page Application will add a basic scaffolding for SPA.
To install the new Formidable installer, run:
npm i -g @formidablejs/installer
New CLI (craftsman)
The new craftsman
CLI has been built into the framework's core, making it easy to create Formidable plugins that register new commands.
This new cli is heavily inspired by Laravel's own artisan
cli, borrowing a lot of the Laravel commands such as the down
and up
commands.
Note, now you need to run the craftsman cli with
node
. To see the complete commands list, run:node craftsman
.
To create a new command, simply run:
node craftsman make:command Hello
This will create a new Hello.imba
class under app/Console/Commands
directory.
Now, you will need to register your newely created command. To do this, open the app/Console/Kernel.imba
class and import your comnmand then register it:
import { ConsoleKernel } from '@formidablejs/framework'import { Hello } from './Commands/Hello'export class Kernel < ConsoleKernel get registered [ Hello ]
Once done, run node craftsman hello
and you should see Hello World
.
To edit your new command, open app/Console/Commands/Hello.imba
:
import { Command } from '@formidablejs/framework'import { Prop } from '@formidablejs/framework'export class Hello < Command get signature 'hello' get description 'My command description' get props { } def handle self.write "<fg:green>Hello World</fg:green>"
The handle
function is what gets executed when the command is ran.
To accept arguments, we can add them in the signature and wrap them around curly braces:
get signature 'hello {name}`
To read our new name
argument, we can use the argument
function:
def handle self.write "<fg:green>Hello {argument('name')}</fg:green>"
Then run:
node craftsman hello Donald
We will then see hello Donald
.
Now, lets make the name
argument optional and give it a description:
import { Command } from '@formidablejs/framework'import { Prop } from '@formidablejs/framework'export class Hello < Command get signature 'hello {?name}' get description 'My command description' get props { name: Prop.string!.description('Your name') } def handle self.write "<fg:green>Hello {argument('name', 'Stranger')}</fg:green>"
Results:
There's a lot you can do with craftman commands, we can require options (e.g.
--read
. etc) and document our arguments or options.
Interactive Shell
Another cool addition/fix, is the interactive shell. This has always been available but it wasn't working as intended. Now that Formidable's cli "craftsman"
works directly with the codebase, it means the interactive shell, can easily read the application's context. e.g. We can pass the User
model into the context, and the interactive shell will be able to access it.
To play around witht the shell, just run:
node craftsman shell
If you would like to access any of your code from the shell, just import the code in the context
config:
import { User } from '../app/Models/User'export { User: User}
As you can see, the interactive shell is great for tinkering with your database data without too much hassle.
Testing
This is by far my favorite update/feature. Formidable now lets you write your tests using Imba
. Why is this a big deal? Well, previously you would write your tests in JavaScript
, this was a bit strange considering the fact that Formidable is a Imba framework. So now that you can write your tests in Imba
, it means we no longer have to create a JavaScript
build of your application before running tests.
A typical test now looks like:
const { current } = require '../storage/framework/address.json'const { SuperTest } = require 'supertest'const request = require 'supertest'describe 'Application (e2e)', do # @type {SuperTest} let app beforeAll do app = request current it '/ (GET: Hello World)', do app.get('/') .set('Accept-Language', 'en') .expect(200) .expect('Hello World') it '/ (GET: Hola Mundo)', do app.get('/') .set('Accept-Language', 'es') .expect(200) .expect('Hola Mundo')
And previously looked like:
const { Application, request } = require('../.formidable/server.app');const { helpers: { config } } = require('@formidablejs/framework');/** * Skip if not in testing environment */const maybe = config('app.env') === 'testing' ? describe : describe.skipmaybe('Application (e2e)', () => { let app; beforeAll(async () => { await Application.then((formidable) => { (app = formidable.fastify()).ready(); }); }); afterAll(async () => await app.close()); it('/ (GET: Hello World)', () => { return request(app.server) .get('/') .set('Accept-Language', 'en') .expect(200) .expect('Hello World'); }); it('/ (GET: Hola Mundo)', () => { return request(app.server) .get('/') .set('Accept-Language', 'es') .expect(200) .expect('Hola Mundo'); });})
Because we no longer build Formidable projects, it means before testing your endpoints, you need to run your server with the --addr
flag:
node craftsman serve --addr
This creates a address.json
file under the storage/framework
directory with the current address.
That's all for now.