What is EggBorn. Js

Eggborn. js is a top-level Javascript full stack development framework.

Eggborn.js is a best practice for full stack development using Javascript. Eggborn.js does not repeat the wheel, but uses the industry’s latest open source technology, the best combination of full stack development. Eggborn.js uses vue.js + Framework7 / Vue Router + Webpack at the front end, koa.js + egg.js at the back end, and mysql at the database. Eggborn.js keeps track of the latest achievements of open source technology and continues to optimize to keep the framework in top shape.

What problem does Eggborn.js focus on: business modularity

The rapid development of Javascript technology has brought a smoother experience for front-end and back-end development and significantly improved development efficiency. However, some netizens still question whether Javascript is capable of developing large Web applications. Large Web applications are characterized by the need to develop a large number of page components as the business grows. Faced with this scenario, there are generally two solutions:

The disadvantage of the single-page construction method is the large deployment package generated. 2 asynchronous page loading mode, the disadvantage is that the page is too scattered, need frequent interaction with the back end.

Eggborn.js implements a third solution:

3 Page components are classified according to business requirements, modularized, and realize the asynchronous loading mechanism of modules, so as to bridge the shortcomings of the first two solutions and perfectly meet the continuous growth of large Web application business needs.

Technical characteristics of eggborn.js

  • Business modularity: Page components are organized by modules
  • Flexible loading mode: modules can be loaded asynchronously or synchronously
  • Modules are highly cohesive: Modules include front-end page components and back-end business logic
  • Flexible parameter configuration: The front and back ends of a module can be configured independently
  • Internationalization: Both the front and back ends of the module support independent internationalization
  • Module isolation: The page, data, logic, routing, configuration and other elements of a module are namespace isolated to avoid variable pollution and conflict between modules
  • Super easy transaction processing: just configure a parameter on the routing record, you can perfect the transaction processing of the database.
  • Progressive development: Due to the highly cohesive nature of modules, business can be deposited as modules that can be reused in multiple projects, either contributed to the NPM open source community or deployed to a company’s private NPM repository.

With eggborn.js, you can reuse not only components, but also business modules.

Quick learning

Install eggborn.js scaffolding

$ npm install -g egg-bornCopy the code

New project

$ egg-born project_name
$ cd project_name
$ npm installCopy the code

Eggborn.js currently provides 2 project scaffolding, respectively

  • front-backend-mysqlBack-end full stack project template
  • front— Front-end project template, back-end can adopt other schemes

Configure mysql connection parameters

If front-backend-mysql is used, configure mysql connection parameters (empty database).

Edit the SRC/backend/config/config. The default. Js file

  // mysql
  config.mysql = {
    clients: {
      // donot change the name  
      __ebdb: {
        host: '127.0.0.1'.port: '3306'.user: 'travis'.password: ' '.database: 'egg-born',}}};Copy the code

Run the project

Start the back-end service

$ npm run dev:backendCopy the code

Start the front-end service

$ npm run dev:frontCopy the code

EggBorn. Js architecture diagram

System architecture

Project file structure

Module file structure


Module development

Naming conventions

In order to continuously precipitate service modules and achieve a highly reusable effect, the namespace of all modules must be fully isolated to avoid mutual pollution and conflict, so the following naming method is adopted:

egg-born-module-{providerId}-{moduleName}

For example, the module egg-born-module-a-version is named as follows:

  • providerId: a
  • moduleName: version
  • fullName: egg-born-module-a-version
  • relativeName: a-version
  • Front-end page routing address: /a/version/{page}
  • /a/version/{controller}/{action}

Loading mechanism

The module supports both asynchronous and synchronous loading. The default is asynchronous loading. To load the module synchronously, add the -sync suffix to the module name, for example, egg-born-module-aa-login-sync.

The new module

Go to the SRC/Module directory and execute the scaffolding to create the module file skeleton

$ egg-born module_relative_nameCopy the code

Eggborn.js currently provides 2 modular scaffoldings, respectively

  • moduleFull stack module template
  • module-frontFront-end module template

Module front-end development

Front-end page routing

Add a page route to front/ SRC /routes.js, as shown in the following example

function load(name) {
  return require(`./pages/${name}.vue`).default;
}

export default[{path: 'welcome/:who'.component: load('welcome')}, {path: 'profile'.component: load('profile'), meta: { requiresAuth: true}}, {path: '/login'.component: load('login')},];Copy the code
  • path: Path. Parameters are supported. In order to/Beginning, representing the root page component.loginPage components are typically configured this way
  • component: page component object
  • meta: Route metadata
  • meta.requiresAuth: If the page component requires login, set this parameter totrue

To reference a page component in a page, use an absolute path, such as

<f7-list-item link="/aa/hello/welcome/You" title="Welcome"></f7-list-item>
<f7-list-item link="/aa/hello/profile" title="Profile"></f7-list-item>Copy the code

Front-end state Management

Vuex is a state management mode developed specifically for vue.js applications. Eggborn. js implements a completely isolated module state management mechanism using Vuex. Add state in front/ SRC /store.js, as in

export default function(Vue) {

  return {
    state: {
      message: 'hello world',}}; }Copy the code

Access the module state in the page component

const message = this.$local.state.message;Copy the code

Access other module states in page components

const message = this.$store.state[providerId][moduleName].message;Copy the code

For more information, see: Vuex

Front-end Parameter Configuration

In front/SRC/config/config. Js add configuration information, such as

export default {
  mode: 1};Copy the code

You can only access the internal parameters of the module from the page component

const mode = this.$config.mode;Copy the code

Front-end internationalization

The following is an example of adding the language definition in the internationalization file zh-cn.js in the front/ SRC /config/locale directory

export default {
  mode: 'model'."Hello world! I'm %s.": 'Hello, world! I am a % s. '};Copy the code

The internationalization language adopts the global merge mode, which is conducive to the sharing of language resources. The page component can be accessed as follows

const mode = this.$text('mode');
const message = this.$text("Hello world! I'm %s.".'zhennann');Copy the code

Module backend development

Back-end API routing

Add API routes to backend/ SRC /routes.js, for example

const home = require('./controller/home.js');

module.exports = [
  { method: 'get'.path: 'home/index'.controller: home, action: 'index'.transaction: true},];Copy the code
  • method: Get/POST
  • path: Path. Parameters are supported
  • component: the Controller object
  • action: Controller method. If this is not set, the path suffix word is automatically used
  • transaction: Defaults to false. If set to true, database transactions are enabled

Access the module API route in the front-end page component

this.$api.get('home/index').then(data= > {
}).catch(err= >{});Copy the code

Access other module API routes in front page components

this.$api.get('/providerId/moduleName/home/index').then(data= > {
}).catch(err= >{});Copy the code

The back-end Controller

Back-end controllers are implemented in the same way as egg.js

module.exports = app= > {
  class HomeController extends app.Controller {

    async index() {
      const message = await this.service.home.index();
      this.ctx.success(message); }}return HomeController;
};Copy the code

For more information, see: egg.js Controller

The back-end Service

Service encapsulates the business logic to be invoked by the Controller in the same way as egg.js.

module.exports = app= > {
  class Home extends app.Service {

    async index() {
      const res = await this.ctx.db.queryOne('show tables');
      returnres; }}return Home;
};Copy the code

Unlike egg.js, the Service operates on the database using ctx.db, which automatically supports database transactions.

For more information, see egg.js Service

Backend Controller call

To support the development of large Web systems, eggborn.js supports calls between module back-end controllers, such as

const message = await this.ctx.performAction({
  method: 'get'.url: 'home/index'.query: {
    username: 'kevin',},params: {
    mode: 1,},body: {
    content: 'ready',}});Copy the code
  • method: Get/POST
  • url: Controllers accessing this module use relative paths, while controllers accessing other modules use/The absolute path at the beginning.
  • query,params,body: Consistent with regular Controller parameters

Back-end database operations

Back-end database operations are consistent with egg.js

For more information, see: egg.js MySQL

Back-end database transactions

Eggborn.js provides a more convenient way to implement database transactions by configuring transaction parameters in the back-end API routing record, and the Service uses CTx.db to operate on the database. If the master Controller calls the child Controller through ctx.performAction, the database transaction start rule is as follows:

The main Controller configuration The child Controller configuration The child Controller is actually enabled
true true true
true false true
false true true
false false false

Configure back-end parameters

In the backend/SRC/config/config. Js add configuration information, such as

module.exports = appInfo= > {
  const config = {};

  config.message = "Hello world! I'm %s.";

  return config;
};Copy the code

The following is an example of how to access this module

const message = this.ctx.config.message;Copy the code

Back-end internationalization

In the backend/SRC/config/locales directory add internationalization files useful – cn. Language definition of js file example below

module.exports = {
  "Hello world! I'm %s.": 'Hello, world! I am a % s. '.'not found': 'Not found'};Copy the code

The internationalization language adopts the global merge mode to facilitate the sharing of language resources. The access mode is as follows

const notFound = this.ctx.text('not found');
const message = this.ctx.text("Hello world! I'm %s.".'zhennann');Copy the code

Backend error handling

In the backend/SRC/config/errors. Js file to add the error code

// error code should start from 1001
module.exports = {
  1001: 'not found'};Copy the code

The following is an example of an error message

this.ctx.fail(1001);Copy the code

The following is an example of an exception that can be thrown

this.ctx.throw(1001);Copy the code

Module management

Module is dependent on

Eggborn.js manages module dependencies through the package.json file. For example, module AA-Module1 depends on Module AA-Module2. You need to perform the following configuration in the package.json file of module AA-Module1

{
  "name": "egg-born-module-aa-module1"."version": "0.0.1"."eggBornModule": {
    "dependencies": {
      "aa-module2": "0.0.1"}},"dependencies": {
    "egg-born-module-aa-module2": "^ 0.0.1." "}}Copy the code

“Egg-born-module-aa-module2 “: “^0.0.1” is set to automatically install module AA-module2 when module AA-Module1 is installed. This is not necessary if the module is not published publicly.

Module data version

Modules typically operate on databases, and the database structure may change when the template version is updated. Eggborn. js implements module data version management, facilitating the accumulation and precipitation of service modules.

Set fileVersion to the current data version in the module’s package.json file

{
  "name": "egg-born-module-aa-module1"."version": "0.0.1"."eggBornModule": {
    "fileVersion": 1}}Copy the code

Add an Api route at the back end of the module

{ method: 'post'.path: 'version/update'.controller: version }Copy the code

Add the version Controller

module.exports = app= > {
  class VersionController extends app.Controller {

    async update() {
      await this.service.version.update(this.ctx.getInt('version'));
      this.ctx.success(); }}return VersionController;
};Copy the code

Add the version Service

module.exports = app= > {

  class Version extends app.Service {

    async update(version) {
      if (version === 1) {
        // do something}}}return Version;
};Copy the code

When the back-end service is started, eggborn.js automatically detects the data version change of the module and executes the corresponding route to complete the data version upgrade.

Module to release

When the module code in the project is stable, the module can be published and contributed to the open source community. It is also possible to set up a private NPM repository within the company and then publish the modules to a private repository to form corporate assets for easy reuse. The module publishing steps are as follows

$ cdPath /to/module -- Go to the module directory $NPM install -- Install module dependencies $NPM run build:front -- Build front-end code $NPM run build: Backend -- build back-end code $NPM Publish -- Publish to the NPM repositoryCopy the code

Test drive

Currently, only back-end test drivers are supported

Back-end Controller tests

Add the Controller test file in the Backend /test/ Controller directory

// controller/home.test.js
const { app, mock, assert } = require('egg-mock/bootstrap');
const parseMockUrl = function(url) {
  const prefix = app.mockUtil.parseUrlFromPackage(__dirname);
  return `${prefix}${url}`;
};

describe('test/controller/home.test.js', () => {

  it('action:index'.async() = > {const result = await app.httpRequest().get(parseMockUrl('home/index'));
    assert(result.body.code === 0);
  });

});Copy the code

Back-end Service testing

Add the service test file in the backend/test/service directory

// service/home.test.js
const { app, mock, assert } = require('egg-mock/bootstrap');
const parseMockUrl = function() {
  return app.mockUtil.parseUrlFromPackage(__dirname);
};

describe('test/service/home.test.js', () => {

  it('index'.async() = > {const ctx = app.mockContext({ mockUrl: parseMockUrl() });
    const message = await ctx.service.home.index();
    assert(message);
  });

});Copy the code

Perform the test

Perform the tests in the project root directory

$ npm run test:backend
$ npm run cov:backendCopy the code

Front-end Architecture Configuration

Front-end startup file

The front-end architecture offers two solutions

  1. Vue.js + Framework7
  2. Vue.js + Vue Router

Framework7 is a mobile development-specific UI library with built-in routing mechanisms. The Vue Router is the official vue. js routing library. You can use the Vue Router with other UI libraries.

Switch in SRC /front/main.js

// choose one

// framework7
import main from './framework7/main.js';

// vuerouter
// import main from './vuerouter/main.js';

// export
export default main;Copy the code

Front-end Parameter Configuration

SRC/front/config/config. Js files can override the parameters in the configuration module parameters

export default{
  module: {
    'aa-hello': {
      mode: 2,}}};Copy the code

Front-end internationalization

Add the internationalization file in the SRC /front/config/locale directory to override the language definition in the module’s internationalization language zh-cn.js file

export default {
  mode: 'model'};Copy the code

Back-end architecture configuration

The backend architecture

The back-end architecture is based on egg.js and fully supports all functions and features provided by egg.js

For more information, see: egg.js

Configure back-end parameters

SRC/backend/config/config. Default. Js files can override the parameters in the configuration module parameters

module.exports = appInfo= > {
  const config = {};

  // module config
  config.module = {
    'aa-hello': {
      mode: 2,}};return config;
};Copy the code

Back-end internationalization

In SRC/backend/config/locales directory add internationalization files, you can override the module international language useful – cn. Language definition of js file example below

module.exports = {
  mode: 'model'};Copy the code

Project deployment

Build front-end code

$ npm run build:frontCopy the code

Start the back-end service

$ npm run start:backendCopy the code

Stop back-end services

$ npm run stop:backendCopy the code

Configure back-end service startup parameters

Edit the build/config.js file

// backend
const backend = {
  port: 7002.hostname: '127.0.0.1'};Copy the code

Nginx configuration

It is strongly recommended to use Nginx to host front-end static resources and reverse proxy back-end services as follows

server {
  listen 80;
  server_name example.com www.example.com;
  set $node_port 7002;

  root /path/to/www;

  location  /api/ {
    proxy_http_version 1.1;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_set_header X-NginX-Proxy true;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_pass http:/ / 127.0.0.1: $$request_uri node_port;proxy_redirect off; }}Copy the code

Making contribution

If you have any questions, please submit the issue, or directly modify and submit PR!