Skip to content

Instantly share code, notes, and snippets.

@briandipalma
Last active December 6, 2018 10:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save briandipalma/7375499 to your computer and use it in GitHub Desktop.
Save briandipalma/7375499 to your computer and use it in GitHub Desktop.
Web component development ideas.

Thoughts on web component development.

Firstly a definition.

A web component is a widget that a user interacts with in a web application. The complexity of the widget does not have to high, it can be as simple as a single button. Best practice would be to create more complex components by composing simpler components.

What's involved in developing one.

For the development of a web component there seem to be three areas of complexity. Each of these is required as a foundation of the next area but they can also be thought of as a cycle.

The three centers are dependency management, providing the component resources to the browser and developing the component.

  • Dependency management.

In most cases components are not stand alone. They would often depend on external resources to implement their functionality. These external resources could be either libraries or other components.

  • Providing component resources to the browser

The resources of the component and its dependencies need to be transferred from the developers file system to the browser.

  • Developing the component.

The developer needs feedback on the effect his changes have on the component.

As a component can be a dependency of another component these areas can also be thought of as a cycle, wherein once a component is developed it can be feed into another component as a dependency to help it compose a more complex component. This could scale to full applications, where the application can be viewed as nothing more then a component with dependencies on other components.

Fleshing out the areas.

####Dependency management.

A developer can either use tools to manage dependencies or he can do it manually. Ruby has gem, Python has pip, Node has npm, Perl has cpan, Go has go get, Dart has pub, Java has mvn, Erlang has rebar. Modern development practice is overwhelmingly in favour of tooling as the way to manage dependencies.

OK, I want to use tooling, what are my options?

The three most frequently used tools for the job of web package management are Bower, component and npm. There are quirks, strengths and weaknesses to each manager but the most important choice is to accept to use tooling instead of manually managing dependencies.

Bower will, arbitrarily, be chosen as the dependency management tool to expedite proceedings with the caveat that the choice could warrant further analysis.

What's a Bower package structure like?

Bower has a bower.json file which is used to specify a package's dependencies i.e.

{
    "name": "mean",
    "version": "0.1.0",
    "dependencies": {
        "bootstrap": "2.3.2",
        "angular": "1.0.6",
        "angular-resource": "1.0.6",
        "angular-cookies": "1.0.6",
        "angular-bootstrap": "0.6.0",
        "angular-ui-utils": "0.0.4"
    }
}

These dependencies are pulled in to the component directory with bower install. The pulled in dependencies are placed in a bower_components directory, in the component directory.

####Providing component resources to the browser

Different types of resources are required by the browser to fully implement a component. There can be JS source code, CSS styling, HTML templates, images, configuration resources, etc. The most important resource, in terms of developer focus and time commitment though is JS source code.

Why is it complex?

Unlike many other platforms the Web platform does not, currently, provide a scalable, automatic, standard way to resolve or load the source code required by components. There is consensus now that modules will be the standard, platform way of encapsulating and referencing JS code, evidenced by the [ES6 module spec] (https://people.mozilla.org/~jorendorff/es6-draft.html#sec-imports)

Therefore a future friendly approach would be to structure component code in a fashion resembling ES6 modules. This would imply explict definitions for all required/dependent functionality and all exported/provided functionality in a JS module, similar to ES6 modules.

// module "x"
import y from "y";

export function f() {}

Once an ES6 style/convention is applied to the JS code loading it in to the browser becomes much simpler. Tooling can be developed that understands the ES6 convention and in modern browser tooling will eventually not be required.

Structure of a component/package

The structure would be simple and therefore flexible. As it's based on a dependency management tool, Bower in this case, there would be a folder for the package's dependencies (bower_components). Next to it there could be src, style, html etc directories. Those directories would contain the component resources.

The devDependencies key in the Bower package specification file would list testing tools, fake resources and styles. This would allow the component to be tested both in terms of functionality, responding to fake services messages and to verify the styling while not shipping it with the component. This allows consumers of the component to easily specify their own style package or their own services.

The explicit listing of dependencies, and the component's separation from the components that consume it resonates with the Unix philosophy rule #1 [Rule of Modularity: Write simple parts connected by clean interfaces.] (http://www.faqs.org/docs/artu/ch01s06.html)

The only way to write complex software that won't fall on its face is to hold its global complexity down — to build it out of simple parts connected by well-defined interfaces, so that most problems are local and you can have some hope of upgrading a part without breaking the whole.

Components that depend on the same dependency can't be broken by a change to that dependency as they consume published versions of the package and not the local development version. It will be much easier for a developer to narrow down the source of a breakage if he is able to upgrade dependencies granularly as opposed to a global upgrade of many dependencies.

How to discover required resources

The Bower spec defines the main attribute which specifies what JS module needs to be loaded when a developer writes

var serviceRegistry = require("service-registry");

Inside the service-registry directory the JS file defined in the main bower.json property will be loaded and provided to the developer, following the same rules as ES6 modules would allow package internal includes using ./ or ../ i.e.

//ServiceRegistry
var serviceRegistryUtil = require("./service-registry-util");

or package external (other packages) using identifiers without any ./ or ../ prefixes i.e.

//ServiceRegistry
var jQuery = require("jquery");

Following the Bower and ES6 module specs should make it relatively easy to create a simple tool which would load all the JS a component requires. It seems that [this already works when using browserify] (https://github.com/eugeneware/debowerify).

Legacy code

Legacy code would have to be broken up and put into seperate bower packages, each package should be independent and relatively easy to re-write within a few days.

The legacy code would also not require namespacing tooling as the code would be contained within a JS module thereby preventing leakages of JS identifiers into the global object. This would allow components to be dragged and dropped and to be immediately consumable without any namespace changing tooling.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment