12

I started working a lot with vue and started to use it in all the projects in the company where I work. And with that, I ended up creating some components, in general autocomplete, I know that there are many, I have already used some, but none have supplied all my needs. However, whenever I go to work on a new project and use the same component, either I recreates it, or I copy and paste it.

So I came to doubt How to create my component, upload to npmjs for whenever I use it, just give a npm install -save ..., and also be able to contribute a bit with the community.

samayo
  • 16,163
  • 12
  • 91
  • 106
Rafael Augusto
  • 467
  • 2
  • 12
  • 28

1 Answers1

39

update

With the release of vue-loader 15.x this answer will no longer work. Please use this instead https://medium.freecodecamp.org/how-to-create-a-vue-js-app-using-single-file-components-without-the-cli-7e73e5b8244f


Here is one way you can create/publish a Vuejs library/component from scratch.

As I am going to write down every step and command, make sure to follow the entire guide and you will be able to create and publish your own Vuejs component on NPM.

After you publish it, like most libraries you can install it using ex:

npm install --save your-component 

And then import the component inside your app using

import something from 'your-component'

To start creating our first component, first create a folder called vuejs-hello-app (or any other name) and inside it, run:

npm init

Just hit enter until the interactive question ends and then npm will generate a file named package.json in that folder containing the following code.

(Note: I changed the description and version from 1.0.0 to 0.1.0 here is the result.)

{
  "name": "vuejs-hello-app",
  "version": "0.1.0",
  "description": "vuejs library demo",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}

After this, we'll need to install the dependencies for our library.

These dependencies are divided into two types: dependency and devDependency

dependency:
is the external library or libraries that our own component runs on. When someone installs your component, npm will make sure this dependency exists or gets installed first. Since we are creating a component for vue, we need to make sure vue is required. So, install it using:

npm install --save vue

devDependency:
is a bunch of libraries that we need only for development purposes. These libraries will help us build and/or transpile.

We install dev dependencies using the method above by adding the the suffix -dev to --save

Now, let us install the minimum dev dependencies we need for our component:

npm install --save-dev babel-core
npm install --save-dev babel-loader
npm install --save-dev babel-preset-env
npm install --save-dev cross-env
npm install --save-dev css-loader
npm install --save-dev file-loader
npm install --save-dev node-sass
npm install --save-dev sass-loader
npm install --save-dev vue-loader
npm install --save-dev vue-template-compiler
npm install --save-dev webpack
npm install --save-dev webpack-dev-server

At this point the libraries will be installed and the package.json will be updated to look like following.

{
  "name": "vuejs-hello-app",
  "version": "0.1.0",
  "description": "vuejs library demo",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack -p"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "babel-core": "^6.26.0",
    "babel-loader": "^7.1.2",
    "babel-preset-env": "^1.6.1",
    "cross-env": "^5.1.1",
    "css-loader": "^0.28.7",
    "file-loader": "^1.1.5",
    "node-sass": "^4.7.2",
    "sass-loader": "^6.0.6",
    "vue-loader": "^13.5.0",
    "vue-template-compiler": "^2.5.9",
    "webpack": "^3.10.0",
    "webpack-dev-server": "^2.9.7"
  },
  "dependencies": {
    "vue": "^2.5.9"
  }
}

(note: I have added "build": "webpack -p" to build our lib with webpack)

Now, since our code needs to be built and transpiled, we need a folder to store the build version. Go ahead and create a folder inside our root folder and call it: dist and in the same place a configuration file for webpack and name it webpack.config.js

All of the files we have so far created are for configuring and stuff. For the actual app that people are going to use, we need to create at least two files inside our src/ directory.

A main.js and VuejsHelloApp.vue put them as: ./src/main.js and ./src/components/VuejsHelloApp.vue

I have mine structured like this:

dist
node_modules
src
  main.js
  components
    VuejsHelloApp.vue
.babelrc
.eslintignore
.gitignore
.npmignore
.travis.yml
CONTRIBUTING
LICENSE
package.json
README.md
webpack.config.js

I will just go through the files listed and describe what each file does in-case anyone is curious:

/dist is where a build (transpiled), minified, non-ES6 version of your code will be stores

node_modules I think we know this already, let's ignore it

src/ this is root dir of your library.

.babelrc is where your babel options are kept, so add this to disable presets on modules

{
  "presets": [
    [
      "env",
      {
        "modules": false
      }
    ]
  ]
}

.eslintignore This is where you tell ESLINT to ignore linting so put this inside:

build/*.js 

.gitignore add files you want to ignore (from git)

.npmignore same as .gitignore for NPM

.travis.yml if you need CI check examples from travis and configure it

CONTRIBUTING not required

LICENSE not required

package.json ignore for now

README.md not required

webpack.config.js This is the important file that let's you create a build, browser compatible version of your code.

So, according to our app, here is a minimal example of what it should look like:

var path = require('path')
var webpack = require('webpack')

module.exports = {
  entry: './src/main.js',

  module: {
    rules: [
      // use babel-loader for js files
      { test: /\.js$/, use: 'babel-loader' },
      // use vue-loader for .vue files
      { test: /\.vue$/, use: 'vue-loader' }
    ]
  },
  // default for pretty much every project
  context: __dirname,
  // specify your entry/main file
  output: {
    // specify your output directory...
    path: path.resolve(__dirname, './dist'),
    // and filename
    filename: 'vuejs-hello-app.js'
  }
}

if (process.env.NODE_ENV === 'production') {
  module.exports.devtool = '#source-map'
  module.exports.plugins = (module.exports.plugins || []).concat([
    new webpack.DefinePlugin({
      'process.env': {
        NODE_ENV: '"production"'
      }
    }),
    new webpack.optimize.UglifyJsPlugin({
      sourceMap: true,
      compress: {
        warnings: false
      }
    }),
    new webpack.LoaderOptionsPlugin({
      minimize: true
    })
  ])
}

Note that the important directives here are entry and output. You can check webpack docs to learn more if you want to fully customize your app.

But basically, we're telling webpack to get the ./src/main.js (our app) and output it as ./dist/vuejs-hello-app.js

Now, we are almost finished setting up everything except the actual app.

Go to /src/components/VuejsHelloApp.vue and dump this simple app, which will move a button right or left when you hover on it

<template>
  <div>
    <button @mouseover='move($event)'> I'm alive </button>
  </div>
</template>

<script>
export default {
  data () {
   return {}
  },

  methods: {
    move (event) {
        let pos = event.target.style.float; 
      if(pos === 'left'){
        event.target.style.float = 'right'
      }else{
        event.target.style.float = 'left'
      }
    }
  }
}

</script>

<style scoped>

</style>

And not but not least, got to ./src/main.js and export your app like:

import VuejsHelloApp from './components/VuejsHelloApp.vue'
export default VuejsHelloApp

Now go to your package.json file replace the "main: "index.js", with "main": "src/main.js",

After this, simply run these commands to build and publish your app:

npm run build
git add .
git commit -m "initial commit"
git push -u origin master
npm login 
npm publish

Importing and using the library.

If everything went smoothly, then simply install your app like this:

npm install --save vuejs-hello-app

And use it in vue like this:

<template>
  <div>
    <VuejsHelloApp> </VuejsHelloApp>
  </div>
</template>

<script>
import VuejsHelloApp from 'vuejs-hello-app'
export default {
  name: 'HelloWorld',
  components: { VuejsHelloApp }
}
</script>

I made this app https://github.com/samayo/vuejs-hello-app while writing the answer, it might help to better understand the code

samayo
  • 16,163
  • 12
  • 91
  • 106
  • Great tutorial. You forget the to add `"build": "webpack -p"` in package.sjon in order to run `npm build` – rap-2-h Mar 02 '18 at 14:15
  • Thanks and nice catch. Just fixed it – samayo Mar 02 '18 at 14:18
  • 1
    A plugin is now required for vue-loader https://vue-loader.vuejs.org/migrating.html#a-plugin-is-now-required – Alberto May 01 '18 at 12:12
  • @samayo that's a great tutorial there is a great tutorial to do so with Vue typescript component? – Erez May 14 '18 at 09:48
  • @Erez Thanks, I haven't tried vue typescript yet, and I don't know if there is a similar tutorial – samayo Jun 11 '18 at 19:07
  • Maybe not what most are interested in, but in order to complete the reply, can you cover how would you also setup the testing part of further development the component eg. multiple entry and outputs for webpack, so the authors can maintain their components. – simultsop Jul 15 '18 at 19:36
  • For starters or anyone wondering how to keep developing and meantime building the component package checkout https://github.com/webpack/docs/wiki/multiple-entry-points on how to run webpack on multiple entries. – simultsop Jul 15 '18 at 19:55
  • thanks, i don't know how to test vue components yet so i did not include that and also the question was about building a component so i wanted to stay on topic, but once i find out i will add more to the answer and will checkout your link – samayo Jul 15 '18 at 22:08
  • Thank you for these great instructions. What would you do if inside the `VuejsHelloApp.vue` file you would need to import another Vue file? If I do so the imported Vue file is not added to the `src` folder. – Chris Dec 07 '18 at 14:06
  • @phpheini Hey, sorry I didn't get notification about your comment, I just saw it now. Anyway, if you want to import a file in a `.vue` folder, you can. Just make sure the dir is in the right place. You can use `./a/b/foo.js` – samayo Apr 06 '19 at 19:20
  • How should we run develop mode for this project? https://github.com/samayo/vuejs-hello-app/issues/2 – SeyyedKhandon Jun 22 '20 at 05:39