Protoculture is a slightly opinionated set of ECMAScript practices backed by an applications framework. It sits between your bundler, chosen libraries, process managers and platforms acting as a guide to organize your abstractions. Everything protoculture does aims to help structure your TypeScript/ES codebase, reducing cognitive overhead and making it easier for multiple people to work together.
The best way to understand how Protoculture works is to think about its main pillars:
The slight opinionation of Protoculture comes from:
- Being authored in TypeScript
- Asynchronous-first via
await& the standard Promise APIs
- The powerful inversify dependency injection system
- Planned integrations with many popular JS libraries, frameworks and utilities
The layering Protoculture provides has similar if not identical siblings in other languages and runtimes, its big advantage is in how everything is tied together. In that sense, protoculture is not a full framework, but an applications framework.
While Protoculture is authored in TypeScript, you can definitely use it from regular ES as well.
Bundles represent a like-static pre-execution phase. The module that contains your Bundle is often also your entrypoint script, instantiating the Bundle and calling its
run method. Protoculture includes inversify for inversion of control,
Bundles initialize this system and act as the top of the dependency graph.
The other role of the
Bundle is to act as a language-level root for an entire module graph. Regardless of what bundler you choose to use, protoculture
Bundles are where everything begins!
Because bundles are the first thing run in a protoculture application, the bundle module automatically includes popular polyfills/ponyfills.
You configure your bundle by assigning it
ServiceProvider types to use.
Platforms represent the environment running your protoculture application. Over time protoculture gains common abstractions that are necessary across different platforms. Platform specific implementations of these abstractions are made available where possible via the dependency injection system.
Most of the time you'll use a provided platform but if you ever create your own, Platforms are also free to do any kind of bootstrap you need and should be used to help make your app universal/isomorphic.
Layers & ServiceProviders
The quickest way to explain a Layer is to say that it's one of several directories you use to group your source code.
Having said that, Layers are one of the most important concepts to appreciate as they represent a horizontal strip of functionality.
Each layer has a
ServiceProvider which can be referenced by one or more Bundles. ServiceProviders are responsible for telling the dependency injection system about new configuration and functionality.
If you've used Laravel, you'll be right at home.
If the philosophy of layers seems too unfamiliar, just start by creating your application under a single layer. Over time as you think of features and concepts that can act independently of each other, move them into their own layers.
This will get you thinking about the abstractions required to allow that layer to be switched on or off independently of other
Layers. In this way, Layers and
ServiceProviders can be an effective mechanism for powering feature flags.
Eventually, you may even find that some layers can be moved into their own packages! This is especially helpful as you discover layers that depend on each other. NPM packages allow you to express those dependencies using semver.
- Grouping screens and data access by domain concern. User edit vs. organization edit.
- Multiple applications on a single page. Rather than load multiple
Bundles, create a single
Bundlethat contains the desired Layers.
- When using any code splitting features, you can code split on your service providers to divide your application by functional group.
- Groups of routes, organized by domain concern or aggregate.
Apps are the simplest level of encapsulation to think about that protoculture offers. If you were making a console application, you
would treat the entrypoint in the
App class as your
main. What's unique about
Apps in protoculture is that you can have several of them.
Apps are also useful when working in the browser as you can have multiple
Bundles that wish to reuse an arbitrary combination of apps!
Remember, Protoculture is asynchronous and supports running multiple apps at once! If a Protoculture bundle detects that it
contains any asynchronous apps, it will automatically set up a heartbeat. This is handy for when you have
long running processes or are using a library that opens up sockets. When all applications are done executing, Protoculture will give every app a chance to do cleanup.
Protoculture is created by Alexander Trauzzi and is available under the Apache 2.0 license.
- ASP.NET Core
- Other cool things in the ES community
- Maybe some Scala?
With all the attention pure functional languages like Elm, Clojure, Haskell, Dart, Scala and Go are getting, this is a good question to ask.
My rationale for preferring TypeScript usually goes like this:
- Tight integration with the NPM ecosystem.
- Future ES features today, no waiting.
- Multi-paradigm type system.
- The language designer behind TypeScript Anders Hejlsberg is responsible for some of the most pervasive programming languages over several decades and has likely influenced many more.
If you take all these reasons - and I probably missed some - TypeScript positions itself in every sweet-spot while still being able to chart its own course, making very few if any compromises along the way.
If you look at the history of this package for versions
1.0.15 and before, it probably will look quite different.
The original idea for protoculture was that it would bundle conventions for TypeScript, React, Redux applications.
The spirit of the library remains the same, however I've changed things quite a fair bit after learning even more about the ES ecosystem. Particularly as it pertains to the various platforms it finds itself on.
The only answer you're probably looking for this far down is: Macross.