Codebase: We use them all the time. Codebase is the packaging of code that developers will use in their projects, which always saves time and avoids reinventing the wheel. It is better to have a reusable package, whether open source or closed source, than to repeatedly build packages with the same features or manually copy and paste from past projects.

More articles from the author

  • Stop Maiming Bodies: The Perils of Pixel Font-Size
  • ES2016: Should the Future of JavaScript Be Developer-Driven?

Is there a more accurate description of a code base than packaged code? With a few exceptions, a code base is usually just one file, or several files in the same folder. Its code should be saved separately and used normally in your project. Library files allow you to adjust the structure or behavior depending on the project. Imagine a USB device that communicates only through a USB port. Some devices, such as the mouse and keyboard, can be configured through interfaces provided by the device.

In this article, I explain how to build library files. Although most of the methods can be applied to other languages, this article focuses on building JavaScript library files.

## Why build your own Javascript library?

First and foremost, library files make it easy to reuse existing code. You don’t need to dig up old projects to copy files, just import library files. This also allows you to componentize your application, making your application’s code base smaller and more maintainable.

Christ Church Library (source)

Any abstract code that makes it easier to implement a specific function or can be reused can be packaged into a library file. JQuery is an interesting example. Although jQuery’s API has a large number of simplified DOM apis, this is important in the past when cross-browser DOM manipulation was difficult.

If an open source project becomes popular and many developers use it, people are likely to participate by asking questions or contributing code. Either way, it helps the library and the projects that depend on it.

A popular open source library also presents a good opportunity. The company may recognize the quality of your work and make you an offer. Maybe the company will ask you to integrate your project into their app. After all, no one knows your project as well as you do.

Of course it could just be a habit – enjoy typing, help others and learn and grow in the process. You can push your limits and try new things.

## Scope and objectives

Before you write the first line of code, you need to determine the functionality of your library — you need to set a goal. With this goal, you can focus on the problems you want to solve with the library. Keep in mind that the original form of your code base is easier to use and remember when solving problems. The simpler the API, the easier it is for users to learn from your code base. Introduce a Unix design philosophy:

Do one thing and do it well

Ask yourself: What problem does your code base solve? What are you going to do about it? Will you do it all yourself, or will you bring in someone else’s code base?

No matter how big the codebase is, try to make a roadmap. Make a list of every feature you want and break it up as much as possible, knowing that you have a small code base that can solve the problem, like a Minimum Viable Product. This will be your first version. From here, you can establish milestones for each new feature. In essence, you’re turning your project into something more than a super block of code, making each feature better and more fun to complete. Trust me, it will keep you in shape.

# # API design

In my opinion, I want to develop my codebase from the user’s point of view. You could call it user-centric design. In essence, you’re creating an outline of your code base, giving it more thought and making it easier for the people who choose it to use. In the meantime, you need to think about where you can customize, which will be discussed later in this article.

The ultimate API test is to experiment with your own techniques, using your code base in your project. Try replacing the previous code with your code base to see if it meets the features you want. Try to make your code base as intuitive as possible, make it flexible to use under boundary conditions, and customize it (covered in a later article).

Here is an outline of what a user agent string code base might look like:

// Start with empty UserAgent string var userAgent = new UserAgent; // Create and add first product: EvilCorpBrowser/1.2 (X11; Linux; En-us) var application = new userAgent.product ('EvilCorpBrowser', '1.2'); application.setComment('X11', 'Linux', 'en-us'); userAgent.addProduct(application); // Create and add second product: Blink/20420101 var engine = new UserAgent.Product('Blink', '20420101'); userAgent.addProduct(engine); / / EvilCorpBrowser / 1.2 (X11; Linux; en-us) Blink/20420101 userAgent.toString(); // Make some more changes to engine product engine.setComment('Hello World'); / / EvilCorpBrowser / 1.2 (X11; Linux; en-us) Blink/20420101 (Hello World) userAgent.toString();Copy the code

Depending on the complexity of your code, you may spend some time on organizational structure. Using design patterns is a great way to organize your code base and even solve some technical problems. It also avoids extensive refactoring by adding new features.

## Flexibility and customization

Flexibility is what makes a code base powerful, but it can be difficult to determine the boundaries between what you can and can’t customize. Chart.js and d3.js are good examples. Both code bases are used for data visualization. Chart.js makes it easy to create different forms of built-in charts. But if you want more control over your images, d3.js is what you need.

There are several ways to give control to the user: configuration, exposing public methods, callbacks, and events.

Configuring a code base is usually done before initialization. However, some code bases allow you to make configuration changes at run time. Configurations are usually limited in small parts, and only changing their values for later use is allowed.

// Configure at initialization
var userAgent = new UserAgent({
  commentSeparator: ';'
});

// Run-time configuration using a public method
userAgent.setOption('commentSeparator', '-');

// Run-time configuration using a public property
userAgent.commentSeparator = '-';Copy the code

Methods are usually exposed to the instance for use, such as getting data from the instance, or setting its data and performing operations.

var userAgent = new UserAgent;

// A getter to retrieve comments from all products
userAgent.getComments();

// An action to shuffle the order of all products
userAgent.shuffleProducts();Copy the code

Callbacks are usually passed in a common method, usually executing the user’s code after an asynchronous operation.

var userAgent = new UserAgent;

userAgent.doAsyncThing(function asyncThingDone() {
  // Run code after async thing is done
});Copy the code

There are many possibilities. A bit like a callback, except adding event handles should not trigger an action. Events are usually used for listening, and as you might guess, this is an event! More like a callback, you can provide more information and return a value to the code base to operate on.

var userAgent = new UserAgent;

// Validate a product on addition
userAgent.on('product.add', function onProductAdd(e, product) {
  var shouldAddProduct = product.toString().length < 5;

  // Tell the library to add the product or not
  return shouldAddProduct;
});Copy the code

In some cases, you might allow users to extend your code base. Therefore, you need to expose some public methods or properties for the user to populate, like Angular modules (angular.module(‘myModule’)) and Jquery fn (jquery.fn.myplugin), or do nothing at all. Simply let the user get the namespace of your code base:

// AngryUserAgent module // Has access to UserAgent namespace (function AngryUserAgent(UserAgent) { // Create new method  .toAngryString() UserAgent.prototype.toAngryString = function() { return this.toString().toUpperCase(); }; })(UserAgent); // Application code var userAgent = new UserAgent; / /... / / EVILCORPBROWSER / 1.2 (X11; LINUX; EN-US) BLINK/20420101 userAgent.toAngryString();Copy the code

Similarly, this allows you to override methods.

// AngryUserAgent module (function AngryUserAgent(UserAgent) { // Store old .toString() method for later use var _toString = UserAgent.prototype.toString; // Overwrite .toString() UserAgent.prototype.toString = function() { return _toString.call(this).toUpperCase(); }; })(UserAgent); var userAgent = new UserAgent; / /... / / EVILCORPBROWSER / 1.2 (X11; LINUX; EN-US) BLINK/20420101 userAgent.toString();Copy the code

In the following example, allowing your users to access the namespace of the code base gives you less control over the definition of extensions and plug-ins. You can (or should) write documentation for your plug-in to follow some conventions.

# # test

Writing an outline is a good start for test-driven development. In simple terms, this means before you write the actual code base, when you write the test criteria. If testing checks that your code features are as expected and that you write tests before you write a code base, this is behavior-driven development. Anyway, if your tests cover every feature of your code base, and your code passes all the tests. You can be sure that your code works.

Jani Hartikainen explains how to Unit Test Your JavaScript Using Mocha and Chai. In this article, Jsmine, Travis, Karma Testing JavaScript with Jasmine, Travis, and Karma Tim Evko has shown how to set up a good test flow using another framework called Jasmine. Both of these testing frameworks are very popular, but there are other frameworks for other needs.

The outline I wrote earlier in this article already tells you what output it expects. This is where all testing begins: with expectations. A Jasmine test for my code base looks like this:

describe('Basic usage', function () { it('should generate a single product', Function () {// Create a single product var product = new userAgent.product ('EvilCorpBrowser', '1.2'); // Create a single product var product = new userAgent.product ('EvilCorpBrowser', '1.2'); product.setComment('X11', 'Linux', 'en-us'); Expect (product. The toString ()). Place (' EvilCorpBrowser/(1.2 X11; Linux; en-us)'); }); it('should combine several products', function () { var userAgent = new UserAgent; // Create and add first product var application = new userAgent.product ('EvilCorpBrowser', '1.2'); application.setComment('X11', 'Linux', 'en-us'); userAgent.addProduct(application); // Create and add second product var engine = new UserAgent.Product('Blink', '20420101'); userAgent.addProduct(engine); Expect (userAgent. ToString ()). Place (' EvilCorpBrowser/(1.2 X11; Linux; en-us) Blink/20420101'); }); it('should update products correctly', function () { var userAgent = new UserAgent; // Create and add first product var application = new userAgent.product ('EvilCorpBrowser', '1.2'); application.setComment('X11', 'Linux', 'en-us'); userAgent.addProduct(application); // Update first product application.setComment('X11', 'Linux', 'nl-nl'); Expect (userAgent. ToString ()). Place (' EvilCorpBrowser/(1.2 X11; Linux; nl-nl)'); }); });Copy the code

Once you’re completely satisfied with the first version of your API design, it’s time to start thinking about the structure and how your code base should be used.

Module loader compatibility

You may have used a module loader. Developers using your code base are likely to use loaders, so you want your code base to be compatible with module loaders. But which one? How do you choose from CommonJS, RequireJS, AMD and other loaders?

Actually, you don’t have to pick! A common module definition (UMD) is a rule whose goal is to support multiple loaders. You can find snippet styles online, or learn from UMD GitHub Repository here and make them compatible with your repository. Start with one of these templates, or use your favorite build tool add UMD with your favorite build tool, and you won’t have to worry about module loaders.

If you want to use the IMPORT /export syntax of ES2015, I recommend using Babel and Babel’s UMD Plugin to convert the code to ES5. This way you can use ES2015 in your projects while generating a compatible code base.

# # documentation

I’m all for using documentation in every project. But this usually involves a lot of work, resulting in documentation being delayed and forgotten at the end.

## basic information

Documentation should start with basic information such as the name and description of the project. This will help others understand what your code base does and whether it is useful to them.

You can better inform your users by providing information such as scope and goals, and providing a roadmap gives them an idea of what changes are likely to come in the future and how they can help.

###API, tutorials and examples

Of course, you need to make sure users know how to use your code base. This starts with the API documentation. Tutorials and examples are great additions, but writing them can be a huge job. However, Inline documentation does not. Here are some annotations that can be parsed and converted into document pages using JSDoc

# # # $task

Some users want to make improvements to your code base. In most cases, this will be contributed code, but some will create a custom version for private use. For these users, it is helpful to provide documentation for meta-tasks such as building a code base, running tests, generating, converting, and downloading data.

# # #

When you open source your code base, it helps to get code contributions. To guide contributors, you can add documentation on the steps to contribute code and the criteria that need to be met. This will help you review and accept contributed code and their correct contributions.

### License

Finally, use licenses. Technically, your code base is still copyrighted even if you don’t choose any technology license, but not everyone knows that.

I found ChooseALicense.com to be a site where you don’t need to be a legal expert to pick a license. After selecting the LICENSE, add the license. TXT file in the root directory of the project.

Package and publish it to the package manager

Versioning is important for a good code base. If you want to include significant changes, users may need to keep the version they are currently using.

Semantic Versioning is the popular version naming standard, or SemVer. The SemVer version includes three numbers, each representing a different degree of change: major change, minor change, and patch

Add releases and releases to your Git repository

If you have a Git repository, you can add version numbers to your repository. Think of it as a snapshot of your warehouse. We also call it tag Tags. Tags can be created by opening the terminal and entering the following text:

# git tag -a [version] -m [version message] git tag -a v1.2.0 -mCopy the code

Many services like GitHub provide an overview of all versions and links to download them.

### Release a common repository

####npm

Many programming languages come with package managers, or third-party package managers. This allows us to download specific code libraries for those languages. Examples include PHP Composer and Ruby RubyGems

Node.js, an independent JavaScript engine, has NPM, if you are not familiar with NPM, we have a good tutorial beginner’s Guide.

By default, your NPM package will be published as a public package. Don’t be afraid, you can also publish private packages, set up a private registry, or avoid publishing at all.

To distribute your packages, your project needs to have a package.json file. You can create it manually or via interactive questions. Start the question and answer by entering the following code:

`npm init`Copy the code

This version property needs to match your Git tag. Also, make sure you have the readme.md file. Like GitHub, NPM uses it in the presentation page of your package.

You can then publish your package by entering the following code:

`npm publish`Copy the code

That’s it! You have successfully released your NPM package.

####Bower

A few years ago, there was another package manager called Bower. This package manager is actually not for a specific language, but for the Internet. You can see that most of these are front-end resources. The key to publishing your package in Bower is whether your codebase is compatible with it.

If you are not familiar with Bower, we also have a tutorial beginner’s Guide.

As with NPM, you can also set up a private repository. You can avoid Posting by asking questions.

Interestingly, in the last year or two, many people have moved to NPM to manage front-end resources. Recent NPM packages are mostly JavaScript related, and most of the front-end resources are published on NPM. Regardless, Bower remains popular. I definitely recommend that you publish your package on Bower.

Did I mention that Bower is actually a module of NPM and was initially inspired by it? The commands are very similar, producing the bower.json file by typing the following:

`bower init`Copy the code

Similar to NPM init, the instructions are straightforward. Finally, publish your package:

`bower register awesomelib https://github.com/you/awesomelib`Copy the code

It’s like putting your codebase out in the wild, and anyone can use it in their Node project or on the network!

# # to summarize

The core product is the library file. Make sure it solves the problem, is easy and easy to use, and you’ll make your team or many developers happy.

Many of the tasks I mentioned are automated, such as running tests, creating tags, upgrading your package in package.json or redistributing your package in NPM or Bower. This is the beginning of your step into continuous integration and using tools like Travis CI or Jenkins. The article by Tim Evko that I mentioned earlier also talks about this.

Did you build and publish the code base? Please share in the comment section below!