Tips for ensuring that npm only creates one instance of a dependency when it is being used by multiple projects

Struggling a bit here. I am diving into npm and configuration files for the first time. The current challenge involves setting up a vue project (though it might not be directly related to the issue) with typescript and then reusing its code and components.

Encountering two specific issues:
1. Ending up with two Vue copies - one in the library project and another in the secondary project utilizing this library.
2. Missing type definitions for Vue in the lib, which could potentially be resolved once the first problem is tackled.

My attempts so far include linking the library project using npm link, importing with relative paths, and building with vue-cli --target lib (where Vue should be externalized). However, none of these attempts have yielded positive results. Perhaps I'm missing something in my approach. I've also checked out similar libraries like Buefy, Vuetify, Vue-router, but none seem to be integrating typescript with vue-property-decorator or making use of import 'vue'.

Here's the structure:
-- some folder
  |--- lib
    |--- vue (package.json)
    |--- Test.vue
    |--- type definitions

  |--- project
    |--- vue (package.json)

The error message points towards $propertyA not being defined on Vue (Property or method "$propertyA" is not defined on the instance but referenced during render). Interestingly enough, using String.has seems to work without any issues. The standard code used by other projects that functions correctly looks like this:

<template>
    <div>{{msg}} -> {{$propertyA}}</div>
</template>
<script>
export default {
    name: 'Test',
    data: () => ({
        msg: 'TEST'
    })
}
</script>

However, when working with the below code in the library, things start to break:

<template>
    <div>{{msg}} -> {{$propertyA}}</div>
</template>
<script lang="ts">
import { Component, Vue, Prop } from 'vue-property-decorator';

@Component
export default class Test extends Vue {
    private msg = 'TEST';
}
</script>

Regarding the type definitions:

import Vue from 'vue';

declare module 'vue/types/vue' {
    export interface Vue {
        $propertyA: string;
    }
}

declare global {
    interface String {
        has: (x: string) => boolean;
    }
}

I'm uncertain about the right strategy to tackle this issue. It seems like having separate projects leads to each one having its own Vue copy, causing discrepancies such as one having $propertyA while the other does not.

Answer №1

After exploring vue-router for ideas, I successfully got it up and running. For anyone facing a similar issue, here is the solution I discovered regarding what needs to be added to the json files of the library:

  • Place your declaration file in types/index.d.ts
  • tsconfig.json:
...
"include": [
  ...  
  "types/index.d.ts"
],
  • package.json:
...
"main": "dist/**Your Lib Name**.common.js", // additional modules can be added for other outputs
"scripts": {
  ...
  "build": "vue-cli-service build --target lib --name **Your Lib Name** src/main.ts",
},
"typings": "types/index.d.ts",
"files": [
  "src",
  "dist/*.js",
  "types/*.d.ts"
],
  • run npm build
  • copy folders dist, types and package.json to node_modules/Your Lib Name in the project where you want to utilize your library

I suspect npm link doesn't function as intended due to the inclusion of the node_modules folder within the library, potentially resulting in duplicated packages, such as Vue in this case.

If you're working with Vue and wish to streamline the process by letting TypeScript generate declaration files automatically, include the following configurations:

  • tsconfig.json:
...
"declaration": true,
"declarationDir": "types_tmp/",
  • vue.config.js:
...
configureWebpack: config => {
  if(process.env.NODE_ENV === 'production') {
    config.module.rules.forEach(rule => {
      if (rule.use) {
        let idx = rule.use.findIndex(w => w.loader === 'thread-loader')
        if (idx !== -1) rule.use.splice(idx, 1)
      }
    })
  }
},
chainWebpack: config => {
  if(process.env.NODE_ENV === 'production') {
    // disable cache (not sure if this is actually useful...)
    config.module.rule("ts").uses.delete("cache-loader");
    config.module.rule("tsx").uses.delete("cache-loader");

    config.module
    .rule('ts')
    .use('ts-loader')
    .loader('ts-loader')
    .tap(opts => {
      opts.transpileOnly = false;
      opts.happyPackMode = false;
      return opts;
    });
  }
}
  • consolidate the necessary .d.ts files into types/index.d.ts

May this information be beneficial to someone who encounters a similar challenge.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Sending various kinds of generic types to React component properties

Currently, my team and I are working on a TypeScript/React project that involves creating a versatile 'Wizard' component for multi-step processes. This Wizard acts as a container, receiving an array of 'panel' component properties and p ...

How can we best organize a VueJS application to accommodate this specific logic?

I am currently working on an app that needs to display data fetched from multiple sources based on a condition. The issue I am facing is that the process of fetching, organizing, and returning the data varies depending on the source, sometimes even requiri ...

What is the proper way to create an unordered list in vue.js?

I need assistance creating an unordered list for a series of errors I am currently printing from my console. I am utilizing vue.js and finding it challenging to grasp the concept behind implementing this feature. Below, you will find the relevant code. He ...

The issue at hand is that the component is not recognized as an NgModule

I am encountering an issue with my NgModule configuration: @NgModule({ imports: [ CommonModule ], exports: [ SP21LoadingBar ], declarations: [SP21LoadingBar] }) export class SP21LoadingBarModule { } When I run the CLI, ...

Verify that each interface in an array includes all of its respective fields - Angular 8

I've recently created a collection of typed interfaces, each with optional fields. I'm wondering if there is an efficient method to verify that all interfaces in the array have their fields filled. Here's the interface I'm working wit ...

Encountering an unfamiliar browser query while attempting to view files for tailwindcss

I attempted to execute npx tailwindcss -i ./src/input.css -o ./dist/output.css --watch but encountered the following error: Error [BrowserslistError]: Unknown browser query `var updateDb = require('update-browserslist-db')`. Maybe you are using o ...

Combining URLs in Angular 6 - A Step-by-Step Guide

How can I concatenate the commonUrl from CommonClass in Angular 6 for category.service.ts? common-class.ts export class CommonClass { constructor(public commonUrl : string = 'http://localhost:3000'){}; } category.service.ts import { CommonC ...

npm is unable to install a forked git repository in its current state

Attempting to install a customized version of ng2-smart-table on my application, but npm seems to be struggling with the process. I've experimented with various commands such as npm install git+http://github.com/myusername/ng2-smart-table.git npm i ...

Angular does not recognize the boolean variable

Within my Angular component, I have declared two boolean variables: editingPercent: boolean = true; editingCap: boolean = false; In the corresponding HTML file, there is a checkbox that updates these variables based on user input: checkedChanged(e) { ...

Is it possible to utilize vue-meta without server-side rendering?

I have been experimenting with the vue-meta npm package for managing my meta tags. However, I am facing an issue where the content inside metaInfo() is not displaying correctly in Google search descriptions. metaInfo () { return { title: 'FA ...

Joi has decided against incorporating custom operators into their extended features

I am having trouble extending the joi class with custom operators. My goal is to validate MongoDB Ids, but when I try to use the extended object, I encounter the following error: error: uncaughtException: JoiObj.string(...).objectId is not a function TypeE ...

"Facing a challenge with npm? Resolve it by manually triggering the npm run jasmine command from the

After installing the jasmine npm module globally, I decided to also install it locally in the project using --save-dev. This was done with the intention of sharing code and ensuring that all team dependencies are easily accessible. The problem arises when ...

Should I use NPM or Yarn? What is the recommended approach for initiating React Native projects and handling dependencies?

Starting a new React Native project can be done by using yarn, which creates a yarn.lock file. This will set up the project like this: react-native init myProjectName However, many common libraries assume that NPM is being used, such as this one: npm in ...

Guide to uploading a recorded audio file (Blob) to a server using ReactJS

I'm having trouble using the react-media-recorder library to send recorded voice as a file to my backend. The backend only supports mp3 and ogg formats. Can anyone provide guidance on how to accomplish this task? Your help would be greatly appreciated ...

The process of adding a package using bower

After coming across a calendar that I wanted to install using bower, I realized that I needed to first install node, npm, and git. I managed to find node and git online and successfully installed them through wizards. To use bower, I knew I had to install ...

Encountered an issue when attempting to deploy ASP.NET Core / Angular app to Azure from Github repository

After creating a default project using dotnet new angular -o Homepage4, I ran the project with dotnet run and everything worked fine. I then saved the project to my GitHub repository. Now, I want to build my Azure site from the GitHub repository. In my Az ...

Issue with Datatables not loading on page reload within an Angular 7 application

Incorporating jQuery.dataTables into my Angular 7 project was a success. I installed all the necessary node modules, configured them accordingly, and added the required files to the angular.json file. Everything functioned perfectly after the initial launc ...

Which is the best choice for a large-scale production app: caret, tilde, or a fixed package.json

I am currently managing a sizeable react application in production and I find myself undecided on whether it is more beneficial to use fixed versions for my packages. Some suggest that using the caret (^) is a safer route, but I worry that this could poten ...

The issue of v-on not functioning properly when used in conjunction with a dynamically generated v-for

I am currently facing an issue with my data looping mechanism using v-for. The problem arises when trying to toggle cells into edit mode by double-clicking after adding a new entry via the 'Add a category' text box. Everything works fine without ...

Having trouble running a React project after cloning it from the repository

Just starting out with React and struggling to clone a functional React project. After cloning and navigating into the folder, I try to start with npm start but encounter the following error in my terminal: npm ERR! code ENOENT npm ERR! syscall open npm ...