Excerpted from Http://cnodejs.org/topic/59eebce1f8d374775c0157d7
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 with JavaScript. Instead of repeating wheels, Eggborn.js uses the industry's newest open source technology for the best combination of all-stack development. Eggborn.js front-End with Vue.js + Framework7/vue Router + Webpack, back end with Koa.js + egg.js, database using MySQL. Eggborn.js keeps track of the latest developments in open source technology and continuously optimizes them to keep the entire framework in top shape.
Eggborn.js focus on what to solve: business modularity
The rapid development of JavaScript technology has resulted in a smoother experience for front-to-back development, significantly improving productivity. But there are still netizens who question whether JavaScript is capable of developing large web applications. Large Web applications are characterised by the need to develop a large number of page components as the business grows. In the face of this scenario, there are usually two solutions:
1 using a single page construction, the disadvantage is that the resulting deployment package is very large. 2 page Asynchronous loading method, the disadvantage is that the page is too fragmented, need to frequently interact with the backend.
Eggborn.js implements a third solution:
The 3-page component, which is categorized by business requirements, is modular and implements the asynchronous loading mechanism of the module, bridging the drawbacks of the first two solutions and satisfying the continued growth of the large Web applications business.
Technical features of Eggborn.js
- Business modularity: Page components organized by module
- Flexible loading mode: Modules can be loaded asynchronously or synchronously
- Module height cohesion: Modules include front-end page components and back-end business logic
- Flexible configuration of parameters: the front and rear end of the module can be configured separately
- Internationalization: The front and back of the module supports independent internationalization
- Module Isolation: The module's pages, data, logic, routing, configuration and other elements have been namespace-isolated processing, to avoid the variables between the module pollution and conflict
- Super-Easy transaction processing: Simply configure a parameter on the routing record to perfectly implement the transaction of the database.
- Progressive development: Due to the high cohesion of the module, the business can be deposited as a module, reused in multiple projects, can be contributed to the NPM open source community, can also be deployed to the company's own private NPM warehouse.
With Eggborn.js, it is not just the components that can be reused, but also the business modules.
Quick Start Installation Eggborn.js Scaffolding
$ npm install -g egg-born
New Project
$ egg-born project_name$ cd project_name$ npm install
Eggborn.js currently offers 2 project scaffolding, respectively
front-backend-mysql
– Front and back end full stack project template
front
– Front-end project templates with other options on the backend
Configure MySQL Connection parameters
If a front-backend-mysql
template is used, configure MySQL connection parameters (empty database)
Edit src/backend/config/config.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‘, }, }, };
Run the project
Start back-end service
$ npm run dev:backend
Start the front-end service
$ npm run dev:front
Eggborn.js Frame Composition System Architecture
Project file Structure
Module file Structure
Module Development naming convention
In order to continuously precipitate the business module to achieve a highly reusable effect, all modules must be fully segregated in the namespace to avoid contamination and conflict, so the following naming method is used:
Egg-born-module-{providerid}-{modulename}
such as modules egg-born-module-a-version
, each link naming information as follows:
providerId
: A
moduleName
: Version
fullName
: egg-born-module-a-version
relativeName
: a-version
- Front-end Page routing address:/a/version/{page}
- Backend API Routing address:/a/version/{controller}/{action}
Loading mechanism
The module supports both asynchronous loading and synchronous loading. The default is asynchronous loading, if you want to load synchronously, just add the suffix after the module name -sync
, such as module egg-born-module-aa-login-sync
.
New module
Enter src/module
directory to execute scaffolding, create module file skeleton
$ egg-born module_relative_name
Eggborn.js currently offers 2 modular scaffolding, respectively
module
– Full Stack module template
module-front
– Front-End module templates
Module front-end development front-end page routing
front/src/routes.js
add page routes in, such as
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‘) },];
path
: path, support parameters. To /
begin with, represents the root page component. login
page components are typically configured like this
component
: Page Component objects
meta
: Route meta Data
meta.requiresAuth
: If the page component needs to be logged in, it must be set totrue
To refer to 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>
Front-end state management
Vuex is a state management model developed specifically for vue.js applications. The eggborn.js uses Vuex to implement a fully isolated module state management mechanism. front/src/store.js
add a state in, such as
export default function(Vue) { return { state: { message: ‘hello world‘, }, };}
Accessing the module status in the page component
const message = this.$local.state.message;
Accessing other module states in the page component
const message = this.$store.state[providerId][moduleName].message;
For more information, see: Vuex
Front-end parameter configuration
front/src/config/config.js
add configuration information in, such as
export default { mode: 1,};
Access to the parameter configuration inside the module is only supported in the page component
const mode = this.$config.mode;
Front-end Internationalization
The front/src/config/locale
language definition in the directory add internationalization file zh-cn.js
file is shown below
export default { mode: ‘模式‘, "Hello world! I‘m %s.": ‘您好,世界!我是%s。‘, };
Internationalized languages take the form of global merging, which facilitates the sharing of language resources and is accessed in the page components as follows
const mode = this.$text(‘mode‘);const message = this.$text("Hello world! I‘m %s.",‘zhennann‘);
Module backend development Back-end API routing
backend/src/routes.js
Add API routes in, such as
const home = require(‘./controller/home.js‘);module.exports = [ { method: ‘get‘, path: ‘home/index‘, controller: home, action: ‘index‘, transaction: true },];
method
: Get/post and Other methods
path
: path, supported parameters
component
: Controller Object
action
: Controller method, if not set, automatically uses path trailing word
transaction
: The default is False, and if set to True, the database transaction is enabled
Accessing this module API routing in the front-end page component
this.$api.get(‘home/index‘).then(data => {}).catch(err => {});
Accessing other module API routes in the front-end page component
this.$api.get(‘/providerId/moduleName/home/index‘).then(data => {}).catch(err => {});
Back-end Controller
The backend controller is implemented in the same way as the 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;};
For more information, see: Egg.js Controller
Back-end service
The service is used to encapsulate the business logic for controller invocation and is implemented in a manner consistent with egg.js.
module.exports = app => { class Home extends app.Service { async index() { const res = await this.ctx.db.queryOne(‘show tables‘); return res; } } return Home;};
Unlike Egg.js, the service uses an ctx.db
operational database to automatically support database transactions.
For more information, see: Egg.js Service
Back-end controller invocation
To support the development of large web systems, Eggborn.js supports calls between the module backend controller, such as
const message = await this.ctx.performAction({ method: ‘get‘, url: ‘home/index‘, query: { username: ‘kevin‘, }, params: { mode: 1, }, body: { content: ‘ready‘, },});
method
: Get/post and Other methods
url
: The controller accessing the module uses a relative path, and the controller that accesses the other module uses the /
absolute path that begins with it.
query
, params
, body
: Consistent with conventional controller parameters
Back-End Database operations
Back-End Database operations aligned 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 simply configuring parameters in the backend API routing records transaction
and service using the ctx.db
operational database. If the master controller is ctx.performAction
called by the child controller, the database transaction opening rule is as follows:
Master Controller Configuration
Child controller Configuration
The child controller is actually enabled
True
True
True
True
False
True
False
True
True
False
False
False
Back-end parameter configuration
backend/src/config/config.js
add configuration information in, such as
module.exports = appInfo => { const config = {}; config.message = "Hello world! I‘m %s."; return config;};
Access to the parameter configuration inside the module such as the following
const message = this.ctx.config.message;
Back-end Internationalization
The backend/src/config/locale
language definition in the directory add internationalization file zh-cn.js
file is shown below
module.exports = { "Hello world! I‘m %s.": ‘您好,世界!我是%s。‘, ‘not found‘: ‘未发现‘,};
The internationalization language takes the global merging way, facilitates the sharing of the language resources, the access way is as follows
const notFound = this.ctx.text(‘not found‘);const message = this.ctx.text("Hello world! I‘m %s.", ‘zhennann‘);
Back-end error handling
backend/src/config/errors.js
Add an error code to the file
// error code should start from 1001module.exports = { 1001: ‘not found‘,};
Returns an error message such as the following
this.ctx.fail(1001);
You can also throw exceptions such as the following
this.ctx.throw(1001);
Module Management module Dependencies
Eggborn.js manages module dependencies through Package.json files. For example, the module Aa-module1 relies on aa-module2 and needs to be configured as follows in the Package.json file of the 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" }}
is set to "egg-born-module-aa-module2": "^0.0.1"
automatically install the module Aa-module2 when the module Aa-module1 is installed. If the module is not published publicly, you do not have to set it.
Module Data version
Modules generally operate the database, and when the template version is upgraded, the database structure is also subject to change. Eggborn.js realizes the management of the module data version and facilitates the accumulation and sedimentation of the business module.
Configuring FileVersion as the current data version in the module's Package.json file
{ "name": "egg-born-module-aa-module1", "version": "0.0.1", "eggBornModule": { "fileVersion": 1 }}
Adding API routes to the backend of a module
{ method: ‘post‘, path: ‘version/update‘, controller: version }
Add 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;};
Add version Service
module.exports = app => { class Version extends app.Service { async update(version) { if (version === 1) { // do something } } } return Version;};
When the backend service is started, Eggborn.js automatically detects changes in the version of the module data and executes the appropriate route to complete the version upgrade of the data.
Module release
When the module code in the project is stable, you can publish the module publicly and contribute to the open source community. It is also possible to set up a NPM private repository within the company, and then publish the modules to a private warehouse to form the company's assets for easy re-use. The module release steps are as follows
$ cd path/to/module -- 进入模块目录$ npm install -- 安装模块依赖$ npm run build:front -- 构建前端代码$ npm run build:backend -- 构建后端代码$ npm publish -- 发布至npm仓库
Test Drive
Only back-end test drivers are currently supported
Back-end controller testing
backend/test/controller
Adding a controller test file to a directory
// controller/home.test.jsconst { 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); });});
Back-end service testing
backend/test/service
Add a service test file to a directory
// service/home.test.jsconst { 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); });});
Perform tests
Executing tests in the project root directory
$ npm run test:backend$ npm run cov:backend
Front-end architecture configuration front-end startup files
Front-end architecture offers two scenarios
- Vue.js + Framework7
- Vue.js + Vue Router
Framework7 is a library of mobile development-specific UI interfaces with a built-in routing mechanism. Vue Router is the official Vue.js routing library that uses Vue router to match a variety of other UI libraries.
src/front/main.js
to switch between files
// choose one// framework7import main from ‘./framework7/main.js‘;// vuerouter// import main from ‘./vuerouter/main.js‘;// exportexport default main;
Front-end parameter configuration
src/front/config/config.js
Parameter configuration in the file can override parameters of the module
export default{ module: { ‘aa-hello‘: { mode: 2, }, },};
Front-end Internationalization
src/front/config/locale
add internationalized files in the directory, you can override the language definitions in the Internationalized language file for the module zh-cn.js
such as the following
export default { mode: ‘模式‘,};
Back-end architecture configuration backend Architecture
Backend architecture based on egg.js, full support for all features and features provided by Egg.js
For more information, see: Egg.js
Back-end parameter configuration
src/backend/config/config.default.js
Parameter configuration in the file can override parameters of the module
module.exports = appInfo => { const config = {}; // module config config.module = { ‘aa-hello‘: { mode: 2, }, }; return config;};
Back-end Internationalization
src/backend/config/locale
add internationalized files in the directory, you can override the language definitions in the Internationalized language file for the module zh-cn.js
such as the following
module.exports = { mode: ‘模式‘,};
Project deployment build front-end code
$ npm run build:front
Start back-end service
$ npm run start:backend
Stop back-end service
$ npm run stop:backend
Back-end service startup parameter configuration
Edit build/config.js
File
// backendconst backend = { port: 7002, hostname: ‘127.0.0.1‘,};
Nginx Configuration
It is strongly recommended to use Nginx to host front-end static resources and reverse proxy back-end services, configured 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:$node_port$request_uri; proxy_redirect off; }}
GitHub contributions
If you have any questions, you are welcome to submit issue, or directly modify the submission pr!
About the full Stack engineer tool Eggborn.js