[Vuetify] Multiple instances of Vue detected

Setting up unit tests today using localeVue with Vuetify and @vue/test-unit I ran into the warning message:

[Vuetify] Multiple instances of Vue detected

After googling around I found a number of issues related to this warning message. There are different ways to solve it, which I will address in this post.

1. Ignore it

It is a warning message, so you can safely ignore it. But that red warning text sure is annoying.

2. Use Vue instead of localeVue

You could use initialize the component using Vue instead of localVue. That said the documentation of @vue/test-unit explicitly warns agains this.

3. Suppress the warning message

A hack, but in my opinion the least evel one of all the options is suppressing the warning message. This can be done very locally in the beforeEach. This is the code I am using that is based on this issue comment.

The SilenceWarnHack.js class:

/**
 * This is a hack to suppress the Vuetify Multiple instances of Vue detected warning.
 * See https://github.com/vuetifyjs/vuetify/issues/4068#issuecomment-446988490 for more information.
 */
export class SilenceWarnHack {
  constructor() {
    this.originalLogError = console.error
  }
  enable() {
    console.error = (...args) => {
      if (args[0].includes('[Vuetify]') && args[0].includes('https://github.com/vuetifyjs/vuetify/issues/4068')) return
      this.originalLogError(...args)
    }
  }
  disable() {
    console.error = this.originalLogError
  }
}

And the beforeEach function that is part of the test file:

import { createLocalVue, shallowMount } from '@vue/test-utils'
import { SilenceWarnHack } from '@tst/helpers/SilenceWarnHack'
import Vuetify from 'vuetify'
import VStatsCard from '@/components/common/VStatsCard.vue'

const silenceWarnHack = new SilenceWarnHack()

describe('VStatsCard.vue', () => {
  let localVue = null
  beforeEach(() => {
    silenceWarnHack.enable()
    localVue = createLocalVue()
    localVue.use(Vuetify)
    silenceWarnHack.disable()
  })
  ...
}

It works like a dream 🙂

Add a global ignore file to git

Had enough of adding your IDE’s files to the .gitignore file? Time to add a global ignore file for git.

Just execute the following commands.

On *nix or with Windows git bash:

git config --global core.excludesfile '~/.gitignore-global'

With Windows cmd:

git config --global core.excludesfile "%USERPROFILE%\.gitignore-global"

Then you need to create the file:

notepad %USERPROFILE%\.gitignore-global

And add for example the following contents:

data/
.idea/
*.log

That’s it, now you only have to do this one time and not for each project individually.

Sending command line arguments to a package.json script

Do you need to pass command line arguments dynamically to a package.json script? This is how to do it.

Static command line arguments can be set with the scripts.

  ...
  "scripts": {
    "cli": "node ./src/build-helper-cli.js -V"
  }
  ...

The script can be called as follows.

 $ npm run cli

Now lets pass it a command line argument dynamically.

$ npm run cli -- add-eslint-disable --dest build

The trick are the two dashes (–) which tell npm what follows are command line arguments for the script being executed. That is it. Easy right?

Local npm module (link) causes “Cannot assign to read only property ‘exports’ of object”

I’m creating a Vue plugin using Vue CLI 3. I was using the vue-cli-service build with target type lib to build the reusable plugin that could be imported into another project. While developing the plugin I was testing it as a local npm module (link) and I ran into this error “Cannot assign to read only property ‘exports’ of object”. I was using npm link to create a local module.

It took a lot of googling around to find the solution. It turns out it has to do with Babel and webpack. As always once you know the solution it is simple. I had to add sourceType unambiguous to my babel.config.js file. This is my babel.config.js file:

module.exports = {
  presets: [
    '@vue/app'
  ],
  sourceType: 'unambiguous'
}

This comment of a webpack issue contains the explanation. Please check it out to understand why this works.

I hope this helps someone and saves them (lots of) time.

Using webpack-chain to overrule key name (app) used for default webpack entry by vue-cli 3

Sometimes you have an irritating problem that you have to solve even though it doesn’t really add value. Yesterday I had one of these problems. I wanted to overrule the key name (app) used for the default webpack entry by vue-cli 3 using webpack-chain. This key determines the name of the file that is generated by the build command. It seemed like such a simple change, which it is once you understand how, but it took me sometime to figure out.

I’m writing a Vue plugin and wanted the build version to be called ‘plugin’ instead of ‘app’. I thought it would be a quick change. Took me a little more time than expected, because of the way webpack-chain works and me not reading the documentation properly.

Anyway here are the steps if you want to do the same.

1. Rename the ‘src’ directory to ‘plugin’ (optional, but I like it)
2. Add the `vue.config.js` file and add the following code
module.exports = {
   chainWebpack: config => {
     // Remove the old 'app' entry
     config
       .entryPoints
       .delete('app')
     // Add the new 'plugin' entry
     config
       .entry('plugin')
       .add('./plugin/index.js')
     config
       .resolve
       .alias
       .set('@', path.resolve(__dirname, 'plugin'))
   },
   ...
}

It first removes the old webpack entry (app), adds a new entry (plugin) and finally changes the alias from ‘src’ to ‘plugin’.

3. Update the `moduleNameMapper` in the `jest.config.js`
...
moduleNameMapper: {
'^@/(.*)$': '/plugin/$1'
},
...

That should do the trick. Do you want to test it?

Generate the resolved webpack file using the following command.

$ vue inspect > webpack.config.resolved

The final entry in the resolved webpack file should be the entry point.

{ 
  ...
  entry: {
    plugin: [
      './plugin/index.js'
    ]
  }
}

For convenience I add the following entry to the `scripts` in the `package.json` file.

{ 
  ...
  "scripts": {
    ...
    "inspect": "vue inspect > webpack.config.resolved"
 }
 ...
}

Now you can run npm run inspect to check the resolved webpack configuration file. Handy!

To ensure everything works as expect test and build the project using the following commands.

$ npm run test:unit

and

$ npm run build

In the build directory dist there should be a file js/plugin..js.

Hope this helps someone. Happy coding!

Adding aliases with Babel

Had enough of complicated import and require statements in your Node/JavaScript files? I’m used to developing in Vue which uses Webpack aliases that by default sets up the @ alias that points to the src directory. I’m working on a project that I am using Babel but not Webpack. It turns out Babel has the cool plugin babel-plugin-module-resolver that also setup aliases.

Install the plugin.

$ npm i --save-dev babel-plugin-module-resolver

So we have the following directory structure.

project
├── src
│  └─ MyCoolService
│    └─index.js
│  └── index.js
├── test
│  └── MyCoolService.spec.js
│  .babelrc
│  package.json

In the spec file I want to test MyCoolService. Importing is messy.

import MyCoolService from '../src/MyCoolService'

I want to do it the Vue way.

import MyCoolService from '@/MyCoolService'

Can it be done? O yes, babel-plugin-module-resolver to the rescue! Create a .babelrc file with the following contents.

// .babelrc
{
  "plugins": [
    ["module-resolver", {
      "root": ["./src/**"]
      "aliases": [
        "@": "./src"
      ]
    }]
  ]
}

Now we can import with the @ alias. Alternatively as the root points to src you can also import as follows.

import MyCoolService from 'MyCoolService'

How cool is that? Happy coding!

Fix Jest describe/it/expected not recognised in Webstorm

Don’t you just hate it when Webstorm underlines functions as unknown, because it doesn’t recognise them? It turns out it is pretty simple to fix if you know how and have a TypeScript (ts) file with definitions available.

UPDATE
It turns out there is a much easier way of adding the definitions.

In File > Settings… > Languages & Frameworks > JavaScript > Libraries, click the button Download..., select ‘jest’ from the list of available definitions, click the button Download and Install. That’s it!

Webstorm rules!

First we need to install the Jest TypeScript definitions.

npm install --save-dev @types/jest

Then we need to add them in Webstorm by adding it as JavaScript library in the Settings.

File > Settings... >  Languages & Frameworks > JavaScript > Libraries

In the dialog click the Add.. button. The following dialog is opened.

Webstorm add JavaScript Library

In the dialog enter the following information.

Name: Jest
Visibility: Project

Then click on the + button and select the option Attach files....

Webstorm add JavaScript Library

The Jest TypeScript definitions are installed in the node_modules directory under your project directory. The Jest TypeScript definitions are installed in @types\jest\index.d.ts. Select the file and click the OK button.

That’s it! Now Webstorm recognises Jest describe/it/expect. O yeah!

Find the location of NPM global packages on Windows

Today I wanted to add a file from a package that I had installed globally with NPM to Webstorm. Where does NPM install the global packages on Windows? How to find the location?

As always, once you know how it is simple. Just execute the following command from cmd.

npm config ls -l | grep prefix

That will show you the location. Which is probably something like C:\Users\\AppData\Roaming\npm.

Docker on Windows tips & tricks

Just some tips & tricks on Docker on Windows I documented for myself.

Location of Docker daemon logs

The Docker daemon logs can be found in the following location.

C:\ProgramData\Docker

By default C:\ProgramData is hidden in Explorer, you need to make it visible in the options (File -> Change folder and search options, select tab View, select the option ‘Show hidden files, folders and drives’ under ‘Hidden files and folders’).

Change folder and search options