Skip to content

devmachiine/npm-nano-module

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

15 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

TLDR

Same thing as require(...) with differences being:

  • No secondary steps needed to install a package. Just use it in code.
  • Packages are single functions that return 1 thing.

Quickstart

git clone https://github.com/devmachiine/npm-ffun.git
cd npm-ffun
node app-test.js

There is tests folder showing the proof of concept.

This project is basically the same thing, with convenient defaults and picture of a ninja.

Dynamic package manager for javascript applications

Sometimes you only need a small part of logic that a module provides. Nano modules are just that - modules that only do just about one thing. Like really small modules, a single function to be exact.

You can think of each function as a 'mini-package', and nano-module as an additional vitamin supplement to familiar package managers like npm or yarn.

Example:

Say that you need a function to add two numbers together, but you are not interested in the 20 other things a math package might bring with it. Nor the other 12 packages it will bring to the party.

You find the code you need in https://example.com/url/math/addition-1992.js

// a single arrow function
(x, y) => x + y

Your app could import just that spot of logic:

// require nano-module
const ff = require('nano-module')

// url (or local file path) to our dependency
const path = 'https://example.com/url/math/addition-1992.js'

// get the async add function
const add = ff(path)

// fetch the function and run it locally
const result = await add(2, 5)

console.log(`2 plus 5 equals ${result)}`))

Outputs:

2 plus 5 equals 7

A little more

Nano modules can also be imported locally, so you don't have to upload them somewhere before using them:

// import same as above..
const rightpad = ff('./utils/string/not-leftpad.js')

// more details on how nano modules can prevent the left-pad like disaster to follow ;)

Nano modules can also use nano-module, aliased as ff (fetch function) themselves to retrieve other functions, and those nested functions can retrieve other functions and so forth, to accomplish more interesting tasks.

Nano modules already find themselves in an async context, so in addition to ff you have await at your disposal:

(test, assert) => {

    const test_remote_call_remote = ff('https://gist.githubusercontent.com/devmachiine/44c86b61bd8b98226d7ddbe97b4196ea/raw/66107ef784c8a72bb99fdac2acd23bdd4a8280f9/remote-remote.js')

    const test_add = await test_remote_call_remote(test, assert)

    return test('remote load remote',
        () => {
            assert(test_add.description, 'remote functions can load other remote functions')
            assert(true, !test_add.error)
        })
}

Here the funcion wasn't given just any old x and y as in the first example, but a test framework. These inputs don't go outside of your application over the wire, everything is ran locally.

Nano modules live in the app directory:

project-name
 - lib
 - docs
 - nano_modules
   - domain
   - domain
    - subpath
      - nano a.js  <-- in here. similar path as the url on the web.
      - nano b.js
 - node_modules
   - module a..
   - module b..
index.js

When a nano is requested, nano-module fetches it from the web (only once), then caches, and returns it.

The next time your app runs, it'll load it from the nano_modules folder on the 1st call, and from memory for subsequent calls.

Stable dependencies

Anyone remember the left-pad incident ?

There is a big hash hint in the last code snippet how the scenario can be prevented ;)

(with a minor drawback, for now.. work in progress..)

Background

The unix philosopy, is a great example of how large software projects and be composed from small single purposed components.

There are lots of packages that go along with the browserify module philosophy, and nano modules is also a way to encourage that approach.

This talk by Rich Hickey explains how dependencies often entail breaking changes. Among other things it talks about:

Semantic versioning:
_._.x will probably not be a breaking change
_.x._ also won't be a breaking change, pinky promise ;)
x._._ okay changes will possibly break your code, oops!

However the version number only reflects the interactions with a module/package. Sometimes. The behaviour changes from version to version, and a 0.0.x bump could still be a breaking change anyway.

Another topic that animated me to start this project, was that I found it somehow crazy that a website can have over 500 MB of dependencies. Do we really need to download all the code, even if you only run a subset ? Not that 5 or even 50GB of dependencies would be problem for our machines, the lazy loading aspect is purely out of curiosity and the inconvenience of waiting for progress bars and spinners.. ⏳

What we want is to re-use shared code, without pushing breaking changes to unknown consumers, and signal updates that people can opt into. (eg. bugfixes, security and performance improvements)

This project is a step in that direction.

Next steps

  • Registry where people can add and search nano modules work in progress here
  • Mechanism to singal interesting updates. Not updating for changes irrelevant to our code (ex. the author changed their mind about a name)
  • Tool to update dependencies in a tested, incremental way
  • Plugin/Extension for auto completion

About

Dynamic package manager for javascript applications

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published