NocoBase 0.19:Application process optimization

NocoBase 0.19 introduces telemetry, application backup and restore, command line optimizations, and various kernel improvements to enhance installation, startup, and upgrade processes.

NocoBase team |

New features

Telemetry

Application backup and restore

Kernel optimizations

Command line optimizations

For NocoBase 0.19 and above, plugin customized commands must be placed in the plugin’s src/server/commands/*.ts directory with the following contents:

export default function(app) {
  app.command('custom1').action();
}

The execution flow of the command line:

The execution flow of the command line

Special configuration of Command

  • ipc() When the app is running, the command line sends commands via ipc to operate the running app instance, when ipc() is not configured, a new app instance will be created and then the operation will be executed (it will not interfere with the running app instance)
  • auth() performs database verification, if the database configuration is incorrect, this command will not be executed.
  • preload() whether to preload the application configuration, that is, execute app.load()

This can be configured according to the actual usage of the command, examples are as follows:

app.command('a').ipc().action()
app.command('a').auth().action()
app.command('a').preload().action()

Installation process optimization

Installation process optimization

Startup process optimization

Startup process optimization

Upgrade process optimization

Upgrade process optimization

The upgrade migrations are categorized into beforeLoad, afterSync, and afterLoad:

  • beforeLoad: Executed before the loading of each module, divided into three stages:
    • Before loading kernel modules
    • Before loading preset plugins
    • Before loading other plugins
  • afterSync: Executed after the synchronization of data table configurations with the database, divided into three stages:
    • After synchronizing kernel tables with the database
    • After synchronizing preset plugin tables with the database
    • After synchronizing other plugin tables with the database
  • afterLoad: Executed only after the complete loading of the application.
export default class extends Migration {
  // When to perform the migration
  on = 'beforeLoad';
  // Execute only when the following app version number is met.
  appVersion = '<=0.13.0-alpha.5';
  // Execute only when the following plugin version number is met.
  pluginVersion = '<=0.13.0-alpha.5';
  // Upgrade script.
  async up() {}
}

Add the create-migration command

Creates a migration file

yarn nocobase create-migration -h

Usage: nocobase create-migration [options] <name>

Options:
  --pkg <pkg>  package name
  --on [on]    Options include beforeLoad, afterSync and afterLoad
  -h, --help   display help for command

Example

$ yarn nocobase create-migration update-ui --pkg=@nocobase/plugin-client

2024-01-07 17:33:13 [info ] add app main into supervisor   
2024-01-07 17:33:13 [info ] migration file in /nocobase/packages/plugins/@nocobase/plugin-client/src/server/migrations/20240107173313-update-ui.ts
✨  Done in 5.02s.

A migration file will be generated in src/server/migrations of the plugin package @nocobase/plugin-client as 20240107173313-update-ui.ts with the following initial contents:

import { Migration } from '@nocobase/server';

export default class extends Migration {
  on = 'afterLoad'; // 'beforeLoad' | 'afterSync' | 'afterLoad'
  appVersion = '<0.18.0-alpha.10';

  async up() {
    // coding
  }
}

The plugin’s convention-based directories

|- /plugin-sample-hello
  |- /dist             # Directory for compiled plugin
  |- /src              # Source code for the plugin
    |- /client
      |- plugin.ts
      |- index.ts      # Client-side entry point
    |- /locale         # Conventional directory for shared multilingual files between frontend and backend
    |- /swagger        # Conventional directory for Swagger documentation
    |- /server
      |- collections   # Conventional directory for plugin's data table configurations
      |- commands      # Conventional directory for custom commands
      |- migrations    # Conventional directory for migration files
      |- plugin.ts     # Plugin class
      |- index.ts      # Server-side entry point
    |- index.ts
  |- .npmignore
  |- client.d.ts
  |- client.js
  |- package.json
  |- server.d.ts
  |- server.js

Testing process optimization

Provided more user-friendly createMockServer() and startMockServer() methods for writing test cases:

  • createMockServer() Quickly creates and starts an application.
  • startMockServer() Quickly starts an application (without reinstalling).
import { createMockServer } from '@nocobase/server';

describe('test example', () => {
  let app: MockServer;

  beforeEach(async () => {
    app = await createMockServer({
      plugins: ['nocobase'],
    });
  });

  afterEach(async () => {
    await app.destroy();
  });

  test('case1', async () => {
    // coding...
  });
});

Breaking changes

Collections, commands, migrations configuration changes to convention-based directories

Example 1: Collections loaded by importCollections, the code is deleted directly, and the collections configuration file must be placed in the src/server/collections directory.

export class AuthPlugin extends Plugin {
  async load() {
-   await this.importCollections(resolve(__dirname, 'collections'));
  }
}

Example 2: Collections loaded through this.db.import, the code is directly deleted, the collections configuration file must be placed in the src/server/collections directory

export class AuthPlugin extends Plugin {
  async load() {
-   await this.db.import({
-     directory: resolve(__dirname, 'collections')
-   });
  }
}

Example 3: A collection defined by db.collection() is recommended to be placed in the src/server/collections directory.

export class AuthPlugin extends Plugin {
  async load() {
-   this.db.collection({
-     name: 'examples',
-   });
  }
}

Add a new src/server/collections/examples.ts file with the following contents:

import { defineCollection } from '@nocobase/database';

export default defineCollection({
  name: 'examples',
});

Example 4: Remove db.addMigrations() and place the migration file in the src/server/migrations directory.

export class AuthPlugin extends Plugin {
  async load() {
-   this.db.addMigrations({
-     namespace: 'auth',
-     directory: resolve(__dirname, 'migrations'),
-     context: {
-       plugin: this,
-     },
-   });
  }
}

Example 5: Customizing the command line

export class MyPlugin extends Plugin {
  load() {
-   this.app
-      .command('echo')
-      .option('-v, --version');
-      .action(async ([options]) => {
-        console.log('Hello World!');
-        if (options.version) {
-          console.log('Current version:', app.getVersion());
-        }
-      });
-  }
}

Add a new src/server/collections/echo.ts file with the following contents:

export default function(app) {
  app
    .command('echo')
    .option('-v, --version');
    .action(async ([options]) => {
      console.log('Hello World!');
      if (options.version) {
        console.log('Current version:', await app.version.get());
      }
    });
}