惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

F
Full Disclosure
Stack Overflow Blog
Stack Overflow Blog
H
Help Net Security
Microsoft Azure Blog
Microsoft Azure Blog
The GitHub Blog
The GitHub Blog
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Recorded Future
Recorded Future
Y
Y Combinator Blog
Cloudbric
Cloudbric
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
S
Schneier on Security
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
C
Cybersecurity and Infrastructure Security Agency CISA
TaoSecurity Blog
TaoSecurity Blog
Security Latest
Security Latest
N
News and Events Feed by Topic
Hacker News - Newest:
Hacker News - Newest: "LLM"
D
DataBreaches.Net
Security Archives - TechRepublic
Security Archives - TechRepublic
H
Hacker News: Front Page
C
Cisco Blogs
L
LangChain Blog
aimingoo的专栏
aimingoo的专栏
Recent Commits to openclaw:main
Recent Commits to openclaw:main
V
Vulnerabilities – Threatpost
L
LINUX DO - 最新话题
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Google Online Security Blog
Google Online Security Blog
D
Darknet – Hacking Tools, Hacker News & Cyber Security
A
About on SuperTechFans
www.infosecurity-magazine.com
www.infosecurity-magazine.com
Jina AI
Jina AI
C
CXSECURITY Database RSS Feed - CXSecurity.com
Schneier on Security
Schneier on Security
T
Tenable Blog
N
News and Events Feed by Topic
W
WeLiveSecurity
有赞技术团队
有赞技术团队
AI
AI
爱范儿
爱范儿
大猫的无限游戏
大猫的无限游戏
Latest news
Latest news
T
The Blog of Author Tim Ferriss
S
Security Affairs
Know Your Adversary
Know Your Adversary
Simon Willison's Weblog
Simon Willison's Weblog
G
GRAHAM CLULEY
Google DeepMind News
Google DeepMind News
The Cloudflare Blog

Maxime Heckel's Blog

On Rendering the Sky, Sunsets, and Planets - The Blog of Maxime Heckel Shades of Halftone - The Blog of Maxime Heckel Field Guide to TSL and WebGPU - The Blog of Maxime Heckel On Shaping Light: Real-Time Volumetric Lighting with Post-Processing and Raymarching for the Web - The Blog of Maxime Heckel Speaking at Figma Config 2025 - The Blog of Maxime Heckel Post-Processing Shaders as a Creative Medium - The Blog of Maxime Heckel On Crafting Painterly Shaders - The Blog of Maxime Heckel The Art of Dithering and Retro Shading for the Web - The Blog of Maxime Heckel Moebius-style post-processing and other stylized shaders - The Blog of Maxime Heckel Shining a light on Caustics with Shaders and React Three Fiber - The Blog of Maxime Heckel Real-time dreamy Cloudscapes with Volumetric Raymarching - The Blog of Maxime Heckel Painting with Math: A Gentle Study of Raymarching - The Blog of Maxime Heckel Building a magical AI-powered semantic search from scratch - The Blog of Maxime Heckel Beautiful and mind-bending effects with WebGL Render Targets - The Blog of Maxime Heckel Refraction, dispersion, and other shader light effects - The Blog of Maxime Heckel The magical world of Particles with React Three Fiber and Shaders - The Blog of Maxime Heckel The Study of Shaders with React Three Fiber - The Blog of Maxime Heckel Building a Design System from scratch - The Blog of Maxime Heckel Everything about Framer Motion layout animations - The Blog of Maxime Heckel Building a Vaporwave scene with Three.js - The Blog of Maxime Heckel Cubic Bézier: from math to motion - The Blog of Maxime Heckel First steps with GPT-3 for frontend developers - The Blog of Maxime Heckel Building the perfect GitHub CI workflow for your frontend team - The Blog of Maxime Heckel Migrating to Next.js - The Blog of Maxime Heckel Static Tweets with MDX and Next.js - The Blog of Maxime Heckel Advanced animation patterns with Framer Motion - The Blog of Maxime Heckel Scrollspy demystified - The Blog of Maxime Heckel The Power of Composition with CSS Variables - The Blog of Maxime Heckel My first failed SwiftUI project - The Blog of Maxime Heckel Guide to creating animations that spark joy with Framer Motion - The Blog of Maxime Heckel Using Shortcuts and serverless to build a personal Apple Health API - The Blog of Maxime Heckel SEO mistakes I've made and how I fixed them - The Blog of Maxime Heckel Going native: SwiftUI from the perspective of a React developer - The Blog of Maxime Heckel Build your own preview deployment service - The Blog of Maxime Heckel The little guide to CI/CD for frontend developers - The Blog of Maxime Heckel Immigrating to the US - The Blog of Maxime Heckel The physics behind spring animations - The Blog of Maxime Heckel Generate screenshots of your code with a serverless function - The Blog of Maxime Heckel How to use Framer Motion with Emotion styled-components - The Blog of Maxime Heckel Data Fetching with NextJS: What I learned - The Blog of Maxime Heckel Learning in public - The Blog of Maxime Heckel Fixing the dark mode flash issue on server rendered websites - The Blog of Maxime Heckel Running scheduled cross-browser end-to-end tests on Github CI - The Blog of Maxime Heckel How I built my first custom ESLint rule - The Blog of Maxime Heckel React Lazy: a take on preloading views - The Blog of Maxime Heckel Automated UI accessibility testing with Cypress - The Blog of Maxime Heckel Building a GraphQL wrapper for the Docker API - The Blog of Maxime Heckel Switching off the lights - Adding dark mode to your React app - The Blog of Maxime Heckel Getting started with Typescript on Gatsby - The Blog of Maxime Heckel Rebuilding Redux with Hooks and Context - The Blog of Maxime Heckel Asynchronous rendering with React - The Blog of Maxime Heckel Using Flow generics to type generic React components - The Blog of Maxime Heckel How to efficiently type your styled-components with Flow - The Blog of Maxime Heckel How I got started with Kubernetes on GKE - The Blog of Maxime Heckel React sub-components Part 3: Whitelisting sub-components with flow - The Blog of Maxime Heckel React sub-components Part 2: Using the new Context API - The Blog of Maxime Heckel React sub-components - The Blog of Maxime Heckel Running Golang tests with Jest - The Blog of Maxime Heckel No title No title
How to fix NPM link duplicate dependencies issues - The Blog of Maxime Heckel
Maxime Heckel · 2020-03-31 · via Maxime Heckel's Blog

This post is about an issue that keeps coming on several of my projects involving third-party libraries linked locally with npm link: Duplicate dependencies. I ran into this issue multiple times, whether it was when working on a styled-components library even on some simple packages using only React as a peer dependency. I thought it could be worth writing about with an example it and explain why it happens and how I solve it.

Context of the problem

As an example, to illustrate the problem, we can consider a main React project called "myApp" bundled with Webpack. The app will be themed through emotion-theming and Emotion which use React Context to inject a theme object to be used by the entire app and any styled-components which are consumers of that “theme context”.

Now let’s consider a third-party package that will be consumed by our app, called "myLib". The "myLib" package has two important specs:

  • It has React and Emotion as peerDependencies meaning that we want the "myLib" to use whatever version of React or Emotion the consumer app is using.

  • It has React and Emotion as devDependencies for development purposes. These are installed locally as we're actively working on this package.

  • It contains a set of Emotion styled-components such as Buttons, Dropdowns, Lists, that have colors, background colors, or fonts set by the theme of "myApp".

Here's an example of a component exported by "myLib" using a value of the theme provided by "myApp":

Example of styled component defined in myLib.

1

import React from 'react';

2

import styled from '@emotion/styled';

4

const StyledButton = styled('button')`

5

background-color: ${(props) => props.theme.colors.blue};

6

border-color: ${(props) => props.theme.colors.black};

9

export { StyledButton };

When developing "myLib" we don't want to have to publish a new version of the dependency every time we make a change to use it in "myApp". Thus we use npm link to use the local version of our package. Running this should technically work straight out of the box right? However, if we try to run this setup, nothing renders, and we end up with the following error:

1

Cannot read property 'colors' of undefined

Even more bizarre, if we try to use the published version of "myLib" instead of the locally linked one, we do not get the error showcased above.

What is happening?

We know that the "production" setup (the one where we used the published version of "myLib") works: the theme is declared and passed through a React Context in "myApp" and is accessible in "myLib" as the components of this package are imported within that same context.

Schema representing a styled component 'StyledButton' from myLib rendered within the Emotion Theme Provider of myApp

Schema representing a styled component 'StyledButton' from myLib rendered within the Emotion Theme Provider of myApp

Corresponding code snippet from myApp rendering StyledButton

1

import React from 'react';

2

import { ThemeProvider } from 'emotion-theming';

4

import { StyledButton } from 'myLib';

14

<ThemeProvider theme={theme}>

16

<StyledButton>Click Me!</StyledButton>

If we try to add a debugger or to run console.log(theme) in "myLib" when npm linked we can see that it is not defined. The context value is somehow not accessible. Troubleshooting this issue will require us to look outside of our app and into how the node_modules installed are architected. The following schema shows how "myApp" and "myLib" share their dependencies when "myLib" is installed:

The schema below, on the other hand, showcases how they share their dependencies when "myLib" is linked:

5

│ └── myLib <- NPM linked package are "symlinked" to their local location

8

├── React <- Local devDependency

9

└── Emotion <- Local devDependency

And that is where we can find the origin of our problem. In the second case, "myApp" and "myLib" use their own React and Emotion dependencies despite having specified these two as peer dependencies in the package.json of "myLib". Even if imported, when using React or Emotion within "myLib" we end up using the ones specified as development depencencies.

This means that the React context used by "myApp" is different than the one that "myLib" uses to get the theme variable. To make this work, we need them to use the same "instance of React".

The fix

To solve this issue, we have to take a look at Webpack. From its documentation, we can see that Webpack can change how modules are resolved when using the resolve.alias option in a Webpack config. Adding such a field lets us declare how to resolve an arbitrary set of packages by providing a path for each of them (I often use this to override long or unpractical import statements). The code snippet below showcases the solution to our problem by setting the react and @emotion-core dependency paths to the node_modules folder of "myApp".

Example of using resolve.alias in a Webpack config file.

4

react: path.resolve('./node_modules/react'),

5

@emotion/core: path.resolve('./node_modules/@emotion/core')

With this change, whether "myLib" is installed or linked to "myApp", it will have a similar dependency tree than the one described in schema 1 above. Setting this option properly might also fix some issues involving hooks described in the React docs which, in a setup similar than the one featured here, is often due to having multiple versions of React used within the same app.

We can now continue to develop our package without any duplicate dependencies issues 🎉. This is obviously one of many ways of fixing this problem, but it's the one that has fixed so many of my problems in the past, and I keep getting back to it every so often.

PS: In these weird times (I'm writing these words during the Covid-19 outbreak) remember to stay safe and stay home!