npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@or-change/duck

v0.6.2

Published

Duck is an extensible, lightweight, flexible, progressive software development frameworks for building software product.

Downloads

14

Readme

lerna

Duck is an extensible, lightweight, flexible, progressive software development frameworks for building software product. It uses dependency injection and control inversion just a little like "Java Spring". It help developers to create, use, manage various runtime objects to inject to whereever required. Everyone can extend framework directly in low cost.

In the past, we often have to face to inflexible, confused project directory problems in development in Node.js. Everyone could disgust require modules from parent directory like require('../../'). Because it represent some coupling out of control. Duck resolve the problems above and provide a programming models to help developer avoid incorrect design.

Duck does not impose any restrictions on your coding style. But it will still provide the necessary guidance to advance the right design. Be brave enough to use your imagination to solve your problems.

On the one hand Duck is a useful framework & pattern for architect or tech leader to take apart development tasks. Developers working at the top will feel comfortable with structuring their work. Duck hopes every developer does NOT need to learn any framework practices. Duck respects, supports and maintains the development team's own practices. What does it mean?

The DUCK knows first when the river becomes warm in SPRING.

Duck is used to build product!

Installation

npm install @or-change/duck

Usage

To build a very simple product,

const Duck = require('@or-change/duck');
const meta = require('./package.json');

// To create the product factory named Simple.
function Simple() {
  const simple = {};

  Duck({
    id: 'com.orchange.duck.demo',
    name: 'Simple Product',
    version: meta.version
  }, ({ product }) => {
    // There will be 2 methods on a Simple product instance.
    
    simple.getMeta = function getMeta() {
      return product.meta;
    };

    simple.getComponents = function getComponents() {
      return product.components;
    }
  });

  return simple;
}

// To create a Simple product instance then use it.
const simple = Simple();

console.log(simple.getMeta());
// => {name: "Simple Product", namespace: "", version: "0.0.0", description: "Default product descrition"}

console.log(simple.getComponents());
// => []
// Because there is no component in the product.

API Reference

Duck

A duck instance is just an EventEmitter instance without any preset event. Everyone can emit necessary event by injection.product.

[RECOMMANDED] Avoid using classes or constructors if there are no special requirements. For a framework for assembly resources like duck, class & constructor cause too much programming burden and are not flexible enough. There is almost no such need for inctanceof. "Duck typing" always be useful.

Duck(options[, callback])

options is an object. callback is a function. Return a product instance. The product instance is extended from EventEmitter.

Options

| Property | Type | Default value | Description | | ------------ | --------- | ----------------------- | ---------------------------- | | id | String | | Product id | | name | String | 'Default Product Name' | Product name | | namespace | String | '' | Namespace component may use | | version | String | '0.0.0' | Current version | | description | String | 'No descrition' | What am I? | | installed | Object | () => {} | Invoking after components | | injection | Object | {} | Initial dependences | | components | Array | [] | Product components list |

[RECOMMANDED] Some dependencies just for current product can be injected into by options.injection to avoid defining components (see components). Because dependencies from components is universal and reusable across products.

[RECOMMANDED] In hook options.installed, some direct dependencies using component dependencies could be created and injected into injection. In other words, injection could still be changed here and then to be non-extensible.

Callback

Only one formal parameter could be accessed is injection. [RECOMMANDED] Using object destructuring assignment syntax to access dependencies of injection can make the code more clear. There is no meaningful context here (this === null). Arrow function is also accepted here if you like.

Injection is very IMPORTANT to be careful for using. Avoid to change injection outside of the Duck instance lifecycle. Because incorrect state may cause fatal runtime errors. This will not help reduce R&D costs.

[RECOMMANDED] Accessing injection & dependencies in callback and providing external accessing by indirect way.

Best practice example,

const Duck = require('@or-change/duck');
const http = require('http');

function MyProduct() {
  const product = {};

  Duck({
    id: 'com.xxx.yyy.zzz',
    component: [
      Duck.Web()
    ]
  }, function callback({ Web }) {
    // Access all dependences safely here.
    // Be careful and responsible for providing external indirect access to injected dependencies.
    product.start = function startServer() {
      return http.createServer(Web.Application.Default()).listen(8080);
    };
  });

  return product;
}

// External access.
const myProduct = MyProduct();

myProduct.start(); // Use injected dependence 'Web' indirectly.

// Use arrow callback function
function MyProductB() {
  Duck({
    id: 'com.xxx.yyy.zzz',
    component: [
      Duck.Web()
    ]
  }, ({ Web }) => {
    // There is no meaningful context here. (this === null)
    // Arrow function is also accepted here if you like will make the code more clear.

    console.log(Web);
  });
}

Lifecycle

  1. Initialization
  • Normalizing options
  • Preparing product instance
  • Creating injection instance with options.injection

Mixin options.injection

  1. Installing components
  • Collecting all component configuration items
  • Invoking all installers of components
  • Setting dependencies or accessing dependencies unsafely
  1. Preset product dependence
  • Setting product instance into injection as a dependence
  • Then freezing injection

Invoking options.installed(injection)

  1. Components created
  • Invoking all created hooks of components
  • Accessing dependencies safely but can NOT changing injection any more

Invoking callback(injection)

Product dependence

A product dependence will be injected into injection after components have been installed. The project provides meta, components and duck getters to reflect the final abstract of the duck instance.

Use project dependence,

const Duck = require('../');

Duck({
  id: 'com.xxx.yy.zz',
}, ({ project }) => {
  console.log(project.meta);
  console.log(project.components);
  console.log(project.duck);
});

project.meta returns a new plain object every time. Pproperties,

| Property | Type | Example Value | Description | | ------------ | --------- | ----------------------- | ---------------------------- | | id | String | 'com.xx.yy.zz' | options.id | | name | String | 'Default Product Name' | options.name | | namespace | String | '' | options.namespace | | version | String | '0.0.0' | options.version | | description | String | 'No descrition' | options.description |

project.components returns a new array about used components. Each element properties,

| Property | Type | Example Value | Description | | ------------ | --------- | ----------------------- | ---------------------------- | | id | String | 'com.xx.yy.zz' | component.id | | name | String | 'Component Name' | component.name | | description | String | 'No descrition' | component.description | | details | any | null | component.getDetails() |

project.duck returns a new plain object about duck. Properties,

| Property | Type | Example Value | Description | | ---------------- | --------- | ----------------------- | ---------------------------- | | version | String | '0.0.0' | duck version | | peerDependencies | object | {} | duck peerDependencies |

Component

Component is use to append some runtime dependencies into injection. Each component instance MUST include 3 items to describe the features & meta of itself. They are id, name, install.

In addition, component.description is a string for describing what the component is. component.created a hook function will be called after the duck has been created.

[RECOMMENDED] Appending dependence only in component.install. Accessing dependence only after duck instance created, like in component.created and Duck(options[, callback]).

[NOTICE] Defining a component means that there are some widespread jobs need to be decoupled. Just use options.injection if there is no special need for flexibility.

Althought accessing when component.install is ok, it means "Component_A depends Component_B" that cause coulping between components. Developers can still handle these problems with care and "Put Component_A before Component_B" to ensure Component_B can use Component_A in install.

Instance

Properties Table

| Property | Type | Default value | Description | | ------------ | --------- | ----------------- | ---------------------------- | | id | String | | Unique component id | | name | String | | Component name for display | | install | Function | | Installer | | description | String | 'No description' | Description | | created | Function | () => {} | Calling after duck created | | getDetails | Function | () => null | Custom Details Snapshot |

Create a component directly,

const Duck = require('@or-change/duck');

Duck({
  id: 'com.orchange.duck.demo',
  components: [
    {
      id: 'com.example.duck.literal',
      name: 'DirectSample',
      install(injection) {
        // Append a dependence named 'foo'
        injection.foo = function () {
          return 'bar';
        }
      },
    }
  ]
}, ({ foo }) => {
  console.log(foo());
  // => 'bar'
});

The example is just want to tell developers that create a component by literal is be allowed. There is NO magic about component. Everyone can do everything in this pattern. [RECOMMANDED] Defining a factory to build a component instance like a provider can make the code clear and maintainable. Many native components have been defined in @or-change/duck. Enjoy them!

Simple web application example,

const http = require('http');
const Duck = require('@or-change/duck');

Duck({
  id: 'com.orchange.duck.demo',
  components: [
    Duck.Web()
  ]
}, ({ Web }) => {
  // Access Web.Application.Default to get the default application factory.
  // Call the factory then return the request listener instance of application.
  // The "Default" Application is provided by Web Component default options.
  http.createServer(Web.Application.Default()).listen(8080);
});

// Now, open your browser and navigate to http://localhost:8080
/**
{
  "meta": {
    "name": "Default Product Name",
    "namespace": "",
    "version": "0.0.0",
    "description": "No descrition"
  },
  "components": [
    {
      "id": "com.oc.duck.web",
      "name": "WebApplication",
      "description": "Used to guide developer to create a web application.",
      "details": null
    }
  ]
}
*/

Native Components

  • Web - How to build a web application product?
  • Webpack - Manage webpack configs.
  • Datahub - Use data middle layer & define models.
  • Electron6 - How to build a integrated Electron application?
  • Log //TODO - Build & manage log channel.

Injection

Injection is the core function to manage dependencies regularly. Dependencies could be in any form. After product dependence injection will be freezed (see lifecycle). Setting new dependence will become invalid.

Instance

An injection is use to set, get, transmit and manage dependencies to everywhere in a product. Each duck instance will create only one injection for itself.

About injection, some facts MUST be known,

  • Cannot get a dependence NOT existed.
  • Cannot set a new dependence override a existed.
  • The injection of a duck will be freezen after duck created.
  • Inline Dependences - There are 2 dependencies on injection when created.
  • injection.injection reference itself for convenience.

Preset dependencies

Project structure & Implementation

I am a leader

What should I think about components?

How to establish an own practices?

What will direct dependencies give me?

Whose IoC is it?

I have a good idea to share.

I am a member

What I want must be in the injection.

Please give ...

License

MIT