Understanding the ESModule Specification: Server and Browser Implementations, Third‑Party Dependency Challenges, and Next‑Generation Web App Development
This article explains the ESModule standard, compares its server‑side (Node.js) and browser implementations, discusses compatibility issues with CommonJS, examines the difficulties of using third‑party dependencies in browsers, and outlines emerging tools such as Snowpack and Vite that leverage native ESModules.
1 ESModule Specification
Overview
Before ES6, the community created several module loading solutions, the most popular being CommonJS for servers and AMD for browsers (via third‑party libraries). ES6 introduced a native module system that satisfies the majority of CommonJS and AMD needs, becoming a universal solution for both browsers and servers.
After ES6 defined the ESModule syntax, browsers began to support it natively, and Node.js also added support.
// commonjs
const axios = require('axios')
// amd
require(['axios'], function (axios) {})
// esmodule
import axios from './node_modules/axios/axios.js'Note: The latest ECMAScript proposal has been accepted; import maps can now manage module import paths.
Server‑Side Implementation
CommonJS
Before ESModule, Node.js used its built‑in Module to implement the CommonJS system, which is not an official JavaScript standard and is unsupported by browsers.
ESModule
Node.js needed to adopt the ESModule standard while preserving compatibility with the existing CommonJS ecosystem, because most third‑party packages are still written in CommonJS.
Compatibility Issues
Because CommonJS and ESModule have fundamental design conflicts, many compatibility problems remain; readers are encouraged to search for detailed discussions.
Node.js >= v13 resolves the conflict by using the .mjs extension for ESModules and the .js extension for CommonJS, while also allowing "type": "module" in package.json to treat .js files as ESModules.
// esmA/index.mjs
export default null
// esmB/index.js
export default null
// esmB/package.json
{
"type": "module"
}Browser Implementation
Modern Browser Support
All major browsers (except IE) have implemented native ESModule loading for the past two‑three years.
Example repository: https://github.com/mdn/js-examples/tree/master/modules/basic-modules
2 Third‑Party Dependency Dilemma
Node.js Module Resolution
Node.js allows importing third‑party packages by name without a relative path, automatically resolving the node_modules directory and the entry point defined in package.json .
const axios = require('axios') // => automatically resolves node_modules path
const axios = require('/User/xxxx/workspace/node_modules/axios') // => resolves package.json entry
const axios = require('/User/xxxx/workspace/node_modules/axios/axios.js')The core resolver performs automatic path concatenation, entry field lookup, and extension/index completion.
Webpack Module Resolution
Webpack bundles all third‑party dependencies into a single bundle.js . Historically it injected Node.js‑style CommonJS handling so that developers could use the same syntax in both Node and browser builds.
However, Webpack’s CommonJS emulation is a separate implementation that mimics Node’s behavior for compatibility.
Browser Module Resolution
Browsers do not support native CommonJS loading; even with ESModule support, they cannot directly consume CommonJS packages, prompting the need for new tooling.
3 Next‑Generation Web App Development Model
To avoid the incompatibility of CommonJS packages with native ESModules, tools convert CommonJS modules to ESModules.
CommonJS to ESModule Converters
JSPM (https://jspm.dev/@babel/core)
Skypack (formerly Pika) (http://cdn.skypack.dev/@babel/core)
ESM.sh (http://esm.sh/@babel/core)
These tools use bundlers such as Rollup or esbuild to rewrite module syntax and rewrite import paths.
const axios = reuqire('axios')
module.exports = axios
// =>
import axios from '/esm/axios.js'
export default axiosIn an HTML file you can then load the transformed module directly:
However, using many third‑party packages without bundling leads to a “request explosion” – e.g., loading a UI library like Ant Design may trigger thousands of network requests.
Snowpack & Vite
These tools split third‑party dependencies from source code, bundling dependencies only once and letting the browser handle them via native ESModule loading, dramatically improving dev‑server start‑up time and hot‑module replacement performance.
4 Adoption Challenges
Despite the benefits, ecosystem maturity, incomplete CommonJS‑to‑ESModule conversion, and dynamic import semantics hinder widespread adoption.
Ecosystem Issues
Many features available in Webpack are not yet supported by newer tools.
Conversion Problems
Most npm packages still ship only CommonJS versions; converting them to ESModules introduces complex edge cases, such as handling dynamic exports, named vs default exports, and legacy compatibility code (e.g., exports.__esModule ).
// moduleA.js (CommonJS dynamic export)
init()
function init() {
exports.a = 1
}
// index.js
require('./moduleA') // => { a: 1 }
// ESModule static export (valid)
export const a = 1
// ESModule static export (invalid – dynamic)
init()
function init() {
export const a = 1
}In CommonJS, exports === module.exports blurs the distinction between named and default exports, whereas ESModules enforce explicit named and default export semantics.
// module.js (ESModule)
export const a = 1
export default { a: 2 }
// index.js
import { a } from './module.js' // => 1
import a from './module.js' // => { a: 2 }
import * as a from './module.js' // => { a: 1, default: { a: 2 } }Proposed Solutions
The ByteDance Web Infra team is actively working on advancing ESModule adoption and will share further solutions in upcoming posts.
Follow the ByteDance Web Infra public account for updates.
ByteDance Web Infra
ByteDance Web Infra team, focused on delivering excellent technical solutions, building an open tech ecosystem, and advancing front-end technology within the company and the industry | The best way to predict the future is to create it
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.