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

gyp ALERT: Received a warning of EACCES when attempting to install angular/cli

Working on Ubuntu 17.04 with Node 8.9.4 LTS installed, I encountered an error loop while trying to install Angular CLI using npm. gyp WARN EACCES user "root" does not have permission to access the dev dir "/usr/lib/node_modules/@angular/cli/node_modules/n ...

Issue with MongoDB $push within an Array of Arrays: The shorthand property 'elements' does not have a value available in scope

I am encountering an issue while trying to insert data into Elements in MongoDB using TypeScript. Any suggestions on how to resolve this problem? Attempt 1 Error: I am receiving an error message stating "No value exists in scope for the shorthand property ...

Challenges when utilizing the command "npm install" within a programmatic context

I'm really excited about the potential of using "npm programmatically," but I've hit a roadblock. The function "npm.load" doesn't seem to be triggering for me. None of the console logs inside of my "npm.load" or "npm.commands.install" functi ...

How to eliminate the hash from a particular page in VueJS

My dilemma is quite similar to the one discussed in this Vue router thread on removing hash on certain pages I need to configure the hash mode for all pages except for mysite.com/success. This specific page is accessed via redirect from ...

I am trying to replace the buttons with a dropdown menu for changing graphs, but unfortunately my function does not seem to work with the <select> element. It works perfectly fine with buttons though

I am currently working on my html and ts code, aiming to implement a dropdown feature for switching between different graphs via the chartType function. The issue I am facing is that an error keeps popping up stating that chartType is not recognized as a ...

The identifier 'name' is not found in the specified data type

How can I resolve the error 'Property 'name' does not exist on type' in TypeScript? Here is the code block : **Environment.prod.ts** export const environment = { production: true, name:"(Production)", apiUrl: 'https://tes ...

Error in Next.js only occurs during the production build when using styled components, tailwind CSS, and twin styling

After successfully building my application in development mode, I encountered an error when attempting a production build. The error appears on the image linked below: https://i.stack.imgur.com/sNr2v.png I suspect that the issue lies within the _document ...

Tips for capturing a broadcasted signal

Currently, I am utilizing Vue3 with the option API. In my code snippet below, specifically in toggle-1.vue, I am emitting an event called onClsDigitizePolygonInteractionInstanceInit. I am interested in understanding how to then listen for or receive this e ...

Encountering an issue while attempting to downgrade NPM's version

After attempting to update the NPM version for certain dependencies, I now find myself in need of downgrading to an older version. Unfortunately, I am encountering difficulties in doing so. Current NPM version: npm v9.8.1 ERROR: npm v9.8.1 is not compati ...

The impact of redefining TypeScript constructor parameter properties when inheriting classes

Exploring the inner workings of TypeScript from a more theoretical perspective. Referencing this particular discussion and drawing from personal experiences, it appears that there are two distinct methods for handling constructor parameter properties when ...

How to navigate between "v-text-fields" using arrow keys in Vue.js

I am currently working on a Vue and Vuetify application. I am wondering if there is a way to allow users to navigate between "v-text-fields" using directional keys for improved usability. <v-text-field ...

What is the significance of the npm -D flag?

Planning on adding this npm package and the installation instructions include using npm install -D load-grunt-config. Can someone explain what the -D flag signifies in this command? ...

How can we effectively divide NGXS state into manageable sections while still allowing them to interact seamlessly with one another?

Background of the inquiry: I am in the process of developing a web assistant for the popular party game Mafia, and my objective is to store each individual game using NGXS. The GitLab repository for this project can be found here. The game includes the f ...

What are some ways I can enhance the typography within Material UI?

Currently, I am in the process of developing a custom theme utilizing createMuiTheme. However, my application requires more typography variants than what Material UI provides out of the box. I need to extend the typography so that it aligns with my specifi ...

Is it possible to bind parameters in the select clause using TypeORM?

I'm currently working on implementing a search feature using the pg_trgm module in my PostgreSQL project built with TypeScript and TypeOrm. My SQL query that works for me looks like this: SELECT t, similarity(t, 'word') AS sml FROM test_t ...

Best practices for managing backend errors with Next.js 14

Currently, I am developing a project in Next.js 14 and I have set up my API requests using fetch within a handler.tsx file as shown below: async function getPositions() { const response = await fetch( process.env.BASE_API_URL + "/positions?enabl ...

Top tip for implementing toggle functionality with a specified duration in React.js

I am incorporating React into my web application. I understand how to implement the toggle logic - maintaining a boolean value in my state and updating it when I interact with the toggle trigger. However, I am struggling with how to add animation to this ...

How to remove various items from Google Cloud Storage with node.js

I'm looking to mass delete multiple objects from Google Cloud Storage. Currently, I've been deleting one object at a time using the following code: var gcloud = require('gcloud')({ projectId: "sampleProject1" }); var gcs = gcloud.sto ...

Encountering a problem in React.js and Typescript involving the spread operator that is causing an error

Could someone assist me with my current predicament? I attempted to work with TypeScript and utilize the useReducer hook. const initialState = { a: "a" }; const [state, dispatch] = useReducer(reducer, {...initialState}); I keep encountering an error ...

Implement flow checking within react-slingshot

I am currently working on a project based on a popular React boilerplate available at the following link: https://github.com/coryhouse/react-slingshot My goal is to seamlessly integrate Flow into the npm start script. This means that when I run the start ...