Nimbly
Nimbly is a JavaScript component framework for single page applications.
Install / Use
/learn @ElliotNB/NimblyREADME
:surfer: Nimbly
https://github.com/elliotnb/nimbly
Version 0.1.5
Licensed under the MIT license:
http://www.opensource.org/licenses/MIT
Quick Start
Want to learn how to use Nimbly as quickly as possible? Follow this quick start guide!
The README below is best used as a reference manual. Beginners should first consult the quick start guide.
Overview
What is Nimbly?
Nimbly is a JavaScript component framework for single page applications.
Why yet another JS framework?
Modern web application development is run amok with excessive tooling and leaky abstractions. Babel, Webpack, JSX, virtual DOM, source maps, etc -- it's all unnecessarily complicated. As the 2018 npm developer survey concluded:
JavaScript in 2018 is somewhat notorious for requiring a lot of tooling to get going, which is quite a reversal from the situation in 2014... True to that, all of our survey respondents would like to see less tooling, less configuration required to get started, and better documentation of the tools that do exist.
The goal of Nimbly is to keep things simple.
What makes Nimbly different?
- Fewer abstractions - Nimbly embraces the native DOM. It does not use a virtual DOM abstraction. Nimbly components render plain HTMLElements.
- No build steps - The code you write runs in the browser. Nimbly does not require transpiling (e.g., Babel) nor a build process (e.g., Webpack).
- No DSLs - Write code with plain HTML, CSS and JavaScript. You don't need to learn another domain specific language (e.g., React JSX).
- Easy to debug - Fewer abstractions, no DSLs and ES5 support without transpiling means that Nimbly components are easy to debug. Short stack traces and a minimum of framework-specific error sleuthing.
- "Plays nice" - Nimbly is self-contained and does not take over the page. Nimbly is perfectly happy existing alongside other non-Nimbly components.
The technical objectives of Nimbly are:
- Encourage adoption of SPA best practices:
- Templating.
- One-way data binding.
- Intuitive and consistent state management.
- Elimination of explicit DOM manipulations.
- Loosely coupled modular components.
- Encourage expressive and easy-to-follow code:
- Reduce boilerplate code.
- Components follow a common structure and organization.
- Easily identifiable state mutations.
- Clear linking of state to display.
- Common public methods and lifecycle hooks for all components.
- Provide easy-to-use patterns for:
- Dependency injection.
- Automated unit testing.
- Coordinate DOM updates amongst all components to minimize page re-draws, optimize performance and improve the user experience.
Requirements
Nimbly requires the following libraries:
Why jQuery?
Nimbly started out as a project to facilitate easier refactors of jQuery-heavy web apps.
For the time being, Nimbly requires jQuery. But fret not, components built with Nimbly are not required to use jQuery.
Nimbly uses jQuery primarily for:
- Merging deeply nested objects via
$.extend. - Updating DOM nodes via
$.replaceWith. - Creation of new DOM elements
$("<div>hello world</div>");
Eventually, this functionality will be bundled directly into Nimbly and jQuery will be retired.
Including jQuery v3.3.1 minified slim adds 69KB to the total footprint of the framework.
Install
<script src="observable-slim.min.js"></script>
<script src="jquery.min.js"></script>
<script src="nimbly.min.js"></script>
Also available via NPM:
$ npm install nimbly --save
Parameters
The Nimbly constructor accepts four parameters:
-
className- String, required, the name of the component class (e.g., HelloWorld) that extends Nimbly. The class name is used for producing helpful debug messages when errors occur within Nimbly. -
defaults- Object, required, a variety of default options and preferences. See below for a definition of each configurable setting. -
data- Object, optional, a plain object that sets the initial state values (overwrites the default state defined indefaults). -
options- Object, optional, overrides thedefaultsby merging over the top of it.
Properties
All Nimbly components have the following public properties:
-
options- Object, the component default settings with any user-defined options merged over the top. -
className- String, the name of the class that initialized the base class. We store this value for debugging and logging purposes. -
domNode- the DOM Node rendered by this component. -
jqDom- jQuery reference tothis.domNode. -
initialized- Boolean, set to true when the this.init() method has completed and the component is ready to render. -
childComponents- Hash, if a component registers (via.registerChild) other components, then those child components will be added to the hash. Child components are indexed on the hash according to what list or repeatable section they belong to. If a component is not part of a list, then that component is added tothis.childComponents.default. -
templates- Hash, where the key is the name of the template and the value is a string containing the template. The hash contains each template used by the component. The template element identifiers are passed in via options.templates and below we will populate this.templates with the content of the template. -
loadingTemplate- String, template content OR an element identifier of the template used to display a loading spinner or loading message. The loadingTemplate is utilized only if the .render() method is invoked before the component has been initialized. It allows the component to return a rendered DomNode that will be subsequently updated as soon as initialization completes. -
data- ES6 Proxy, serves as a proxy to the component state data (this._data) and enables the component to observe any changes that occur to the data. All modifications to component data should be made through this property.
Base Class Methods
These methods are implemented by the Nimbly base class and are available on all components that extend Nimbly:
Public
All Nimbly components have the following public methods:
-
observe(fnChanges)- Allows external entities to observe changes that occur on the this.data property.- Parameters:
fnChanges- a function that is invoked with with a single argument whenever 'var data' is modified. The single argument will have the following format:[{"type":"add","target":{"blah":42},"property":"blah","newValue":42,"currentPath":"testing.blah"}]
- Returns: ES6 Proxy.
- Parameters:
-
init()- Runs any initialization procedures (stored on this.options.initList or defined in the defaults) required before the component renders for the first time. Typically this means retrieving data from external APIs.- Parameters: None.
- Returns: Nothing.
-
render()- Renders and returns the component. The render method will first verify that the component has been initialized, if it has not been initialized, then it will invokethis.init(). If the initialization is already in progress, then it will return a temporary 'loading' display. If the component has already been initialized, then the standard render methodthis._render()is invoked.- Parameters: None.
- Returns: jQuery-referenced DocumentFragment, the component ready to be inserted into the main DOM.
-
refresh()- This method is invoked when we want to re-render the component.- Parameters: None.
- Returns: Nothing.
-
destroy()- This method will remove this.jqDom from the DOM and delete the observable that was created during initialization. If the component initialized any child components, then those will be destroyed as well. This helps ensure that memory usage does not balloon after repeated refreshes and UI updates.- Parameters: None.
- Returns: Nothing.
-
eachChildComponent- This method will iterate over each component that has been registered as a child of the current component. This method accepts one parameter, a callback function. That callback function invoked upon each interation ofeachChildComponent. The callback function is passed three parameters: 1. a reference to the child component instance, 2. the template section the component belongs to, and 3. a method that when invoked will unregister and destroy the child component.- Parameters:
handler- function, required, accepts three parameters: 1. the current section name (string), 2. the child component (object) and 3. a callback method to remove the child component (function)
- Parameters:
Protected
JavaScript does not support protected methods, but the following methods are intended to be used as protected methods. They should not be invoked externally, but they may be invoked within component class that extends the Nimbly base class.
registerChild(childComponent, sectionName)- When a component nests other components within it, we refer to the original component as the "parent component" and the nested compon
