Sunday, December 31, 2017

Creating libraries with Vue components

Vue.js is great. There is no question about it. It's small, versatile, conscious, easy to learn - you name it. With the addition of POI it is probably also one of the most friendly frameworks to work with. Let's see how we can share single-file components between projects!

Method 1: npm link

npm link is probably one of the least known features if your primary occupation is creation of web application and you have never created an NPM package yourself. It has been there in NPM for ages and is the primary tool for library creators.

To use it when you have created your library and want to test it then what you do is you run

npm link

in the library folder and you run

npm link <library-name>

in the project that you want to use the library in. That gives you practically a hard binding between the library and the project using a symlink which means that if you introduce a change in the library then the project sees those changes immediately. It's a fantastic tool when you're in the process of working on the library. It can be further streamlined when we specify a dependency using the file: protocol like so:

"dependencies": {
  "my-library": "file:path-to-library"
}

This is also a great option if the library itself is part of your project and is being used to simply tear the application code from the reusable components. This is a great idea because if the application code changed often and the components change seldom then the size of your client.js gets smaller as all code from node_modules (this includes libraries referenced with the file: protocol) get pushed into the vendor.js block.

"dependencies": {
  "project-components": "file:../project-components"
}

This will automatically setup a link named project-components inside node_modules. What's even more interesting, when you do the npm install to install dependencies then the project-component's dependencies will be installed in ../project-components/node_modules automatically thus each project that uses that library won't need a copy of the shared dependencies.

Method 2: npm publish

When you want to go for a reusable library that you'd like to share between multiple projects then the right way to go is to use a repository. There is a multitude of options but the one I find really useful in an organization are npmjs.com for all things opensource and verdaccio for all the packages that you would like to keep available only for in-house components. The nice thing about verdaccio is that it automatically acts as a proxy to npmjs.com so all you do in your project is you tell npm that the repository is located where verdaccio is

npm set registry http://localhost:4873/

and you're all set.

Example

To show you how it is done I have created a sample project on GitHub. It consists of 3 parts: the library containing 2 components, a host application using those components and a little bit of automation to start the repository server.

Patterns

When creating a component library there are 2 options that one can use:

  • include the modules that build the library
  • include the built version of the library

Which one to use depends on the library itself. If you create a library that is to be used in all sorts of projects but you wrote it in some non-standard way (let's say you used CoffeeScript) then to make it useful for the rest of us you need to point the main to the compiled version. However, if you created a library specifically for use within a specific environment it makes sense to create an index.js and point your main entry in package.json to it and to put all your code in the lib folder:

export { default as componentA } from './lib/componentA.vue'
export { default as componentB } from './lib/componentB.vue'
That way, if someone wants to include all of your library they just include it and all is great:

import myLib from 'myLib'

Or using requirejs:

const myLib = require('myLib')

If for whatever reason they want to include only a portion of it, let's say just one or two components and not the whole shebang, then they are free to do so as follows:

import componentA from 'myLib/lib/componentA.vue'

Or using requirejs:

const componentA = require('myLib/lib/componentA.vue')

The latter form allows for the treeshaking algorithm to exclude everything that is not used by the application in the resulting file thus making the final bundle smaller (sometimes a lot smaller - see the use of lodash).

To create a compiled version of your library with POI all you need is to run the following command:

poi build --library index.js

and in the dist folder you'll get a library.js that you point the main in package.json to and you're done!

That's it! It is really simple to create libraries shared between parts of your project and not all that much more complex to create universal applications shared with everyone else in the NPM ecosystem.

Happy coding in 2018!

No comments: