As you might have already seen, I am MUCH more used to Python, C, etc than modern JavaScript. Things have changed a lot since I last used it for anything but client side.
Problem is, I am doing some projects with a gang of lads who have pivoted from WordPress to using NodeJS, so in the deep end I go!
During development, we ran into repeated issues using certain open-source libraries because of how JavaScript modules are loaded.
There are two main styles of loading code in JavaScript:
require()
is the older "CommonJS" method (used in traditional Node.js)import ... from
is the newer "ES Module" method (used in modern projects and browsers)
What Are ES Modules and How Are They Different
ES Modules (ECMAScript Modules) are the modern standard for structuring JavaScript code. They are designed to be consistent, support better tooling, and match how code is shared on the web.
Key differences:
Syntax:
- CommonJS:
const fs = require('fs');
- ES Module:
import fs from 'fs';
- CommonJS:
Exporting:
- CommonJS:
module.exports = myFunction;
- ES Module:
export default myFunction;
- CommonJS:
Loading:
- CommonJS loads modules synchronously (one at a time)
- ES Modules are loaded asynchronously and follow stricter rules
Scope:
- CommonJS runs in a local scope
- ES Modules run in strict mode by default
Why This Matters
If your project is set to use ES Modules (by adding "type": "module"
to package.json
), you can no longer use require()
. Many older npm libraries still expect to be loaded with require()
, and mixing the two formats leads to errors or missing functionality.
Real Example That Caused Problems
We tried to use this with an ES Module project:
const unified = require('unified'); // Not allowed in ES Module mode
So we tried:
import unified from 'unified'; // This threw "unified is not a function"
The correct version was:
import { unified } from 'unified'; // Named import works correctly
Another example that failed:
const remarkDocx = require('remark-docx'); // Not allowed in ES Module projects
This also failed:
import remarkDocx from 'remark-docx'; // remarkDocx is not a function
We ended up replacing the library entirely with one that supports modern imports cleanly.
How You Might Run Into This
You’ll likely hit these issues if you:
- Use
"type": "module"
in yourpackage.json
- Try to use
require()
in a modern project - Use Electron, Vite, Astro, or other modern tools that expect ES Module format
- Mix imports and requires without checking the library’s export format
Common error messages:
require is not defined
x is not a function
Cannot set properties of undefined
Cannot find package 'x'
even though it’s installed
What We Did to Fix It
- Used
await import('package')
instead ofrequire('package')
- Accessed
.default
only when needed, and only on known CommonJS packages - Avoided mixing both
import
andrequire
in the same file - Replaced
remark-docx
withdocx
for exporting Word documents, because it works cleanly with ES Modules
Bottom Line
Some open-source libraries don’t fully support the modern JavaScript format we use in this app. That caused strange bugs and crashes, especially when exporting to Word with images. We resolved the issues by changing how we load code and switching to a better-supported export library.
This change makes the app more stable and easier to maintain over time but it is a heck of a mind-eff for people who are new to this kind of JS development and just want to go back to the cozy world of basically anything else!