Learning by fixing: Node.js, modules and packages

The mystery

  • it only happens with the Lozenge component, which uses Compiled - a new css-in-js library
  • it was working locally because the version of Node in the CI was newer than on my local machine.

ESM or CJS

import React from 'react';
const React = require('react').default;

Modules resolution and packages

...var _react = _interopRequireDefault(require("react"));

var _runtime = require("@compiled/react/runtime");

var _constants = require("@atlaskit/theme/constants");
...
  • Compiled’s runtime is indeed required by the Lozenge, as expected
  • It is required as a deep import from @compiled/react package
  • package.json file at the root, with all the usual fields that you’d expect from an npm package, like name, version or dependencies;
  • dist folder, with CJS and ESM code for the entire package
  • runtime folder, also with package.json file. This one looks weird, it only has a few fields, and all of them are relative links to files inside dist folder. No name, version, etc
{
"main": "../dist/cjs/runtime.js",
"module": "../dist/esm/runtime.js",
"browser": "../dist/browser/runtime.js",
"types": "../dist/esm/runtime.d.ts"
}
  • /node_modules/@atlaskit/lozenge/dist/cjs/Lozenge
  • /node_modules/@atlaskit/lozenge/dist/cjs
  • /node_modules/@atlaskit/lozenge/dist
  • /node_modules/@atlaskit/lozenge
{
"main": "../dist/cjs/runtime.js",
"module": "../dist/esm/runtime.js",
"browser": "../dist/browser/runtime.js",
"types": "../dist/esm/runtime.d.ts"
}
  • all the fields are correct and on their places
  • both CJS and ESM code is there
  • all the packages are on their right places and according to node resolution algorithm correct code should be used
  • the build fails on the new version of Node but works on the older one

Package exports

  • whatever happens is related to ESM specifically
  • and since we verified that all the fields and code are correct, then there has to be something explicit in Compiled, related to ESM, that overrides the default node behaviour
"exports": {
".": "./dist/esm/index.js",
"./babel-plugin": "./dist/esm/babel-plugin.js",
"./runtime": "./dist/esm/runtime.js"
},
  • parse the required path (@compiled/react/runtime), extract from it package scope (@compiled), package name (react) and subpath (everything else from the path, i.e. /runtime)
  • If there is a package.json available in the path that is a combination of scope + name (@compiled/react), then it extracts exports from it and tries to match it with the required path
"exports": {
...
"./runtime": {
"import": "./dist/esm/runtime.js",
"require": "./dist/cjs/runtime.js"
}
}
  • find @compiled/react folder in project’s node_modules
  • parse node_modules/@compiled/react/package.json file
  • extract exports field from it
  • match ./runtime entry with our requested path
  • detect that the request comes from CJS file and resolve the correct ./dist/cjs/runtime.js file
  • find @compiled/react/runtime folder in project’s node_modules
  • parse node_modules/@compiled/react/runtime/package.json file
  • extract main field from it
  • resolve the correct ../dist/cjs/runtime.js file

--

--

--

Frontend architect, coder. Love solving problems, fixing things and writing in-depth tech articles: https://www.developerway.com

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

Solana Web3 Tutorial (3) —Create a Program Derived Account(PDA)

Node.js — module.exports vs. exports

Parsin’ the Interruption

Dealing with URL query parameters in Javascript using URLSearchParams

Rename React Native Project Using Single Command

Do you really need jQuery?

How to build an HTML5 game’s controller with Arduino, NodeJS and socket.io — Part 1

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Nadia Makarevich

Nadia Makarevich

Frontend architect, coder. Love solving problems, fixing things and writing in-depth tech articles: https://www.developerway.com

More from Medium

Fetch-API finally in NodeJS

React project structure for scale: decomposition, layers and hierarchy

React 18 Interesting Features to Utilize in Day-to-Day Coding

React is always a best choice to create SPA application. React recently launched v18 where it brought many important features which should be used in new React based project development.

Build dynamic breadcrumb routes and child routes with matchPath in React Router v6