An open API service indexing awesome lists of open source software.

https://github.com/momsfriendlydevco/doop

The MEVN micro-framework used by MomsFriendlyDevCo
https://github.com/momsfriendlydevco/doop

Last synced: over 1 year ago
JSON representation

The MEVN micro-framework used by MomsFriendlyDevCo

Awesome Lists containing this project

README

          






Doop@3!
=======
The MEVN micro-framework used by [MomsFriendlyDevCo](http://mfdc.biz).

**If we hit that bullseye, the rest of the dominoes will fall like a house of cards. Checkmate - Zapp Brannigan**

Basic principles:

* Doop tries to have the lowest understanding cost possible
* Doop units are designed to be as generic and transferable between projects as possible

Terminology:

* The Doop documentation endeavour to use requirement levels that abide by the definitions specified by [RFC 2119 (Requirement Levels)](http://www.ietf.org/rfc/rfc2119.txt)

Major releases:

* **[V3 - Cubert](https://github.com/MomsFriendlyDevCo/Doop/tree/master)** - Current stable release (Vue@3 compatible frontend)
* **[V2 - Bender](https://github.com/MomsFriendlyDevCo/Doop/tree/v2)** - Previous stable release (Vue@2 frontend)
* **[V1 - Amy](https://github.com/MomsFriendlyDevCo/Doop/releases/tag/v1)** - Initial Doop implementation

General concept
===============
Doop is made up of two types of files. Files ending in `.vue` are frontend Vue framework(esk) and `.doop` are backend Express framework(esk).

Within these two file types there can be blocks of code which expose things like controllers, schemas, models, CSS, HTML templates and so on.

Generally all areas of an application are exposed at the root level (e.g. `widgets/`) with shared components living inside directories such as `filters`, `widgets` and so on.

NPM modules
-----------
MFDC relies on various common NPM modules across all its projects.

You can read more about how MFDC structures its project in the [Momsronomicon](https://github.com/MomsFriendlyDevCo/Momsronomicon/blob/master/devstack-node.md).

Project directories and files
-----------------------------
The project tree breakdown is listed below. For each path an 'edit chance' is given (i.e. the possibility of the developer needing to change the contents of that directory) and a brief description.

| Path or Glob | Description
|--------------------------------|----------------------------------
| `/` | The project root
| `/app/` | Core initialization files
| `/assets/` | Generic static assets such as logo images and favicons
| `/build/` | Build scripts
| `/cache/` | Generic cache handling
| `/config/index.js` | Base config file showing default variables subsequently overridden by each `NODE_ENV` config file
| `/config/*.js` | Other config files, loaded selectively based on the `NODE_ENV` environment variable
| `/config/private.js` | Private config details. This file is listed in `.gitignore` and should *never* be checked in to GitHub as it can contain private details - e.g. database connection passwords or API keys
| `/config/production.conf.js` | Production server config details. This should include settings to enable all minimizers and other optimizations for production-ready code
| `/config/` | Storage for all config scripts read at startup, see `config/index.js` for default config setup. Other files are read depending on the `NODE_ENV` setting
| `/dashboard/` | Front end application entry point
| `/data/` | Generic data for the project - could contain resource files used during automated builds
| `/db/` | The main database driver and schema loader
| `/debug/` | Various debugging utilities
| `/directives/` | Shared frontend Vue directives
| `/dist/` | Generated files directory. Do not edit the contents of this directory as it is auto-generated by Gulp
| `/docs/` | Any miscellaneous files not relevant to the operation of the project but which need to be retained e.g. scope documents, ERD diagrams
| `/errors/` | Error handling and reporting
| `/filters/` | Shared frontend Vue filters
| `/fonts.fa5/` | Font-Awesome 5
| `/fonts/` | Other font files
| `/.git/` | Git storage and meta information
| `/gulpfile.js` | Main Gulp build-system config file
| `/layouts/` | Global page layout templates
| `/layouts/main.html` | Default page layout template
| `/middleware/db.*.doop` | Database middleware
| `/middleware/` | Express and Database middleware
| `/middleware/express.*.doop` | Express middleware
| `/node_modules/` | Install directory for all NPM controlled packages
| `/scenario/` | Database scenario templates
| `/server/` | Server bootstrapping scripts
| `/services/` | Shared frontend Vue services (usually available as `vm.$SERVICE`)
| `/tests/` | Optional testing files
| `/theme/bootstrap-extensions/` | Various CSS files which extend Bootstrap@4
| `/theme/` | Site theme
| `/theme/theme-overrides/` | Various CSS files which fix issues with the main theme
| `/users` | User schemas and management
| `/vendors` | Externally supported vendor scripts
| `/widgets` | Shared frontend Vue services
| `/**/*.mjs` | Isomorphic JS files available to frontend/backend as required via `import` / `require` respectively
| `/**/*.doop` | Backend Doop modules
| `/**/*.gulp.js` | Global Gulp build-system task files
| `/**/*.vue` | Frontend Vue modules

Modules
=======
The following modules are provided separately and can be optionally included within a project.

| Module | Default | Description |
|----------------------------|---------|-------------------------------------------------------------------------|
| `@doop/service-components` | Yes | `$components` service allowing cross talk and enumeration of components |
| `@doop/service-data` | Yes | Various data manipulation service components |
| `@doop/service-toast` | Yes | `$toast` service to display simple UI messages |
| `@doop/service-data` | Yes | Various data I/O services - `$assign`, `${has,get,set}Path`, `$push` |
| `@doop/service-morph` | Yes | Animation library to transform DOM components with animations |
| `@doop/directive-jump` | Yes | `v-jump` directive to easily scroll around pages using `` style anchors |

Content Blocks
==============

Backend .doop files
--------------------
Doop backend files are made of `` blocks which execute when a named event is emitted (via `app.emit(event)`).

For example simple ReST endpoints endpoint are registered like so:

```vue

/**
* This function does something
*/
app.get('/api/foobar', (req, res) => {
// Do something //
});

```

Database schemas are registered similarly:

```vue

app.middleware.db.schema('widgets', {
title: String,
});

```

More advanced functions can be registered in a specific place within the load order (see the [server file](`./skeleton/server/index.js`) for the exact load order)

```vue

// Server has now loaded

```

Some `` attributes are provided which makes typing a little less tedious:

| Block | Alias of | Definition |
|--------------|----------------------------|------------------------------|
| `endpoint` | `` | An API endpoint |
| `middleware` | `<script on="middleware">` | Database / server middleware |
| `schema` | `<script on="schemas">` | A database schema |

For the `server` block the `on` event must be specified and can contain a CSV of multiple events.

For a reference of which events fire and in what order see the [server](./server/index.js) and [gulpfile](./gulpfile.js).

Frontend .vue files
--------------------
Vue files follow the regular Vue [Single-Page-Component](https://vue-loader.vuejs.org/spec.html) format with the following block types:

| Block | Contents | Definition |
|-------------|----------------------------|--------------------------------------------------------------------------|
| `script` | Frontend javascript | A Vue frontend definition (limit of one block per file) |
| `style` | CSS | Global level CSS |
| `template` | HTML | Template file (the file name is used to match it against the controller) |

For example the following file registers a Vue component with the name `widget`:

```vue
<script lang="js" frontend>
app.component('widget', {
// Vue component definition
})

```

`.vue` files can also contain an optional properties which gets specical treatment during the component load phase:

```vue

app.component('ordersEdit', {
route: '/orders/:id', // Set up a route for this component automatically
routeRequiresAuth: true, // Require a session to access this component (the default), otherwise let guest users view
// ... Vue component definition ... //
})

```

Special component properties supported by Doop:

| Property | Type | Default | Description |
|---------------------|---------|---------|------------------------------------------------------------------------------|
| `route` | String | | Auto-installed route to access the component |
| `routeRequiresAuth` | Boolean | `true` | Whether the route should redirect to the login page if no session is present |

Standard frontend component registration types are:

| Type | Syntax example | Description |
|--------------------|---------------------------------------------------------------|----------------------------------------------------------|
| Vue Component | `app.component('name', { ... Vue Component dedinition ... })` | Register a Vue frontend component (`route` key optional) |
| Doop / Vue filter | `app.filter('name', (value, options) => {}` | Register a filter function |
| Doop / Vue service | `app.service('$name', { ... definition ... })` | Register a service |

**Notes:**
* Names of exported items (such as components, filters, services and templates) are all automatically derive from the filename and transformed via CamelCase. The name can be overridden by specifying the name attribute e.g. `` to export as `vm.$myService`.
* Services are accessible via either `vm.$SERVICE` or `app.service.$SERVICE`
* All registered filters are likewise available via `vm.$filters.FILTER` or `app.filter.FILTER`

Syntax
------

All `.vue` files are compiled via Babel and executed with the following presets:

* [babel-preset-env](https://babeljs.io/docs/en/babel-preset-env)
* [babel-plugin-proposal-optional-chaining](https://babeljs.io/docs/en/babel-plugin-proposal-optional-chaining)

In essence this is really just an in-built version of the [lodash.get](https://lodash.com/docs#get) function wrapped in regular JavaScript syntax.

```javascript
// Assuming:
var obj = {
foo: {
bar: {
baz: 42,
},
},
};

var baz = obj?.foo?.bar?.baz; //= 42
var nonExistant = obj?.qux?.baz; //= undefined
```

* [babel-plugin-proposal-pipeline-operator](https://babeljs.io/docs/en/babel-plugin-proposal-pipeline-operator) using the [#F sharp standard](https://github.com/valtech-nyc/proposal-fsharp-pipelines)

Chain multiple functions in a pipeline using something like Promise / arrow function syntax:

```javascript
var result = 'hello'
|> doubleSay
|> capitalize
|> x => exclaim('Howdy or', x);
```

API
===

Backend
--------
Doop is exposed as a global level `app` object which contains the following functions:

app
---
The App object is a global, available everywhere in the project. It is a mutated version of the [ExpressJS App object](http://expressjs.com/en/4x/api.html#app) and [eventer](https://github.com/MomsFriendlyDevCo/eventer) classes.

app.cache
---------
Globally available instance of [Generic-Cache](https://github.com/MomsFriendlyDevCo/generic-cache)

app.config
----------
An object used to hold the calculated contents of the `/config` files. This is typically a combination of the main `index.js` file, any `NODE_ENV` specific files and the `private.js` file. To see the config of the profile you are currently using run `gulp app.config`.

app.db OR db
------------
In a typical Doop deployment this object represents an object of all loaded models. This may not be the case in all projects, depending on the database driver used.

`db` is also registered as a global for convenience.

app.emit(event, args...)
------------------------
Emit an event using [eventer](https://github.com/MomsFriendlyDevCo/eventer).

app.log(...msg)
---------------
Various logging functionality. Try to use `app.log()` instead of `console.log()` as text output via it is properly prefixed to the running file name.

app.log.as(name, ...msg)
------------------------
Module name prefixed version of `app.log()`.

app.log.colors
--------------
Globally available version of [Chalk](https://github.com/chalk/chalk).

app.log.dump(...msg)
--------------------
Globally available version of [dumper.js](https://github.com/ziishaned/dumper.js)

app.log.debug(...msg)
---------------------
Globally available version of [debug](https://github.com/visionmedia/debug)

app.log.error(Error)
--------------------
Globally available version of [Crash](https://github.com/MomsFriendlyDevCo/crash).
Use `app.log.errorCrash(Error)` to perform a fatal error.

app.log.warn(...msg)
--------------------
Same as `app.log()` but with a "[WARNING]" prefix.

app.log.warn.as(module, ...msg)
-------------------------------
Prefixed version of `app.log.warn()`

app.middleware
--------------
In a typical Doop deployment this object represents an object of available middleware. Use `app.middleware.express` or `app.middleware.db` for the Express and database middlewares respectively.

app.on(event, handler)
----------------------
Register an event listener using [eventer](https://github.com/MomsFriendlyDevCo/eventer).

Testing + Debugging
===================

Unit tests
----------
Larger projects can populate the `/tests/` directory with [Mocha](https://mochajs.org) + [Chai](http://chaijs.com/api/bdd) test cases. Tests can also be specified per-unit by adding any file matching the glob `*.test.js` within their unit directory.

To run a Unit test you will need to have Mocha installed (`sudo npm i -g mocha`). Either run mocha with no specified files to process *all* test files or specify the specific test file(s) you wish Mocha to examine as command line arguments.

Run the *all* the tests with mocha in the project root directory with `mocha`.

**TIP:** Unit tests can be skipped temporarily by either adding an 'x' before `describe` / `it` or adding `.skip` as a suffix. e.g. To temporarily skip a test rename the function `describe('something something')` to `xdescribe('something something')` or `describe.skip('something something')`.
**TIP::** As with the above you can also force Mocha to *only* run one test - this is useful if your test is deeply nested within an existing file and you don't want to add `skip` to each other case. To use this add `.only` as a suffix for the `describe` / `it` declaration. e.g. `it('should do this', function() { ... })` becomes `it.only('should do this', function() { ... })`.

Command line debugging
----------------------
Doop, like most modules, responds to the `DEBUG` flag used by the [Debug](https://github.com/visionmedia/debug) module. This turns on verbose logging when running within a console.
The `DEBUG` variable can be set to the specific module you would like to log, a number of them via comma-separated-values or a glob expression. For example `DEBUG=doop gulp` runs Gulp and tells Doop to run in debug mode.